Add pluginDetails

This commit is contained in:
Krzysztof Bialoglowicz 2019-08-26 19:08:32 +02:00
parent 8afe11c032
commit 4cfb408d5e
11 changed files with 484 additions and 40 deletions

View 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;

View file

@ -0,0 +1,2 @@
export { default } from "./PluginInfo";
export * from "./PluginInfo";

View 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;

View file

@ -0,0 +1,2 @@
export { default } from "./PluginSettings";
export * from "./PluginSettings";

View 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;

View file

@ -0,0 +1,2 @@
export { default } from "./PluginsDetailsPage";
export * from "./PluginsDetailsPage";

View file

@ -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>

View file

@ -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>
</>
);

View file

@ -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);

View file

@ -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);

View 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;