Add quick app install from manifest (#2378)
* Create a button that navigates to app install page * Add translations keys * Extract messages * Change type literal to enum * Update snapshots
This commit is contained in:
parent
be76836e12
commit
1fb4479058
6 changed files with 178 additions and 3 deletions
|
@ -3627,6 +3627,9 @@
|
||||||
"context": "product field",
|
"context": "product field",
|
||||||
"string": "Charge Taxes"
|
"string": "Charge Taxes"
|
||||||
},
|
},
|
||||||
|
"QVraQY": {
|
||||||
|
"string": "App manifest URL"
|
||||||
|
},
|
||||||
"QY7FSs": {
|
"QY7FSs": {
|
||||||
"context": "button",
|
"context": "button",
|
||||||
"string": "create product type"
|
"string": "create product type"
|
||||||
|
@ -6007,6 +6010,10 @@
|
||||||
"context": "set balance dialog subtitle",
|
"context": "set balance dialog subtitle",
|
||||||
"string": "What would you like to set cards balance to. When you change the balance both values will be changed"
|
"string": "What would you like to set cards balance to. When you change the balance both values will be changed"
|
||||||
},
|
},
|
||||||
|
"kIXV5V": {
|
||||||
|
"context": "install with app manifest button",
|
||||||
|
"string": "Install with App Manifest"
|
||||||
|
},
|
||||||
"kIvvax": {
|
"kIvvax": {
|
||||||
"string": "Search Products..."
|
"string": "Search Products..."
|
||||||
},
|
},
|
||||||
|
@ -6461,6 +6468,9 @@
|
||||||
"context": "dialog title",
|
"context": "dialog title",
|
||||||
"string": "Delete Warehouse"
|
"string": "Delete Warehouse"
|
||||||
},
|
},
|
||||||
|
"o/q4fc": {
|
||||||
|
"string": "Usually ends with /api/manifest"
|
||||||
|
},
|
||||||
"o5KXAN": {
|
"o5KXAN": {
|
||||||
"context": "delete webhook",
|
"context": "delete webhook",
|
||||||
"string": "Are you sure you want to delete {name}?"
|
"string": "Are you sure you want to delete {name}?"
|
||||||
|
@ -7247,6 +7257,9 @@
|
||||||
"context": "order history message",
|
"context": "order history message",
|
||||||
"string": "Order was confirmed"
|
"string": "Order was confirmed"
|
||||||
},
|
},
|
||||||
|
"ubmFc8": {
|
||||||
|
"string": "Install"
|
||||||
|
},
|
||||||
"ud0w8h": {
|
"ud0w8h": {
|
||||||
"context": "number of postal code ranges",
|
"context": "number of postal code ranges",
|
||||||
"string": "{number} postal code ranges"
|
"string": "{number} postal code ranges"
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
import { TextField } from "@material-ui/core";
|
||||||
|
import { Button } from "@saleor/components/Button";
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
|
enum AvailableStates {
|
||||||
|
Initial,
|
||||||
|
InputOpen,
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
installButton: {
|
||||||
|
marginLeft: theme.spacing(2),
|
||||||
|
height: 52,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "InstallWithManifestFormButton",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onSubmitted(manifestUrl: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const InstallWithManifestFormButton = ({ onSubmitted }: Props) => {
|
||||||
|
const styles = useStyles();
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const [state, setState] = useState<AvailableStates>(AvailableStates.Initial);
|
||||||
|
|
||||||
|
const handleFormSubmit: React.FormEventHandler<HTMLFormElement> = e => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const form = new FormData(e.currentTarget);
|
||||||
|
const inputValue = form.get("manifest-url") as string;
|
||||||
|
|
||||||
|
try {
|
||||||
|
new URL(inputValue);
|
||||||
|
|
||||||
|
onSubmitted(inputValue);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Invalid URL from input. Should be validated by browser");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case AvailableStates.Initial: {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
data-test-id="add-app-from-manifest"
|
||||||
|
onClick={() => setState(AvailableStates.InputOpen)}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="kIXV5V"
|
||||||
|
defaultMessage="Install with App Manifest"
|
||||||
|
description="install with app manifest button"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case AvailableStates.InputOpen: {
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleFormSubmit}>
|
||||||
|
<TextField
|
||||||
|
required
|
||||||
|
type="url"
|
||||||
|
name="manifest-url"
|
||||||
|
label={intl.formatMessage({
|
||||||
|
id: "QVraQY",
|
||||||
|
defaultMessage: "App manifest URL",
|
||||||
|
})}
|
||||||
|
defaultValue=""
|
||||||
|
helperText={intl.formatMessage({
|
||||||
|
id: "o/q4fc",
|
||||||
|
defaultMessage: "Usually ends with /api/manifest",
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
size="medium"
|
||||||
|
type="submit"
|
||||||
|
className={styles.installButton}
|
||||||
|
variant="primary"
|
||||||
|
>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "ubmFc8",
|
||||||
|
defaultMessage: "Install",
|
||||||
|
})}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1 @@
|
||||||
|
export * from "./InstallWithManifestFormButton";
|
|
@ -6,18 +6,20 @@ import {
|
||||||
TableRow,
|
TableRow,
|
||||||
Typography,
|
Typography,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
|
import { InstallWithManifestFormButton } from "@saleor/apps/components/InstallWithManifestFormButton";
|
||||||
import { useAppListContext } from "@saleor/apps/context";
|
import { useAppListContext } from "@saleor/apps/context";
|
||||||
import { appUrl } from "@saleor/apps/urls";
|
import { appUrl, createAppInstallUrl } from "@saleor/apps/urls";
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
import { IconButton } from "@saleor/components/IconButton";
|
import { IconButton } from "@saleor/components/IconButton";
|
||||||
import { TableButtonWrapper } from "@saleor/components/TableButtonWrapper/TableButtonWrapper";
|
import { TableButtonWrapper } from "@saleor/components/TableButtonWrapper/TableButtonWrapper";
|
||||||
import TableRowLink from "@saleor/components/TableRowLink";
|
import TableRowLink from "@saleor/components/TableRowLink";
|
||||||
import { AppListItemFragment, AppsListQuery } from "@saleor/graphql";
|
import { AppListItemFragment, AppsListQuery } from "@saleor/graphql";
|
||||||
|
import useNavigator from "@saleor/hooks/useNavigator";
|
||||||
import { DeleteIcon, ResponsiveTable } from "@saleor/macaw-ui";
|
import { DeleteIcon, ResponsiveTable } from "@saleor/macaw-ui";
|
||||||
import { renderCollection } from "@saleor/misc";
|
import { renderCollection } from "@saleor/misc";
|
||||||
import { ListProps } from "@saleor/types";
|
import { ListProps } from "@saleor/types";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React from "react";
|
import React, { useCallback } from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import { useStyles } from "../../styles";
|
import { useStyles } from "../../styles";
|
||||||
|
@ -37,6 +39,14 @@ const InstalledApps: React.FC<InstalledAppsProps> = ({
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
const { activateApp, deactivateApp } = useAppListContext();
|
const { activateApp, deactivateApp } = useAppListContext();
|
||||||
|
const navigate = useNavigator();
|
||||||
|
|
||||||
|
const navigateToAppInstallPage = useCallback(
|
||||||
|
(url: string) => {
|
||||||
|
navigate(createAppInstallUrl(url));
|
||||||
|
},
|
||||||
|
[navigate],
|
||||||
|
);
|
||||||
|
|
||||||
const getHandleToggle = (app: AppListItemFragment) => () => {
|
const getHandleToggle = (app: AppListItemFragment) => () => {
|
||||||
if (app.isActive) {
|
if (app.isActive) {
|
||||||
|
@ -54,6 +64,11 @@ const InstalledApps: React.FC<InstalledAppsProps> = ({
|
||||||
defaultMessage: "Third Party Apps",
|
defaultMessage: "Third Party Apps",
|
||||||
description: "section header",
|
description: "section header",
|
||||||
})}
|
})}
|
||||||
|
toolbar={
|
||||||
|
<InstallWithManifestFormButton
|
||||||
|
onSubmitted={navigateToAppInstallPage}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<ResponsiveTable>
|
<ResponsiveTable>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
|
|
|
@ -54,7 +54,8 @@ export const appDeepPath = (id: string, subPath: string) =>
|
||||||
urlJoin(appPath(id), subPath);
|
urlJoin(appPath(id), subPath);
|
||||||
export const customAppPath = (id: string) => urlJoin(customAppListPath, id);
|
export const customAppPath = (id: string) => urlJoin(customAppListPath, id);
|
||||||
export const appInstallPath = urlJoin(appsSection, "install");
|
export const appInstallPath = urlJoin(appsSection, "install");
|
||||||
export const appInstallUrl = appInstallPath;
|
export const createAppInstallUrl = (manifestUrl: string) =>
|
||||||
|
`${appInstallPath}?manifestUrl=${manifestUrl}`;
|
||||||
|
|
||||||
export const appDetailsUrl = (id: string, params?: AppDetailsUrlQueryParams) =>
|
export const appDetailsUrl = (id: string, params?: AppDetailsUrlQueryParams) =>
|
||||||
appDetailsPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
appDetailsPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
|
||||||
|
|
|
@ -25459,6 +25459,22 @@ exports[`Storyshots Views / Apps / Apps list default 1`] = `
|
||||||
Third Party Apps
|
Third Party Apps
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiCardHeader-action-id"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-outlined-id MuiButton-outlinedPrimary-id"
|
||||||
|
data-test-id="add-app-from-manifest"
|
||||||
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiButton-label-id"
|
||||||
|
>
|
||||||
|
Install with App Manifest
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="ResponsiveTable-root-id"
|
class="ResponsiveTable-root-id"
|
||||||
|
@ -25997,6 +26013,22 @@ exports[`Storyshots Views / Apps / Apps list loading 1`] = `
|
||||||
Third Party Apps
|
Third Party Apps
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiCardHeader-action-id"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-outlined-id MuiButton-outlinedPrimary-id"
|
||||||
|
data-test-id="add-app-from-manifest"
|
||||||
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiButton-label-id"
|
||||||
|
>
|
||||||
|
Install with App Manifest
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="ResponsiveTable-root-id"
|
class="ResponsiveTable-root-id"
|
||||||
|
@ -26138,6 +26170,22 @@ exports[`Storyshots Views / Apps / Apps list no data 1`] = `
|
||||||
Third Party Apps
|
Third Party Apps
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiCardHeader-action-id"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-outlined-id MuiButton-outlinedPrimary-id"
|
||||||
|
data-test-id="add-app-from-manifest"
|
||||||
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiButton-label-id"
|
||||||
|
>
|
||||||
|
Install with App Manifest
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="ResponsiveTable-root-id"
|
class="ResponsiveTable-root-id"
|
||||||
|
|
Loading…
Reference in a new issue