Apps tabs (#2380)
* Add tabs to apps page * Detect app in tunnel * Disable manifest install if Saleor Apps context * Show only app origin instead full manifest * Add copy manifest feature * Update tests * Add ENV with marketplace endpoint for fetching saleor apps * Fetch Saleor apps for Marketplace and display them in the tab, otherwise hide * Code review fixes * Extract translation messages * Update tests
This commit is contained in:
parent
5c48f5387e
commit
d67e4799b2
19 changed files with 522 additions and 261 deletions
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -25,7 +25,8 @@ greatly reduce the amount of work needed to review your work. -->
|
||||||
Modify API_URI if you want test instance to use custom backend. CYPRESS_API_URI is optional, use when necessary. -->
|
Modify API_URI if you want test instance to use custom backend. CYPRESS_API_URI is optional, use when necessary. -->
|
||||||
|
|
||||||
API_URI=https://automation-dashboard.staging.saleor.cloud/graphql/
|
API_URI=https://automation-dashboard.staging.saleor.cloud/graphql/
|
||||||
MARKETPLACE_URL=https://marketplace-gray.vercel.app/
|
MARKETPLACE_URL=https://apps.saleor.io
|
||||||
|
SALEOR_APPS_ENDPOINT=https://apps.saleor.io/api/saleor-apps
|
||||||
|
|
||||||
### Do you want to run more stable tests?
|
### Do you want to run more stable tests?
|
||||||
To run all tests, just select the stable checkbox. To speed up tests, increase the number of containers. Tests will be re-run only when the "run e2e" label is added.
|
To run all tests, just select the stable checkbox. To speed up tests, increase the number of containers. Tests will be re-run only when the "run e2e" label is added.
|
||||||
|
|
1
.github/workflows/deploy-cloud.yaml
vendored
1
.github/workflows/deploy-cloud.yaml
vendored
|
@ -18,6 +18,7 @@ jobs:
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
MARKETPLACE_URL: "https://apps.saleor.io/"
|
MARKETPLACE_URL: "https://apps.saleor.io/"
|
||||||
|
SALEOR_APPS_ENDPOINT: "https://apps.saleor.io/api/saleor-apps"
|
||||||
IS_CLOUD_INSTANCE: true
|
IS_CLOUD_INSTANCE: true
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
1
.github/workflows/deploy-demo-staging.yaml
vendored
1
.github/workflows/deploy-demo-staging.yaml
vendored
|
@ -21,6 +21,7 @@ jobs:
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
MARKETPLACE_URL: "https://apps.saleor.io/"
|
MARKETPLACE_URL: "https://apps.saleor.io/"
|
||||||
|
SALEOR_APPS_ENDPOINT: "https://apps.saleor.io/api/saleor-apps"
|
||||||
ENVIRONMENT: demo-staging
|
ENVIRONMENT: demo-staging
|
||||||
DEMO_MODE: true
|
DEMO_MODE: true
|
||||||
steps:
|
steps:
|
||||||
|
|
1
.github/workflows/deploy-demo.yaml
vendored
1
.github/workflows/deploy-demo.yaml
vendored
|
@ -16,6 +16,7 @@ jobs:
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
MARKETPLACE_URL: "https://apps.saleor.io/"
|
MARKETPLACE_URL: "https://apps.saleor.io/"
|
||||||
|
SALEOR_APPS_ENDPOINT: "https://apps.saleor.io/api/saleor-apps"
|
||||||
ENVIRONMENT: demo
|
ENVIRONMENT: demo
|
||||||
DEMO_MODE: true
|
DEMO_MODE: true
|
||||||
steps:
|
steps:
|
||||||
|
|
1
.github/workflows/deploy-master-staging.yaml
vendored
1
.github/workflows/deploy-master-staging.yaml
vendored
|
@ -18,6 +18,7 @@ jobs:
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
MARKETPLACE_URL: "https://apps.saleor.io/"
|
MARKETPLACE_URL: "https://apps.saleor.io/"
|
||||||
|
SALEOR_APPS_ENDPOINT: "https://apps.saleor.io/api/saleor-apps"
|
||||||
ENVIRONMENT: saleor-master-staging
|
ENVIRONMENT: saleor-master-staging
|
||||||
IS_CLOUD_INSTANCE: true
|
IS_CLOUD_INSTANCE: true
|
||||||
steps:
|
steps:
|
||||||
|
|
1
.github/workflows/deploy-staging.yaml
vendored
1
.github/workflows/deploy-staging.yaml
vendored
|
@ -23,6 +23,7 @@ jobs:
|
||||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||||
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||||
MARKETPLACE_URL: "https://apps.saleor.io/"
|
MARKETPLACE_URL: "https://apps.saleor.io/"
|
||||||
|
SALEOR_APPS_ENDPOINT: "https://apps.saleor.io/api/saleor-apps"
|
||||||
VERSION: ${{ github.event.inputs.git_ref || github.ref_name }}
|
VERSION: ${{ github.event.inputs.git_ref || github.ref_name }}
|
||||||
IS_CLOUD_INSTANCE: true
|
IS_CLOUD_INSTANCE: true
|
||||||
steps:
|
steps:
|
||||||
|
|
|
@ -6,11 +6,12 @@ COPY . .
|
||||||
ARG APP_MOUNT_URI
|
ARG APP_MOUNT_URI
|
||||||
ARG API_URI
|
ARG API_URI
|
||||||
ARG MARKETPLACE_URL
|
ARG MARKETPLACE_URL
|
||||||
|
ARG SALEOR_APPS_ENDPOINT
|
||||||
ARG STATIC_URL
|
ARG STATIC_URL
|
||||||
ENV API_URI ${API_URI:-http://localhost:8000/graphql/}
|
ENV API_URI ${API_URI:-http://localhost:8000/graphql/}
|
||||||
ENV APP_MOUNT_URI ${APP_MOUNT_URI:-/dashboard/}
|
ENV APP_MOUNT_URI ${APP_MOUNT_URI:-/dashboard/}
|
||||||
ENV STATIC_URL ${STATIC_URL:-/dashboard/}
|
ENV STATIC_URL ${STATIC_URL:-/dashboard/}
|
||||||
RUN STATIC_URL=${STATIC_URL} API_URI=${API_URI} MARKETPLACE_URL=${MARKETPLACE_URL} APP_MOUNT_URI=${APP_MOUNT_URI} npm run build
|
RUN STATIC_URL=${STATIC_URL} API_URI=${API_URI} MARKETPLACE_URL=${MARKETPLACE_URL} SALEOR_APPS_ENDPOINT=${SALEOR_APPS_ENDPOINT} APP_MOUNT_URI=${APP_MOUNT_URI} npm run build
|
||||||
|
|
||||||
FROM nginx:stable
|
FROM nginx:stable
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
|
@ -6,6 +6,7 @@ COPY . .
|
||||||
ARG APP_MOUNT_URI
|
ARG APP_MOUNT_URI
|
||||||
ARG API_URI
|
ARG API_URI
|
||||||
ARG MARKETPLACE_URL
|
ARG MARKETPLACE_URL
|
||||||
|
ARG SALEOR_APPS_ENDPOINT
|
||||||
ARG STATIC_URL
|
ARG STATIC_URL
|
||||||
ENV API_URI ${API_URI:-http://localhost:8000/graphql/}
|
ENV API_URI ${API_URI:-http://localhost:8000/graphql/}
|
||||||
ENV APP_MOUNT_URI ${APP_MOUNT_URI:-/}
|
ENV APP_MOUNT_URI ${APP_MOUNT_URI:-/}
|
||||||
|
|
|
@ -97,6 +97,9 @@
|
||||||
"context": "dialog header",
|
"context": "dialog header",
|
||||||
"string": "Change Password"
|
"string": "Change Password"
|
||||||
},
|
},
|
||||||
|
"+niGip": {
|
||||||
|
"string": "Saleor Apps"
|
||||||
|
},
|
||||||
"+pLi+M": {
|
"+pLi+M": {
|
||||||
"context": "issued by app label",
|
"context": "issued by app label",
|
||||||
"string": "Issued by app"
|
"string": "Issued by app"
|
||||||
|
@ -2013,6 +2016,9 @@
|
||||||
"context": "change warehouse dialog warehouse list label",
|
"context": "change warehouse dialog warehouse list label",
|
||||||
"string": "Warehouses A to Z"
|
"string": "Warehouses A to Z"
|
||||||
},
|
},
|
||||||
|
"EqDdoh": {
|
||||||
|
"string": "Local apps are custom webhooks & token pairs that can be used to connect apps and access Saleor API. Read more."
|
||||||
|
},
|
||||||
"ErNH3D": {
|
"ErNH3D": {
|
||||||
"string": "Define where this attribute should be used in Saleor system"
|
"string": "Define where this attribute should be used in Saleor system"
|
||||||
},
|
},
|
||||||
|
@ -2077,6 +2083,9 @@
|
||||||
"context": "dialog content",
|
"context": "dialog content",
|
||||||
"string": "Select method you want to use to change address"
|
"string": "Select method you want to use to change address"
|
||||||
},
|
},
|
||||||
|
"FLtdaw": {
|
||||||
|
"string": "Saleor apps are hosted and maintained by Saleor Team. They are preinstalled for you and ready to use"
|
||||||
|
},
|
||||||
"FNAZoh": {
|
"FNAZoh": {
|
||||||
"string": "Last login"
|
"string": "Last login"
|
||||||
},
|
},
|
||||||
|
@ -2646,6 +2655,9 @@
|
||||||
"context": "currency code select",
|
"context": "currency code select",
|
||||||
"string": "{code} - {countries}"
|
"string": "{code} - {countries}"
|
||||||
},
|
},
|
||||||
|
"J8frvS": {
|
||||||
|
"string": "3rd party apps"
|
||||||
|
},
|
||||||
"JDz5h8": {
|
"JDz5h8": {
|
||||||
"context": "number of subcategories in category",
|
"context": "number of subcategories in category",
|
||||||
"string": "Subcategories"
|
"string": "Subcategories"
|
||||||
|
@ -3438,6 +3450,10 @@
|
||||||
"context": "attribute list",
|
"context": "attribute list",
|
||||||
"string": "Attribute {number}"
|
"string": "Attribute {number}"
|
||||||
},
|
},
|
||||||
|
"PbQJY5": {
|
||||||
|
"context": "section header",
|
||||||
|
"string": "Saleor Apps"
|
||||||
|
},
|
||||||
"PbqNhi": {
|
"PbqNhi": {
|
||||||
"context": "order status",
|
"context": "order status",
|
||||||
"string": "Partially fulfilled"
|
"string": "Partially fulfilled"
|
||||||
|
@ -3628,6 +3644,9 @@
|
||||||
"context": "number of collections",
|
"context": "number of collections",
|
||||||
"string": "Collections ({quantity})"
|
"string": "Collections ({quantity})"
|
||||||
},
|
},
|
||||||
|
"QdQ9z7": {
|
||||||
|
"string": "(TUNNEL - DEVELOPMENT)"
|
||||||
|
},
|
||||||
"Qe4XHv": {
|
"Qe4XHv": {
|
||||||
"context": "years after label",
|
"context": "years after label",
|
||||||
"string": "years after issue"
|
"string": "years after issue"
|
||||||
|
@ -4153,6 +4172,9 @@
|
||||||
"context": "attribute values",
|
"context": "attribute values",
|
||||||
"string": "Value {number}"
|
"string": "Value {number}"
|
||||||
},
|
},
|
||||||
|
"UxTSw7": {
|
||||||
|
"string": "Webhooks & Events"
|
||||||
|
},
|
||||||
"UxdBmI": {
|
"UxdBmI": {
|
||||||
"context": "collection availability",
|
"context": "collection availability",
|
||||||
"string": "Availability"
|
"string": "Availability"
|
||||||
|
@ -7398,6 +7420,9 @@
|
||||||
"context": "gift card history message",
|
"context": "gift card history message",
|
||||||
"string": "Gift card tags were updated"
|
"string": "Gift card tags were updated"
|
||||||
},
|
},
|
||||||
|
"vkY3W9": {
|
||||||
|
"string": "Third party apps are installed with App Manifests. They contain UI accessible from dashboard and can extend it. Read more here."
|
||||||
|
},
|
||||||
"vlLyvk": {
|
"vlLyvk": {
|
||||||
"string": "{inputType} attributes cannot be used as variant selection attributes."
|
"string": "{inputType} attributes cannot be used as variant selection attributes."
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
import { Typography } from "@material-ui/core";
|
||||||
|
import { CopyIcon, makeStyles, Tooltip } from "@saleor/macaw-ui";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
"@keyframes pulse": {
|
||||||
|
from: { transform: "scale(1)" },
|
||||||
|
to: { transform: "scale(1.2)" },
|
||||||
|
},
|
||||||
|
manifestText: {
|
||||||
|
color: theme.palette.text.secondary,
|
||||||
|
"&:hover svg": {
|
||||||
|
visibility: "visible",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
copyIcon: {
|
||||||
|
marginRight: theme.spacing(1),
|
||||||
|
visibility: "hidden",
|
||||||
|
verticalAlign: "middle",
|
||||||
|
transition: "0.2s",
|
||||||
|
},
|
||||||
|
copyIconColorful: {
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
animation: "$pulse 0.2s",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{ name: "AppManifestTableDisplay" },
|
||||||
|
);
|
||||||
|
|
||||||
|
interface AppManifestTableDisplayProps {
|
||||||
|
manifestUrl: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAppDomainFromManifest = (manifest: string) => new URL(manifest).host;
|
||||||
|
|
||||||
|
export const AppManifestTableDisplay = ({
|
||||||
|
manifestUrl,
|
||||||
|
}: AppManifestTableDisplayProps) => {
|
||||||
|
const styles = useStyles();
|
||||||
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip placement="top" title={manifestUrl} header="App Manifest URL">
|
||||||
|
<Typography
|
||||||
|
onMouseOut={() => setCopied(false)}
|
||||||
|
className={styles.manifestText}
|
||||||
|
onClick={e => {
|
||||||
|
try {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
navigator.clipboard.writeText(manifestUrl);
|
||||||
|
setCopied(true);
|
||||||
|
} catch (e) {
|
||||||
|
// Copy not supported, ignore
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{!!navigator.clipboard && (
|
||||||
|
<CopyIcon
|
||||||
|
className={clsx(styles.copyIcon, {
|
||||||
|
[styles.copyIconColorful]: copied,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{getAppDomainFromManifest(manifestUrl)}
|
||||||
|
</Typography>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
46
src/apps/components/AppPageTabs/AppPageTabs.tsx
Normal file
46
src/apps/components/AppPageTabs/AppPageTabs.tsx
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import { PageTab, PageTabs } from "@saleor/macaw-ui";
|
||||||
|
import React, { ComponentProps } from "react";
|
||||||
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
|
export type AppPageTabValue =
|
||||||
|
| "THIRD_PARTY"
|
||||||
|
| "WEBHOOKS_AND_EVENTS"
|
||||||
|
| "SALEOR_APPS";
|
||||||
|
|
||||||
|
type AllProps = ComponentProps<typeof PageTabs>;
|
||||||
|
type AvailableProps = Omit<AllProps, "children" | "onChange" | "value"> & {
|
||||||
|
value: AppPageTabValue;
|
||||||
|
showSaleorApps: boolean;
|
||||||
|
onChange(newValue: AppPageTabValue): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AppPageTabs = ({ showSaleorApps, ...props }: AvailableProps) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
return (
|
||||||
|
<PageTabs {...props}>
|
||||||
|
<PageTab
|
||||||
|
value="THIRD_PARTY"
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "3rd party apps",
|
||||||
|
id: "J8frvS",
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<PageTab
|
||||||
|
value="WEBHOOKS_AND_EVENTS"
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Webhooks & Events",
|
||||||
|
id: "UxTSw7",
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
{showSaleorApps && (
|
||||||
|
<PageTab
|
||||||
|
value="SALEOR_APPS"
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Saleor Apps",
|
||||||
|
id: "+niGip",
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</PageTabs>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,11 +1,17 @@
|
||||||
|
import {
|
||||||
|
AppPageTabs,
|
||||||
|
AppPageTabValue,
|
||||||
|
} from "@saleor/apps/components/AppPageTabs/AppPageTabs";
|
||||||
|
import { useSaleorApps } from "@saleor/apps/hooks/useSaleorApps";
|
||||||
import CardSpacer from "@saleor/components/CardSpacer";
|
import CardSpacer from "@saleor/components/CardSpacer";
|
||||||
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 { AppsInstallationsQuery, AppsListQuery } from "@saleor/graphql";
|
import { AppsInstallationsQuery, AppsListQuery } from "@saleor/graphql";
|
||||||
import { sectionNames } from "@saleor/intl";
|
import { sectionNames } from "@saleor/intl";
|
||||||
|
import { makeStyles } from "@saleor/macaw-ui";
|
||||||
import { ListProps } from "@saleor/types";
|
import { ListProps } from "@saleor/types";
|
||||||
import React from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import AppsInProgress from "../AppsInProgress/AppsInProgress";
|
import AppsInProgress from "../AppsInProgress/AppsInProgress";
|
||||||
import CustomApps from "../CustomApps/CustomApps";
|
import CustomApps from "../CustomApps/CustomApps";
|
||||||
|
@ -22,6 +28,17 @@ export interface AppsListPageProps extends ListProps {
|
||||||
onAppInstallRetry: (id: string) => void;
|
onAppInstallRetry: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles = makeStyles(
|
||||||
|
theme => ({
|
||||||
|
topTabs: {
|
||||||
|
marginBottom: theme.spacing(4),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
name: "AppsListPageStyles",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const AppsListPage: React.FC<AppsListPageProps> = ({
|
const AppsListPage: React.FC<AppsListPageProps> = ({
|
||||||
appsInProgressList,
|
appsInProgressList,
|
||||||
customAppsList,
|
customAppsList,
|
||||||
|
@ -33,34 +50,140 @@ const AppsListPage: React.FC<AppsListPageProps> = ({
|
||||||
onAppInstallRetry,
|
onAppInstallRetry,
|
||||||
...listProps
|
...listProps
|
||||||
}) => {
|
}) => {
|
||||||
|
const {
|
||||||
|
fetchApps,
|
||||||
|
apps: fetchedSaleorApps,
|
||||||
|
saleorAppsEnabled,
|
||||||
|
} = useSaleorApps();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (saleorAppsEnabled) {
|
||||||
|
fetchApps();
|
||||||
|
}
|
||||||
|
}, [saleorAppsEnabled, fetchApps]);
|
||||||
|
|
||||||
|
const styles = useStyles();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const [activeTab, setActiveTab] = useState<AppPageTabValue>("THIRD_PARTY");
|
||||||
|
|
||||||
const appsInProgress = appsInProgressList?.appsInstallations;
|
const appsInProgress = appsInProgressList?.appsInstallations;
|
||||||
|
|
||||||
|
const thirdPartyApps = useMemo(
|
||||||
|
() =>
|
||||||
|
installedAppsList?.filter(
|
||||||
|
app =>
|
||||||
|
!(fetchedSaleorApps ?? []).find(fetchedApp =>
|
||||||
|
app.node.manifestUrl.includes(fetchedApp.hostname),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
[installedAppsList, fetchedSaleorApps],
|
||||||
|
);
|
||||||
|
|
||||||
|
const saleorApps = useMemo(
|
||||||
|
() =>
|
||||||
|
fetchedSaleorApps
|
||||||
|
?.map(app =>
|
||||||
|
installedAppsList?.find(installedApp =>
|
||||||
|
installedApp.node.manifestUrl.includes(app.hostname),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.filter(Boolean),
|
||||||
|
[installedAppsList, fetchedSaleorApps],
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderContent = () => {
|
||||||
|
switch (activeTab) {
|
||||||
|
case "THIRD_PARTY": {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Third party apps are installed with App Manifests. They contain UI
|
||||||
|
accessible from dashboard and can extend it. Read more here."
|
||||||
|
id="vkY3W9"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<InstalledApps
|
||||||
|
title={intl.formatMessage({
|
||||||
|
id: "BvmnJq",
|
||||||
|
defaultMessage: "Third Party Apps",
|
||||||
|
description: "section header",
|
||||||
|
})}
|
||||||
|
appsList={thirdPartyApps}
|
||||||
|
onRemove={onInstalledAppRemove}
|
||||||
|
displayQuickManifestButton
|
||||||
|
{...listProps}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<CardSpacer />
|
||||||
|
|
||||||
|
{!!appsInProgress?.length && (
|
||||||
|
<>
|
||||||
|
<CardSpacer />
|
||||||
|
<AppsInProgress
|
||||||
|
appsList={appsInProgress}
|
||||||
|
onAppInstallRetry={onAppInstallRetry}
|
||||||
|
onRemove={onAppInProgressRemove}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case "WEBHOOKS_AND_EVENTS": {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Local apps are custom webhooks & token pairs that can be used to
|
||||||
|
connect apps and access Saleor API. Read more."
|
||||||
|
id="EqDdoh"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<CustomApps
|
||||||
|
appsList={customAppsList}
|
||||||
|
getCustomAppHref={getCustomAppHref}
|
||||||
|
onRemove={onCustomAppRemove}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case "SALEOR_APPS": {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<p>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Saleor apps are hosted and maintained by Saleor Team. They are
|
||||||
|
preinstalled for you and ready to use"
|
||||||
|
id="FLtdaw"
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<InstalledApps
|
||||||
|
title={intl.formatMessage({
|
||||||
|
id: "PbQJY5",
|
||||||
|
defaultMessage: "Saleor Apps",
|
||||||
|
description: "section header",
|
||||||
|
})}
|
||||||
|
appsList={saleorApps}
|
||||||
|
onRemove={onInstalledAppRemove}
|
||||||
|
{...listProps}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<PageHeader title={intl.formatMessage(sectionNames.apps)} />
|
<PageHeader title={intl.formatMessage(sectionNames.apps)} />
|
||||||
<InstalledApps
|
<AppPageTabs
|
||||||
appsList={installedAppsList}
|
showSaleorApps={saleorAppsEnabled}
|
||||||
onRemove={onInstalledAppRemove}
|
className={styles.topTabs}
|
||||||
{...listProps}
|
onChange={setActiveTab}
|
||||||
|
value={activeTab}
|
||||||
/>
|
/>
|
||||||
<CardSpacer />
|
{renderContent()}
|
||||||
<CustomApps
|
|
||||||
appsList={customAppsList}
|
|
||||||
getCustomAppHref={getCustomAppHref}
|
|
||||||
onRemove={onCustomAppRemove}
|
|
||||||
/>
|
|
||||||
{!!appsInProgress?.length && (
|
|
||||||
<>
|
|
||||||
<CardSpacer />
|
|
||||||
<AppsInProgress
|
|
||||||
appsList={appsInProgress}
|
|
||||||
onAppInstallRetry={onAppInstallRetry}
|
|
||||||
onRemove={onAppInProgressRemove}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,9 +6,11 @@ import {
|
||||||
TableRow,
|
TableRow,
|
||||||
Typography,
|
Typography,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
|
import { AppManifestTableDisplay } from "@saleor/apps/components/AppManifestTableDisplay/AppManifestTableDisplay";
|
||||||
import { InstallWithManifestFormButton } from "@saleor/apps/components/InstallWithManifestFormButton";
|
import { InstallWithManifestFormButton } from "@saleor/apps/components/InstallWithManifestFormButton";
|
||||||
import { useAppListContext } from "@saleor/apps/context";
|
import { useAppListContext } from "@saleor/apps/context";
|
||||||
import { appUrl, createAppInstallUrl } from "@saleor/apps/urls";
|
import { appUrl, createAppInstallUrl } from "@saleor/apps/urls";
|
||||||
|
import { isAppInTunnel } from "@saleor/apps/utils";
|
||||||
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";
|
||||||
|
@ -18,9 +20,8 @@ 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 React, { useCallback } from "react";
|
import React, { useCallback } from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import { useStyles } from "../../styles";
|
import { useStyles } from "../../styles";
|
||||||
import { AppPermissions } from "../AppPermissions/AppPermissions";
|
import { AppPermissions } from "../AppPermissions/AppPermissions";
|
||||||
|
@ -29,14 +30,17 @@ import AppsSkeleton from "../AppsSkeleton";
|
||||||
export interface InstalledAppsProps extends ListProps {
|
export interface InstalledAppsProps extends ListProps {
|
||||||
appsList: AppsListQuery["apps"]["edges"];
|
appsList: AppsListQuery["apps"]["edges"];
|
||||||
onRemove: (id: string) => void;
|
onRemove: (id: string) => void;
|
||||||
|
displayQuickManifestButton?: boolean;
|
||||||
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InstalledApps: React.FC<InstalledAppsProps> = ({
|
const InstalledApps: React.FC<InstalledAppsProps> = ({
|
||||||
appsList,
|
appsList,
|
||||||
onRemove,
|
onRemove,
|
||||||
|
title,
|
||||||
|
displayQuickManifestButton = false,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
const { activateApp, deactivateApp } = useAppListContext();
|
const { activateApp, deactivateApp } = useAppListContext();
|
||||||
const navigate = useNavigator();
|
const navigate = useNavigator();
|
||||||
|
@ -59,15 +63,15 @@ const InstalledApps: React.FC<InstalledAppsProps> = ({
|
||||||
return (
|
return (
|
||||||
<Card className={classes.apps}>
|
<Card className={classes.apps}>
|
||||||
<CardTitle
|
<CardTitle
|
||||||
title={intl.formatMessage({
|
title={title}
|
||||||
id: "BvmnJq",
|
|
||||||
defaultMessage: "Third Party Apps",
|
|
||||||
description: "section header",
|
|
||||||
})}
|
|
||||||
toolbar={
|
toolbar={
|
||||||
<InstallWithManifestFormButton
|
displayQuickManifestButton ? (
|
||||||
onSubmitted={navigateToAppInstallPage}
|
<InstallWithManifestFormButton
|
||||||
/>
|
onSubmitted={navigateToAppInstallPage}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
undefined
|
||||||
|
)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ResponsiveTable>
|
<ResponsiveTable>
|
||||||
|
@ -85,15 +89,22 @@ const InstalledApps: React.FC<InstalledAppsProps> = ({
|
||||||
<span data-tc="name" className={classes.appName}>
|
<span data-tc="name" className={classes.appName}>
|
||||||
{app.node.name}
|
{app.node.name}
|
||||||
</span>
|
</span>
|
||||||
|
{app.node.manifestUrl &&
|
||||||
|
isAppInTunnel(app.node.manifestUrl) ? (
|
||||||
|
<Typography variant="caption">
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="(TUNNEL - DEVELOPMENT)"
|
||||||
|
id="QdQ9z7"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
) : null}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
<TableCell className={classes.colAction}>
|
<TableCell className={classes.colAction}>
|
||||||
{app.node.manifestUrl && (
|
{app.node.manifestUrl && (
|
||||||
<Typography
|
<AppManifestTableDisplay
|
||||||
className={clsx(classes.text, classes.manifestUrl)}
|
manifestUrl={app.node.manifestUrl}
|
||||||
variant="body2"
|
/>
|
||||||
>
|
|
||||||
{app.node.manifestUrl}
|
|
||||||
</Typography>
|
|
||||||
)}
|
)}
|
||||||
<TableButtonWrapper>
|
<TableButtonWrapper>
|
||||||
<Switch
|
<Switch
|
||||||
|
|
44
src/apps/hooks/useSaleorApps.ts
Normal file
44
src/apps/hooks/useSaleorApps.ts
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import { SALEOR_APPS_ENDPOINT } from "@saleor/config";
|
||||||
|
import { useCallback, useState } from "react";
|
||||||
|
|
||||||
|
export interface SaleorApp {
|
||||||
|
name: string;
|
||||||
|
hostname: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const saleorAppsEnabled = Boolean(SALEOR_APPS_ENDPOINT);
|
||||||
|
|
||||||
|
export const useSaleorApps = () => {
|
||||||
|
const [apps, setApps] = useState<SaleorApp[] | undefined>(undefined);
|
||||||
|
|
||||||
|
const fetchApps = useCallback(async () => {
|
||||||
|
if (!saleorAppsEnabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fetch(SALEOR_APPS_ENDPOINT)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then((data: SaleorApp[]) => {
|
||||||
|
if (
|
||||||
|
!data.every(
|
||||||
|
item =>
|
||||||
|
typeof item.hostname === "string" ||
|
||||||
|
typeof item.name === "string",
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
console.error(
|
||||||
|
'Invalid Saleor Apps data received from Marketplace. Expected array of objects with "name" and "hostname" properties',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setApps(data);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
saleorAppsEnabled,
|
||||||
|
apps,
|
||||||
|
fetchApps,
|
||||||
|
};
|
||||||
|
};
|
|
@ -53,7 +53,7 @@ export const useStyles = makeStyles(
|
||||||
},
|
},
|
||||||
colName: {
|
colName: {
|
||||||
paddingLeft: 0,
|
paddingLeft: 0,
|
||||||
width: theme.spacing(30),
|
minWidth: theme.spacing(30),
|
||||||
},
|
},
|
||||||
colSpinner: {
|
colSpinner: {
|
||||||
"& svg": {
|
"& svg": {
|
||||||
|
@ -213,9 +213,6 @@ export const useStyles = makeStyles(
|
||||||
marginRight: theme.spacing(1),
|
marginRight: theme.spacing(1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
manifestUrl: {
|
|
||||||
marginRight: theme.spacing(1),
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
{ name: "AppList" },
|
{ name: "AppList" },
|
||||||
);
|
);
|
||||||
|
|
4
src/apps/utils.ts
Normal file
4
src/apps/utils.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
const tunnelKeywords = [".ngrok.io", ".saleor.live"];
|
||||||
|
|
||||||
|
export const isAppInTunnel = (manifestUrl: string) =>
|
||||||
|
Boolean(tunnelKeywords.find(keyword => manifestUrl.includes(keyword)));
|
|
@ -9,6 +9,7 @@ export const API_URI = process.env.API_URI;
|
||||||
export const SW_INTERVAL = parseInt(process.env.SW_INTERVAL, 10);
|
export const SW_INTERVAL = parseInt(process.env.SW_INTERVAL, 10);
|
||||||
export const IS_CLOUD_INSTANCE = process.env.IS_CLOUD_INSTANCE === "true";
|
export const IS_CLOUD_INSTANCE = process.env.IS_CLOUD_INSTANCE === "true";
|
||||||
export const MARKETPLACE_URL = process.env.MARKETPLACE_URL;
|
export const MARKETPLACE_URL = process.env.MARKETPLACE_URL;
|
||||||
|
export const SALEOR_APPS_ENDPOINT = process.env.SALEOR_APPS_ENDPOINT;
|
||||||
|
|
||||||
export const DEFAULT_INITIAL_SEARCH_DATA: SearchVariables = {
|
export const DEFAULT_INITIAL_SEARCH_DATA: SearchVariables = {
|
||||||
after: null,
|
after: null,
|
||||||
|
|
|
@ -25005,6 +25005,53 @@ exports[`Storyshots Views / Apps / Apps list default 1`] = `
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiTabs-root-id PageTab-containerRoot-id AppsListPageStyles-topTabs-id"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTabs-scroller-id MuiTabs-fixed-id"
|
||||||
|
style="overflow:hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTabs-flexContainer-id PageTab-containerFlex-id"
|
||||||
|
role="tablist"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-selected="true"
|
||||||
|
class="MuiButtonBase-root-id MuiTab-root-id PageTab-tabRoot-id MuiTab-textColorInherit-id MuiTab-selected-id"
|
||||||
|
role="tab"
|
||||||
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiTab-wrapper-id"
|
||||||
|
>
|
||||||
|
3rd party apps
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="PrivateTabIndicator-root-id PrivateTabIndicator-colorSecondary-id MuiTabs-indicator-id"
|
||||||
|
style="display:none"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-selected="false"
|
||||||
|
class="MuiButtonBase-root-id MuiTab-root-id PageTab-tabRoot-id MuiTab-textColorInherit-id"
|
||||||
|
role="tab"
|
||||||
|
tabindex="-1"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiTab-wrapper-id"
|
||||||
|
>
|
||||||
|
Webhooks & Events
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
Third party apps are installed with App Manifests. They contain UI accessible from dashboard and can extend it. Read more here.
|
||||||
|
</p>
|
||||||
<div
|
<div
|
||||||
class="MuiPaper-root-id MuiCard-root-id AppList-apps-id MuiPaper-elevation0-id MuiPaper-rounded-id"
|
class="MuiPaper-root-id MuiCard-root-id AppList-apps-id MuiPaper-elevation0-id MuiPaper-rounded-id"
|
||||||
>
|
>
|
||||||
|
@ -25071,9 +25118,9 @@ exports[`Storyshots Views / Apps / Apps list default 1`] = `
|
||||||
class="MuiTableCell-root-id MuiTableCell-body-id AppList-colAction-id"
|
class="MuiTableCell-root-id MuiTableCell-body-id AppList-colAction-id"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root-id AppList-text-id AppList-manifestUrl-id MuiTypography-body2-id"
|
class="MuiTypography-root-id AppManifestTableDisplay-manifestText-id MuiTypography-body1-id"
|
||||||
>
|
>
|
||||||
http://localhost:3000/api/manifest
|
localhost:3000
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
class="MuiSwitch-root-id"
|
class="MuiSwitch-root-id"
|
||||||
|
@ -25168,9 +25215,9 @@ exports[`Storyshots Views / Apps / Apps list default 1`] = `
|
||||||
class="MuiTableCell-root-id MuiTableCell-body-id AppList-colAction-id"
|
class="MuiTableCell-root-id MuiTableCell-body-id AppList-colAction-id"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="MuiTypography-root-id AppList-text-id AppList-manifestUrl-id MuiTypography-body2-id"
|
class="MuiTypography-root-id AppManifestTableDisplay-manifestText-id MuiTypography-body1-id"
|
||||||
>
|
>
|
||||||
http://localhost:3000/api/manifest
|
localhost:3000
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
class="MuiSwitch-root-id"
|
class="MuiSwitch-root-id"
|
||||||
|
@ -25254,96 +25301,6 @@ exports[`Storyshots Views / Apps / Apps list default 1`] = `
|
||||||
<div
|
<div
|
||||||
class="CardSpacer-spacer-id"
|
class="CardSpacer-spacer-id"
|
||||||
/>
|
/>
|
||||||
<div
|
|
||||||
class="MuiPaper-root-id MuiCard-root-id AppList-customApps-id MuiPaper-elevation0-id MuiPaper-rounded-id"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCardHeader-root-id"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCardHeader-content-id"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="MuiTypography-root-id MuiCardHeader-title-id MuiTypography-h5-id MuiTypography-displayBlock-id"
|
|
||||||
>
|
|
||||||
Internal Apps
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="MuiCardHeader-action-id"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
aria-disabled="false"
|
|
||||||
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-outlined-id MuiButton-outlinedPrimary-id"
|
|
||||||
data-test-id="create-app"
|
|
||||||
href="/apps/custom/add"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="MuiButton-label-id"
|
|
||||||
>
|
|
||||||
Create App
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="ResponsiveTable-root-id"
|
|
||||||
>
|
|
||||||
<table
|
|
||||||
class="MuiTable-root-id"
|
|
||||||
>
|
|
||||||
<tbody
|
|
||||||
class="MuiTableBody-root-id"
|
|
||||||
>
|
|
||||||
<tr
|
|
||||||
class="MuiTableRow-root-id AppList-tableRow-id MuiTableRow-hover-id"
|
|
||||||
>
|
|
||||||
<td
|
|
||||||
class="MuiTableCell-root-id MuiTableCell-body-id AppList-colName-id"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="AppList-appName-id"
|
|
||||||
data-tc="name"
|
|
||||||
>
|
|
||||||
app custom
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td
|
|
||||||
class="MuiTableCell-root-id MuiTableCell-body-id AppList-colAction-id"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
class="MuiButtonBase-root-id IconButton-secondary-id IconButton-hoverOutline-id"
|
|
||||||
color="primary"
|
|
||||||
tabindex="0"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
aria-hidden="true"
|
|
||||||
class="MuiSvgIcon-root-id MacawIcon-root-id"
|
|
||||||
fill="none"
|
|
||||||
focusable="false"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
width="24"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M9 10v8m3-8v8m3-8v8M5 4.5V21a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4.5m-14 0H4m1 0h4m10 0h1m-1 0h-4m-6 0V3a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v1.5m-6 0h6"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
stroke-width="1.5"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="CardSpacer-spacer-id"
|
class="CardSpacer-spacer-id"
|
||||||
/>
|
/>
|
||||||
|
@ -25559,6 +25516,53 @@ exports[`Storyshots Views / Apps / Apps list loading 1`] = `
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiTabs-root-id PageTab-containerRoot-id AppsListPageStyles-topTabs-id"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTabs-scroller-id MuiTabs-fixed-id"
|
||||||
|
style="overflow:hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTabs-flexContainer-id PageTab-containerFlex-id"
|
||||||
|
role="tablist"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-selected="true"
|
||||||
|
class="MuiButtonBase-root-id MuiTab-root-id PageTab-tabRoot-id MuiTab-textColorInherit-id MuiTab-selected-id"
|
||||||
|
role="tab"
|
||||||
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiTab-wrapper-id"
|
||||||
|
>
|
||||||
|
3rd party apps
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="PrivateTabIndicator-root-id PrivateTabIndicator-colorSecondary-id MuiTabs-indicator-id"
|
||||||
|
style="display:none"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-selected="false"
|
||||||
|
class="MuiButtonBase-root-id MuiTab-root-id PageTab-tabRoot-id MuiTab-textColorInherit-id"
|
||||||
|
role="tab"
|
||||||
|
tabindex="-1"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiTab-wrapper-id"
|
||||||
|
>
|
||||||
|
Webhooks & Events
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
Third party apps are installed with App Manifests. They contain UI accessible from dashboard and can extend it. Read more here.
|
||||||
|
</p>
|
||||||
<div
|
<div
|
||||||
class="MuiPaper-root-id MuiCard-root-id AppList-apps-id MuiPaper-elevation0-id MuiPaper-rounded-id"
|
class="MuiPaper-root-id MuiCard-root-id AppList-apps-id MuiPaper-elevation0-id MuiPaper-rounded-id"
|
||||||
>
|
>
|
||||||
|
@ -25622,68 +25626,6 @@ exports[`Storyshots Views / Apps / Apps list loading 1`] = `
|
||||||
<div
|
<div
|
||||||
class="CardSpacer-spacer-id"
|
class="CardSpacer-spacer-id"
|
||||||
/>
|
/>
|
||||||
<div
|
|
||||||
class="MuiPaper-root-id MuiCard-root-id AppList-customApps-id MuiPaper-elevation0-id MuiPaper-rounded-id"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCardHeader-root-id"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCardHeader-content-id"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="MuiTypography-root-id MuiCardHeader-title-id MuiTypography-h5-id MuiTypography-displayBlock-id"
|
|
||||||
>
|
|
||||||
Internal Apps
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="MuiCardHeader-action-id"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
aria-disabled="false"
|
|
||||||
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-outlined-id MuiButton-outlinedPrimary-id"
|
|
||||||
data-test-id="create-app"
|
|
||||||
href="/apps/custom/add"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="MuiButton-label-id"
|
|
||||||
>
|
|
||||||
Create App
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="ResponsiveTable-root-id"
|
|
||||||
>
|
|
||||||
<table
|
|
||||||
class="MuiTable-root-id"
|
|
||||||
>
|
|
||||||
<tbody
|
|
||||||
class="MuiTableBody-root-id"
|
|
||||||
>
|
|
||||||
<tr
|
|
||||||
class="MuiTableRow-root-id AppList-tableRow-id MuiTableRow-hover-id"
|
|
||||||
>
|
|
||||||
<td
|
|
||||||
class="MuiTableCell-root-id MuiTableCell-body-id AppList-colName-id"
|
|
||||||
colspan="2"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="Skeleton-skeleton-id"
|
|
||||||
data-test-id="skeleton"
|
|
||||||
>
|
|
||||||
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
@ -25716,6 +25658,53 @@ exports[`Storyshots Views / Apps / Apps list no data 1`] = `
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="MuiTabs-root-id PageTab-containerRoot-id AppsListPageStyles-topTabs-id"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTabs-scroller-id MuiTabs-fixed-id"
|
||||||
|
style="overflow:hidden"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="MuiTabs-flexContainer-id PageTab-containerFlex-id"
|
||||||
|
role="tablist"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-selected="true"
|
||||||
|
class="MuiButtonBase-root-id MuiTab-root-id PageTab-tabRoot-id MuiTab-textColorInherit-id MuiTab-selected-id"
|
||||||
|
role="tab"
|
||||||
|
tabindex="0"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiTab-wrapper-id"
|
||||||
|
>
|
||||||
|
3rd party apps
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="PrivateTabIndicator-root-id PrivateTabIndicator-colorSecondary-id MuiTabs-indicator-id"
|
||||||
|
style="display:none"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
aria-selected="false"
|
||||||
|
class="MuiButtonBase-root-id MuiTab-root-id PageTab-tabRoot-id MuiTab-textColorInherit-id"
|
||||||
|
role="tab"
|
||||||
|
tabindex="-1"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="MuiTab-wrapper-id"
|
||||||
|
>
|
||||||
|
Webhooks & Events
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
Third party apps are installed with App Manifests. They contain UI accessible from dashboard and can extend it. Read more here.
|
||||||
|
</p>
|
||||||
<div
|
<div
|
||||||
class="MuiPaper-root-id MuiCard-root-id AppList-apps-id MuiPaper-elevation0-id MuiPaper-rounded-id"
|
class="MuiPaper-root-id MuiCard-root-id AppList-apps-id MuiPaper-elevation0-id MuiPaper-rounded-id"
|
||||||
>
|
>
|
||||||
|
@ -25777,66 +25766,6 @@ exports[`Storyshots Views / Apps / Apps list no data 1`] = `
|
||||||
<div
|
<div
|
||||||
class="CardSpacer-spacer-id"
|
class="CardSpacer-spacer-id"
|
||||||
/>
|
/>
|
||||||
<div
|
|
||||||
class="MuiPaper-root-id MuiCard-root-id AppList-customApps-id MuiPaper-elevation0-id MuiPaper-rounded-id"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCardHeader-root-id"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiCardHeader-content-id"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="MuiTypography-root-id MuiCardHeader-title-id MuiTypography-h5-id MuiTypography-displayBlock-id"
|
|
||||||
>
|
|
||||||
Internal Apps
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="MuiCardHeader-action-id"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
aria-disabled="false"
|
|
||||||
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-outlined-id MuiButton-outlinedPrimary-id"
|
|
||||||
data-test-id="create-app"
|
|
||||||
href="/apps/custom/add"
|
|
||||||
role="button"
|
|
||||||
tabindex="0"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="MuiButton-label-id"
|
|
||||||
>
|
|
||||||
Create App
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="ResponsiveTable-root-id"
|
|
||||||
>
|
|
||||||
<table
|
|
||||||
class="MuiTable-root-id"
|
|
||||||
>
|
|
||||||
<tbody
|
|
||||||
class="MuiTableBody-root-id"
|
|
||||||
>
|
|
||||||
<tr
|
|
||||||
class="MuiTableRow-root-id AppList-tableRow-id MuiTableRow-hover-id"
|
|
||||||
>
|
|
||||||
<td
|
|
||||||
class="MuiTableCell-root-id MuiTableCell-body-id AppList-colName-id"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="MuiTypography-root-id AppList-text-id MuiTypography-body2-id"
|
|
||||||
>
|
|
||||||
Your custom-created apps will be shown here.
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -39,6 +39,7 @@ const htmlWebpackPlugin = new HtmlWebpackPlugin({
|
||||||
const environmentPlugin = new webpack.EnvironmentPlugin({
|
const environmentPlugin = new webpack.EnvironmentPlugin({
|
||||||
API_URI: "",
|
API_URI: "",
|
||||||
MARKETPLACE_URL: "",
|
MARKETPLACE_URL: "",
|
||||||
|
SALEOR_APPS_ENDPOINT: "",
|
||||||
APP_MOUNT_URI: "/",
|
APP_MOUNT_URI: "/",
|
||||||
DEMO_MODE: false,
|
DEMO_MODE: false,
|
||||||
ENVIRONMENT: "",
|
ENVIRONMENT: "",
|
||||||
|
|
Loading…
Reference in a new issue