Add authorization section
This commit is contained in:
parent
0e88e0196d
commit
974dec9db4
16 changed files with 484 additions and 123 deletions
|
@ -86,10 +86,18 @@ export const buttonMessages = defineMessages({
|
|||
defaultMessage: "Cancel",
|
||||
description: "button"
|
||||
},
|
||||
clear: {
|
||||
defaultMessage: "Clear",
|
||||
description: "button"
|
||||
},
|
||||
confirm: {
|
||||
defaultMessage: "Confirm",
|
||||
description: "button"
|
||||
},
|
||||
create: {
|
||||
defaultMessage: "Create",
|
||||
description: "button"
|
||||
},
|
||||
delete: {
|
||||
defaultMessage: "Delete",
|
||||
description: "button"
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
import Button from "@material-ui/core/Button";
|
||||
import Card from "@material-ui/core/Card";
|
||||
import CardContent from "@material-ui/core/CardContent";
|
||||
import makeStyles from "@material-ui/core/styles/makeStyles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import React from "react";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import Hr from "@saleor/components/Hr";
|
||||
import { buttonMessages } from "@saleor/intl";
|
||||
import { Plugin_plugin_configuration } from "@saleor/plugins/types/Plugin";
|
||||
import { isSecretField } from "@saleor/plugins/utils";
|
||||
import { ConfigurationTypeFieldEnum } from "@saleor/types/globalTypes";
|
||||
|
||||
interface PluginAuthorizationProps {
|
||||
fields: Plugin_plugin_configuration[];
|
||||
onClear: (field: string) => void;
|
||||
onEdit: (field: string) => void;
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
button: {
|
||||
marginRight: theme.spacing()
|
||||
},
|
||||
hr: {
|
||||
margin: theme.spacing(2, 0)
|
||||
},
|
||||
item: {
|
||||
alignItems: "center",
|
||||
display: "flex"
|
||||
},
|
||||
spacer: {
|
||||
flex: 1
|
||||
}
|
||||
}));
|
||||
|
||||
const PluginAuthorization: React.FC<PluginAuthorizationProps> = props => {
|
||||
const { fields, onClear, onEdit } = props;
|
||||
|
||||
const classes = useStyles(props);
|
||||
const intl = useIntl();
|
||||
|
||||
const secretFields = fields.filter(field =>
|
||||
isSecretField(fields, field.name)
|
||||
);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Authorization",
|
||||
description: "section header"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
{secretFields.map((field, fieldIndex) => (
|
||||
<>
|
||||
<div className={classes.item} key={field.name}>
|
||||
{field.type === ConfigurationTypeFieldEnum.SECRET ? (
|
||||
<div>
|
||||
<Typography variant="body1">{field.label}</Typography>
|
||||
{field.value !== null && (
|
||||
<Typography>**** {field.value}</Typography>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<Typography variant="body1">{field.label}</Typography>
|
||||
)}
|
||||
<div className={classes.spacer} />
|
||||
{field.value === null ? (
|
||||
<Button
|
||||
className={classes.button}
|
||||
color="primary"
|
||||
onClick={() => onEdit(field.name)}
|
||||
>
|
||||
<FormattedMessage {...buttonMessages.create} />
|
||||
</Button>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
className={classes.button}
|
||||
color="primary"
|
||||
onClick={() => onClear(field.name)}
|
||||
>
|
||||
<FormattedMessage {...buttonMessages.clear} />
|
||||
</Button>
|
||||
<Button color="primary" onClick={() => onEdit(field.name)}>
|
||||
<FormattedMessage {...buttonMessages.edit} />
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{fieldIndex !== secretFields.length - 1 && (
|
||||
<Hr className={classes.hr} />
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
PluginAuthorization.displayName = "PluginAuthorization";
|
||||
export default PluginAuthorization;
|
2
src/plugins/components/PluginAuthorization/index.ts
Normal file
2
src/plugins/components/PluginAuthorization/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./PluginAuthorization";
|
||||
export * from "./PluginAuthorization";
|
|
@ -9,6 +9,7 @@ import { ConfigurationTypeFieldEnum } from "@saleor/types/globalTypes";
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { Plugin_plugin_configuration } from "@saleor/plugins/types/Plugin";
|
||||
import { FormData } from "../PluginsDetailsPage";
|
||||
|
||||
interface PluginSettingsProps {
|
||||
|
@ -16,19 +17,26 @@ interface PluginSettingsProps {
|
|||
errors: FormErrors<"name" | "configuration">;
|
||||
disabled: boolean;
|
||||
onChange: (event: React.ChangeEvent<any>) => void;
|
||||
fields: Array<{
|
||||
name: string;
|
||||
type: ConfigurationTypeFieldEnum | null;
|
||||
value: string;
|
||||
helpText: string | null;
|
||||
label: string | null;
|
||||
}>;
|
||||
fields: Plugin_plugin_configuration[];
|
||||
}
|
||||
|
||||
const useStyles = makeStyles(() => ({
|
||||
const useStyles = makeStyles(theme => ({
|
||||
authItem: {
|
||||
display: "flex"
|
||||
},
|
||||
button: {
|
||||
marginRight: theme.spacing()
|
||||
},
|
||||
item: {
|
||||
paddingBottom: 10,
|
||||
paddingTop: 10
|
||||
"&:not(:last-child)": {
|
||||
marginBottom: theme.spacing(3)
|
||||
}
|
||||
},
|
||||
itemLabel: {
|
||||
fontWeight: 500
|
||||
},
|
||||
spacer: {
|
||||
flex: 1
|
||||
}
|
||||
}));
|
||||
|
||||
|
@ -41,6 +49,7 @@ const PluginSettings: React.FC<PluginSettingsProps> = ({
|
|||
}) => {
|
||||
const classes = useStyles({});
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
|
@ -50,35 +59,40 @@ const PluginSettings: React.FC<PluginSettingsProps> = ({
|
|||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
{data.configuration.map((configuration, index) => (
|
||||
<div className={classes.item} key={index}>
|
||||
{fields[index].type === ConfigurationTypeFieldEnum.STRING && (
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
error={!!errors.name}
|
||||
helperText={fields[index].helpText}
|
||||
label={fields[index].label}
|
||||
name={configuration.name}
|
||||
fullWidth
|
||||
value={configuration.value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
{fields[index].type === ConfigurationTypeFieldEnum.BOOLEAN && (
|
||||
<ControlledCheckbox
|
||||
name={configuration.name}
|
||||
label={fields[index].label}
|
||||
checked={
|
||||
typeof configuration.value !== "boolean"
|
||||
? configuration.value === "true"
|
||||
: configuration.value
|
||||
}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{data.configuration.map(field => {
|
||||
const fieldData = fields.find(
|
||||
configField => configField.name === field.name
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={classes.item} key={field.name}>
|
||||
{fieldData.type === ConfigurationTypeFieldEnum.BOOLEAN ? (
|
||||
<ControlledCheckbox
|
||||
name={field.name}
|
||||
label={fieldData.label}
|
||||
checked={
|
||||
typeof field.value !== "boolean"
|
||||
? field.value === "true"
|
||||
: field.value
|
||||
}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
/>
|
||||
) : (
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
error={!!errors.name}
|
||||
helperText={fieldData.helpText}
|
||||
label={fieldData.label}
|
||||
name={field.name}
|
||||
fullWidth
|
||||
value={field.value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import makeStyles from "@material-ui/core/styles/makeStyles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
|
@ -13,7 +14,12 @@ import { ConfigurationItemInput } from "@saleor/types/globalTypes";
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import Hr from "@saleor/components/Hr";
|
||||
import { ChangeEvent } from "@saleor/hooks/useForm";
|
||||
import { isSecretField } from "@saleor/plugins/utils";
|
||||
import { Plugin_plugin } from "../../types/Plugin";
|
||||
import PluginAuthorization from "../PluginAuthorization";
|
||||
import PluginInfo from "../PluginInfo";
|
||||
import PluginSettings from "../PluginSettings";
|
||||
|
||||
|
@ -28,27 +34,49 @@ export interface PluginsDetailsPageProps {
|
|||
plugin: Plugin_plugin;
|
||||
saveButtonBarState: ConfirmButtonTransitionState;
|
||||
onBack: () => void;
|
||||
onClear: (field: string) => void;
|
||||
onEdit: (field: string) => void;
|
||||
onSubmit: (data: FormData) => void;
|
||||
}
|
||||
|
||||
const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = ({
|
||||
disabled,
|
||||
errors,
|
||||
plugin,
|
||||
saveButtonBarState,
|
||||
onBack,
|
||||
onSubmit
|
||||
}) => {
|
||||
const useStyles = makeStyles(
|
||||
{
|
||||
spacer: {
|
||||
gridColumnEnd: "span 2"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "PluginsDetailsPage"
|
||||
}
|
||||
);
|
||||
|
||||
const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = props => {
|
||||
const {
|
||||
disabled,
|
||||
errors,
|
||||
plugin,
|
||||
saveButtonBarState,
|
||||
onBack,
|
||||
onClear,
|
||||
onEdit,
|
||||
onSubmit
|
||||
} = props;
|
||||
|
||||
const classes = useStyles(props);
|
||||
const intl = useIntl();
|
||||
const initialForm: FormData = {
|
||||
active: maybe(() => plugin.active, false),
|
||||
configuration: maybe(() => plugin.configuration, [])
|
||||
configuration: maybe(() =>
|
||||
plugin.configuration.filter(
|
||||
field => !isSecretField(plugin.configuration, field.name)
|
||||
)
|
||||
)
|
||||
};
|
||||
|
||||
return (
|
||||
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}>
|
||||
{({ data, errors, hasChanged, submit, set, triggerChange }) => {
|
||||
const onChange = event => {
|
||||
const onChange = (event: ChangeEvent) => {
|
||||
const newData = {
|
||||
active: data.active,
|
||||
configuration: data.configuration
|
||||
|
@ -94,7 +122,7 @@ const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = ({
|
|||
<Typography>
|
||||
{intl.formatMessage({
|
||||
defaultMessage:
|
||||
"These are general information about your store. They define what is the URL of your store and what is shown in brow sers taskbar."
|
||||
"These are general information about your store. They define what is the URL of your store and what is shown in browsers taskbar."
|
||||
})}
|
||||
</Typography>
|
||||
</div>
|
||||
|
@ -106,6 +134,7 @@ const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = ({
|
|||
/>
|
||||
{data.configuration && (
|
||||
<>
|
||||
<Hr className={classes.spacer} />
|
||||
<div>
|
||||
<Typography variant="h6">
|
||||
{intl.formatMessage({
|
||||
|
@ -120,13 +149,27 @@ const PluginsDetailsPage: React.FC<PluginsDetailsPageProps> = ({
|
|||
})}
|
||||
</Typography>
|
||||
</div>
|
||||
<PluginSettings
|
||||
data={data}
|
||||
fields={maybe(() => plugin.configuration, [])}
|
||||
errors={errors}
|
||||
disabled={disabled}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<div>
|
||||
<PluginSettings
|
||||
data={data}
|
||||
fields={maybe(() => plugin.configuration, [])}
|
||||
errors={errors}
|
||||
disabled={disabled}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<CardSpacer />
|
||||
{maybe(() =>
|
||||
plugin.configuration.some(field =>
|
||||
isSecretField(plugin.configuration, field.name)
|
||||
)
|
||||
) && (
|
||||
<PluginAuthorization
|
||||
fields={plugin.configuration}
|
||||
onClear={onClear}
|
||||
onEdit={onEdit}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
|
|
|
@ -30,7 +30,7 @@ export const plugin: Plugin_plugin = {
|
|||
label: "Username or account",
|
||||
name: "Username or account",
|
||||
type: ConfigurationTypeFieldEnum.STRING,
|
||||
value: ""
|
||||
value: "avatax_user"
|
||||
},
|
||||
{
|
||||
__typename: "ConfigurationItem",
|
||||
|
@ -38,8 +38,32 @@ export const plugin: Plugin_plugin = {
|
|||
label: "Password or license",
|
||||
name: "Password or license",
|
||||
type: ConfigurationTypeFieldEnum.STRING,
|
||||
value: "TEM8S2-2ET83-CGKP1-DPSI2-EPZO1"
|
||||
},
|
||||
{
|
||||
__typename: "ConfigurationItem",
|
||||
helpText: "This key will enable you to connect to Avatax API",
|
||||
label: "API key",
|
||||
name: "apiKey",
|
||||
type: ConfigurationTypeFieldEnum.SECRET,
|
||||
value: "9ab9"
|
||||
},
|
||||
{
|
||||
__typename: "ConfigurationItem",
|
||||
helpText: "",
|
||||
label: "Password",
|
||||
name: "password",
|
||||
type: ConfigurationTypeFieldEnum.PASSWORD,
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
__typename: "ConfigurationItem",
|
||||
helpText: "",
|
||||
label: "Empty Password",
|
||||
name: "password-not-set",
|
||||
type: ConfigurationTypeFieldEnum.PASSWORD,
|
||||
value: null
|
||||
},
|
||||
{
|
||||
__typename: "ConfigurationItem",
|
||||
helpText: "Determines if Saleor should use Avatax sandbox API.",
|
||||
|
@ -51,7 +75,6 @@ export const plugin: Plugin_plugin = {
|
|||
],
|
||||
description:
|
||||
"Lorem ipsum dolor sit amet enim. Etiam ullamcorper. Suspendisse a pellentesque dui, non felis. Maecenas malesuada elit lectus felis, malesuada ultricies. Curabitur et ligula. Ut molestie a, ultricies porta urna. Vestibulum commodo volutpat a, convallis ac, laoreet enim. Phasellus fermentum in, dolor. Pellentesque facilisis. Nulla imperdiet sit amet magna.",
|
||||
|
||||
id: "UGx1Z2luQ29uZmlndXJhdGlvbjoy",
|
||||
name: "Username or account"
|
||||
};
|
||||
|
|
|
@ -12,7 +12,7 @@ export interface Plugin_plugin_configuration {
|
|||
__typename: "ConfigurationItem";
|
||||
name: string;
|
||||
type: ConfigurationTypeFieldEnum | null;
|
||||
value: string;
|
||||
value: string | null;
|
||||
helpText: string | null;
|
||||
label: string | null;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { PluginUpdateInput, ConfigurationTypeFieldEnum } from "./../../types/globalTypes";
|
||||
import {
|
||||
PluginUpdateInput,
|
||||
ConfigurationTypeFieldEnum
|
||||
} from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: PluginUpdate
|
||||
|
@ -18,7 +21,7 @@ export interface PluginUpdate_pluginUpdate_plugin_configuration {
|
|||
__typename: "ConfigurationItem";
|
||||
name: string;
|
||||
type: ConfigurationTypeFieldEnum | null;
|
||||
value: string;
|
||||
value: string | null;
|
||||
helpText: string | null;
|
||||
label: string | null;
|
||||
}
|
||||
|
@ -29,7 +32,9 @@ export interface PluginUpdate_pluginUpdate_plugin {
|
|||
name: string;
|
||||
description: string;
|
||||
active: boolean;
|
||||
configuration: (PluginUpdate_pluginUpdate_plugin_configuration | null)[] | null;
|
||||
configuration:
|
||||
| (PluginUpdate_pluginUpdate_plugin_configuration | null)[]
|
||||
| null;
|
||||
}
|
||||
|
||||
export interface PluginUpdate_pluginUpdate {
|
||||
|
|
|
@ -12,7 +12,7 @@ export interface PluginsDetailsFragment_configuration {
|
|||
__typename: "ConfigurationItem";
|
||||
name: string;
|
||||
type: ConfigurationTypeFieldEnum | null;
|
||||
value: string;
|
||||
value: string | null;
|
||||
helpText: string | null;
|
||||
label: string | null;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { stringify as stringifyQs } from "qs";
|
||||
import urlJoin from "url-join";
|
||||
|
||||
import { Pagination, SingleAction } from "../types";
|
||||
import { Dialog, Pagination, SingleAction } from "../types";
|
||||
|
||||
export const pluginsSection = "/plugins/";
|
||||
|
||||
|
@ -11,6 +11,9 @@ export const pluginsListUrl = (params?: PluginsListUrlQueryParams) =>
|
|||
pluginsListPath + "?" + stringifyQs(params);
|
||||
|
||||
export const pluginsPath = (id: string) => urlJoin(pluginsSection, id);
|
||||
export type PluginsUrlQueryParams = SingleAction;
|
||||
export type PluginUrlDialog = "clear" | "edit";
|
||||
export type PluginsUrlQueryParams = Dialog<PluginUrlDialog> & {
|
||||
field?: string;
|
||||
};
|
||||
export const pluginsUrl = (id: string, params?: PluginsUrlQueryParams) =>
|
||||
pluginsPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
||||
|
|
12
src/plugins/utils.ts
Normal file
12
src/plugins/utils.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { ConfigurationTypeFieldEnum } from "@saleor/types/globalTypes";
|
||||
import { Plugin_plugin_configuration } from "./types/Plugin";
|
||||
|
||||
export function isSecretField(
|
||||
config: Plugin_plugin_configuration[],
|
||||
field: string
|
||||
) {
|
||||
return [
|
||||
ConfigurationTypeFieldEnum.PASSWORD,
|
||||
ConfigurationTypeFieldEnum.SECRET
|
||||
].includes(config.find(configField => configField.name === field).type);
|
||||
}
|
87
src/plugins/views/PluginDetails.test.ts
Normal file
87
src/plugins/views/PluginDetails.test.ts
Normal file
|
@ -0,0 +1,87 @@
|
|||
import {
|
||||
ConfigurationItemInput,
|
||||
ConfigurationTypeFieldEnum
|
||||
} from "../../types/globalTypes";
|
||||
import { Plugin_plugin_configuration } from "../types/Plugin";
|
||||
import { getConfigurationInput } from "./PluginsDetails";
|
||||
|
||||
const baseConfig: Omit<
|
||||
Plugin_plugin_configuration,
|
||||
"name" | "type" | "value"
|
||||
> = {
|
||||
__typename: "ConfigurationItem",
|
||||
helpText: "",
|
||||
label: ""
|
||||
};
|
||||
|
||||
const config: Plugin_plugin_configuration[] = [
|
||||
{
|
||||
...baseConfig,
|
||||
name: "field-1",
|
||||
type: ConfigurationTypeFieldEnum.STRING,
|
||||
value: "val1"
|
||||
},
|
||||
{
|
||||
...baseConfig,
|
||||
name: "field-2",
|
||||
type: ConfigurationTypeFieldEnum.STRING,
|
||||
value: "val2"
|
||||
},
|
||||
{
|
||||
...baseConfig,
|
||||
name: "field-3",
|
||||
type: ConfigurationTypeFieldEnum.PASSWORD,
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
...baseConfig,
|
||||
name: "field-4",
|
||||
type: ConfigurationTypeFieldEnum.SECRET,
|
||||
value: "val4"
|
||||
}
|
||||
];
|
||||
|
||||
const input: ConfigurationItemInput[] = [
|
||||
{
|
||||
name: "field-1",
|
||||
value: "value1"
|
||||
},
|
||||
{
|
||||
name: "field-2",
|
||||
value: "value2"
|
||||
},
|
||||
{
|
||||
name: "field-3",
|
||||
value: "value3"
|
||||
},
|
||||
{
|
||||
name: "field-4",
|
||||
value: "value4"
|
||||
}
|
||||
];
|
||||
|
||||
test("Ensure that no secret is sent in input", () => {
|
||||
const output: ConfigurationItemInput[] = getConfigurationInput(config, input);
|
||||
|
||||
expect(output).toHaveLength(2);
|
||||
expect(
|
||||
output.find(
|
||||
field =>
|
||||
config.find(configField => configField.name === field.name).type ===
|
||||
ConfigurationTypeFieldEnum.PASSWORD
|
||||
)
|
||||
).toBeFalsy();
|
||||
expect(
|
||||
output.find(
|
||||
field =>
|
||||
config.find(configField => configField.name === field.name).type ===
|
||||
ConfigurationTypeFieldEnum.SECRET
|
||||
)
|
||||
).toBeFalsy();
|
||||
});
|
||||
|
||||
test("Handles null input", () => {
|
||||
const output = getConfigurationInput(null, null);
|
||||
|
||||
expect(output).toBeNull();
|
||||
});
|
|
@ -4,27 +4,73 @@ import useNotifier from "@saleor/hooks/useNotifier";
|
|||
import React from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
import { ConfigurationItemInput } from "@saleor/types/globalTypes";
|
||||
import { getMutationState, maybe } from "../../misc";
|
||||
import PluginsDetailsPage from "../components/PluginsDetailsPage";
|
||||
import { TypedPluginUpdate } from "../mutations";
|
||||
import { TypedPluginsDetailsQuery } from "../queries";
|
||||
import { pluginsListUrl, PluginsListUrlQueryParams } from "../urls";
|
||||
import { Plugin_plugin_configuration } from "../types/Plugin";
|
||||
import {
|
||||
pluginsListUrl,
|
||||
pluginsUrl,
|
||||
PluginsUrlQueryParams,
|
||||
PluginUrlDialog
|
||||
} from "../urls";
|
||||
import { isSecretField } from "../utils";
|
||||
|
||||
export interface PluginsDetailsProps {
|
||||
id: string;
|
||||
params: PluginsListUrlQueryParams;
|
||||
params: PluginsUrlQueryParams;
|
||||
}
|
||||
|
||||
export const PluginsDetails: React.FC<PluginsDetailsProps> = ({ id }) => {
|
||||
export function getConfigurationInput(
|
||||
config: Plugin_plugin_configuration[] | null,
|
||||
input: ConfigurationItemInput[] | null
|
||||
): ConfigurationItemInput[] | null {
|
||||
if (config === null || input === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return input
|
||||
.filter(field => !isSecretField(config, field.name))
|
||||
.map(field => ({
|
||||
name: field.name,
|
||||
value: field.value.toString()
|
||||
}));
|
||||
}
|
||||
|
||||
export const PluginsDetails: React.FC<PluginsDetailsProps> = ({
|
||||
id,
|
||||
params
|
||||
}) => {
|
||||
const navigate = useNavigator();
|
||||
const notify = useNotifier();
|
||||
const intl = useIntl();
|
||||
|
||||
const closeModal = () =>
|
||||
navigate(
|
||||
pluginsUrl(id, {
|
||||
...params,
|
||||
action: undefined,
|
||||
field: undefined
|
||||
}),
|
||||
true
|
||||
);
|
||||
|
||||
const openModal = (action: PluginUrlDialog, field?: string) =>
|
||||
navigate(
|
||||
pluginsUrl(id, {
|
||||
...params,
|
||||
action,
|
||||
field
|
||||
})
|
||||
);
|
||||
|
||||
return (
|
||||
<TypedPluginUpdate>
|
||||
{(pluginUpdate, pluginUpdateOpts) => (
|
||||
<TypedPluginsDetailsQuery variables={{ id }}>
|
||||
{PluginDetails => {
|
||||
{pluginDetails => {
|
||||
const formTransitionState = getMutationState(
|
||||
pluginUpdateOpts.called,
|
||||
pluginUpdateOpts.loading,
|
||||
|
@ -56,35 +102,30 @@ export const PluginsDetails: React.FC<PluginsDetailsProps> = ({ id }) => {
|
|||
return (
|
||||
<>
|
||||
<WindowTitle
|
||||
title={maybe(() => PluginDetails.data.plugin.name)}
|
||||
title={maybe(() => pluginDetails.data.plugin.name)}
|
||||
/>
|
||||
<PluginsDetailsPage
|
||||
disabled={PluginDetails.loading}
|
||||
disabled={pluginDetails.loading}
|
||||
errors={formErrors}
|
||||
saveButtonBarState={formTransitionState}
|
||||
plugin={maybe(() => PluginDetails.data.plugin)}
|
||||
plugin={maybe(() => pluginDetails.data.plugin)}
|
||||
onBack={() => navigate(pluginsListUrl())}
|
||||
onSubmit={formData => {
|
||||
const configurationInput =
|
||||
formData.configuration &&
|
||||
formData.configuration.map(item => {
|
||||
return {
|
||||
name: item.name,
|
||||
value: item.value.toString()
|
||||
};
|
||||
});
|
||||
onClear={field => openModal("clear", field)}
|
||||
onEdit={field => openModal("edit", field)}
|
||||
onSubmit={formData =>
|
||||
pluginUpdate({
|
||||
variables: {
|
||||
id,
|
||||
input: {
|
||||
active: formData.active,
|
||||
configuration: configurationInput
|
||||
? configurationInput
|
||||
: null
|
||||
configuration: getConfigurationInput(
|
||||
pluginDetails.data.plugin.configuration,
|
||||
formData.configuration
|
||||
)
|
||||
}
|
||||
}
|
||||
});
|
||||
}}
|
||||
})
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -2,7 +2,12 @@
|
|||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { SiteDomainInput, ShopSettingsInput, AddressInput, AuthorizationKeyType } from "./../../types/globalTypes";
|
||||
import {
|
||||
SiteDomainInput,
|
||||
ShopSettingsInput,
|
||||
AddressInput,
|
||||
AuthorizationKeyType
|
||||
} from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: ShopSettingsUpdate
|
||||
|
@ -143,5 +148,5 @@ export interface ShopSettingsUpdate {
|
|||
export interface ShopSettingsUpdateVariables {
|
||||
shopDomainInput: SiteDomainInput;
|
||||
shopSettingsInput: ShopSettingsInput;
|
||||
addressInput: AddressInput;
|
||||
addressInput?: AddressInput | null;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ const props: PluginsDetailsPageProps = {
|
|||
disabled: false,
|
||||
errors: [],
|
||||
onBack: () => undefined,
|
||||
onClear: () => undefined,
|
||||
onEdit: () => undefined,
|
||||
onSubmit: () => undefined,
|
||||
plugin,
|
||||
saveButtonBarState: "default"
|
||||
|
@ -33,4 +35,13 @@ storiesOf("Views / Plugins / Plugin details", module)
|
|||
"Password or license"
|
||||
] as Array<keyof FormData>).map(formError)}
|
||||
/>
|
||||
))
|
||||
.add("not configurable", () => (
|
||||
<PluginsDetailsPage
|
||||
{...props}
|
||||
plugin={{
|
||||
...plugin,
|
||||
configuration: null
|
||||
}}
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -8,39 +8,41 @@
|
|||
|
||||
export enum AddressTypeEnum {
|
||||
BILLING = "BILLING",
|
||||
SHIPPING = "SHIPPING",
|
||||
SHIPPING = "SHIPPING"
|
||||
}
|
||||
|
||||
export enum AttributeInputTypeEnum {
|
||||
DROPDOWN = "DROPDOWN",
|
||||
MULTISELECT = "MULTISELECT",
|
||||
MULTISELECT = "MULTISELECT"
|
||||
}
|
||||
|
||||
export enum AttributeTypeEnum {
|
||||
PRODUCT = "PRODUCT",
|
||||
VARIANT = "VARIANT",
|
||||
VARIANT = "VARIANT"
|
||||
}
|
||||
|
||||
export enum AttributeValueType {
|
||||
COLOR = "COLOR",
|
||||
GRADIENT = "GRADIENT",
|
||||
STRING = "STRING",
|
||||
URL = "URL",
|
||||
URL = "URL"
|
||||
}
|
||||
|
||||
export enum AuthorizationKeyType {
|
||||
FACEBOOK = "FACEBOOK",
|
||||
GOOGLE_OAUTH2 = "GOOGLE_OAUTH2",
|
||||
GOOGLE_OAUTH2 = "GOOGLE_OAUTH2"
|
||||
}
|
||||
|
||||
export enum CollectionPublished {
|
||||
HIDDEN = "HIDDEN",
|
||||
PUBLISHED = "PUBLISHED",
|
||||
PUBLISHED = "PUBLISHED"
|
||||
}
|
||||
|
||||
export enum ConfigurationTypeFieldEnum {
|
||||
BOOLEAN = "BOOLEAN",
|
||||
STRING = "STRING",
|
||||
PASSWORD = "PASSWORD",
|
||||
SECRET = "SECRET",
|
||||
STRING = "STRING"
|
||||
}
|
||||
|
||||
export enum CountryCode {
|
||||
|
@ -293,23 +295,23 @@ export enum CountryCode {
|
|||
YT = "YT",
|
||||
ZA = "ZA",
|
||||
ZM = "ZM",
|
||||
ZW = "ZW",
|
||||
ZW = "ZW"
|
||||
}
|
||||
|
||||
export enum DiscountStatusEnum {
|
||||
ACTIVE = "ACTIVE",
|
||||
EXPIRED = "EXPIRED",
|
||||
SCHEDULED = "SCHEDULED",
|
||||
SCHEDULED = "SCHEDULED"
|
||||
}
|
||||
|
||||
export enum DiscountValueTypeEnum {
|
||||
FIXED = "FIXED",
|
||||
PERCENTAGE = "PERCENTAGE",
|
||||
PERCENTAGE = "PERCENTAGE"
|
||||
}
|
||||
|
||||
export enum FulfillmentStatus {
|
||||
CANCELED = "CANCELED",
|
||||
FULFILLED = "FULFILLED",
|
||||
FULFILLED = "FULFILLED"
|
||||
}
|
||||
|
||||
export enum LanguageCodeEnum {
|
||||
|
@ -355,19 +357,19 @@ export enum LanguageCodeEnum {
|
|||
UK = "UK",
|
||||
VI = "VI",
|
||||
ZH_HANS = "ZH_HANS",
|
||||
ZH_HANT = "ZH_HANT",
|
||||
ZH_HANT = "ZH_HANT"
|
||||
}
|
||||
|
||||
export enum OrderAction {
|
||||
CAPTURE = "CAPTURE",
|
||||
MARK_AS_PAID = "MARK_AS_PAID",
|
||||
REFUND = "REFUND",
|
||||
VOID = "VOID",
|
||||
VOID = "VOID"
|
||||
}
|
||||
|
||||
export enum OrderDirection {
|
||||
ASC = "ASC",
|
||||
DESC = "DESC",
|
||||
DESC = "DESC"
|
||||
}
|
||||
|
||||
export enum OrderEventsEmailsEnum {
|
||||
|
@ -376,7 +378,7 @@ export enum OrderEventsEmailsEnum {
|
|||
ORDER_CONFIRMATION = "ORDER_CONFIRMATION",
|
||||
PAYMENT_CONFIRMATION = "PAYMENT_CONFIRMATION",
|
||||
SHIPPING_CONFIRMATION = "SHIPPING_CONFIRMATION",
|
||||
TRACKING_UPDATED = "TRACKING_UPDATED",
|
||||
TRACKING_UPDATED = "TRACKING_UPDATED"
|
||||
}
|
||||
|
||||
export enum OrderEventsEnum {
|
||||
|
@ -400,7 +402,7 @@ export enum OrderEventsEnum {
|
|||
PLACED = "PLACED",
|
||||
PLACED_FROM_DRAFT = "PLACED_FROM_DRAFT",
|
||||
TRACKING_UPDATED = "TRACKING_UPDATED",
|
||||
UPDATED_ADDRESS = "UPDATED_ADDRESS",
|
||||
UPDATED_ADDRESS = "UPDATED_ADDRESS"
|
||||
}
|
||||
|
||||
export enum OrderStatus {
|
||||
|
@ -408,7 +410,7 @@ export enum OrderStatus {
|
|||
DRAFT = "DRAFT",
|
||||
FULFILLED = "FULFILLED",
|
||||
PARTIALLY_FULFILLED = "PARTIALLY_FULFILLED",
|
||||
UNFULFILLED = "UNFULFILLED",
|
||||
UNFULFILLED = "UNFULFILLED"
|
||||
}
|
||||
|
||||
export enum OrderStatusFilter {
|
||||
|
@ -417,7 +419,7 @@ export enum OrderStatusFilter {
|
|||
PARTIALLY_FULFILLED = "PARTIALLY_FULFILLED",
|
||||
READY_TO_CAPTURE = "READY_TO_CAPTURE",
|
||||
READY_TO_FULFILL = "READY_TO_FULFILL",
|
||||
UNFULFILLED = "UNFULFILLED",
|
||||
UNFULFILLED = "UNFULFILLED"
|
||||
}
|
||||
|
||||
export enum PaymentChargeStatusEnum {
|
||||
|
@ -425,7 +427,7 @@ export enum PaymentChargeStatusEnum {
|
|||
FULLY_REFUNDED = "FULLY_REFUNDED",
|
||||
NOT_CHARGED = "NOT_CHARGED",
|
||||
PARTIALLY_CHARGED = "PARTIALLY_CHARGED",
|
||||
PARTIALLY_REFUNDED = "PARTIALLY_REFUNDED",
|
||||
PARTIALLY_REFUNDED = "PARTIALLY_REFUNDED"
|
||||
}
|
||||
|
||||
export enum PermissionEnum {
|
||||
|
@ -443,7 +445,7 @@ export enum PermissionEnum {
|
|||
MANAGE_STAFF = "MANAGE_STAFF",
|
||||
MANAGE_TRANSLATIONS = "MANAGE_TRANSLATIONS",
|
||||
MANAGE_USERS = "MANAGE_USERS",
|
||||
MANAGE_WEBHOOKS = "MANAGE_WEBHOOKS",
|
||||
MANAGE_WEBHOOKS = "MANAGE_WEBHOOKS"
|
||||
}
|
||||
|
||||
export enum ProductErrorCode {
|
||||
|
@ -457,7 +459,7 @@ export enum ProductErrorCode {
|
|||
NOT_PRODUCTS_IMAGE = "NOT_PRODUCTS_IMAGE",
|
||||
REQUIRED = "REQUIRED",
|
||||
UNIQUE = "UNIQUE",
|
||||
VARIANT_NO_DIGITAL_CONTENT = "VARIANT_NO_DIGITAL_CONTENT",
|
||||
VARIANT_NO_DIGITAL_CONTENT = "VARIANT_NO_DIGITAL_CONTENT"
|
||||
}
|
||||
|
||||
export enum ProductOrderField {
|
||||
|
@ -466,37 +468,37 @@ export enum ProductOrderField {
|
|||
NAME = "NAME",
|
||||
PRICE = "PRICE",
|
||||
PUBLISHED = "PUBLISHED",
|
||||
TYPE = "TYPE",
|
||||
TYPE = "TYPE"
|
||||
}
|
||||
|
||||
export enum ProductTypeConfigurable {
|
||||
CONFIGURABLE = "CONFIGURABLE",
|
||||
SIMPLE = "SIMPLE",
|
||||
SIMPLE = "SIMPLE"
|
||||
}
|
||||
|
||||
export enum ProductTypeEnum {
|
||||
DIGITAL = "DIGITAL",
|
||||
SHIPPABLE = "SHIPPABLE",
|
||||
SHIPPABLE = "SHIPPABLE"
|
||||
}
|
||||
|
||||
export enum SaleType {
|
||||
FIXED = "FIXED",
|
||||
PERCENTAGE = "PERCENTAGE",
|
||||
PERCENTAGE = "PERCENTAGE"
|
||||
}
|
||||
|
||||
export enum ShippingMethodTypeEnum {
|
||||
PRICE = "PRICE",
|
||||
WEIGHT = "WEIGHT",
|
||||
WEIGHT = "WEIGHT"
|
||||
}
|
||||
|
||||
export enum StaffMemberStatus {
|
||||
ACTIVE = "ACTIVE",
|
||||
DEACTIVATED = "DEACTIVATED",
|
||||
DEACTIVATED = "DEACTIVATED"
|
||||
}
|
||||
|
||||
export enum StockAvailability {
|
||||
IN_STOCK = "IN_STOCK",
|
||||
OUT_OF_STOCK = "OUT_OF_STOCK",
|
||||
OUT_OF_STOCK = "OUT_OF_STOCK"
|
||||
}
|
||||
|
||||
export enum TaxRateType {
|
||||
|
@ -524,19 +526,19 @@ export enum TaxRateType {
|
|||
SOCIAL_HOUSING = "SOCIAL_HOUSING",
|
||||
STANDARD = "STANDARD",
|
||||
WATER = "WATER",
|
||||
WINE = "WINE",
|
||||
WINE = "WINE"
|
||||
}
|
||||
|
||||
export enum VoucherDiscountType {
|
||||
FIXED = "FIXED",
|
||||
PERCENTAGE = "PERCENTAGE",
|
||||
SHIPPING = "SHIPPING",
|
||||
SHIPPING = "SHIPPING"
|
||||
}
|
||||
|
||||
export enum VoucherTypeEnum {
|
||||
ENTIRE_ORDER = "ENTIRE_ORDER",
|
||||
SHIPPING = "SHIPPING",
|
||||
SPECIFIC_PRODUCT = "SPECIFIC_PRODUCT",
|
||||
SPECIFIC_PRODUCT = "SPECIFIC_PRODUCT"
|
||||
}
|
||||
|
||||
export enum WebhookErrorCode {
|
||||
|
@ -544,7 +546,7 @@ export enum WebhookErrorCode {
|
|||
INVALID = "INVALID",
|
||||
NOT_FOUND = "NOT_FOUND",
|
||||
REQUIRED = "REQUIRED",
|
||||
UNIQUE = "UNIQUE",
|
||||
UNIQUE = "UNIQUE"
|
||||
}
|
||||
|
||||
export enum WebhookEventTypeEnum {
|
||||
|
@ -555,14 +557,14 @@ export enum WebhookEventTypeEnum {
|
|||
ORDER_FULFILLED = "ORDER_FULFILLED",
|
||||
ORDER_FULLY_PAID = "ORDER_FULLY_PAID",
|
||||
ORDER_UPDATED = "ORDER_UPDATED",
|
||||
PRODUCT_CREATED = "PRODUCT_CREATED",
|
||||
PRODUCT_CREATED = "PRODUCT_CREATED"
|
||||
}
|
||||
|
||||
export enum WeightUnitsEnum {
|
||||
G = "G",
|
||||
KG = "KG",
|
||||
LB = "LB",
|
||||
OZ = "OZ",
|
||||
OZ = "OZ"
|
||||
}
|
||||
|
||||
export interface AddressInput {
|
||||
|
|
Loading…
Reference in a new issue