diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index e681b1a3a..a66d76c93 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -25,3 +25,4 @@ 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. -->
API_URI=https://automation-dashboard.staging.saleor.cloud/graphql/
+MARKETPLACE_URL=https://marketplace-gray.vercel.app/
diff --git a/.github/workflows/deploy-master-staging.yaml b/.github/workflows/deploy-master-staging.yaml
index c89146b12..77ed23bc7 100644
--- a/.github/workflows/deploy-master-staging.yaml
+++ b/.github/workflows/deploy-master-staging.yaml
@@ -10,6 +10,7 @@ jobs:
runs-on: ubuntu-20.04
env:
API_URI: /graphql/
+ MARKETPLACE_URL: "https://marketplace-gray.vercel.app/"
APP_MOUNT_URI: /dashboard/
STATIC_URL: /dashboard/static/
SENTRY_ORG: saleor
@@ -52,4 +53,4 @@ jobs:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CLOUD_DEPLOYMENTS_WEBHOOK_URL }}
JOB_TITLE: "Dashboard deployment to ${{ env.ENVIRONMENT }}"
run: |
- python3 ./.github/workflows/notify/notify-slack.py
\ No newline at end of file
+ python3 ./.github/workflows/notify/notify-slack.py
diff --git a/.github/workflows/test-env-deploy.yml b/.github/workflows/test-env-deploy.yml
index 31f750c4b..d9125ed91 100644
--- a/.github/workflows/test-env-deploy.yml
+++ b/.github/workflows/test-env-deploy.yml
@@ -57,11 +57,21 @@ jobs:
pattern: (http|https)://[a-zA-Z0-9.-]+/graphql/?
run: |
echo "::set-output name=custom_api_uri::$(echo $pull_request_body | grep -Eo "$prefix$pattern" | sed s/$prefix// | head -n 1)"
+ - name: Get MARKETPLACE_URL
+ id: marketplace_url
+ # Search for MARKETPLACE_URL in PR description
+ env:
+ pull_request_body: ${{ github.event.pull_request.body }}
+ prefix: MARKETPLACE_URL=
+ pattern: (http|https)://[a-zA-Z0-9.-]+/?
+ run: |
+ echo "::set-output name=custom_marketplace_url::$(echo $pull_request_body | grep -Eo "$prefix$pattern" | sed s/$prefix// | head -n 1)"
- name: Run build
env:
# Use custom API_URI or the default one
API_URI: ${{ steps.api_uri.outputs.custom_api_uri || 'https://qa.staging.saleor.cloud/graphql/' }}
+ MARKETPLACE_URL: ${{ steps.marketplace_url.outputs.custom_marketplace_url }}
APP_MOUNT_URI: /
STATIC_URL: /
IS_CLOUD_INSTANCE: true
@@ -113,7 +123,6 @@ jobs:
env_url: https://${{ steps.set-domain.outputs.domain }}/storybook/index.html
deployment_id: ${{ steps.storybook-deployment.outputs.deployment_id }}
-
cypress-run-critical:
needs: deploy
runs-on: ubuntu-latest
diff --git a/Dockerfile b/Dockerfile
index ecf980ee6..45c2c3cec 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -5,11 +5,12 @@ RUN npm install
COPY . .
ARG APP_MOUNT_URI
ARG API_URI
+ARG MARKETPLACE_URL
ARG STATIC_URL
ENV API_URI ${API_URI:-http://localhost:8000/graphql/}
ENV APP_MOUNT_URI ${APP_MOUNT_URI:-/dashboard/}
ENV STATIC_URL ${STATIC_URL:-/dashboard/}
-RUN STATIC_URL=${STATIC_URL} API_URI=${API_URI} APP_MOUNT_URI=${APP_MOUNT_URI} npm run build
+RUN STATIC_URL=${STATIC_URL} API_URI=${API_URI} MARKETPLACE_URL=${MARKETPLACE_URL} APP_MOUNT_URI=${APP_MOUNT_URI} npm run build
FROM nginx:stable
WORKDIR /app
diff --git a/Dockerfile.dev b/Dockerfile.dev
index 3147c17dd..e2d65bc6c 100644
--- a/Dockerfile.dev
+++ b/Dockerfile.dev
@@ -5,6 +5,7 @@ RUN npm install
COPY . .
ARG APP_MOUNT_URI
ARG API_URI
+ARG MARKETPLACE_URL
ARG STATIC_URL
ENV API_URI ${API_URI:-http://localhost:8000/graphql/}
ENV APP_MOUNT_URI ${APP_MOUNT_URI:-/}
diff --git a/cypress/elements/account/left-menu/left-menu-selectors.js b/cypress/elements/account/left-menu/left-menu-selectors.js
index a6aa78a56..df7c06537 100644
--- a/cypress/elements/account/left-menu/left-menu-selectors.js
+++ b/cypress/elements/account/left-menu/left-menu-selectors.js
@@ -5,6 +5,7 @@ export const LEFT_MENU_SELECTORS = {
home: "[data-test='menu-item-label'][data-test-id='home']",
orders: "[data-test='menu-item-label'][data-test-id='orders']",
discounts: "[data-test='menu-item-label'][data-test-id='discounts']",
+ appSection: "[data-test='menu-item-label'][data-test-id='apps_section']",
app: "[data-test='menu-item-label'][data-test-id='apps']",
translations: "[data-test='menu-item-label'][data-test-id='translations']",
customers: "[data-test='menu-item-label'][data-test-id='customers']"
@@ -22,3 +23,9 @@ export const CATALOG = {
categories: "[data-test='submenu-item-label'][data-test-id='categories']",
collections: "[data-test='submenu-item-label'][data-test-id='collections']"
};
+
+export const APP_MENU_SELECTORS = {
+ app: "[data-test='submenu-item-label'][data-test-id='apps']"
+};
+
+export const appCommonSelector = "[data-test-id*='apps']";
diff --git a/cypress/fixtures/permissions.js b/cypress/fixtures/permissions.js
index 478433887..a90e1b56f 100644
--- a/cypress/fixtures/permissions.js
+++ b/cypress/fixtures/permissions.js
@@ -7,9 +7,6 @@ const configurationAsParent = {
};
export const PERMISSIONS = {
- app: {
- permissionSelectors: [menuSelectors.LEFT_MENU_SELECTORS.app]
- },
channel: {
parent: configurationAsParent,
permissionSelectors: [CONFIGURATION_SELECTORS.channels]
diff --git a/cypress/fixtures/permissionsUsers.js b/cypress/fixtures/permissionsUsers.js
index 68cb1b4f8..d5c4b6d77 100644
--- a/cypress/fixtures/permissionsUsers.js
+++ b/cypress/fixtures/permissionsUsers.js
@@ -9,7 +9,7 @@ export const PERMISSIONS_OPTIONS = {
},
app: {
user: ONE_PERMISSION_USERS.app,
- permissions: [PERMISSIONS.app],
+ permissions: [],
testCase: "TC: SALEOR_3402"
},
channel: {
diff --git a/cypress/integration/navigation.js b/cypress/integration/navigation.js
index e22d8913c..30844a39a 100644
--- a/cypress/integration/navigation.js
+++ b/cypress/integration/navigation.js
@@ -1,17 +1,55 @@
///
///
+import {
+ APP_MENU_SELECTORS,
+ appCommonSelector,
+ LEFT_MENU_SELECTORS
+} from "../elements/account/left-menu/left-menu-selectors";
import { PERMISSIONS_OPTIONS } from "../fixtures/permissionsUsers";
import filterTests from "../support/filterTests";
import * as permissionsSteps from "../support/pages/permissionsPage";
describe("As a staff user I want to navigate through shop using different permissions", () => {
- Object.keys(PERMISSIONS_OPTIONS).forEach(key => {
+ const permissionsOptions = PERMISSIONS_OPTIONS;
+
+ before(() => {
+ cy.loginUserViaRequest()
+ .visit("/")
+ .get(appCommonSelector)
+ .should("be.visible")
+ .get("body")
+ .then($body => {
+ // This will be deleted when Marketplace is released
+ // Consider this solution as temporary
+
+ let appPermissions;
+
+ if ($body.find(LEFT_MENU_SELECTORS.appSection).length) {
+ appPermissions = {
+ parent: {
+ parentMenuSelector: LEFT_MENU_SELECTORS.appSection,
+ parentSelectors: [APP_MENU_SELECTORS]
+ },
+ permissionSelectors: [APP_MENU_SELECTORS.app]
+ };
+ } else {
+ appPermissions = {
+ permissionSelectors: [LEFT_MENU_SELECTORS.app]
+ };
+ }
+
+ permissionsOptions.all.permissions.push(appPermissions);
+ permissionsOptions.app.permissions = [appPermissions];
+ });
+ });
+
+ Object.keys(permissionsOptions).forEach(key => {
const tags =
key === "all" ? ["critical", "all", "refactored"] : ["all", "refactored"];
filterTests({ definedTags: tags }, () => {
- it(`should be able to navigate through shop as a staff member using ${key} permission. ${PERMISSIONS_OPTIONS[key].testCase}`, () => {
- const permissionOption = PERMISSIONS_OPTIONS[key];
+ it(`should be able to navigate through shop as a staff member using ${key} permission. ${permissionsOptions[key].testCase}`, () => {
+ const permissionOption = permissionsOptions[key];
const permissions = permissionOption.permissions;
cy.clearSessionData();
permissionsSteps.navigateToAllAvailablePageAndCheckIfDisplayed(
diff --git a/locale/defaultMessages.json b/locale/defaultMessages.json
index 32bbffc12..345c9468b 100644
--- a/locale/defaultMessages.json
+++ b/locale/defaultMessages.json
@@ -1218,10 +1218,6 @@
"context": "WarehouseSettings public stock label",
"string": "Public Stock"
},
- "89PSdB": {
- "context": "link",
- "string": "Edit settings"
- },
"8B8E+3": {
"context": "navigator placeholder",
"string": "Order Number"
@@ -1929,6 +1925,10 @@
"context": "date time attribute type",
"string": "Date Time"
},
+ "E+M17x": {
+ "context": "marketplace section name",
+ "string": "Marketplace"
+ },
"E22x4H": {
"context": "no card defuned alert message",
"string": "You haven’t defined a gift card product!"
@@ -5700,10 +5700,6 @@
"hX5PAb": {
"string": "No results found"
},
- "hdcGSJ": {
- "context": "button",
- "string": "Support/FAQ"
- },
"hkENym": {
"string": "Customer"
},
@@ -6204,10 +6200,6 @@
"llBnr+": {
"string": "Warehouse Name"
},
- "llC1q8": {
- "context": "button",
- "string": "App home page"
- },
"lm9NSK": {
"context": "password reset, button",
"string": "Send an email with reset link"
diff --git a/src/apps/components/AppDetailsPage/AppDetailsPage.stories.tsx b/src/apps/components/AppDetailsPage/AppDetailsPage.stories.tsx
index 78ae94664..644e6faf4 100644
--- a/src/apps/components/AppDetailsPage/AppDetailsPage.stories.tsx
+++ b/src/apps/components/AppDetailsPage/AppDetailsPage.stories.tsx
@@ -9,7 +9,6 @@ const props: AppDetailsPageProps = {
data: appDetails,
loading: false,
navigateToApp: () => undefined,
- navigateToAppSettings: () => undefined,
onAppActivateOpen: () => undefined,
onAppDeactivateOpen: () => undefined
};
diff --git a/src/apps/components/AppDetailsPage/AppDetailsPage.tsx b/src/apps/components/AppDetailsPage/AppDetailsPage.tsx
index 2324b6869..7c25ec3bb 100644
--- a/src/apps/components/AppDetailsPage/AppDetailsPage.tsx
+++ b/src/apps/components/AppDetailsPage/AppDetailsPage.tsx
@@ -16,7 +16,6 @@ import { FormattedMessage, useIntl } from "react-intl";
import ReactMarkdown from "react-markdown";
import activateIcon from "../../../../assets/images/activate-icon.svg";
-import settingsIcon from "../../../../assets/images/settings-icon.svg";
import supportIcon from "../../../../assets/images/support-icon.svg";
import { useStyles } from "../../styles";
import DeactivatedText from "../DeactivatedText";
@@ -25,7 +24,6 @@ export interface AppDetailsPageProps {
loading: boolean;
data: AppQuery["app"];
navigateToApp: () => void;
- navigateToAppSettings: () => void;
onAppActivateOpen: () => void;
onAppDeactivateOpen: () => void;
}
@@ -34,7 +32,6 @@ export const AppDetailsPage: React.FC = ({
data,
loading,
navigateToApp,
- navigateToAppSettings,
onAppActivateOpen,
onAppDeactivateOpen
}) => {
@@ -76,20 +73,6 @@ export const AppDetailsPage: React.FC = ({
description="link"
/>
- {data.configurationUrl && (
-
-
-
-
- )}
= ({
-
-
-
- {!loading ? (
- <>
- {data?.dataPrivacy}
+ {(loading || data?.dataPrivacyUrl) && (
+
+
+
+ {!loading ? (
= ({
description="app privacy policy link"
/>
- >
- ) : (
-
- )}
-
-
+ ) : (
+
+ )}
+
+
+ )}
);
diff --git a/src/apps/components/AppFrame/AppFrame.tsx b/src/apps/components/AppFrame/AppFrame.tsx
index a74a02109..acf50dd79 100644
--- a/src/apps/components/AppFrame/AppFrame.tsx
+++ b/src/apps/components/AppFrame/AppFrame.tsx
@@ -1,5 +1,6 @@
import useShop from "@saleor/hooks/useShop";
import { useTheme } from "@saleor/macaw-ui";
+import clsx from "clsx";
import React from "react";
import urlJoin from "url-join";
@@ -10,6 +11,7 @@ interface Props {
src: string;
appToken: string;
appId: string;
+ className?: string;
onLoad?(): void;
onError?(): void;
}
@@ -20,6 +22,7 @@ export const AppFrame: React.FC = ({
src,
appToken,
appId,
+ className,
onLoad,
onError
}) => {
@@ -55,7 +58,7 @@ export const AppFrame: React.FC = ({
src={urlJoin(src, `?domain=${shop.domain.host}&id=${appId}`)}
onError={onError}
onLoad={handleLoad}
- className={classes.iframe}
+ className={clsx(classes.iframe, className)}
sandbox="allow-same-origin allow-forms allow-scripts"
/>
);
diff --git a/src/apps/components/AppPage/AppPage.tsx b/src/apps/components/AppPage/AppPage.tsx
index 09754dfd5..9394178fe 100644
--- a/src/apps/components/AppPage/AppPage.tsx
+++ b/src/apps/components/AppPage/AppPage.tsx
@@ -70,32 +70,6 @@ export const AppPage: React.FC = ({
description="button"
/>
-
-
diff --git a/src/apps/urls.ts b/src/apps/urls.ts
index ca7d3292a..6ad3ea2fc 100644
--- a/src/apps/urls.ts
+++ b/src/apps/urls.ts
@@ -55,9 +55,6 @@ export const appInstallUrl = appInstallPath;
export const appDetailsUrl = (id: string, params?: AppDetailsUrlQueryParams) =>
appDetailsPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
-export const appSettingsUrl = (id: string, params?: AppDetailsUrlQueryParams) =>
- appSettingsPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
-
export const appUrl = (id: string, params?: AppDetailsUrlQueryParams) =>
appPath(encodeURIComponent(id)) + "?" + stringifyQs(params);
export const appDeepUrl = (
diff --git a/src/apps/views/AppDetails/AppDetails.tsx b/src/apps/views/AppDetails/AppDetails.tsx
index 98ea54fa3..38fd4eba5 100644
--- a/src/apps/views/AppDetails/AppDetails.tsx
+++ b/src/apps/views/AppDetails/AppDetails.tsx
@@ -16,9 +16,9 @@ import AppActivateDialog from "../../components/AppActivateDialog";
import AppDeactivateDialog from "../../components/AppDeactivateDialog";
import AppDetailsPage from "../../components/AppDetailsPage";
import {
+ appDetailsUrl,
AppDetailsUrlDialog,
AppDetailsUrlQueryParams,
- appSettingsUrl,
appsListPath,
appUrl
} from "../../urls";
@@ -88,7 +88,7 @@ export const AppDetails: React.FC = ({ id, params }) => {
const [openModal, closeModal] = createDialogActionHandlers<
AppDetailsUrlDialog,
AppDetailsUrlQueryParams
- >(navigate, params => appUrl(id, params), params);
+ >(navigate, params => appDetailsUrl(id, params), params);
const handleActivateConfirm = () => {
activateApp(mutationOpts);
@@ -121,7 +121,6 @@ export const AppDetails: React.FC = ({ id, params }) => {
data={data?.app}
loading={loading}
navigateToApp={() => navigate(appUrl(id))}
- navigateToAppSettings={() => navigate(appSettingsUrl(id))}
onAppActivateOpen={() => openModal("app-activate")}
onAppDeactivateOpen={() => openModal("app-deactivate")}
/>
diff --git a/src/components/AppLayout/menuStructure.ts b/src/components/AppLayout/menuStructure.ts
index 80562e547..a2dc79102 100644
--- a/src/components/AppLayout/menuStructure.ts
+++ b/src/components/AppLayout/menuStructure.ts
@@ -11,12 +11,14 @@ import {
extensionMountPoints,
useExtensions
} from "@saleor/apps/useExtensions";
+import { MARKETPLACE_URL } from "@saleor/config";
import { configurationMenuUrl } from "@saleor/configuration";
import { getConfigMenuItemsPermissions } from "@saleor/configuration/utils";
import { giftCardListUrl } from "@saleor/giftCards/urls";
import { PermissionEnum, UserFragment } from "@saleor/graphql";
import { commonMessages, sectionNames } from "@saleor/intl";
import { SidebarMenuItem } from "@saleor/macaw-ui";
+import { marketplaceUrl } from "@saleor/marketplace/urls";
import { pageListPath } from "@saleor/pages/urls";
import { IntlShape } from "react-intl";
@@ -55,6 +57,42 @@ function useMenuStructure(
label: intl.formatMessage(sectionNames.appExtensions)
};
+ // This will be deleted when Marketplace is released
+ // Consider this solution as temporary
+ const getAppSection = () => {
+ if (MARKETPLACE_URL) {
+ return {
+ ariaLabel: "apps_section",
+ iconSrc: appsIcon,
+ label: intl.formatMessage(sectionNames.apps),
+ permissions: [PermissionEnum.MANAGE_APPS],
+ id: "apps_section",
+ children: [
+ {
+ label: intl.formatMessage(sectionNames.apps),
+ id: "apps",
+ url: appsListPath
+ },
+ {
+ ariaLabel: "marketplace",
+ label: intl.formatMessage(sectionNames.marketplace),
+ id: "marketplace",
+ url: marketplaceUrl
+ }
+ ]
+ };
+ }
+
+ return {
+ ariaLabel: "apps",
+ iconSrc: appsIcon,
+ label: intl.formatMessage(sectionNames.apps),
+ permissions: [PermissionEnum.MANAGE_APPS],
+ id: "apps",
+ url: appsListPath
+ };
+ };
+
const menuItems: FilterableMenuItem[] = [
{
ariaLabel: "home",
@@ -202,14 +240,7 @@ function useMenuStructure(
id: "pages",
url: pageListPath
},
- {
- ariaLabel: "apps",
- iconSrc: appsIcon,
- label: intl.formatMessage(sectionNames.apps),
- permissions: [PermissionEnum.MANAGE_APPS],
- id: "apps",
- url: appsListPath
- },
+ getAppSection(),
{
ariaLabel: "translations",
children: extensions.NAVIGATION_TRANSLATIONS.length > 0 && [
diff --git a/src/config.ts b/src/config.ts
index 876dfcfbe..9b0de7d8c 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -8,6 +8,7 @@ export const APP_DEFAULT_URI = "/";
export const API_URI = process.env.API_URI;
export const SW_INTERVAL = parseInt(process.env.SW_INTERVAL, 10);
export const IS_CLOUD_INSTANCE = process.env.IS_CLOUD_INSTANCE === "true";
+export const MARKETPLACE_URL = process.env.MARKETPLACE_URL;
export const DEFAULT_INITIAL_SEARCH_DATA: SearchVariables = {
after: null,
diff --git a/src/index.tsx b/src/index.tsx
index 2f2e89389..9e63e48f5 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -47,6 +47,8 @@ import { giftCardsSectionUrlName } from "./giftCards/urls";
import { apolloClient, saleorClient } from "./graphql/client";
import HomePage from "./home";
import { commonMessages } from "./intl";
+import MarketplaceSection from "./marketplace";
+import { marketplaceUrl } from "./marketplace/urls";
import NavigationSection from "./navigation";
import { navigationSection } from "./navigation/urls";
import { NotFound } from "./NotFound";
@@ -250,6 +252,11 @@ const Routes: React.FC = () => {
path={appsSection}
component={AppsSection}
/>
+
{
+ const classes = useStyles();
+ const intl = useIntl();
+ const navigate = useNavigator();
+
+ if (!MARKETPLACE_URL) {
+ return navigate("/")} />;
+ }
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+};
+
+export default Component;
diff --git a/src/marketplace/styles.ts b/src/marketplace/styles.ts
new file mode 100644
index 000000000..024af05c0
--- /dev/null
+++ b/src/marketplace/styles.ts
@@ -0,0 +1,15 @@
+import { makeStyles } from "@saleor/macaw-ui";
+
+const useStyles = makeStyles(
+ () => ({
+ iframe: {
+ height: "100vh",
+ position: "sticky"
+ }
+ }),
+ {
+ name: "marketplaceStyles"
+ }
+);
+
+export { useStyles };
diff --git a/src/marketplace/urls.ts b/src/marketplace/urls.ts
new file mode 100644
index 000000000..b190437c6
--- /dev/null
+++ b/src/marketplace/urls.ts
@@ -0,0 +1,3 @@
+const marketplaceSection = "/marketplace/";
+
+export const marketplaceUrl = marketplaceSection;
diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap
index 72ba092b5..93471c493 100644
--- a/src/storybook/__snapshots__/Stories.test.ts.snap
+++ b/src/storybook/__snapshots__/Stories.test.ts.snap
@@ -24699,34 +24699,6 @@ exports[`Storyshots Views / Apps / App default 1`] = `
About
-
-
- App home page
-
-
-
-
- Support/FAQ
-
-
-