Add pluginDetails
This commit is contained in:
parent
8afe11c032
commit
4cfb408d5e
11 changed files with 484 additions and 40 deletions
91
src/plugins/components/PluginInfo/PluginInfo.tsx
Normal file
91
src/plugins/components/PluginInfo/PluginInfo.tsx
Normal file
|
@ -0,0 +1,91 @@
|
|||
import Card from "@material-ui/core/Card";
|
||||
import CardContent from "@material-ui/core/CardContent";
|
||||
import {
|
||||
createStyles,
|
||||
Theme,
|
||||
withStyles,
|
||||
WithStyles
|
||||
} from "@material-ui/core/styles";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import React from "react";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import ControlledSwitch from "@saleor/components/ControlledSwitch";
|
||||
import FormSpacer from "@saleor/components/FormSpacer";
|
||||
import Hr from "@saleor/components/Hr";
|
||||
import i18n from "../../../i18n";
|
||||
import { FormData } from "../PluginsDetailsPage";
|
||||
|
||||
interface PluginInfoProps {
|
||||
data: FormData;
|
||||
errors: Partial<{
|
||||
description: string;
|
||||
domain: string;
|
||||
name: string;
|
||||
}>;
|
||||
disabled: boolean;
|
||||
onChange: (event: React.ChangeEvent<any>) => void;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
title: {
|
||||
fontSize: 14,
|
||||
color: "#616161",
|
||||
paddingTop: 10
|
||||
},
|
||||
status: {
|
||||
fontSize: 16,
|
||||
color: "#3D3D3D",
|
||||
paddingTop: 20,
|
||||
fontWeight: "400"
|
||||
}
|
||||
});
|
||||
|
||||
const PluginInfo = withStyles(styles, { name: "PluginInfo" })(
|
||||
({
|
||||
data,
|
||||
disabled,
|
||||
classes,
|
||||
errors,
|
||||
onChange
|
||||
}: PluginInfoProps & WithStyles<typeof styles>) => {
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={i18n.t("Plugin Information and Status", {
|
||||
context: "plugin configuration"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
<Typography className={classes.title} variant="h6">
|
||||
{i18n.t("Plugin Name")}
|
||||
</Typography>
|
||||
<Typography>{data.name}</Typography>
|
||||
{data.description && (
|
||||
<>
|
||||
<Typography className={classes.title} variant="h6">
|
||||
{i18n.t("Plugin Description")}
|
||||
</Typography>
|
||||
<Typography>{data.description}</Typography>
|
||||
</>
|
||||
)}
|
||||
<FormSpacer />
|
||||
<Hr />
|
||||
<Typography className={classes.status} variant="h6">
|
||||
{i18n.t("Status")}
|
||||
</Typography>
|
||||
<ControlledSwitch
|
||||
checked={data.active}
|
||||
label={"Set plugin as Active"}
|
||||
name={"active" as keyof FormData}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
);
|
||||
PluginInfo.displayName = "PluginInfo";
|
||||
export default PluginInfo;
|
2
src/plugins/components/PluginInfo/index.ts
Normal file
2
src/plugins/components/PluginInfo/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./PluginInfo";
|
||||
export * from "./PluginInfo";
|
83
src/plugins/components/PluginSettings/PluginSettings.tsx
Normal file
83
src/plugins/components/PluginSettings/PluginSettings.tsx
Normal file
|
@ -0,0 +1,83 @@
|
|||
import Card from "@material-ui/core/Card";
|
||||
import CardContent from "@material-ui/core/CardContent";
|
||||
import ControlledSwitch from "@saleor/components/ControlledSwitch";
|
||||
import {
|
||||
createStyles,
|
||||
Theme,
|
||||
withStyles,
|
||||
WithStyles
|
||||
} from "@material-ui/core/styles";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import React from "react";
|
||||
|
||||
import CardTitle from "@saleor/components/CardTitle";
|
||||
import FormSpacer from "@saleor/components/FormSpacer";
|
||||
import i18n from "../../../i18n";
|
||||
import { FormData } from "../PluginsDetailsPage";
|
||||
|
||||
interface PluginSettingsProps {
|
||||
data: FormData;
|
||||
errors: Partial<{
|
||||
description: string;
|
||||
domain: string;
|
||||
name: string;
|
||||
}>;
|
||||
disabled: boolean;
|
||||
onChange: (event: React.ChangeEvent<any>) => void;
|
||||
}
|
||||
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
item: {
|
||||
marginBottom: 5,
|
||||
marginTop: 10
|
||||
}
|
||||
});
|
||||
|
||||
const PluginSettings = withStyles(styles, { name: "PluginSettings" })(
|
||||
({
|
||||
data,
|
||||
disabled,
|
||||
classes,
|
||||
errors,
|
||||
onChange
|
||||
}: PluginSettingsProps & WithStyles<typeof styles>) => (
|
||||
<Card>
|
||||
<CardTitle
|
||||
title={i18n.t("Plugin Settings", {
|
||||
context: "plugin configuration"
|
||||
})}
|
||||
/>
|
||||
<CardContent>
|
||||
{data.configuration.map((configuration, index) => (
|
||||
<div className={classes.item} key={`item-${index}`}>
|
||||
{configuration.type === "STRING" && (
|
||||
<TextField
|
||||
className={classes.item}
|
||||
disabled={disabled}
|
||||
error={!!errors.name}
|
||||
label={configuration.label}
|
||||
name={configuration.name}
|
||||
fullWidth
|
||||
value={configuration.value}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
{configuration.type === "BOOLEAN" && (
|
||||
<ControlledSwitch
|
||||
className={classes.item}
|
||||
checked={configuration.value}
|
||||
label={configuration.label}
|
||||
name={configuration.name}
|
||||
onChange={onChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
);
|
||||
PluginSettings.displayName = "PluginSettings";
|
||||
export default PluginSettings;
|
2
src/plugins/components/PluginSettings/index.ts
Normal file
2
src/plugins/components/PluginSettings/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./PluginSettings";
|
||||
export * from "./PluginSettings";
|
147
src/plugins/components/PluginsDetailsPage/PluginsDetailsPage.tsx
Normal file
147
src/plugins/components/PluginsDetailsPage/PluginsDetailsPage.tsx
Normal file
|
@ -0,0 +1,147 @@
|
|||
import React from "react";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import AppHeader from "@saleor/components/AppHeader";
|
||||
import CardSpacer from "@saleor/components/CardSpacer";
|
||||
import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton";
|
||||
import Container from "@saleor/components/Container";
|
||||
import Form from "@saleor/components/Form";
|
||||
import Grid from "@saleor/components/Grid";
|
||||
import PageHeader from "@saleor/components/PageHeader";
|
||||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||
import SeoForm from "@saleor/components/SeoForm";
|
||||
import VisibilityCard from "@saleor/components/VisibilityCard";
|
||||
import i18n from "../../../i18n";
|
||||
import { maybe } from "../../../misc";
|
||||
import { UserError } from "../../../types";
|
||||
import { PageDetails_page } from "../../types/PluginDetails";
|
||||
import PluginInfo from "../PluginInfo";
|
||||
import PluginSettings from "../PluginSettings";
|
||||
|
||||
export interface FormData {
|
||||
name: string;
|
||||
description: string;
|
||||
active: boolean;
|
||||
id: string;
|
||||
configuration: [
|
||||
{
|
||||
name: string;
|
||||
value: string;
|
||||
type: string;
|
||||
helpText: string;
|
||||
label: string;
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
export interface PageDetailsPageProps {
|
||||
disabled: boolean;
|
||||
errors: UserError[];
|
||||
plugin: PageDetails_page;
|
||||
saveButtonBarState: ConfirmButtonTransitionState;
|
||||
onBack: () => void;
|
||||
onSubmit: (data: FormData) => void;
|
||||
}
|
||||
|
||||
const PageDetailsPage: React.StatelessComponent<PageDetailsPageProps> = ({
|
||||
disabled,
|
||||
errors,
|
||||
plugin,
|
||||
saveButtonBarState,
|
||||
onBack,
|
||||
onSubmit
|
||||
}) => {
|
||||
const initialForm: FormData = {
|
||||
name: maybe(() => plugin.name, ""),
|
||||
description: maybe(() => plugin.description, ""),
|
||||
active: maybe(() => plugin.active, false),
|
||||
configuration: maybe(() => plugin.configuration, [])
|
||||
};
|
||||
return (
|
||||
<Form errors={errors} initial={initialForm} onSubmit={onSubmit}>
|
||||
{({
|
||||
change,
|
||||
data,
|
||||
errors: formErrors,
|
||||
hasChanged,
|
||||
submit,
|
||||
set,
|
||||
triggerChange
|
||||
}) => {
|
||||
const newData = {
|
||||
active: data.active,
|
||||
configuration: data.configuration
|
||||
};
|
||||
|
||||
const onChange = event => {
|
||||
const { name, value } = event.target;
|
||||
name === "active"
|
||||
? (newData.active = value)
|
||||
: (newData.active = data.active);
|
||||
|
||||
newData.configuration.map(item => {
|
||||
if (item.name === name) {
|
||||
item.value = value;
|
||||
}
|
||||
});
|
||||
|
||||
triggerChange();
|
||||
set(newData);
|
||||
};
|
||||
return (
|
||||
<Container>
|
||||
<AppHeader onBack={onBack}>{i18n.t("Plugins")}</AppHeader>
|
||||
<PageHeader
|
||||
title={`${maybe(() => plugin.name, "")} ${i18n.t("Details")}`}
|
||||
/>
|
||||
<Grid variant="inverted">
|
||||
<div>
|
||||
<Typography variant="h6">
|
||||
{i18n.t("Plugin Information and Status")}
|
||||
</Typography>
|
||||
<Typography>
|
||||
{i18n.t(
|
||||
"These are general information about your store. They define what is the URL of your store and what is shown in brow sers taskbar."
|
||||
)}
|
||||
</Typography>
|
||||
</div>
|
||||
<PluginInfo
|
||||
data={data}
|
||||
errors={errors}
|
||||
disabled={disabled}
|
||||
onChange={onChange}
|
||||
/>
|
||||
{data.configuration && (
|
||||
<>
|
||||
<div>
|
||||
<Typography variant="h6">
|
||||
{i18n.t("Plugin Settings")}
|
||||
</Typography>
|
||||
<Typography>
|
||||
{i18n.t(
|
||||
"This adress will be used to generate invoices and calculate shipping rates. Email adress you provide here will be used as a contact adress for your customers."
|
||||
)}
|
||||
</Typography>
|
||||
</div>
|
||||
<PluginSettings
|
||||
data={data}
|
||||
errors={errors}
|
||||
disabled={disabled}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Grid>
|
||||
<SaveButtonBar
|
||||
disabled={disabled || !hasChanged}
|
||||
state={saveButtonBarState}
|
||||
onCancel={onBack}
|
||||
onSave={submit}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}}
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
PageDetailsPage.displayName = "PageDetailsPage";
|
||||
export default PageDetailsPage;
|
2
src/plugins/components/PluginsDetailsPage/index.ts
Normal file
2
src/plugins/components/PluginsDetailsPage/index.ts
Normal file
|
@ -0,0 +1,2 @@
|
|||
export { default } from "./PluginsDetailsPage";
|
||||
export * from "./PluginsDetailsPage";
|
|
@ -49,7 +49,7 @@ const styles = (theme: Theme) =>
|
|||
|
||||
const numberOfColumns = 4;
|
||||
|
||||
const PluginList = withStyles(styles, { name: "PageList" })(
|
||||
const PluginList = withStyles(styles, { name: "PluginList" })(
|
||||
({
|
||||
classes,
|
||||
settings,
|
||||
|
@ -66,7 +66,6 @@ const PluginList = withStyles(styles, { name: "PageList" })(
|
|||
toggleAll,
|
||||
toolbar
|
||||
}: PluginListProps & WithStyles<typeof styles>) => {
|
||||
console.log(plugins);
|
||||
return (
|
||||
<Card>
|
||||
<Table>
|
||||
|
|
|
@ -20,26 +20,26 @@ const PluginList: React.StatelessComponent<RouteComponentProps<any>> = ({
|
|||
return <PluginsListComponent params={params} />;
|
||||
};
|
||||
|
||||
// const PageDetails: React.StatelessComponent<RouteComponentProps<any>> = ({
|
||||
// match
|
||||
// }) => {
|
||||
// const qs = parseQs(location.search.substr(1));
|
||||
// const params: PluginsListUrlQueryParams = qs;
|
||||
const PageDetails: React.StatelessComponent<RouteComponentProps<any>> = ({
|
||||
match
|
||||
}) => {
|
||||
const qs = parseQs(location.search.substr(1));
|
||||
const params: PluginsListUrlQueryParams = qs;
|
||||
|
||||
// return (
|
||||
// <PluginsDetailsComponent
|
||||
// id={decodeURIComponent(match.params.id)}
|
||||
// params={params}
|
||||
// />
|
||||
// );
|
||||
// };
|
||||
return (
|
||||
<PluginsDetailsComponent
|
||||
id={decodeURIComponent(match.params.id)}
|
||||
params={params}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const Component = () => (
|
||||
<>
|
||||
<WindowTitle title={i18n.t("Plugins")} />
|
||||
<Switch>
|
||||
<Route exact path={pluginsListPath} component={PluginList} />
|
||||
{/* <Route path={pluginsPath(":id")} component={PageDetails} /> */}
|
||||
<Route path={pluginsPath(":id")} component={PageDetails} />
|
||||
</Switch>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import gql from "graphql-tag";
|
||||
|
||||
import { TypedMutation } from "../mutations";
|
||||
import { pluginsDetailsFragment } from "./queries";
|
||||
import {
|
||||
pluginConfigurationUpdate,
|
||||
pluginConfigurationUpdateVariables
|
||||
} from "./types/pluginConfigurationUpdate";
|
||||
|
||||
const pluginConfigurationUpdate = gql`
|
||||
${pluginsDetailsFragment}
|
||||
mutation pluginConfigurationUpdate(
|
||||
$id: ID!
|
||||
$input: PluginConfigurationUpdateInput!
|
||||
) {
|
||||
pluginConfigurationUpdate(id: $id, input: $input) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
}
|
||||
pluginConfiguration {
|
||||
...pluginsDetailsFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const TypedPluginConfigurationUpdate = TypedMutation<
|
||||
pluginConfigurationUpdate,
|
||||
pluginConfigurationUpdateVariables
|
||||
>(pluginConfigurationUpdate);
|
|
@ -13,19 +13,19 @@ export const pluginsFragment = gql`
|
|||
}
|
||||
`;
|
||||
|
||||
// export const pluginsDetailsFragment = gql`
|
||||
// ${pluginsFragment}
|
||||
// fragment pluginsDetailsFragment on PluginConfiguration {
|
||||
// ...pluginFragment
|
||||
// configuration {
|
||||
// name
|
||||
// type
|
||||
// value
|
||||
// helpText
|
||||
// label
|
||||
// }
|
||||
// }
|
||||
// `;
|
||||
export const pluginsDetailsFragment = gql`
|
||||
${pluginsFragment}
|
||||
fragment pluginsDetailsFragment on PluginConfiguration {
|
||||
...pluginFragment
|
||||
configuration {
|
||||
name
|
||||
type
|
||||
value
|
||||
helpText
|
||||
label
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const pluginsList = gql`
|
||||
${pluginsFragment}
|
||||
|
@ -54,15 +54,15 @@ export const TypedPluginsListQuery = TypedQuery<
|
|||
PluginsListVariables
|
||||
>(pluginsList);
|
||||
|
||||
// const pluginsDetails = gql`
|
||||
// ${pluginsDetailsFragment}
|
||||
// query pluginConfiguration($id: ID!) {
|
||||
// page(id: $id) {
|
||||
// ...pluginsDetailsFragment
|
||||
// }
|
||||
// }
|
||||
// `;
|
||||
// export const TypedPluginsDetailsQuery = TypedQuery<
|
||||
// PluginDetails,
|
||||
// PluginDetailsVariables
|
||||
// >(pluginsDetails);
|
||||
const pluginsDetails = gql`
|
||||
${pluginsDetailsFragment}
|
||||
query pluginConfiguration($id: ID!) {
|
||||
pluginConfiguration(id: $id) {
|
||||
...pluginsDetailsFragment
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const TypedPluginsDetailsQuery = TypedQuery<
|
||||
PluginDetails,
|
||||
PluginDetailsVariables
|
||||
>(pluginsDetails);
|
||||
|
|
88
src/plugins/views/PluginsDetails.tsx
Normal file
88
src/plugins/views/PluginsDetails.tsx
Normal file
|
@ -0,0 +1,88 @@
|
|||
import DialogContentText from "@material-ui/core/DialogContentText";
|
||||
import React from "react";
|
||||
|
||||
import ActionDialog from "@saleor/components/ActionDialog";
|
||||
import { WindowTitle } from "@saleor/components/WindowTitle";
|
||||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import i18n from "../../i18n";
|
||||
import { getMutationState, maybe } from "../../misc";
|
||||
import { PluginConfigurationUpdateInput } from "../../types/globalTypes";
|
||||
import PluginsDetailsPage, { FormData } from "../components/PluginsDetailsPage";
|
||||
import { TypedPluginConfigurationUpdate } from "../mutations";
|
||||
import { TypedPluginsDetailsQuery } from "../queries";
|
||||
import { pluginsListUrl, pluginsUrl, PluginsUrlQueryParams } from "../urls";
|
||||
|
||||
export interface PluginsDetailsProps {
|
||||
id: string;
|
||||
params: PluginsUrlQueryParams;
|
||||
}
|
||||
|
||||
export const PluginsDetails: React.StatelessComponent<PluginsDetailsProps> = ({
|
||||
id,
|
||||
params
|
||||
}) => {
|
||||
const navigate = useNavigator();
|
||||
const notify = useNotifier();
|
||||
|
||||
return (
|
||||
<TypedPluginConfigurationUpdate>
|
||||
{(pluginConfigurationUpdate, pluginConfigurationUpdateOpts) => (
|
||||
<TypedPluginsDetailsQuery variables={{ id }}>
|
||||
{PluginDetails => {
|
||||
const formTransitionState = getMutationState(
|
||||
pluginConfigurationUpdateOpts.called,
|
||||
pluginConfigurationUpdateOpts.loading,
|
||||
maybe(
|
||||
() =>
|
||||
pluginConfigurationUpdateOpts.data.pluginConfiguration.errors
|
||||
)
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<WindowTitle
|
||||
title={maybe(
|
||||
() => PluginDetails.data.pluginConfiguration.name
|
||||
)}
|
||||
/>
|
||||
<PluginsDetailsPage
|
||||
disabled={PluginDetails.loading}
|
||||
errors={maybe(
|
||||
() =>
|
||||
pluginConfigurationUpdateOpts.data.pluginConfiguration
|
||||
.errors,
|
||||
[]
|
||||
)}
|
||||
saveButtonBarState={formTransitionState}
|
||||
plugin={maybe(() => PluginDetails.data.pluginConfiguration)}
|
||||
onBack={() => navigate(pluginsListUrl())}
|
||||
onSubmit={formData => {
|
||||
const configurationInput = [];
|
||||
formData.configuration.map(item => {
|
||||
configurationInput.push({
|
||||
name: item.name,
|
||||
value: item.value
|
||||
});
|
||||
});
|
||||
pluginConfigurationUpdate({
|
||||
variables: {
|
||||
id,
|
||||
input: {
|
||||
active: formData.active,
|
||||
configuration: configurationInput
|
||||
}
|
||||
}
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</TypedPluginsDetailsQuery>
|
||||
)}
|
||||
</TypedPluginConfigurationUpdate>
|
||||
);
|
||||
};
|
||||
PluginsDetails.displayName = "PluginsDetails";
|
||||
export default PluginsDetails;
|
Loading…
Reference in a new issue