From a9a1ef1ba725f0735b39bd354b1be9f73313b9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Zori=C4=87?= Date: Thu, 26 Sep 2024 13:19:45 +0200 Subject: [PATCH 1/6] fix(api-headless-cms): singleton model reference field (#4296) --- .../contentAPI/mocks/contentModels.ts | 103 ++++++++++++++++++ .../contentAPI/singletonContentEntry.test.ts | 2 +- .../useSingletonCategoryHandler.ts | 2 +- .../graphql/schema/createSingularResolvers.ts | 2 +- .../src/graphql/schema/createSingularSDL.ts | 2 +- .../src/utils/getSchemaFromFieldPlugins.ts | 6 +- 6 files changed, 111 insertions(+), 6 deletions(-) diff --git a/packages/api-headless-cms/__tests__/contentAPI/mocks/contentModels.ts b/packages/api-headless-cms/__tests__/contentAPI/mocks/contentModels.ts index 50510526ec1..1643a2658f3 100644 --- a/packages/api-headless-cms/__tests__/contentAPI/mocks/contentModels.ts +++ b/packages/api-headless-cms/__tests__/contentAPI/mocks/contentModels.ts @@ -253,6 +253,109 @@ const models: CmsModel[] = [ tenant: "root", webinyVersion }, + // category + { + createdOn: new Date().toISOString(), + savedOn: new Date().toISOString(), + locale: "en-US", + titleFieldId: "title", + lockedFields: [], + name: "Category Singleton", + description: "Product category Singleton", + modelId: "categorySingleton", + singularApiName: "CategoryApiNameWhichIsABitDifferentThanModelIdSingleton", + pluralApiName: "CategoriesApiModelSingleton", + group: { + id: contentModelGroup.id, + name: contentModelGroup.name + }, + layout: [[ids.field11], [ids.field12]], + fields: [ + { + id: ids.field11, + multipleValues: false, + helpText: "", + label: "Title", + type: "text", + storageId: "text@titleStorageId", + fieldId: "title", + validation: [ + { + name: "required", + message: "This field is required" + }, + { + name: "minLength", + message: "Enter at least 3 characters", + settings: { + min: 3.0 + } + } + ], + listValidation: [], + placeholderText: "placeholder text", + predefinedValues: { + enabled: false, + values: [] + }, + renderer: { + name: "renderer" + } + }, + { + id: ids.field12, + multipleValues: false, + helpText: "", + label: "Slug", + type: "text", + storageId: "text@slugStorageId", + fieldId: "slug", + validation: [ + { + name: "required", + message: "This field is required" + } + ], + listValidation: [], + placeholderText: "placeholder text", + predefinedValues: { + enabled: false, + values: [] + }, + renderer: { + name: "renderer" + } + }, + { + id: ids.field34, + multipleValues: false, + helpText: "", + label: "Category", + type: "ref", + storageId: "ref@categoryRef", + fieldId: "categoryRef", + validation: [], + listValidation: [], + placeholderText: "placeholder text", + settings: { + models: [ + { + modelId: "categorySingleton" + } + ] + }, + predefinedValues: { + enabled: false, + values: [] + }, + renderer: { + name: "renderer" + } + } + ], + tenant: "root", + webinyVersion + }, // product { createdOn: new Date().toISOString(), diff --git a/packages/api-headless-cms/__tests__/contentAPI/singletonContentEntry.test.ts b/packages/api-headless-cms/__tests__/contentAPI/singletonContentEntry.test.ts index 893e9515939..6659bd37add 100644 --- a/packages/api-headless-cms/__tests__/contentAPI/singletonContentEntry.test.ts +++ b/packages/api-headless-cms/__tests__/contentAPI/singletonContentEntry.test.ts @@ -5,7 +5,7 @@ import { CMS_MODEL_SINGLETON_TAG } from "~/constants"; describe("singleton model content entries", () => { const plugins = createPluginFromCmsModel({ - ...getCmsModel("category"), + ...getCmsModel("categorySingleton"), tags: [CMS_MODEL_SINGLETON_TAG] }); diff --git a/packages/api-headless-cms/__tests__/testHelpers/useSingletonCategoryHandler.ts b/packages/api-headless-cms/__tests__/testHelpers/useSingletonCategoryHandler.ts index b0a1465d905..af5b5dc5cb2 100644 --- a/packages/api-headless-cms/__tests__/testHelpers/useSingletonCategoryHandler.ts +++ b/packages/api-headless-cms/__tests__/testHelpers/useSingletonCategoryHandler.ts @@ -66,7 +66,7 @@ const updateCategoryMutation = (model: CmsModel) => { }; export const useSingletonCategoryHandler = (params: GraphQLHandlerParams) => { - const model = getCmsModel("category"); + const model = getCmsModel("categorySingleton"); const contentHandler = useGraphQLHandler(params); return { diff --git a/packages/api-headless-cms/src/graphql/schema/createSingularResolvers.ts b/packages/api-headless-cms/src/graphql/schema/createSingularResolvers.ts index 4985f2d790d..c1327e8d742 100644 --- a/packages/api-headless-cms/src/graphql/schema/createSingularResolvers.ts +++ b/packages/api-headless-cms/src/graphql/schema/createSingularResolvers.ts @@ -31,7 +31,7 @@ export const createSingularResolvers: CreateSingularResolvers = ({ } const createFieldResolvers = createFieldResolversFactory({ - endpointType: "manage", + endpointType: type, models, model, fieldTypePlugins diff --git a/packages/api-headless-cms/src/graphql/schema/createSingularSDL.ts b/packages/api-headless-cms/src/graphql/schema/createSingularSDL.ts index f0728b0a5b0..55f1e183c86 100644 --- a/packages/api-headless-cms/src/graphql/schema/createSingularSDL.ts +++ b/packages/api-headless-cms/src/graphql/schema/createSingularSDL.ts @@ -34,7 +34,7 @@ export const createSingularSDL: CreateSingularSDL = ({ models, model, fields: model.fields, - type: "manage", + type, fieldTypePlugins }); diff --git a/packages/api-headless-cms/src/utils/getSchemaFromFieldPlugins.ts b/packages/api-headless-cms/src/utils/getSchemaFromFieldPlugins.ts index 14cb1f7aaea..09d2d224d68 100644 --- a/packages/api-headless-cms/src/utils/getSchemaFromFieldPlugins.ts +++ b/packages/api-headless-cms/src/utils/getSchemaFromFieldPlugins.ts @@ -34,13 +34,15 @@ interface Params { export const createGraphQLSchemaPluginFromFieldPlugins = (params: Params) => { const { models, fieldTypePlugins, type, createPlugin = defaultCreatePlugin } = params; + const apiType = TYPE_MAP[type]; + const plugins: ICmsGraphQLSchemaPlugin[] = []; for (const key in fieldTypePlugins) { const fieldTypePlugin = fieldTypePlugins[key]; - if (!TYPE_MAP[type] || !fieldTypePlugin[TYPE_MAP[type]]) { + if (!apiType || !fieldTypePlugin[apiType]) { continue; } - const createSchema = fieldTypePlugin[TYPE_MAP[type]].createSchema; + const createSchema = fieldTypePlugin[apiType].createSchema; // Render gql types generated by field type plugins if (!createSchema) { continue; From c35c61aa7379631e2e45c21a11c985b6de65a414 Mon Sep 17 00:00:00 2001 From: Pavel Denisjuk Date: Thu, 26 Sep 2024 13:34:31 +0200 Subject: [PATCH 2/6] fix(app-headless-cms): add missing contexts to singleton entry form (#4298) --- packages/app-aco/src/contexts/app.tsx | 4 +- .../components/NewReferencedEntryDialog.tsx | 51 +++++++++++++++---- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/packages/app-aco/src/contexts/app.tsx b/packages/app-aco/src/contexts/app.tsx index 43843ab4cb2..e3afcbbb39f 100644 --- a/packages/app-aco/src/contexts/app.tsx +++ b/packages/app-aco/src/contexts/app.tsx @@ -60,7 +60,7 @@ interface CreateAppParams { getFields?: () => AcoModelField[]; } -const createApp = (data: CreateAppParams): AcoApp => { +export const createAppFromModel = (data: CreateAppParams): AcoApp => { return { ...data, getFields: @@ -138,7 +138,7 @@ export const AcoAppProvider = ({ ...prev, loading: false, model: inputModel, - app: createApp({ + app: createAppFromModel({ id, model: inputModel, getFields diff --git a/packages/app-headless-cms/src/admin/plugins/fieldRenderers/ref/components/NewReferencedEntryDialog.tsx b/packages/app-headless-cms/src/admin/plugins/fieldRenderers/ref/components/NewReferencedEntryDialog.tsx index 8440f8bd78e..113d99f4911 100644 --- a/packages/app-headless-cms/src/admin/plugins/fieldRenderers/ref/components/NewReferencedEntryDialog.tsx +++ b/packages/app-headless-cms/src/admin/plugins/fieldRenderers/ref/components/NewReferencedEntryDialog.tsx @@ -17,12 +17,19 @@ import { import { useCms } from "~/admin/hooks"; import { FullWidthDialog } from "./dialog/Dialog"; import { NavigateFolderProvider as AbstractNavigateFolderProvider } from "@webiny/app-aco/contexts/navigateFolder"; +import { SearchRecordsProvider } from "@webiny/app-aco/contexts/records"; import { FolderTree, useNavigateFolder } from "@webiny/app-aco"; import styled from "@emotion/styled"; import { Elevation } from "@webiny/ui/Elevation"; import { SplitView, LeftPanel, RightPanel } from "@webiny/app-admin/components/SplitView"; import { CircularProgress } from "@webiny/ui/Progress"; import { usePersistEntry } from "~/admin/hooks/usePersistEntry"; +import { + AcoAppContext, + AcoAppProviderContext, + createAppFromModel +} from "@webiny/app-aco/contexts/app"; +import { DialogsProvider } from "@webiny/app-admin"; const t = i18n.ns("app-headless-cms/admin/fields/ref"); @@ -159,22 +166,46 @@ export const NewReferencedEntryDialog = ({ }, [onChange, model] ); + if (!model) { return null; } + const acoAppContext: AcoAppProviderContext = { + app: createAppFromModel({ + model, + id: `cms:${model.modelId}` + }), + mode: "cms", + client: apolloClient, + model, + folderIdPath: "wbyAco_location.folderId", + folderIdInPath: "wbyAco_location.folderId_in", + loading: false + }; + return ( - - - - - + + + + + + + + + + + - + ); }; From 1d2077734249f6c12c76b5b1ae3611eec1505f13 Mon Sep 17 00:00:00 2001 From: Pavel Denisjuk Date: Thu, 26 Sep 2024 13:34:53 +0200 Subject: [PATCH 3/6] fix(ui): make dropdown fill the available space (#4297) --- packages/ui/src/Select/styled.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/Select/styled.tsx b/packages/ui/src/Select/styled.tsx index d24690790b8..787574e6a31 100644 --- a/packages/ui/src/Select/styled.tsx +++ b/packages/ui/src/Select/styled.tsx @@ -8,7 +8,7 @@ export const webinySelect = css` background-color: transparent; border-color: transparent; color: var(--webiny-theme-color-primary); - min-width: 200px; + width: 100%; .rmwc-select__native-control { opacity: 0; From 7a1603edf3ce733e19c234a78c702afdff90e84e Mon Sep 17 00:00:00 2001 From: adrians5j Date: Thu, 26 Sep 2024 10:36:49 +0200 Subject: [PATCH 4/6] fix: remove `data-on-enter` part of the condition (not used anywhere) Searched the whole codebase for usages of `data-on-enter` and didn't find any. This was also causing the cmd+enter not to submit the form correctly in case it was pressed before the value was stored in the form state (delayed on change). --- packages/ui/src/DelayedOnChange/DelayedOnChange.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/DelayedOnChange/DelayedOnChange.ts b/packages/ui/src/DelayedOnChange/DelayedOnChange.ts index 03656b476f1..636ebbf20d5 100644 --- a/packages/ui/src/DelayedOnChange/DelayedOnChange.ts +++ b/packages/ui/src/DelayedOnChange/DelayedOnChange.ts @@ -8,6 +8,7 @@ const emptyFunction = (): undefined => { export interface ApplyValueCb { (value: TValue): void; } + /** * This component is used to wrap Input and Textarea components to optimize form re-render. * These 2 are the only components that trigger form model change on each character input. @@ -145,7 +146,7 @@ export const DelayedOnChange = ({ if (ev.key === "Tab") { applyValue((ev.target as HTMLInputElement).value as any as TValue); realOnKeyDown(ev); - } else if (ev.key === "Enter" && props["data-on-enter"]) { + } else if (ev.key === "Enter") { applyValue((ev.target as HTMLInputElement).value as any as TValue); realOnKeyDown(ev); } else { From d2c074f24c3ca00c1084e8113a8edeb0165bb936 Mon Sep 17 00:00:00 2001 From: adrians5j Date: Thu, 26 Sep 2024 10:39:35 +0200 Subject: [PATCH 5/6] fix: remove `console.log` call --- .../admin/views/contentModels/NewContentModelDialog.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/app-headless-cms/src/admin/views/contentModels/NewContentModelDialog.tsx b/packages/app-headless-cms/src/admin/views/contentModels/NewContentModelDialog.tsx index 66ad6fecb33..83ded9896be 100644 --- a/packages/app-headless-cms/src/admin/views/contentModels/NewContentModelDialog.tsx +++ b/packages/app-headless-cms/src/admin/views/contentModels/NewContentModelDialog.tsx @@ -288,12 +288,7 @@ const NewContentModelDialog = ({ open, onClose }: NewContentModelDialogProps) => - { - console.log("submitting click", data); - submit(ev); - }} - > + + {t`Create Model`} From 5f712dd44899cb3632ea0f671812ee7378bca205 Mon Sep 17 00:00:00 2001 From: adrians5j Date: Thu, 26 Sep 2024 13:27:43 +0200 Subject: [PATCH 6/6] fix: remove `console.log` call --- .../admin/views/contentModels/NewContentModelDialog.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/app-headless-cms/src/admin/views/contentModels/NewContentModelDialog.tsx b/packages/app-headless-cms/src/admin/views/contentModels/NewContentModelDialog.tsx index 83ded9896be..f9a780911c5 100644 --- a/packages/app-headless-cms/src/admin/views/contentModels/NewContentModelDialog.tsx +++ b/packages/app-headless-cms/src/admin/views/contentModels/NewContentModelDialog.tsx @@ -164,13 +164,7 @@ const NewContentModelDialog = ({ open, onClose }: NewContentModelDialogProps) => return ( {open && ( - - data={{ group, singleton: false }} - onSubmit={data => { - console.log("submitting", data); - onSubmit(data); - }} - > + data={{ group, singleton: false }} onSubmit={onSubmit}> {({ Bind, submit, data }) => { return ( <>