From 6f1c5c943666a3035606f48b6d2dfc05ded34e94 Mon Sep 17 00:00:00 2001 From: Lukasz Ostrowski Date: Fri, 25 Aug 2023 11:34:28 +0200 Subject: [PATCH] Add Payload CMS (#905) --- .changeset/light-bobcats-prove.md | 5 + .changeset/strong-pugs-cover.md | 5 + apps/cms-v2/package.json | 2 + .../modules/configuration/metadata-manager.ts | 4 +- .../schemas/payloadcms-provider.schema.ts | 27 ++ .../schemas/root-config.schema.ts | 3 + .../builder.io/builder-io-config-form.tsx | 4 +- .../contentful/contentful-config-form.tsx | 10 +- .../providers/datocms/datocms-config-form.tsx | 10 +- .../src/modules/providers/payloadcms/logo.png | Bin 0 -> 7604 bytes .../payloadcms-bulk-sync-processor.ts | 51 ++++ .../providers/payloadcms/payloadcms-client.ts | 172 ++++++++++++ .../payloadcms/payloadcms-config-form.tsx | 263 ++++++++++++++++++ .../payloadcms-webhooks-processor.ts | 69 +++++ .../providers/payloadcms/payloadcms.tsx | 29 ++ .../modules/providers/providers-registry.ts | 18 +- .../modules/providers/providers-resolver.tsx | 80 +++--- .../providers/strapi/strapi-config-form.tsx | 4 +- apps/cms-v2/src/modules/theme/styles.css | 2 +- apps/cms-v2/src/modules/ui/modal.tsx | 3 +- apps/cms-v2/src/pages/add-provider/[type].tsx | 5 +- .../modules/configuration/metadata-manager.ts | 4 +- pnpm-lock.yaml | 22 +- 23 files changed, 723 insertions(+), 69 deletions(-) create mode 100644 .changeset/light-bobcats-prove.md create mode 100644 .changeset/strong-pugs-cover.md create mode 100644 apps/cms-v2/src/modules/configuration/schemas/payloadcms-provider.schema.ts create mode 100644 apps/cms-v2/src/modules/providers/payloadcms/logo.png create mode 100644 apps/cms-v2/src/modules/providers/payloadcms/payloadcms-bulk-sync-processor.ts create mode 100644 apps/cms-v2/src/modules/providers/payloadcms/payloadcms-client.ts create mode 100644 apps/cms-v2/src/modules/providers/payloadcms/payloadcms-config-form.tsx create mode 100644 apps/cms-v2/src/modules/providers/payloadcms/payloadcms-webhooks-processor.ts create mode 100644 apps/cms-v2/src/modules/providers/payloadcms/payloadcms.tsx diff --git a/.changeset/light-bobcats-prove.md b/.changeset/light-bobcats-prove.md new file mode 100644 index 0000000..c37dbb2 --- /dev/null +++ b/.changeset/light-bobcats-prove.md @@ -0,0 +1,5 @@ +--- +"saleor-app-cms-v2": patch +--- + +Fix styling of modal in the dark mode diff --git a/.changeset/strong-pugs-cover.md b/.changeset/strong-pugs-cover.md new file mode 100644 index 0000000..8309515 --- /dev/null +++ b/.changeset/strong-pugs-cover.md @@ -0,0 +1,5 @@ +--- +"saleor-app-cms-v2": minor +--- + +Added Payload CMS support. diff --git a/apps/cms-v2/package.json b/apps/cms-v2/package.json index 0123ebe..74ae114 100644 --- a/apps/cms-v2/package.json +++ b/apps/cms-v2/package.json @@ -35,6 +35,7 @@ "p-ratelimit": "1.0.1", "pino": "^8.14.1", "pino-pretty": "^10.0.0", + "qs": "6.11.2", "react": "18.2.0", "react-dom": "18.2.0", "react-error-boundary": "4.0.10", @@ -56,6 +57,7 @@ "@graphql-typed-document-node/core": "3.2.0", "@testing-library/react": "^13.4.0", "@testing-library/react-hooks": "^8.0.1", + "@types/qs": "^6.9.7", "@types/react": "18.2.5", "@types/react-dom": "18.2.5", "eslint": "8.46.0", diff --git a/apps/cms-v2/src/modules/configuration/metadata-manager.ts b/apps/cms-v2/src/modules/configuration/metadata-manager.ts index 8a0e4c4..6877d9c 100644 --- a/apps/cms-v2/src/modules/configuration/metadata-manager.ts +++ b/apps/cms-v2/src/modules/configuration/metadata-manager.ts @@ -2,11 +2,11 @@ import { SettingsManager } from "@saleor/app-sdk/settings-manager"; import { EncryptedMetadataManagerFactory } from "@saleor/apps-shared"; import { Client } from "urql"; -const metadataManagerFactory = new EncryptedMetadataManagerFactory(process.env.SECRET_KEY!); - export const createSettingsManager = ( client: Pick, appId: string, ): SettingsManager => { + const metadataManagerFactory = new EncryptedMetadataManagerFactory(process.env.SECRET_KEY!); + return metadataManagerFactory.create(client, appId); }; diff --git a/apps/cms-v2/src/modules/configuration/schemas/payloadcms-provider.schema.ts b/apps/cms-v2/src/modules/configuration/schemas/payloadcms-provider.schema.ts new file mode 100644 index 0000000..22197e9 --- /dev/null +++ b/apps/cms-v2/src/modules/configuration/schemas/payloadcms-provider.schema.ts @@ -0,0 +1,27 @@ +import { PayloadCMS } from "@/modules/providers/payloadcms/payloadcms"; +import { z } from "zod"; +import { SaleorProviderFieldsMappingSchema } from "./saleor-provider-fields-mapping.schema"; + +const InputSchema = z.object({ + type: z.literal(PayloadCMS.type), + authToken: z.string(), + configName: z.string().min(1), + collectionName: z.string().min(1), + productVariantFieldsMapping: SaleorProviderFieldsMappingSchema, + payloadApiUrl: z.string().url(), + authenticatedUserSlug: z.string(), +}); + +const FullSchema = InputSchema.extend({ + id: z.string(), +}); + +export namespace PayloadCmsProviderConfig { + export type InputShape = z.infer; + export type FullShape = z.infer; + + export const Schema = { + Input: InputSchema, + Full: FullSchema, + }; +} diff --git a/apps/cms-v2/src/modules/configuration/schemas/root-config.schema.ts b/apps/cms-v2/src/modules/configuration/schemas/root-config.schema.ts index 4ef5ff8..5182976 100644 --- a/apps/cms-v2/src/modules/configuration/schemas/root-config.schema.ts +++ b/apps/cms-v2/src/modules/configuration/schemas/root-config.schema.ts @@ -4,6 +4,7 @@ import { ContentfulProviderConfig } from "./contentful-provider.schema"; import { BuilderIoProviderConfig } from "./builder-provider.schema"; import { StrapiProviderConfig } from "./strapi-provider.schema"; import { DatocmsProviderConfig } from "./datocms-provider.schema"; +import { PayloadCmsProviderConfig } from "./payloadcms-provider.schema"; export namespace ProvidersConfig { const AnyFull = z.union([ @@ -14,6 +15,7 @@ export namespace ProvidersConfig { DatocmsProviderConfig.Schema.Full, StrapiProviderConfig.Schema.Full, BuilderIoProviderConfig.Schema.Full, + PayloadCmsProviderConfig.Schema.Full, ]); export const Schema = { @@ -23,6 +25,7 @@ export namespace ProvidersConfig { DatocmsProviderConfig.Schema.Input, StrapiProviderConfig.Schema.Input, BuilderIoProviderConfig.Schema.Input, + PayloadCmsProviderConfig.Schema.Input, ]), AnyFullList: z.array(AnyFull), }; diff --git a/apps/cms-v2/src/modules/providers/builder.io/builder-io-config-form.tsx b/apps/cms-v2/src/modules/providers/builder.io/builder-io-config-form.tsx index 075eeb8..1374e0f 100644 --- a/apps/cms-v2/src/modules/providers/builder.io/builder-io-config-form.tsx +++ b/apps/cms-v2/src/modules/providers/builder.io/builder-io-config-form.tsx @@ -104,7 +104,7 @@ const PureForm = ({ defaultValues, onSubmit, onDelete }: PureFormProps) => { padding={2} > Saleor Field - Contentful field + Builder.io field {SaleorProviderFieldsMappingKeys.map((saleorField) => ( // todo extract this table to component @@ -190,7 +190,7 @@ const EditFormVariant = (props: { configId: string }) => { }, { enabled: !!props.configId, - } + }, ); const { mutate } = trpcClient.providersConfigs.updateOne.useMutation({ onSuccess() { diff --git a/apps/cms-v2/src/modules/providers/contentful/contentful-config-form.tsx b/apps/cms-v2/src/modules/providers/contentful/contentful-config-form.tsx index f925578..1fe8551 100644 --- a/apps/cms-v2/src/modules/providers/contentful/contentful-config-form.tsx +++ b/apps/cms-v2/src/modules/providers/contentful/contentful-config-form.tsx @@ -53,7 +53,7 @@ const PureForm = ({ }); notifyError( "Error", - "Could not fetch content types from Contentful. Please check your credentials." + "Could not fetch content types from Contentful. Please check your credentials.", ); }, }); @@ -76,7 +76,7 @@ const PureForm = ({ }); notifyError( "Error", - "Could not fetch environments from Contentful. Please check your credentials." + "Could not fetch environments from Contentful. Please check your credentials.", ); }, }); @@ -197,7 +197,7 @@ const PureForm = ({ newTab size="small" href={`https://app.contentful.com/spaces/${getValues( - "spaceId" + "spaceId", )}/settings/environments`} > here @@ -247,7 +247,7 @@ const PureForm = ({ - Map fields from Saleor to your contentful schema. + Map fields from Saleor to your Contentful schema. All fields should be type of Text. Channels should @@ -357,7 +357,7 @@ const EditVariant = ({ configId }: { configId: string }) => { }, { enabled: !!configId, - } + }, ); const { mutate } = trpcClient.providersConfigs.updateOne.useMutation({ onSuccess() { diff --git a/apps/cms-v2/src/modules/providers/datocms/datocms-config-form.tsx b/apps/cms-v2/src/modules/providers/datocms/datocms-config-form.tsx index 42dea79..81441f7 100644 --- a/apps/cms-v2/src/modules/providers/datocms/datocms-config-form.tsx +++ b/apps/cms-v2/src/modules/providers/datocms/datocms-config-form.tsx @@ -43,7 +43,7 @@ const PureForm = ({ defaultValues, onSubmit, onDelete }: PureFormProps) => { notifyError( "Error", - "Could not fetch content types from DatoCMS. Please check your credentials." + "Could not fetch content types from DatoCMS. Please check your credentials.", ); }, }); @@ -61,7 +61,7 @@ const PureForm = ({ defaultValues, onSubmit, onDelete }: PureFormProps) => { notifyError( "Error", - "Could not fetch content types from DatoCMS. Please check your credentials." + "Could not fetch content types from DatoCMS. Please check your credentials.", ); }, }); @@ -161,7 +161,7 @@ const PureForm = ({ defaultValues, onSubmit, onDelete }: PureFormProps) => { {fieldsData && ( - Map fields from Saleor to your contentful schema. + Map fields from Saleor to your DatoCMS schema. All fields should be type of Text. Channels should @@ -177,7 +177,7 @@ const PureForm = ({ defaultValues, onSubmit, onDelete }: PureFormProps) => { padding={2} > Saleor Field - Contentful field + DatoCMS field {SaleorProviderFieldsMappingKeys.map((saleorField) => ( // todo extract this table to component @@ -271,7 +271,7 @@ const EditFormVariant = (props: { configId: string }) => { }, { enabled: !!props.configId, - } + }, ); const { mutate } = trpcClient.providersConfigs.updateOne.useMutation({ onSuccess() { diff --git a/apps/cms-v2/src/modules/providers/payloadcms/logo.png b/apps/cms-v2/src/modules/providers/payloadcms/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f8af7f5e905d1eb10cb5c0b9795ca9fbc4bf88b2 GIT binary patch literal 7604 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 Zsw>YqBRQ> { + const client = new PayloadCMSClient(); + + products.flatMap( + (product) => + product.variants?.map((variant) => { + if (hooks.onUploadStart) { + hooks.onUploadStart({ variantId: variant.id }); + } + + return client + .upsertProductVariant({ + configuration: this.config, + variant: { + id: variant.id, + name: variant.name, + channelListings: variant.channelListings, + product: { + id: product.id, + name: product.name, + slug: product.slug, + }, + }, + }) + .then((r) => { + if (hooks.onUploadSuccess) { + hooks.onUploadSuccess({ variantId: variant.id }); + } + }) + .catch((e) => { + if (hooks.onUploadError) { + hooks.onUploadError({ variantId: variant.id, error: e }); + } + }); + }), + ); + } +} diff --git a/apps/cms-v2/src/modules/providers/payloadcms/payloadcms-client.ts b/apps/cms-v2/src/modules/providers/payloadcms/payloadcms-client.ts new file mode 100644 index 0000000..794b1b3 --- /dev/null +++ b/apps/cms-v2/src/modules/providers/payloadcms/payloadcms-client.ts @@ -0,0 +1,172 @@ +import { createLogger } from "@saleor/apps-shared"; +import { WebhookProductVariantFragment } from "../../../../generated/graphql"; + +import { PayloadCmsProviderConfig } from "@/modules/configuration/schemas/payloadcms-provider.schema"; +import { FieldsMapper } from "../fields-mapper"; + +import qs from "qs"; +import { z } from "zod"; + +type Context = { + configuration: PayloadCmsProviderConfig.FullShape; + variant: WebhookProductVariantFragment; +}; + +/** + * Client uses REST API with built-in query language + * https://payloadcms.com/docs/queries/overview#rest-queries + */ +export class PayloadCMSClient { + private logger = createLogger({ name: "PayloadCMSClient" }); + + private mapVariantToPayloadFields({ configuration, variant }: Context) { + const fields = FieldsMapper.mapProductVariantToConfigurationFields({ + variant, + configMapping: configuration.productVariantFieldsMapping, + }); + + return fields; + } + + private constructCollectionUrl(config: PayloadCmsProviderConfig.FullShape) { + return `${config.payloadApiUrl}/${config.collectionName}`; + } + + getItemsBySaleorVariantId(context: Context) { + const queryString = qs.stringify( + { + where: { + [context.configuration.productVariantFieldsMapping.variantId]: { + equals: context.variant.id, + }, + }, + }, + { + addQueryPrefix: true, + }, + ); + + return fetch(`${this.constructCollectionUrl(context.configuration)}${queryString}`, { + headers: this.getHeaders(context), + }).then((r) => r.json()); + } + + async deleteProductVariant(context: Context) { + const queryString = qs.stringify( + { + where: { + [context.configuration.productVariantFieldsMapping.variantId]: { + equals: context.variant.id, + }, + }, + }, + { + addQueryPrefix: true, + }, + ); + + try { + const response = await fetch( + this.constructCollectionUrl(context.configuration) + queryString, + { + method: "DELETE", + headers: this.getHeaders(context), + }, + ); + + if (response.status >= 400) { + throw new Error("Error while deleting product variant"); + } + } catch (e) { + this.logger.error(e); + + throw e; + } + } + + private getHeaders(context: Context) { + const headers = new Headers({ + "Content-Type": "application/json", + }); + + /** + * https://payloadcms.com/docs/authentication/config#api-keys + */ + if ( + context.configuration.authToken.length > 0 && + context.configuration.authenticatedUserSlug.length > 0 + ) { + headers.append( + "Authorization", + `${context.configuration.authenticatedUserSlug} API-Key ${context.configuration.authToken}`, + ); + } + + return headers; + } + + uploadProductVariant(context: Context) { + this.logger.debug("Trying to upload product variant"); + + return fetch(this.constructCollectionUrl(context.configuration), { + method: "POST", + body: JSON.stringify(this.mapVariantToPayloadFields(context)), + headers: this.getHeaders(context), + }) + .then((r) => { + if (r.status >= 400) { + throw new Error(`Error while uploading product variant: ${r.statusText}`); + } + }) + .catch((e) => { + this.logger.error(e); + + throw e; + }); + } + + async updateProductVariant({ configuration, variant }: Context) { + this.logger.debug("Trying to update product variant"); + + const queryString = qs.stringify( + { + where: { + [configuration.productVariantFieldsMapping.variantId]: { + equals: variant.id, + }, + }, + }, + { + addQueryPrefix: true, + }, + ); + + try { + const response = await fetch(this.constructCollectionUrl(configuration) + queryString, { + method: "PATCH", + body: JSON.stringify(this.mapVariantToPayloadFields({ configuration, variant })), + headers: this.getHeaders({ configuration, variant }), + }); + + if (response.status >= 400) { + throw new Error("Error while updating product variant"); + } + } catch (e) { + this.logger.error(e); + + throw e; + } + } + + async upsertProductVariant(context: Context) { + this.logger.debug("Trying to upsert product variant"); + + try { + await this.uploadProductVariant(context); + } catch (e) { + this.logger.debug("Failed to upload, will try to update"); + + await this.updateProductVariant(context); + } + } +} diff --git a/apps/cms-v2/src/modules/providers/payloadcms/payloadcms-config-form.tsx b/apps/cms-v2/src/modules/providers/payloadcms/payloadcms-config-form.tsx new file mode 100644 index 0000000..e3d0743 --- /dev/null +++ b/apps/cms-v2/src/modules/providers/payloadcms/payloadcms-config-form.tsx @@ -0,0 +1,263 @@ +import { SaleorProviderFieldsMappingKeys } from "@/modules/configuration"; +import { PayloadCmsProviderConfig } from "@/modules/configuration/schemas/payloadcms-provider.schema"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useDashboardNotification } from "@saleor/apps-shared"; +import { Box, Button, Text } from "@saleor/macaw-ui/next"; +import { Input, Select } from "@saleor/react-hook-form-macaw"; +import { useRouter } from "next/router"; +import React from "react"; +import { useForm } from "react-hook-form"; +import { printSaleorProductFields } from "../../configuration/print-saleor-product-fields"; +import { trpcClient } from "../../trpc/trpc-client"; +import { ButtonsBox } from "../../ui/buttons-box"; +import { TextLink } from "@saleor/apps-ui"; + +type FormShape = Omit; + +type PureFormProps = { + defaultValues: FormShape; + onSubmit(values: FormShape): void; + onDelete?(): void; +}; + +/* + * todo react on token change, refresh mutation + */ +const PureForm = ({ defaultValues, onSubmit, onDelete }: PureFormProps) => { + const { notifyError } = useDashboardNotification(); + + const { control, getValues, setValue, watch, handleSubmit, clearErrors, setError } = useForm({ + defaultValues: defaultValues, + resolver: zodResolver(PayloadCmsProviderConfig.Schema.Input.omit({ type: true })), + }); + + return ( + { + onSubmit(vals); + })} + > + + + Provide connection details + + + + + Authorization + + + Payload can be configured to have open operations (not recommended) or to require an API + key. Key can be generated per user. To authenticate, you need to provide both user slug + and the key itself.{" "} + + + Read more in Payload docs + + + If your API is open (e.g. for development purposes) leave both fields empty. + + + + + + + + Configure fields mapping + + + + + Map fields from Saleor to your Payload schema. + + + All fields should be type of Text. Channels should be + type of JSON. + + + Saleor Field + Payload field + + {SaleorProviderFieldsMappingKeys.map((saleorField) => ( + // todo extract this table to component + + + + {printSaleorProductFields(saleorField)} + + + {saleorField === "channels" ? "JSON field" : "Text field"} + + + + + ))} + + + + + {onDelete && ( + + )} + + + + ); +}; + +const AddFormVariant = () => { + const { push } = useRouter(); + const { notifySuccess } = useDashboardNotification(); + + const { mutate } = trpcClient.providersConfigs.addOne.useMutation({ + onSuccess() { + notifySuccess("Success", "Added new configuration"); + push("/configuration"); + }, + }); + + return ( + { + mutate({ + ...values, + type: "payloadcms", + }); + }} + defaultValues={{ + payloadApiUrl: "", + authToken: "", + configName: "", + collectionName: "", + authenticatedUserSlug: "", + productVariantFieldsMapping: { + channels: "", + variantName: "", + productId: "", + productName: "", + productSlug: "", + variantId: "", + }, + }} + /> + ); +}; + +const EditFormVariant = (props: { configId: string }) => { + const { push } = useRouter(); + const { notifySuccess } = useDashboardNotification(); + + const { data } = trpcClient.providersConfigs.getOne.useQuery( + { + id: props.configId, + }, + { + enabled: !!props.configId, + }, + ); + + const { mutate } = trpcClient.providersConfigs.updateOne.useMutation({ + onSuccess() { + notifySuccess("Success", "Updated configuration"); + push("/configuration"); + }, + }); + + const { mutate: deleteProvider } = trpcClient.providersConfigs.deleteOne.useMutation({ + onSuccess() { + notifySuccess("Success", "Removed configuration"); + push("/configuration"); + }, + }); + + if (!data) { + return null; + } + + if (data.type !== "payloadcms") { + throw new Error("Trying to fill Payload CMS form with non Payload CMS data"); + } + + return ( + { + deleteProvider({ + id: props.configId, + }); + }} + onSubmit={(values) => { + mutate({ + ...values, + type: "payloadcms", + id: props.configId, + }); + }} + defaultValues={data} + /> + ); +}; + +export const PayloadCMSConfigForm = { + PureVariant: PureForm, + AddVariant: AddFormVariant, + EditVariant: EditFormVariant, +}; diff --git a/apps/cms-v2/src/modules/providers/payloadcms/payloadcms-webhooks-processor.ts b/apps/cms-v2/src/modules/providers/payloadcms/payloadcms-webhooks-processor.ts new file mode 100644 index 0000000..b6c097e --- /dev/null +++ b/apps/cms-v2/src/modules/providers/payloadcms/payloadcms-webhooks-processor.ts @@ -0,0 +1,69 @@ +import { + WebhookProductFragment, + WebhookProductVariantFragment, +} from "../../../../generated/graphql"; + +import { PayloadCmsProviderConfig } from "@/modules/configuration/schemas/payloadcms-provider.schema"; +import { createLogger } from "@saleor/apps-shared"; +import { ProductWebhooksProcessor } from "../../webhooks-operations/product-webhooks-processor"; +import { PayloadCMSClient } from "./payloadcms-client"; + +/* + * todo error handling + */ +export class PayloadCmsWebhooksProcessor implements ProductWebhooksProcessor { + private client = new PayloadCMSClient(); + + private logger = createLogger({ name: "PayloadCmsWebhooksProcessor" }); + + constructor(private providerConfig: PayloadCmsProviderConfig.FullShape) {} + + async onProductVariantUpdated(productVariant: WebhookProductVariantFragment): Promise { + this.logger.trace("onProductVariantUpdated called"); + + await this.client.upsertProductVariant({ + configuration: this.providerConfig, + variant: productVariant, + }); + } + + async onProductVariantCreated(productVariant: WebhookProductVariantFragment): Promise { + this.logger.trace("onProductVariantCreated called"); + + await this.client.uploadProductVariant({ + configuration: this.providerConfig, + variant: productVariant, + }); + } + async onProductVariantDeleted(productVariant: WebhookProductVariantFragment): Promise { + this.logger.trace("onProductVariantDeleted called"); + + await this.client.deleteProductVariant({ + configuration: this.providerConfig, + variant: productVariant, + }); + } + + async onProductUpdated(product: WebhookProductFragment): Promise { + this.logger.trace("onProductUpdated called"); + + const client = new PayloadCMSClient(); + + await Promise.all( + (product.variants ?? []).map((variant) => { + return client.upsertProductVariant({ + configuration: this.providerConfig, + variant: { + id: variant.id, + name: variant.name, + product: { + id: product.id, + name: product.name, + slug: product.slug, + }, + }, + }); + }), + ); + } +} diff --git a/apps/cms-v2/src/modules/providers/payloadcms/payloadcms.tsx b/apps/cms-v2/src/modules/providers/payloadcms/payloadcms.tsx new file mode 100644 index 0000000..a543c80 --- /dev/null +++ b/apps/cms-v2/src/modules/providers/payloadcms/payloadcms.tsx @@ -0,0 +1,29 @@ +import { Box, Text } from "@saleor/macaw-ui/next"; + +import { CMSProviderMeta } from "../cms-provider-meta"; +import logo from "./logo.png"; +import { TextLink } from "@saleor/apps-ui"; + +export const PayloadCMS = { + formSideInfo: ( + + + Configure the Payload CMS integration by providing required information. + + + Fields are not validated - ensure you enter correct values. + + + Consult{" "} + + docs + {" "} + for more information how to set up Payload CMS. + + + ), + type: "payloadcms" as const, + logoUrl: logo.src, + displayName: "Payload", + description: "Open source, typescript first headless CMS. GraphQL included.", +} satisfies CMSProviderMeta; diff --git a/apps/cms-v2/src/modules/providers/providers-registry.ts b/apps/cms-v2/src/modules/providers/providers-registry.ts index 79e1569..4711cc8 100644 --- a/apps/cms-v2/src/modules/providers/providers-registry.ts +++ b/apps/cms-v2/src/modules/providers/providers-registry.ts @@ -1,12 +1,24 @@ import { BuilderIo } from "./builder.io/builder-io"; import { Contentful } from "./contentful/contentful"; import { Datocms } from "./datocms/datocms"; +import { PayloadCMS } from "./payloadcms/payloadcms"; import { Strapi } from "./strapi/strapi"; -export type CMS = typeof Contentful | typeof Datocms | typeof Strapi | typeof BuilderIo; +export type CMS = + | typeof Contentful + | typeof Datocms + | typeof Strapi + | typeof BuilderIo + | typeof PayloadCMS; export type CMSType = CMS["type"]; -export const cmsTypes = [Contentful.type, Datocms.type, Strapi.type, BuilderIo.type] as const; +export const cmsTypes = [ + Contentful.type, + Datocms.type, + Strapi.type, + BuilderIo.type, + PayloadCMS.type, +] as const; -export const CMSProviders = [Contentful, Datocms, Strapi, BuilderIo] as const; +export const CMSProviders = [Contentful, Datocms, Strapi, BuilderIo, PayloadCMS] as const; diff --git a/apps/cms-v2/src/modules/providers/providers-resolver.tsx b/apps/cms-v2/src/modules/providers/providers-resolver.tsx index 7d46ba7..4477247 100644 --- a/apps/cms-v2/src/modules/providers/providers-resolver.tsx +++ b/apps/cms-v2/src/modules/providers/providers-resolver.tsx @@ -22,6 +22,10 @@ import { DatocmsProviderConfig } from "../configuration/schemas/datocms-provider import { BuilderIo } from "./builder.io/builder-io"; import { BuilderIoWebhooksProcessor } from "./builder.io/builder-io-webhooks-processor"; import { BuilderIoBulkSyncProcessor } from "./builder.io/builder-io-bulk-sync-processor"; +import { PayloadCmsBulkSyncProcessor } from "./payloadcms/payloadcms-bulk-sync-processor"; +import { PayloadCmsProviderConfig } from "../configuration/schemas/payloadcms-provider.schema"; +import { PayloadCMS } from "./payloadcms/payloadcms"; +import { PayloadCmsWebhooksProcessor } from "./payloadcms/payloadcms-webhooks-processor"; /** * Almost-single source of new providers. Every time app will need to resolve a provider, it will use on of these factories. @@ -39,9 +43,9 @@ export const ProvidersResolver = { case "builder.io": { return new BuilderIoBulkSyncProcessor(config); } - - default: - throw new Error(`Unknown provider`); + case "payloadcms": { + return new PayloadCmsBulkSyncProcessor(config); + } } }, getProviderInputSchema(type: CMSType) { @@ -54,9 +58,8 @@ export const ProvidersResolver = { return StrapiProviderConfig.Schema.Input; case "builder.io": return BuilderIoProviderConfig.Schema.Input; - default: { - throw new Error("Failed to build input schema"); - } + case "payloadcms": + return PayloadCmsProviderConfig.Schema.Input; } }, getProviderSchema(type: CMSType) { @@ -69,12 +72,11 @@ export const ProvidersResolver = { return StrapiProviderConfig.Schema.Full; case "builder.io": return BuilderIoProviderConfig.Schema.Full; - default: { - throw new Error("Failed to build provdier schema"); - } + case "payloadcms": + return PayloadCmsProviderConfig.Schema.Full; } }, - createProviderMeta(type: CMSType | string): CMS { + createProviderMeta(type: CMSType): CMS { switch (type) { case "contentful": { return Contentful; @@ -88,8 +90,8 @@ export const ProvidersResolver = { case "builder.io": { return BuilderIo; } - default: { - throw new Error("Unknown provider"); + case "payloadcms": { + return PayloadCMS; } } }, @@ -107,13 +109,13 @@ export const ProvidersResolver = { case "builder.io": { return new BuilderIoWebhooksProcessor(config); } - default: { - throw new Error("Failed to build webhook processor."); + case "payloadcms": { + return new PayloadCmsWebhooksProcessor(config); } } }, getEditProviderFormComponent: ( - type: CMSType + type: CMSType, ): ComponentType<{ configId: string; }> => { @@ -121,33 +123,37 @@ export const ProvidersResolver = { case "contentful": { return dynamic(() => import("./contentful/contentful-config-form").then( - (module) => module.ContentfulConfigForm.EditVariant - ) + (module) => module.ContentfulConfigForm.EditVariant, + ), ); } case "datocms": { return dynamic(() => import("./datocms/datocms-config-form").then( - (module) => module.DatoCMSConfigForm.EditVariant - ) + (module) => module.DatoCMSConfigForm.EditVariant, + ), ); } case "strapi": { return dynamic(() => import("./strapi/strapi-config-form").then( - (module) => module.StrapiConfigForm.EditVariant - ) + (module) => module.StrapiConfigForm.EditVariant, + ), ); } case "builder.io": { return dynamic(() => import("./builder.io/builder-io-config-form").then( - (module) => module.BuilderIoConfigForm.EditVariant - ) + (module) => module.BuilderIoConfigForm.EditVariant, + ), ); } - default: { - throw new Error("Provider form not registered"); + case "payloadcms": { + return dynamic(() => + import("./payloadcms/payloadcms-config-form").then( + (module) => module.PayloadCMSConfigForm.EditVariant, + ), + ); } } }, @@ -156,31 +162,37 @@ export const ProvidersResolver = { case "contentful": { return dynamic(() => import("./contentful/contentful-config-form").then( - (module) => module.ContentfulConfigForm.AddVariant - ) + (module) => module.ContentfulConfigForm.AddVariant, + ), ); } case "datocms": { return dynamic(() => import("./datocms/datocms-config-form").then( - (module) => module.DatoCMSConfigForm.AddVariant - ) + (module) => module.DatoCMSConfigForm.AddVariant, + ), ); } case "strapi": { return dynamic(() => - import("./strapi/strapi-config-form").then((module) => module.StrapiConfigForm.AddVariant) + import("./strapi/strapi-config-form").then( + (module) => module.StrapiConfigForm.AddVariant, + ), ); } case "builder.io": { return dynamic(() => import("./builder.io/builder-io-config-form").then( - (module) => module.BuilderIoConfigForm.AddVariant - ) + (module) => module.BuilderIoConfigForm.AddVariant, + ), ); } - default: { - throw new Error("Provider form not registered"); + case "payloadcms": { + return dynamic(() => + import("./payloadcms/payloadcms-config-form").then( + (module) => module.PayloadCMSConfigForm.AddVariant, + ), + ); } } }, diff --git a/apps/cms-v2/src/modules/providers/strapi/strapi-config-form.tsx b/apps/cms-v2/src/modules/providers/strapi/strapi-config-form.tsx index e444879..52fc192 100644 --- a/apps/cms-v2/src/modules/providers/strapi/strapi-config-form.tsx +++ b/apps/cms-v2/src/modules/providers/strapi/strapi-config-form.tsx @@ -86,7 +86,7 @@ const PureForm = ({ defaultValues, onSubmit, onDelete }: PureFormProps) => { padding={2} > Saleor Field - Contentful field + Strapi field {SaleorProviderFieldsMappingKeys.map((saleorField) => ( // todo extract this table to component @@ -172,7 +172,7 @@ const EditFormVariant = (props: { configId: string }) => { }, { enabled: !!props.configId, - } + }, ); const { mutate } = trpcClient.providersConfigs.updateOne.useMutation({ onSuccess() { diff --git a/apps/cms-v2/src/modules/theme/styles.css b/apps/cms-v2/src/modules/theme/styles.css index a19ddb8..0327b1e 100644 --- a/apps/cms-v2/src/modules/theme/styles.css +++ b/apps/cms-v2/src/modules/theme/styles.css @@ -9,7 +9,7 @@ dialog { .dialog-overlay { z-index: 1; - background: rgba(255, 255, 255, 0.8); + background: rgba(var(--mu-colors-background-plain), 0.8); backdrop-filter: blur(5px); content: ""; position: fixed; diff --git a/apps/cms-v2/src/modules/ui/modal.tsx b/apps/cms-v2/src/modules/ui/modal.tsx index da438e5..ffe6874 100644 --- a/apps/cms-v2/src/modules/ui/modal.tsx +++ b/apps/cms-v2/src/modules/ui/modal.tsx @@ -1,5 +1,4 @@ import { Box, BoxProps } from "@saleor/macaw-ui/next"; -import { forwardRef } from "react"; export const Modal = ({ onClose, ...rest }: { onClose(): void } & BoxProps) => { return ( @@ -12,6 +11,8 @@ export const Modal = ({ onClose, ...rest }: { onClose(): void } & BoxProps) => { as="dialog" __maxWidth="400px" boxShadow={"modal"} + backgroundColor="surfaceNeutralPlain" + color="textNeutralDefault" open {...rest} /> diff --git a/apps/cms-v2/src/pages/add-provider/[type].tsx b/apps/cms-v2/src/pages/add-provider/[type].tsx index 4141d2d..89e3cfc 100644 --- a/apps/cms-v2/src/pages/add-provider/[type].tsx +++ b/apps/cms-v2/src/pages/add-provider/[type].tsx @@ -1,9 +1,6 @@ -import { ContentfulConfigForm } from "@/modules/providers/contentful/contentful-config-form"; -import { DatoCMSConfigForm } from "@/modules/providers/datocms/datocms-config-form"; import { CMSType } from "@/modules/providers/providers-registry"; import { ProvidersResolver } from "@/modules/providers/providers-resolver"; -import { StrapiConfigForm } from "@/modules/providers/strapi/strapi-config-form"; import { AppHeader } from "@/modules/ui/app-header"; import { AppSection } from "@/modules/ui/app-section"; import { Breadcrumbs } from "@saleor/apps-ui"; @@ -16,7 +13,7 @@ const AddProviderPage: NextPage = () => { const { query } = useRouter(); const provider = useMemo(() => { - return query.type ? ProvidersResolver.createProviderMeta(query.type as string) : null; + return query.type ? ProvidersResolver.createProviderMeta(query.type as CMSType) : null; }, [query.type]); if (!provider) return null; diff --git a/apps/segment/src/modules/configuration/metadata-manager.ts b/apps/segment/src/modules/configuration/metadata-manager.ts index 8a0e4c4..6877d9c 100644 --- a/apps/segment/src/modules/configuration/metadata-manager.ts +++ b/apps/segment/src/modules/configuration/metadata-manager.ts @@ -2,11 +2,11 @@ import { SettingsManager } from "@saleor/app-sdk/settings-manager"; import { EncryptedMetadataManagerFactory } from "@saleor/apps-shared"; import { Client } from "urql"; -const metadataManagerFactory = new EncryptedMetadataManagerFactory(process.env.SECRET_KEY!); - export const createSettingsManager = ( client: Pick, appId: string, ): SettingsManager => { + const metadataManagerFactory = new EncryptedMetadataManagerFactory(process.env.SECRET_KEY!); + return metadataManagerFactory.create(client, appId); }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7d8b053..7b9b960 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -106,6 +106,9 @@ importers: pino-pretty: specifier: ^10.0.0 version: 10.0.0 + qs: + specifier: 6.11.2 + version: 6.11.2 react: specifier: 18.2.0 version: 18.2.0 @@ -164,6 +167,9 @@ importers: '@testing-library/react-hooks': specifier: ^8.0.1 version: 8.0.1(@types/react@18.2.5)(react-dom@18.2.0)(react@18.2.0) + '@types/qs': + specifier: ^6.9.7 + version: 6.9.7 '@types/react': specifier: 18.2.5 version: 18.2.5 @@ -5799,7 +5805,7 @@ packages: /@changesets/apply-release-plan@6.1.4: resolution: {integrity: sha512-FMpKF1fRlJyCZVYHr3CbinpZZ+6MwvOtWUuO8uo+svcATEoc1zRDcj23pAurJ2TZ/uVz1wFHH6K3NlACy0PLew==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.22.10 '@changesets/config': 2.3.1 '@changesets/get-version-range-type': 0.3.2 '@changesets/git': 2.0.0 @@ -5816,7 +5822,7 @@ packages: /@changesets/assemble-release-plan@5.2.4: resolution: {integrity: sha512-xJkWX+1/CUaOUWTguXEbCDTyWJFECEhmdtbkjhn5GVBGxdP/JwaHBIU9sW3FR6gD07UwZ7ovpiPclQZs+j+mvg==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.22.10 '@changesets/errors': 0.1.4 '@changesets/get-dependents-graph': 1.3.6 '@changesets/types': 5.2.1 @@ -5894,7 +5900,7 @@ packages: /@changesets/get-release-plan@3.0.17: resolution: {integrity: sha512-6IwKTubNEgoOZwDontYc2x2cWXfr6IKxP3IhKeK+WjyD6y3M4Gl/jdQvBw+m/5zWILSOCAaGLu2ZF6Q+WiPniw==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.22.10 '@changesets/assemble-release-plan': 5.2.4 '@changesets/config': 2.3.1 '@changesets/pre': 1.0.14 @@ -5908,7 +5914,7 @@ packages: /@changesets/git@2.0.0: resolution: {integrity: sha512-enUVEWbiqUTxqSnmesyJGWfzd51PY4H7mH9yUw0hPVpZBJ6tQZFMU3F3mT/t9OJ/GjyiM4770i+sehAn6ymx6A==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.22.10 '@changesets/errors': 0.1.4 '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 @@ -5930,7 +5936,7 @@ packages: /@changesets/pre@1.0.14: resolution: {integrity: sha512-dTsHmxQWEQekHYHbg+M1mDVYFvegDh9j/kySNuDKdylwfMEevTeDouR7IfHNyVodxZXu17sXoJuf2D0vi55FHQ==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.22.10 '@changesets/errors': 0.1.4 '@changesets/types': 5.2.1 '@manypkg/get-packages': 1.1.3 @@ -5939,7 +5945,7 @@ packages: /@changesets/read@0.5.9: resolution: {integrity: sha512-T8BJ6JS6j1gfO1HFq50kU3qawYxa4NTbI/ASNVVCBTsKquy2HYwM9r7ZnzkiMe8IEObAJtUVGSrePCOxAK2haQ==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.22.10 '@changesets/git': 2.0.0 '@changesets/logger': 0.0.5 '@changesets/parse': 0.3.16 @@ -5957,7 +5963,7 @@ packages: /@changesets/write@0.2.3: resolution: {integrity: sha512-Dbamr7AIMvslKnNYsLFafaVORx4H0pvCA2MHqgtNCySMe1blImEyAEOzDmcgKAkgz4+uwoLz7demIrX+JBr/Xw==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.22.10 '@changesets/types': 5.2.1 fs-extra: 7.0.1 human-id: 1.0.2 @@ -7698,7 +7704,7 @@ packages: /@manypkg/get-packages@1.1.3: resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} dependencies: - '@babel/runtime': 7.22.6 + '@babel/runtime': 7.22.10 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0