Inform about app replacements of plugins in plugins page (#4047)

* Inform about app replacements of plugins in plugins page

* Change Alert implementation to macaw Box
This commit is contained in:
Lukasz Ostrowski 2023-08-03 15:53:58 +02:00 committed by GitHub
parent 677f77771a
commit a25a8db3d0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 132 additions and 7 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-dashboard": minor
---
Added information in Plugins Page about the App Store. Now plugins page informs that Apps will replace plugins in the future. Also every plugin that is "active" will display an inline message to visit the App Store for the app replacement

View file

@ -3511,6 +3511,9 @@
"context": "dialog header",
"string": "Cancel Orders"
},
"NL6mvR": {
"string": "Visit App Store to replace with the App"
},
"NLNonj": {
"context": "send to channel select label",
"string": "Send to channel"
@ -8667,6 +8670,9 @@
"context": "table header channel col label",
"string": "Channel"
},
"yfhLcv": {
"string": "We are working on replacing plugins with apps. Read more about"
},
"yhv3HX": {
"context": "voucher requirements, header",
"string": "Minimum Requirements"

View file

@ -1,7 +1,8 @@
import { Typography } from "@material-ui/core";
import { TypographyProps } from "@material-ui/core/Typography";
import { makeStyles } from "@saleor/macaw-ui";
import React from "react";
import { Text, TextProps } from "@saleor/macaw-ui/next";
import React, { HTMLAttributes } from "react";
const useStyles = makeStyles(
{
@ -18,6 +19,9 @@ interface ExternalLinkProps extends React.HTMLProps<HTMLAnchorElement> {
typographyProps?: TypographyProps;
}
/**
* @deprecated use ExternalLinkNext
*/
const ExternalLink: React.FC<ExternalLinkProps> = props => {
const { className, children, href, typographyProps, target, rel, ...rest } =
props;
@ -42,3 +46,18 @@ const ExternalLink: React.FC<ExternalLinkProps> = props => {
};
ExternalLink.displayName = "ExternalLink";
export default ExternalLink;
export const ExternalLinkNext = (
props: TextProps & Omit<HTMLAttributes<HTMLAnchorElement>, "children">,
) => {
const opensNewTab = props.target === "_blank";
return (
<Text
{...props}
as="a"
rel={props.rel ?? opensNewTab ? "noopener noreferer" : ""}
textDecoration="none"
/>
);
};

View file

@ -5,13 +5,20 @@ import TableRowLink from "@dashboard/components/TableRowLink";
import { PluginBaseFragment } from "@dashboard/graphql";
import useNavigator from "@dashboard/hooks/useNavigator";
import { renderCollection } from "@dashboard/misc";
import { getPluginsWithAppReplacementsIds } from "@dashboard/plugins/plugins-with-app-replacements";
import { PluginListUrlSortField, pluginUrl } from "@dashboard/plugins/urls";
import { ListProps, SortPage } from "@dashboard/types";
import { TableBody, TableCell, TableFooter } from "@material-ui/core";
import {
TableBody,
TableCell,
TableFooter,
Typography,
} from "@material-ui/core";
import { EditIcon, makeStyles } from "@saleor/macaw-ui";
import React from "react";
import { useIntl } from "react-intl";
import { pluginsMiscMessages } from "./messages";
import PluginChannelAvailabilityCell from "./PluginChannelAvailabilityCell";
import PluginChannelConfigurationCell from "./PluginChannelConfigurationCell";
import PluginListTableHead from "./PluginListTableHead";
@ -25,6 +32,10 @@ export const useStyles = makeStyles(
{ name: "PluginsList" },
);
const pluginsWithAppReplacements = getPluginsWithAppReplacementsIds();
const hasAppReplacement = (pluginId: string) =>
pluginsWithAppReplacements.includes(pluginId);
export interface PluginListProps
extends ListProps,
SortPage<PluginListUrlSortField> {
@ -56,8 +67,16 @@ const PluginList: React.FC<PluginListProps> = props => {
<TableBody>
{renderCollection(
plugins,
plugin =>
plugin ? (
plugin => {
const hasReplacement = plugin && hasAppReplacement(plugin.id);
const activeChannelConfigurations =
plugin?.channelConfigurations?.filter(c => c.active);
const isActive =
plugin?.globalConfiguration?.active ||
(activeChannelConfigurations &&
activeChannelConfigurations.length > 0);
return plugin ? (
<TableRowLink
data-test-id="plugin"
hover={!!plugin}
@ -67,7 +86,16 @@ const PluginList: React.FC<PluginListProps> = props => {
onClick={() => plugin && navigate(pluginUrl(plugin.id))}
key={plugin ? plugin.id : "skeleton"}
>
<TableCell colSpan={5}>{plugin.name}</TableCell>
<TableCell colSpan={5}>
<Typography>{plugin.name}</Typography>
{hasReplacement && isActive && (
<Typography variant="caption" color="error">
{intl.formatMessage(
pluginsMiscMessages.appReplacementMessage,
)}
</Typography>
)}
</TableCell>
<PluginChannelConfigurationCell plugin={plugin} />
<PluginChannelAvailabilityCell plugin={plugin} />
<TableCell align="right">
@ -80,7 +108,8 @@ const PluginList: React.FC<PluginListProps> = props => {
<Skeleton />
</TableCell>
</TableRowLink>
),
);
},
() => (
<TableRowLink>
<TableCell colSpan={totalColSpan}>

View file

@ -75,3 +75,10 @@ export const pluginStatusMessages = defineMessages({
description: "status label deactivated",
},
});
export const pluginsMiscMessages = defineMessages({
appReplacementMessage: {
defaultMessage: "Visit App Store to replace with the App",
id: 'NL6mvR',
},
});

View file

@ -1,10 +1,12 @@
// @ts-strict-ignore
import { TopNav } from "@dashboard/components/AppLayout/TopNav";
import { ExternalLinkNext } from "@dashboard/components/ExternalLink";
import FilterBar from "@dashboard/components/FilterBar";
import { ListPageLayout } from "@dashboard/components/Layouts";
import { configurationMenuUrl } from "@dashboard/configuration";
import { PluginBaseFragment } from "@dashboard/graphql";
import { sectionNames } from "@dashboard/intl";
import { getStatusColor } from "@dashboard/misc";
import { PluginListUrlSortField } from "@dashboard/plugins/urls";
import {
FilterPageProps,
@ -13,6 +15,7 @@ import {
TabPageProps,
} from "@dashboard/types";
import { Card } from "@material-ui/core";
import { Box, Text } from "@saleor/macaw-ui/next";
import React from "react";
import { useIntl } from "react-intl";
@ -22,7 +25,10 @@ import {
PluginFilterKeys,
PluginListFilterOpts,
} from "./filters";
import { pluginsFilterErrorMessages } from "./messages";
import {
pluginsFilterErrorMessages,
pluginsListPageMessages,
} from "./messages";
export interface PluginsListPageProps
extends PageListProps,
@ -56,6 +62,27 @@ const PluginsListPage: React.FC<PluginsListPageProps> = ({
title={intl.formatMessage(sectionNames.plugins)}
/>
<Card>
<div>
<Box
paddingX={7}
paddingY={5}
marginBottom={5}
__backgroundColor={getStatusColor("warning")}
>
<Text variant="heading" as="h2">
{intl.formatMessage(pluginsListPageMessages.warningHeadline)}
</Text>
<Text variant="body">
{intl.formatMessage(pluginsListPageMessages.appStoreWarning)}{" "}
<ExternalLinkNext
target="_blank"
href="https://docs.saleor.io/docs/3.x/developer/app-store/overview"
>
Saleor App Store.
</ExternalLinkNext>
</Text>
</Box>
</div>
<FilterBar
errorMessages={pluginsFilterErrorMessages}
currentTab={currentTab}

View file

@ -12,3 +12,15 @@ export const pluginsFilterErrorMessages = defineMessages({
description: "plugin filters error messages channels",
},
});
export const pluginsListPageMessages = defineMessages({
appStoreWarning: {
defaultMessage:
"We are working on replacing plugins with apps. Read more about",
id: "yfhLcv",
},
warningHeadline: {
defaultMessage: "Warning",
id: "3SVI5p",
},
});

View file

@ -0,0 +1,20 @@
/**
* Provides a static list of plugins IDs that are already re-implemented
* as apps and available in the App Store.
*
* In the future they will be officially deprecated, but now called "with app replacements"
*
* Ids are part of plugins query
* https://docs.saleor.io/docs/3.x/api-reference/miscellaneous/queries/plugins
*/
export const getPluginsWithAppReplacementsIds = () => {
return [
"mirumee.payments.adyen",
"mirumee.taxes.avalara",
"mirumee.invoicing",
"mirumee.notifications.sendgrid_email",
"saleor.payments.stripe",
"mirumee.payments.stripe",
"mirumee.notifications.user_email",
];
};