Rebase master

This commit is contained in:
Krzysztof Bialoglowicz 2019-08-30 15:10:07 +02:00
parent 658c9cd9db
commit 9b076dcae4
10 changed files with 153 additions and 139 deletions

View file

@ -26,7 +26,6 @@ import { taxSection } from "@saleor/taxes/urls";
import { PermissionEnum } from "@saleor/types/globalTypes"; import { PermissionEnum } from "@saleor/types/globalTypes";
import ConfigurationPage, { MenuItem } from "./ConfigurationPage"; import ConfigurationPage, { MenuItem } from "./ConfigurationPage";
<<<<<<< HEAD
export function createConfigurationMenu(intl: IntlShape): MenuItem[] { export function createConfigurationMenu(intl: IntlShape): MenuItem[] {
return [ return [
{ {
@ -108,82 +107,25 @@ export function createConfigurationMenu(intl: IntlShape): MenuItem[] {
permission: PermissionEnum.MANAGE_PAGES, permission: PermissionEnum.MANAGE_PAGES,
title: intl.formatMessage(sectionNames.pages), title: intl.formatMessage(sectionNames.pages),
url: pageListUrl() url: pageListUrl()
},
{
description: intl.formatMessage({
defaultMessage: "View and update your plugins and their settings.",
id: "configurationPluginsPages"
}),
icon: (
<Plugins
fontSize="inherit"
viewBox="-8 -5 44 44"
preserveAspectRatio="xMinYMin meet"
/>
),
permission: PermissionEnum.MANAGE_SETTINGS,
title: intl.formatMessage(sectionNames.plugins),
url: pluginsListUrl()
} }
]; ];
} }
=======
export const configurationMenu: MenuItem[] = [
{
description: i18n.t("Determine attributes used to create product types"),
icon: <ProductTypes fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_PRODUCTS,
title: i18n.t("Attributes"),
url: attributeListUrl()
},
{
description: i18n.t("Define types of products you sell"),
icon: <ProductTypes fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_PRODUCTS,
title: i18n.t("Product Types"),
url: productTypeListUrl()
},
{
description: i18n.t("Manage your employees and their permissions"),
icon: <StaffMembers fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_STAFF,
title: i18n.t("Staff Members"),
url: staffListUrl()
},
{
description: i18n.t("Manage how you ship out orders."),
icon: <ShippingMethods fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_SHIPPING,
title: i18n.t("Shipping Methods"),
url: shippingZonesListUrl()
},
{
description: i18n.t("Manage how your store charges tax"),
icon: <Taxes fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_PRODUCTS,
title: i18n.t("Taxes"),
url: taxSection
},
{
description: i18n.t("Define how users can navigate through your store"),
icon: <Navigation fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_MENUS,
title: i18n.t("Navigation"),
url: menuListUrl()
},
{
description: i18n.t("View and update your site settings"),
icon: <SiteSettings fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_SETTINGS,
title: i18n.t("Site Settings"),
url: siteSettingsUrl()
},
{
description: i18n.t("Manage and add additional pages"),
icon: <Pages fontSize="inherit" viewBox="0 0 44 44" />,
permission: PermissionEnum.MANAGE_PAGES,
title: i18n.t("Pages"),
url: pageListUrl()
},
{
description: i18n.t("View and update your plugins and their settings."),
icon: (
<Plugins
fontSize="inherit"
viewBox="-8 -5 44 44"
preserveAspectRatio="xMinYMin meet"
/>
),
permission: PermissionEnum.MANAGE_SETTINGS,
title: i18n.t("Plugins"),
url: pluginsListUrl()
}
];
>>>>>>> Add plugin page, plugin list view
export const configurationMenuUrl = "/configuration/"; export const configurationMenuUrl = "/configuration/";

View file

@ -152,6 +152,10 @@ export const sectionNames = defineMessages({
defaultMessage: "Pages", defaultMessage: "Pages",
description: "pages section name" description: "pages section name"
}, },
plugins: {
defaultMessage: "Plugins",
description: "plugins section name"
},
productTypes: { productTypes: {
defaultMessage: "Product Types", defaultMessage: "Product Types",
description: "product types section name" description: "product types section name"

View file

@ -3,12 +3,12 @@ import CardContent from "@material-ui/core/CardContent";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import makeStyles from "@material-ui/styles/makeStyles"; import makeStyles from "@material-ui/styles/makeStyles";
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import CardTitle from "@saleor/components/CardTitle"; import CardTitle from "@saleor/components/CardTitle";
import ControlledSwitch from "@saleor/components/ControlledSwitch"; import ControlledSwitch from "@saleor/components/ControlledSwitch";
import FormSpacer from "@saleor/components/FormSpacer"; import FormSpacer from "@saleor/components/FormSpacer";
import Hr from "@saleor/components/Hr"; import Hr from "@saleor/components/Hr";
import i18n from "../../../i18n";
import { FormData } from "../PluginsDetailsPage"; import { FormData } from "../PluginsDetailsPage";
interface PluginInfoProps { interface PluginInfoProps {
@ -35,32 +35,48 @@ const PluginInfo: React.StatelessComponent<PluginInfoProps> = ({
onChange onChange
}) => { }) => {
const classes = useStyles({}); const classes = useStyles({});
const intl = useIntl();
return ( return (
<Card> <Card>
<CardTitle <CardTitle
title={i18n.t("Plugin Information and Status", { title={intl.formatMessage({
context: "plugin configuration" defaultMessage: "Plugin Information and Status",
description: "plugin title"
})} })}
/> />
<CardContent> <CardContent>
<Typography className={classes.title} variant="h6"> <Typography className={classes.title} variant="h6">
{i18n.t("Plugin Name")} {intl.formatMessage({
defaultMessage: "Plugin Name",
description: "plugin name"
})}
</Typography> </Typography>
<Typography>{name}</Typography> <Typography>{name}</Typography>
{description && ( {description && (
<> <>
<Typography className={classes.title} variant="h6"> <Typography className={classes.title} variant="h6">
{i18n.t("Plugin Description")} {intl.formatMessage({
defaultMessage: "Plugin Description",
description: "plugin description"
})}
</Typography> </Typography>
<Typography>{description}</Typography> <Typography>{description}</Typography>
</> </>
)} )}
<FormSpacer /> <FormSpacer />
<Hr /> <Hr />
<Typography className={classes.status}>{i18n.t("Status")}</Typography> <Typography className={classes.status}>
{intl.formatMessage({
defaultMessage: "Status",
description: "plugin status"
})}
</Typography>
<ControlledSwitch <ControlledSwitch
checked={data.active} checked={data.active}
label={"Set plugin as Active"} label={intl.formatMessage({
defaultMessage: "Set plugin as Active",
description: "plugin active label"
})}
name={"active" as keyof FormData} name={"active" as keyof FormData}
onChange={onChange} onChange={onChange}
/> />

View file

@ -7,7 +7,8 @@ import ControlledSwitch from "@saleor/components/ControlledSwitch";
import { FormErrors } from "@saleor/types"; import { FormErrors } from "@saleor/types";
import { ConfigurationTypeFieldEnum } from "@saleor/types/globalTypes"; import { ConfigurationTypeFieldEnum } from "@saleor/types/globalTypes";
import React from "react"; import React from "react";
import i18n from "../../../i18n"; import { useIntl } from "react-intl";
import { FormData } from "../PluginsDetailsPage"; import { FormData } from "../PluginsDetailsPage";
interface PluginSettingsProps { interface PluginSettingsProps {
@ -15,7 +16,7 @@ interface PluginSettingsProps {
errors: FormErrors<"name" | "configuration">; errors: FormErrors<"name" | "configuration">;
disabled: boolean; disabled: boolean;
onChange: (event: React.ChangeEvent<any>) => void; onChange: (event: React.ChangeEvent<any>) => void;
plugin: Array<{ fields: Array<{
name: string; name: string;
type: ConfigurationTypeFieldEnum | null; type: ConfigurationTypeFieldEnum | null;
value: string; value: string;
@ -36,32 +37,34 @@ const PluginSettings: React.StatelessComponent<PluginSettingsProps> = ({
disabled, disabled,
errors, errors,
onChange, onChange,
plugin fields
}) => { }) => {
const classes = useStyles({}); const classes = useStyles({});
const intl = useIntl();
return ( return (
<Card> <Card>
<CardTitle <CardTitle
title={i18n.t("Plugin Settings", { title={intl.formatMessage({
context: "plugin configuration" defaultMessage: "Plugin Settings",
description: "plugin section title"
})} })}
/> />
<CardContent> <CardContent>
{data.configuration.map((configuration, index) => ( {data.configuration.map((configuration, index) => (
<div className={classes.item} key={index}> <div className={classes.item} key={index}>
{plugin[index].type === ConfigurationTypeFieldEnum.STRING && ( {fields[index].type === ConfigurationTypeFieldEnum.STRING && (
<TextField <TextField
disabled={disabled} disabled={disabled}
error={!!errors.name} error={!!errors.name}
helperText={plugin[index].helpText} helperText={fields[index].helpText}
label={plugin[index].label} label={fields[index].label}
name={configuration.name} name={configuration.name}
fullWidth fullWidth
value={configuration.value} value={configuration.value}
onChange={onChange} onChange={onChange}
/> />
)} )}
{plugin[index].type === ConfigurationTypeFieldEnum.BOOLEAN && ( {fields[index].type === ConfigurationTypeFieldEnum.BOOLEAN && (
<ControlledSwitch <ControlledSwitch
checked={ checked={
typeof configuration.value !== "boolean" typeof configuration.value !== "boolean"
@ -69,7 +72,7 @@ const PluginSettings: React.StatelessComponent<PluginSettingsProps> = ({
: configuration.value : configuration.value
} }
disabled={disabled} disabled={disabled}
label={plugin[index].label} label={fields[index].label}
name={configuration.name} name={configuration.name}
onChange={onChange} onChange={onChange}
/> />

View file

@ -6,12 +6,13 @@ import Form from "@saleor/components/Form";
import Grid from "@saleor/components/Grid"; import Grid from "@saleor/components/Grid";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SaveButtonBar from "@saleor/components/SaveButtonBar";
import { sectionNames } from "@saleor/intl";
import { maybe } from "@saleor/misc"; import { maybe } from "@saleor/misc";
import { UserError } from "@saleor/types"; import { UserError } from "@saleor/types";
import { ConfigurationItemInput } from "@saleor/types/globalTypes"; import { ConfigurationItemInput } from "@saleor/types/globalTypes";
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import i18n from "../../../i18n";
import { Plugin_plugin } from "../../types/Plugin"; import { Plugin_plugin } from "../../types/Plugin";
import PluginInfo from "../PluginInfo"; import PluginInfo from "../PluginInfo";
import PluginSettings from "../PluginSettings"; import PluginSettings from "../PluginSettings";
@ -38,6 +39,7 @@ const PluginsDetailsPage: React.StatelessComponent<PluginsDetailsPageProps> = ({
onBack, onBack,
onSubmit onSubmit
}) => { }) => {
const intl = useIntl();
const initialForm: FormData = { const initialForm: FormData = {
active: maybe(() => plugin.active, false), active: maybe(() => plugin.active, false),
configuration: maybe(() => plugin.configuration, []) configuration: maybe(() => plugin.configuration, [])
@ -67,19 +69,29 @@ const PluginsDetailsPage: React.StatelessComponent<PluginsDetailsPageProps> = ({
}; };
return ( return (
<Container> <Container>
<AppHeader onBack={onBack}>{i18n.t("Plugins")}</AppHeader> <AppHeader onBack={onBack}>
{intl.formatMessage(sectionNames.plugins)}
</AppHeader>
<PageHeader <PageHeader
title={`${maybe(() => plugin.name, "")} ${i18n.t("Details")}`} title={`${maybe(() => plugin.name, "")} ${intl.formatMessage({
defaultMessage: "Details",
description: "plugin page title"
})}`}
/> />
<Grid variant="inverted"> <Grid variant="inverted">
<div> <div>
<Typography variant="h6"> <Typography variant="h6">
{i18n.t("Plugin Information and Status")} {intl.formatMessage({
defaultMessage: "Plugin Information and Status",
description: "plugin section title"
})}
</Typography> </Typography>
<Typography> <Typography>
{i18n.t( {intl.formatMessage({
"These are general information about your store. They define what is the URL of your store and what is shown in brow sers taskbar." 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.",
description: "plugin section description"
})}
</Typography> </Typography>
</div> </div>
<PluginInfo <PluginInfo
@ -92,17 +104,22 @@ const PluginsDetailsPage: React.StatelessComponent<PluginsDetailsPageProps> = ({
<> <>
<div> <div>
<Typography variant="h6"> <Typography variant="h6">
{i18n.t("Plugin Settings")} {intl.formatMessage({
defaultMessage: "Plugin Settings",
description: "plugin section title"
})}
</Typography> </Typography>
<Typography> <Typography>
{i18n.t( {intl.formatMessage({
"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." defaultMessage:
)} "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.",
description: "plugin section description"
})}
</Typography> </Typography>
</div> </div>
<PluginSettings <PluginSettings
data={data} data={data}
plugin={maybe(() => plugin.configuration, [])} fields={maybe(() => plugin.configuration, [])}
errors={errors} errors={errors}
disabled={disabled} disabled={disabled}
onChange={onChange} onChange={onChange}

View file

@ -12,15 +12,15 @@ import TableFooter from "@material-ui/core/TableFooter";
import TableRow from "@material-ui/core/TableRow"; import TableRow from "@material-ui/core/TableRow";
import EditIcon from "@material-ui/icons/Edit"; import EditIcon from "@material-ui/icons/Edit";
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import Skeleton from "@saleor/components/Skeleton"; import Skeleton from "@saleor/components/Skeleton";
import StatusLabel from "@saleor/components/StatusLabel"; import StatusLabel from "@saleor/components/StatusLabel";
import TableHead from "@saleor/components/TableHead"; import TableHead from "@saleor/components/TableHead";
import TablePagination from "@saleor/components/TablePagination"; import TablePagination from "@saleor/components/TablePagination";
import i18n from "@saleor/i18n"; import { translateBoolean } from "@saleor/intl";
import { maybe, renderCollection } from "@saleor/misc"; import { maybe, renderCollection } from "@saleor/misc";
import { ListProps } from "@saleor/types"; import { ListProps } from "@saleor/types";
import { translateBoolean } from "@saleor/utils/i18n";
import { Plugins_plugins_edges_node } from "../../types/Plugins"; import { Plugins_plugins_edges_node } from "../../types/Plugins";
export interface PluginListProps extends ListProps { export interface PluginListProps extends ListProps {
@ -61,6 +61,7 @@ const PluginList = withStyles(styles, { name: "PluginList" })(
onUpdateListSettings, onUpdateListSettings,
onPreviousPage onPreviousPage
}: PluginListProps & WithStyles<typeof styles>) => { }: PluginListProps & WithStyles<typeof styles>) => {
const intl = useIntl();
return ( return (
<Card> <Card>
<Table> <Table>
@ -70,13 +71,22 @@ const PluginList = withStyles(styles, { name: "PluginList" })(
items={plugins} items={plugins}
> >
<TableCell className={classes.colName} padding="dense"> <TableCell className={classes.colName} padding="dense">
{i18n.t("Name", { context: "table header" })} {intl.formatMessage({
defaultMessage: "Name",
description: "plugin list table header"
})}
</TableCell> </TableCell>
<TableCell className={classes.colActive} padding="dense"> <TableCell className={classes.colActive} padding="dense">
{i18n.t("Active", { context: "table header" })} {intl.formatMessage({
defaultMessage: "Active",
description: "plugin list table header"
})}
</TableCell> </TableCell>
<TableCell className={classes.colAction} padding="dense"> <TableCell className={classes.colAction} padding="dense">
{i18n.t("Action", { context: "table header" })} {intl.formatMessage({
defaultMessage: "Action",
description: "plugin list table header"
})}
</TableCell> </TableCell>
</TableHead> </TableHead>
<TableFooter> <TableFooter>
@ -114,7 +124,7 @@ const PluginList = withStyles(styles, { name: "PluginList" })(
{maybe<React.ReactNode>( {maybe<React.ReactNode>(
() => ( () => (
<StatusLabel <StatusLabel
label={translateBoolean(plugin.active)} label={translateBoolean(plugin.active, intl)}
status={plugin.active ? "success" : "error"} status={plugin.active ? "success" : "error"}
/> />
), ),
@ -132,7 +142,10 @@ const PluginList = withStyles(styles, { name: "PluginList" })(
() => ( () => (
<TableRow> <TableRow>
<TableCell colSpan={numberOfColumns}> <TableCell colSpan={numberOfColumns}>
{i18n.t("No plugins found")} {intl.formatMessage({
defaultMessage: "No plugins found",
description: "plugin no found"
})}
</TableCell> </TableCell>
</TableRow> </TableRow>
) )

View file

@ -1,9 +1,10 @@
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import AppHeader from "@saleor/components/AppHeader"; import AppHeader from "@saleor/components/AppHeader";
import Container from "@saleor/components/Container"; import Container from "@saleor/components/Container";
import PageHeader from "@saleor/components/PageHeader"; import PageHeader from "@saleor/components/PageHeader";
import i18n from "@saleor/i18n"; import { sectionNames } from "@saleor/intl";
import { PageListProps } from "@saleor/types"; import { PageListProps } from "@saleor/types";
import { Plugins_plugins_edges_node } from "../../types/Plugins"; import { Plugins_plugins_edges_node } from "../../types/Plugins";
import PluginsList from "../PluginsList/PluginsList"; import PluginsList from "../PluginsList/PluginsList";
@ -23,21 +24,29 @@ const PluginsListPage: React.StatelessComponent<PluginsListPageProps> = ({
onUpdateListSettings, onUpdateListSettings,
pageInfo, pageInfo,
plugins plugins
}) => ( }) => {
<Container> const intl = useIntl();
<AppHeader onBack={onBack}>{i18n.t("Configuration")}</AppHeader> return (
<PageHeader title={i18n.t("Plugins")} /> <Container>
<PluginsList <AppHeader onBack={onBack}>
disabled={disabled} {intl.formatMessage({
settings={settings} defaultMessage: "Configuration",
plugins={plugins} description: "plugin back button"
onNextPage={onNextPage} })}
onPreviousPage={onPreviousPage} </AppHeader>
onUpdateListSettings={onUpdateListSettings} <PageHeader title={intl.formatMessage(sectionNames.plugins)} />
onRowClick={onRowClick} <PluginsList
pageInfo={pageInfo} disabled={disabled}
/> settings={settings}
</Container> plugins={plugins}
); onNextPage={onNextPage}
onPreviousPage={onPreviousPage}
onUpdateListSettings={onUpdateListSettings}
onRowClick={onRowClick}
pageInfo={pageInfo}
/>
</Container>
);
};
PluginsListPage.displayName = "PluginsListPage"; PluginsListPage.displayName = "PluginsListPage";
export default PluginsListPage; export default PluginsListPage;

View file

@ -1,9 +1,10 @@
import { parse as parseQs } from "qs"; import { parse as parseQs } from "qs";
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import { Route, RouteComponentProps, Switch } from "react-router-dom"; import { Route, RouteComponentProps, Switch } from "react-router-dom";
import { sectionNames } from "@saleor/intl";
import { WindowTitle } from "../components/WindowTitle"; import { WindowTitle } from "../components/WindowTitle";
import i18n from "../i18n";
import { import {
pluginsListPath, pluginsListPath,
PluginsListUrlQueryParams, PluginsListUrlQueryParams,
@ -34,14 +35,17 @@ const PageDetails: React.StatelessComponent<RouteComponentProps<any>> = ({
); );
}; };
const Component = () => ( const Component = () => {
<> const intl = useIntl();
<WindowTitle title={i18n.t("Plugins")} /> return (
<Switch> <>
<Route exact path={pluginsListPath} component={PluginList} /> <WindowTitle title={intl.formatMessage(sectionNames.plugins)} />
<Route path={pluginsPath(":id")} component={PageDetails} /> <Switch>
</Switch> <Route exact path={pluginsListPath} component={PluginList} />
</> <Route path={pluginsPath(":id")} component={PageDetails} />
); </Switch>
</>
);
};
export default Component; export default Component;

View file

@ -1,8 +1,9 @@
import { WindowTitle } from "@saleor/components/WindowTitle"; import { WindowTitle } from "@saleor/components/WindowTitle";
import useNavigator from "@saleor/hooks/useNavigator"; import useNavigator from "@saleor/hooks/useNavigator";
import useNotifier from "@saleor/hooks/useNotifier"; import useNotifier from "@saleor/hooks/useNotifier";
import i18n from "@saleor/i18n";
import React from "react"; import React from "react";
import { useIntl } from "react-intl";
import { getMutationState, maybe } from "../../misc"; import { getMutationState, maybe } from "../../misc";
import PluginsDetailsPage from "../components/PluginsDetailsPage"; import PluginsDetailsPage from "../components/PluginsDetailsPage";
import { TypedPluginUpdate } from "../mutations"; import { TypedPluginUpdate } from "../mutations";
@ -19,6 +20,7 @@ export const PluginsDetails: React.StatelessComponent<PluginsDetailsProps> = ({
}) => { }) => {
const navigate = useNavigator(); const navigate = useNavigator();
const notify = useNotifier(); const notify = useNotifier();
const intl = useIntl();
return ( return (
<TypedPluginUpdate> <TypedPluginUpdate>
@ -45,7 +47,10 @@ export const PluginsDetails: React.StatelessComponent<PluginsDetailsProps> = ({
} else { } else {
if (pluginUpdateOpts.data) { if (pluginUpdateOpts.data) {
notify({ notify({
text: i18n.t("Succesfully updated plugin settings") text: intl.formatMessage({
defaultMessage: "Succesfully updated plugin settings",
description: "plugin success message"
})
}); });
} }
} }

View file

@ -7,6 +7,7 @@ import usePaginator, {
import { maybe } from "@saleor/misc"; import { maybe } from "@saleor/misc";
import { ListViews } from "@saleor/types"; import { ListViews } from "@saleor/types";
import React from "react"; import React from "react";
import PluginsListPage from "../components/PluginsListPage/PluginsListPage"; import PluginsListPage from "../components/PluginsListPage/PluginsListPage";
import { TypedPluginsListQuery } from "../queries"; import { TypedPluginsListQuery } from "../queries";
import { PluginsListUrlQueryParams, pluginsUrl } from "../urls"; import { PluginsListUrlQueryParams, pluginsUrl } from "../urls";