Refactor AppDetailsPage to Macaw Next (#3818)
* Refactor AppDetailsPage to Macaw Next * Update locales * CR fixes * Add error boundary
This commit is contained in:
parent
c12a42932d
commit
a1482cc453
12 changed files with 203 additions and 128 deletions
5
.changeset/orange-falcons-judge.md
Normal file
5
.changeset/orange-falcons-judge.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
"saleor-dashboard": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Refactored Manage App screen to use Macaw/next. Added missing empty-state messages, like missing permissions or app description.
|
|
@ -1927,6 +1927,10 @@
|
||||||
"context": "dialog content",
|
"context": "dialog content",
|
||||||
"string": "Which address would you like to use as shipping address for selected customer:"
|
"string": "Which address would you like to use as shipping address for selected customer:"
|
||||||
},
|
},
|
||||||
|
"CHoZ8S": {
|
||||||
|
"context": "app privacy policy link",
|
||||||
|
"string": "View this app’s privacy policy."
|
||||||
|
},
|
||||||
"CJEIRC": {
|
"CJEIRC": {
|
||||||
"string": "Product export has finished and was sent to your email address."
|
"string": "Product export has finished and was sent to your email address."
|
||||||
},
|
},
|
||||||
|
@ -2597,10 +2601,6 @@
|
||||||
"context": "button",
|
"context": "button",
|
||||||
"string": "Unassign"
|
"string": "Unassign"
|
||||||
},
|
},
|
||||||
"Go50v2": {
|
|
||||||
"context": "app privacy policy link",
|
|
||||||
"string": "View this app’s privacy policy"
|
|
||||||
},
|
|
||||||
"GpqEl5": {
|
"GpqEl5": {
|
||||||
"context": "shipping method description",
|
"context": "shipping method description",
|
||||||
"string": "Description"
|
"string": "Description"
|
||||||
|
@ -5444,6 +5444,9 @@
|
||||||
"b+jcaN": {
|
"b+jcaN": {
|
||||||
"string": "There are still fulfillments created for this order. Cancel the fulfillments first before you cancel the order."
|
"string": "There are still fulfillments created for this order. Cancel the fulfillments first before you cancel the order."
|
||||||
},
|
},
|
||||||
|
"b088Xv": {
|
||||||
|
"string": "App doesn't provide a description."
|
||||||
|
},
|
||||||
"b1t9bM": {
|
"b1t9bM": {
|
||||||
"context": "empty headers text",
|
"context": "empty headers text",
|
||||||
"string": "No custom request headers created for this webhook. Use the button below to add new custom request header."
|
"string": "No custom request headers created for this webhook. Use the button below to add new custom request header."
|
||||||
|
@ -5946,6 +5949,9 @@
|
||||||
"context": "attributes, section header",
|
"context": "attributes, section header",
|
||||||
"string": "Variant Attributes"
|
"string": "Variant Attributes"
|
||||||
},
|
},
|
||||||
|
"f3hf+w": {
|
||||||
|
"string": "App doesn't provide a privacy policy."
|
||||||
|
},
|
||||||
"f91E8b": {
|
"f91E8b": {
|
||||||
"context": "app repository",
|
"context": "app repository",
|
||||||
"string": "Repository"
|
"string": "Repository"
|
||||||
|
@ -8231,6 +8237,9 @@
|
||||||
"context": "order refund amount",
|
"context": "order refund amount",
|
||||||
"string": "Proposed refund amount"
|
"string": "Proposed refund amount"
|
||||||
},
|
},
|
||||||
|
"wDYozn": {
|
||||||
|
"string": "App doesn't have any permissions granted."
|
||||||
|
},
|
||||||
"wHdMAX": {
|
"wHdMAX": {
|
||||||
"context": "sale value, header",
|
"context": "sale value, header",
|
||||||
"string": "Value"
|
"string": "Value"
|
||||||
|
|
|
@ -1,27 +1,45 @@
|
||||||
import CardTitle from "@dashboard/components/CardTitle";
|
|
||||||
import Skeleton from "@dashboard/components/Skeleton";
|
import Skeleton from "@dashboard/components/Skeleton";
|
||||||
import { Card, CardContent } from "@material-ui/core";
|
import { Box, BoxProps, Text } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
|
|
||||||
interface AboutCardProps {
|
type AboutCardProps = {
|
||||||
aboutApp?: string | null;
|
aboutApp?: string | null;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
}
|
} & BoxProps;
|
||||||
|
|
||||||
const AboutCard: React.FC<AboutCardProps> = ({ aboutApp, loading }) => {
|
export const AboutCard: React.FC<AboutCardProps> = ({
|
||||||
|
aboutApp,
|
||||||
|
loading,
|
||||||
|
...boxProps
|
||||||
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const renderContent = () => {
|
||||||
|
if (loading) {
|
||||||
|
return <Skeleton />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aboutApp) {
|
||||||
|
return <ReactMarkdown source={aboutApp} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aboutApp) {
|
||||||
|
return <Text>{intl.formatMessage(messages.noAboutApp)}</Text>;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Leaking "if" statement, should never happen');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Box {...boxProps}>
|
||||||
<CardTitle title={intl.formatMessage(messages.aboutAppTitle)} />
|
<Text variant={"heading"} as={"h2"} marginBottom={4}>
|
||||||
<CardContent>
|
{intl.formatMessage(messages.aboutAppTitle)}
|
||||||
{!loading ? <ReactMarkdown source={aboutApp ?? ""} /> : <Skeleton />}
|
</Text>
|
||||||
</CardContent>
|
<Box>{renderContent()}</Box>
|
||||||
</Card>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default AboutCard;
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Meta, StoryObj } from "@storybook/react";
|
import { Meta, StoryObj } from "@storybook/react";
|
||||||
|
|
||||||
import { appDetails } from "../../fixtures";
|
import { appDetails } from "../../fixtures";
|
||||||
import AppDetailsPage, { AppDetailsPageProps } from "./AppDetailsPage";
|
import { AppDetailsPage, AppDetailsPageProps } from "./AppDetailsPage";
|
||||||
|
|
||||||
const props: AppDetailsPageProps = {
|
const props: AppDetailsPageProps = {
|
||||||
data: appDetails,
|
data: appDetails,
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { render } from "@testing-library/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import { appDetails } from "../../fixtures";
|
import { appDetails } from "../../fixtures";
|
||||||
import AppDetailsPage from "./AppDetailsPage";
|
import { AppDetailsPage } from "./AppDetailsPage";
|
||||||
|
|
||||||
const mockHeader = jest.fn();
|
const mockHeader = jest.fn();
|
||||||
jest.mock("./Header", () => props => {
|
jest.mock("./Header", () => props => {
|
||||||
|
@ -12,22 +12,29 @@ jest.mock("./Header", () => props => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockAboutCard = jest.fn();
|
const mockAboutCard = jest.fn();
|
||||||
jest.mock("./AboutCard", () => props => {
|
jest.mock("./AboutCard", () => ({
|
||||||
mockAboutCard(props);
|
AboutCard: props => {
|
||||||
return <></>;
|
mockAboutCard(props);
|
||||||
});
|
return <></>;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
const mockPermissionsCard = jest.fn();
|
const mockPermissionsCard = jest.fn();
|
||||||
jest.mock("./PermissionsCard", () => props => {
|
|
||||||
mockPermissionsCard(props);
|
jest.mock("./PermissionsCard", () => ({
|
||||||
return <></>;
|
PermissionsCard: props => {
|
||||||
});
|
mockPermissionsCard(props);
|
||||||
|
return <></>;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
const mockDataPrivacyCard = jest.fn();
|
const mockDataPrivacyCard = jest.fn();
|
||||||
jest.mock("./DataPrivacyCard", () => props => {
|
jest.mock("./DataPrivacyCard", () => ({
|
||||||
mockDataPrivacyCard(props);
|
DataPrivacyCard: props => {
|
||||||
return <></>;
|
mockDataPrivacyCard(props);
|
||||||
});
|
return <></>;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockHeader.mockClear();
|
mockHeader.mockClear();
|
||||||
|
@ -36,6 +43,9 @@ beforeEach(() => {
|
||||||
mockDataPrivacyCard.mockClear();
|
mockDataPrivacyCard.mockClear();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Rewrite tests to actually render the tree
|
||||||
|
*/
|
||||||
describe("Apps AppDetailsPage", () => {
|
describe("Apps AppDetailsPage", () => {
|
||||||
it("displays app details when app data passed", () => {
|
it("displays app details when app data passed", () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
@ -61,17 +71,23 @@ describe("Apps AppDetailsPage", () => {
|
||||||
onAppDeactivateOpen,
|
onAppDeactivateOpen,
|
||||||
onAppDeleteOpen,
|
onAppDeleteOpen,
|
||||||
});
|
});
|
||||||
expect(mockAboutCard).toHaveBeenCalledWith({
|
expect(mockAboutCard).toHaveBeenCalledWith(
|
||||||
aboutApp: appDetails.aboutApp,
|
expect.objectContaining({
|
||||||
loading: false,
|
aboutApp: appDetails.aboutApp,
|
||||||
});
|
loading: false,
|
||||||
expect(mockPermissionsCard).toHaveBeenCalledWith({
|
}),
|
||||||
permissions: appDetails.permissions,
|
);
|
||||||
loading: false,
|
expect(mockPermissionsCard).toHaveBeenCalledWith(
|
||||||
});
|
expect.objectContaining({
|
||||||
expect(mockDataPrivacyCard).toHaveBeenCalledWith({
|
permissions: appDetails.permissions,
|
||||||
dataPrivacyUrl: appDetails.dataPrivacyUrl,
|
loading: false,
|
||||||
loading: false,
|
}),
|
||||||
});
|
);
|
||||||
|
expect(mockDataPrivacyCard).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
dataPrivacyUrl: appDetails.dataPrivacyUrl,
|
||||||
|
loading: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import CardSpacer from "@dashboard/components/CardSpacer";
|
|
||||||
import { AppQuery } from "@dashboard/graphql";
|
import { AppQuery } from "@dashboard/graphql";
|
||||||
|
import errorTracker from "@dashboard/services/errorTracking";
|
||||||
|
import { Box, Text } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { ErrorBoundary } from "react-error-boundary";
|
||||||
|
|
||||||
import AboutCard from "./AboutCard";
|
import { AboutCard } from "./AboutCard";
|
||||||
import DataPrivacyCard from "./DataPrivacyCard";
|
import { DataPrivacyCard } from "./DataPrivacyCard";
|
||||||
import Header from "./Header";
|
import Header from "./Header";
|
||||||
import PermissionsCard from "./PermissionsCard";
|
import { PermissionsCard } from "./PermissionsCard";
|
||||||
|
|
||||||
export interface AppDetailsPageProps {
|
export interface AppDetailsPageProps {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
@ -27,25 +29,33 @@ export const AppDetailsPage: React.FC<AppDetailsPageProps> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<ErrorBoundary
|
||||||
|
onError={errorTracker.captureException}
|
||||||
|
fallbackRender={() => (
|
||||||
|
<Box padding={4}>
|
||||||
|
<Text>Error, please refresh the page</Text>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
>
|
||||||
<Header
|
<Header
|
||||||
data={data}
|
data={data}
|
||||||
onAppActivateOpen={onAppActivateOpen}
|
onAppActivateOpen={onAppActivateOpen}
|
||||||
onAppDeactivateOpen={onAppDeactivateOpen}
|
onAppDeactivateOpen={onAppDeactivateOpen}
|
||||||
onAppDeleteOpen={onAppDeleteOpen}
|
onAppDeleteOpen={onAppDeleteOpen}
|
||||||
/>
|
/>
|
||||||
<AboutCard aboutApp={data?.aboutApp} loading={loading} />
|
<AboutCard margin={6} aboutApp={data?.aboutApp} loading={loading} />
|
||||||
<CardSpacer />
|
<PermissionsCard
|
||||||
<PermissionsCard permissions={data?.permissions} loading={loading} />
|
margin={6}
|
||||||
<CardSpacer />
|
permissions={data?.permissions}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
<DataPrivacyCard
|
<DataPrivacyCard
|
||||||
|
margin={6}
|
||||||
dataPrivacyUrl={data?.dataPrivacyUrl}
|
dataPrivacyUrl={data?.dataPrivacyUrl}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
/>
|
/>
|
||||||
<CardSpacer />
|
</ErrorBoundary>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
AppDetailsPage.displayName = "AppDetailsPage";
|
AppDetailsPage.displayName = "AppDetailsPage";
|
||||||
export default AppDetailsPage;
|
|
||||||
|
|
|
@ -1,47 +1,53 @@
|
||||||
// @ts-strict-ignore
|
|
||||||
import CardTitle from "@dashboard/components/CardTitle";
|
|
||||||
import ExternalLink from "@dashboard/components/ExternalLink";
|
import ExternalLink from "@dashboard/components/ExternalLink";
|
||||||
import Skeleton from "@dashboard/components/Skeleton";
|
import Skeleton from "@dashboard/components/Skeleton";
|
||||||
import { Card, CardContent } from "@material-ui/core";
|
import { Box, BoxProps, Text } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
import { useStyles } from "./styles";
|
|
||||||
|
|
||||||
interface DataPrivacyCardProps {
|
type DataPrivacyCardProps = {
|
||||||
dataPrivacyUrl?: string | null;
|
dataPrivacyUrl?: string | null;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
}
|
} & BoxProps;
|
||||||
|
|
||||||
const DataPrivacyCard: React.FC<DataPrivacyCardProps> = ({
|
export const DataPrivacyCard: React.FC<DataPrivacyCardProps> = ({
|
||||||
dataPrivacyUrl,
|
dataPrivacyUrl,
|
||||||
loading,
|
loading,
|
||||||
|
...boxProps
|
||||||
}) => {
|
}) => {
|
||||||
const classes = useStyles();
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
if (!dataPrivacyUrl && !loading) {
|
if (!dataPrivacyUrl && !loading) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const renderContent = () => {
|
||||||
|
if (loading) {
|
||||||
|
return <Skeleton />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataPrivacyUrl) {
|
||||||
|
return (
|
||||||
|
<ExternalLink href={dataPrivacyUrl} target="_blank">
|
||||||
|
<FormattedMessage {...messages.dataPrivacyDescription} />
|
||||||
|
</ExternalLink>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dataPrivacyUrl) {
|
||||||
|
return <Text>{intl.formatMessage(messages.noDataPrivacyPage)}</Text>;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Leaking "if" statement, should never happen');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Box {...boxProps}>
|
||||||
<CardTitle title={intl.formatMessage(messages.dataPrivacyTitle)} />
|
<Text variant={"heading"} marginBottom={4} as={"h2"}>
|
||||||
<CardContent>
|
{intl.formatMessage(messages.dataPrivacyTitle)}
|
||||||
{!loading ? (
|
</Text>
|
||||||
<ExternalLink
|
<Box>{renderContent()}</Box>
|
||||||
className={classes.linkContainer}
|
</Box>
|
||||||
href={dataPrivacyUrl}
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<FormattedMessage {...messages.dataPrivacyDescription} />
|
|
||||||
</ExternalLink>
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default DataPrivacyCard;
|
|
||||||
|
|
|
@ -1,48 +1,61 @@
|
||||||
// @ts-strict-ignore
|
|
||||||
import CardTitle from "@dashboard/components/CardTitle";
|
|
||||||
import Skeleton from "@dashboard/components/Skeleton";
|
import Skeleton from "@dashboard/components/Skeleton";
|
||||||
import { AppQuery } from "@dashboard/graphql";
|
import { PermissionEnum } from "@dashboard/graphql";
|
||||||
import { Card, CardContent, Typography } from "@material-ui/core";
|
import { Box, BoxProps, Text } from "@saleor/macaw-ui/next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
import { useStyles } from "./styles";
|
|
||||||
|
|
||||||
interface PermissionsCardProps {
|
type PermissionsCardProps = {
|
||||||
permissions?: AppQuery["app"]["permissions"];
|
permissions: Array<{
|
||||||
|
name: string;
|
||||||
|
code: PermissionEnum;
|
||||||
|
}> | null;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
}
|
} & BoxProps;
|
||||||
|
|
||||||
const PermissionsCard: React.FC<PermissionsCardProps> = ({
|
export const PermissionsCard: React.FC<PermissionsCardProps> = ({
|
||||||
permissions,
|
permissions,
|
||||||
loading,
|
loading,
|
||||||
|
...boxProps
|
||||||
}) => {
|
}) => {
|
||||||
const classes = useStyles();
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
|
const renderContent = () => {
|
||||||
|
if (loading) {
|
||||||
|
return <Skeleton />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permissions && permissions.length === 0) {
|
||||||
|
return <Text>{intl.formatMessage(messages.appNoPermissions)}</Text>;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permissions && permissions.length > 0) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Text as={"p"} marginBottom={4}>
|
||||||
|
<FormattedMessage {...messages.appPermissionsDescription} />
|
||||||
|
</Text>
|
||||||
|
<Box as={"ul"}>
|
||||||
|
{permissions?.map(perm => (
|
||||||
|
<Box as={"li"} paddingX={4} paddingY={2} key={perm.code}>
|
||||||
|
<Text>{perm.name}</Text>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Leaking "if" statement, should never happen');
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Box {...boxProps}>
|
||||||
<CardTitle title={intl.formatMessage(messages.appPermissionsTitle)} />
|
<Text variant={"heading"} marginBottom={4} as={"h2"}>
|
||||||
<CardContent>
|
{intl.formatMessage(messages.appPermissionsTitle)}
|
||||||
{!loading ? (
|
</Text>
|
||||||
<>
|
<Box>{renderContent()}</Box>
|
||||||
<Typography>
|
</Box>
|
||||||
<FormattedMessage {...messages.appPermissionsDescription} />
|
|
||||||
</Typography>
|
|
||||||
{!!permissions?.length && (
|
|
||||||
<ul className={classes.permissionsContainer}>
|
|
||||||
{permissions?.map(perm => (
|
|
||||||
<li key={perm.code}>{perm.name}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Skeleton />
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default PermissionsCard;
|
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
export * from "./AppDetailsPage";
|
export * from "./AppDetailsPage";
|
||||||
export { default } from "./AppDetailsPage";
|
|
||||||
|
|
|
@ -16,6 +16,10 @@ export default defineMessages({
|
||||||
defaultMessage: "App permissions",
|
defaultMessage: "App permissions",
|
||||||
description: "section header",
|
description: "section header",
|
||||||
},
|
},
|
||||||
|
appNoPermissions: {
|
||||||
|
defaultMessage: "App doesn't have any permissions granted.",
|
||||||
|
id: "wDYozn",
|
||||||
|
},
|
||||||
appPermissionsDescription: {
|
appPermissionsDescription: {
|
||||||
id: "7oQUMG",
|
id: "7oQUMG",
|
||||||
defaultMessage: "This app has permissions to:",
|
defaultMessage: "This app has permissions to:",
|
||||||
|
@ -27,8 +31,16 @@ export default defineMessages({
|
||||||
description: "section header",
|
description: "section header",
|
||||||
},
|
},
|
||||||
dataPrivacyDescription: {
|
dataPrivacyDescription: {
|
||||||
id: "Go50v2",
|
id: "CHoZ8S",
|
||||||
defaultMessage: "View this app’s privacy policy",
|
defaultMessage: "View this app’s privacy policy.",
|
||||||
description: "app privacy policy link",
|
description: "app privacy policy link",
|
||||||
},
|
},
|
||||||
|
noDataPrivacyPage: {
|
||||||
|
id: "f3hf+w",
|
||||||
|
defaultMessage: "App doesn't provide a privacy policy.",
|
||||||
|
},
|
||||||
|
noAboutApp: {
|
||||||
|
id: "b088Xv",
|
||||||
|
defaultMessage: "App doesn't provide a description.",
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -38,10 +38,6 @@ export const useStyles = makeStyles(
|
||||||
marginTop: 0,
|
marginTop: 0,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
},
|
},
|
||||||
linkContainer: {
|
|
||||||
fontWeight: 500,
|
|
||||||
marginTop: theme.spacing(1.5),
|
|
||||||
},
|
|
||||||
marketplaceContent: {
|
marketplaceContent: {
|
||||||
"& button": {
|
"& button": {
|
||||||
marginTop: theme.spacing(1),
|
marginTop: theme.spacing(1),
|
||||||
|
@ -51,15 +47,6 @@ export const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
padding: theme.spacing(1),
|
padding: theme.spacing(1),
|
||||||
},
|
},
|
||||||
permissionsContainer: {
|
|
||||||
"& li": {
|
|
||||||
"&:last-child": {
|
|
||||||
marginBottom: 0,
|
|
||||||
},
|
|
||||||
marginBottom: theme.spacing(1),
|
|
||||||
},
|
|
||||||
paddingLeft: theme.spacing(2),
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
{ name: "AppDetailsPage" },
|
{ name: "AppDetailsPage" },
|
||||||
);
|
);
|
||||||
|
|
|
@ -18,7 +18,7 @@ import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import AppActivateDialog from "../../components/AppActivateDialog";
|
import AppActivateDialog from "../../components/AppActivateDialog";
|
||||||
import AppDeactivateDialog from "../../components/AppDeactivateDialog";
|
import AppDeactivateDialog from "../../components/AppDeactivateDialog";
|
||||||
import AppDetailsPage from "../../components/AppDetailsPage";
|
import { AppDetailsPage } from "../../components/AppDetailsPage";
|
||||||
import {
|
import {
|
||||||
AppDetailsUrlDialog,
|
AppDetailsUrlDialog,
|
||||||
AppDetailsUrlQueryParams,
|
AppDetailsUrlQueryParams,
|
||||||
|
|
Loading…
Reference in a new issue