diff --git a/.adiorc.js b/.adiorc.js index 3b4052f9737..212f20cf113 100644 --- a/.adiorc.js +++ b/.adiorc.js @@ -34,6 +34,8 @@ module.exports = { "fs", "http", "https", + "inspector", + "node:fs", "os", "path", "readline", diff --git a/package.json b/package.json index e1f962e879e..acc4a0e5aca 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@commitlint/cli": "^11.0.0", "@commitlint/config-conventional": "^11.0.0", "@octokit/rest": "^20.0.2", - "@types/fs-extra": "^8.0.1", + "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.11", "@types/node": "^18.0.0", "@types/prettier": "^2.7.3", @@ -63,7 +63,7 @@ "eslint-plugin-standard": "^5.0.0", "execa": "^5.1.1", "folder-hash": "^4.0.0", - "fs-extra": "^7.0.0", + "fs-extra": "^11.2.0", "get-stream": "^3.0.0", "get-yarn-workspaces": "^1.0.2", "git-cz": "^1.7.1", diff --git a/packages/api-form-builder/package.json b/packages/api-form-builder/package.json index c683e2a4c15..8ea8e4b6d78 100644 --- a/packages/api-form-builder/package.json +++ b/packages/api-form-builder/package.json @@ -54,7 +54,7 @@ "@webiny/cli": "0.0.0", "@webiny/project-utils": "0.0.0", "csvtojson": "^2.0.10", - "fs-extra": "^9.1.0", + "fs-extra": "^11.2.0", "jest": "^29.7.0", "jest-dynalite": "^3.2.0", "rimraf": "^5.0.5", diff --git a/packages/api-headless-cms-ddb-es/__tests__/plugins/dynamoDb/storage/plugins.ts b/packages/api-headless-cms-ddb-es/__tests__/plugins/dynamoDb/storage/plugins.ts index d60d59335a4..9529bb0c541 100644 --- a/packages/api-headless-cms-ddb-es/__tests__/plugins/dynamoDb/storage/plugins.ts +++ b/packages/api-headless-cms-ddb-es/__tests__/plugins/dynamoDb/storage/plugins.ts @@ -4,7 +4,6 @@ import { createLongTextStorageTransformPlugin } from "~/dynamoDb/storage/longTex import { createRichTextStorageTransformPlugin } from "~/dynamoDb/storage/richText"; import { createDefaultStorageTransform } from "@webiny/api-headless-cms/storage/default"; import { createObjectStorageTransform } from "@webiny/api-headless-cms/storage/object"; -import { createDynamicZoneStorageTransform } from "@webiny/api-headless-cms/graphqlFields/dynamicZone/dynamicZoneStorage"; export const createStoragePluginsContainer = () => { return new PluginsContainer([ @@ -12,7 +11,6 @@ export const createStoragePluginsContainer = () => { createObjectStorageTransform(), createDateStorageTransformPlugin(), createLongTextStorageTransformPlugin(), - createRichTextStorageTransformPlugin(), - createDynamicZoneStorageTransform() + createRichTextStorageTransformPlugin() ]); }; diff --git a/packages/api-headless-cms-ddb/__tests__/plugins/dynamoDb/storage/plugins.ts b/packages/api-headless-cms-ddb/__tests__/plugins/dynamoDb/storage/plugins.ts index d60d59335a4..9529bb0c541 100644 --- a/packages/api-headless-cms-ddb/__tests__/plugins/dynamoDb/storage/plugins.ts +++ b/packages/api-headless-cms-ddb/__tests__/plugins/dynamoDb/storage/plugins.ts @@ -4,7 +4,6 @@ import { createLongTextStorageTransformPlugin } from "~/dynamoDb/storage/longTex import { createRichTextStorageTransformPlugin } from "~/dynamoDb/storage/richText"; import { createDefaultStorageTransform } from "@webiny/api-headless-cms/storage/default"; import { createObjectStorageTransform } from "@webiny/api-headless-cms/storage/object"; -import { createDynamicZoneStorageTransform } from "@webiny/api-headless-cms/graphqlFields/dynamicZone/dynamicZoneStorage"; export const createStoragePluginsContainer = () => { return new PluginsContainer([ @@ -12,7 +11,6 @@ export const createStoragePluginsContainer = () => { createObjectStorageTransform(), createDateStorageTransformPlugin(), createLongTextStorageTransformPlugin(), - createRichTextStorageTransformPlugin(), - createDynamicZoneStorageTransform() + createRichTextStorageTransformPlugin() ]); }; diff --git a/packages/api-headless-cms/__tests__/contentAPI/contentModel.crud.test.ts b/packages/api-headless-cms/__tests__/contentAPI/contentModel.crud.test.ts index 6e836399c79..919a4151845 100644 --- a/packages/api-headless-cms/__tests__/contentAPI/contentModel.crud.test.ts +++ b/packages/api-headless-cms/__tests__/contentAPI/contentModel.crud.test.ts @@ -602,7 +602,7 @@ describe("content model test", () => { }); }); - test("error when assigning titleFieldId on non existing field", async () => { + test("when assigning `titleFieldId` to a non-existing field, fall back to the first applicable field", async () => { const { createContentModelMutation, updateContentModelMutation } = useGraphQLHandler(manageHandlerOpts); const [createResponse] = await createContentModelMutation({ @@ -649,15 +649,10 @@ describe("content model test", () => { expect(response).toMatchObject({ data: { updateContentModel: { - data: null, - error: { - code: "VALIDATION_ERROR", - message: `Field selected for the title field does not exist in the model.`, - data: { - fieldId: "nonExistingTitleFieldId", - fields: expect.any(Array) - } - } + data: { + titleFieldId: "field1" + }, + error: null } } }); diff --git a/packages/api-headless-cms/__tests__/contentAPI/dynamicZoneField.test.ts b/packages/api-headless-cms/__tests__/contentAPI/dynamicZoneField.test.ts index ece1d61fba4..8d021058cd8 100644 --- a/packages/api-headless-cms/__tests__/contentAPI/dynamicZoneField.test.ts +++ b/packages/api-headless-cms/__tests__/contentAPI/dynamicZoneField.test.ts @@ -4,6 +4,8 @@ import { usePageManageHandler } from "../testHelpers/usePageManageHandler"; import { usePageReadHandler } from "../testHelpers/usePageReadHandler"; import { useAuthorManageHandler } from "~tests/testHelpers/useAuthorManageHandler"; import { CmsModel } from "~tests/types"; +import { ContextPlugin } from "@webiny/api"; +import { CmsContext, CmsEntry } from "~/types"; const singularPageApiName = pageModel.singularApiName; @@ -266,11 +268,45 @@ const setupAuthor = async ({ manager }: SetupAuthorParams) => { return authorPublishResponse.data.publishAuthor.data; }; +type Values = { + content: Array<{ _templateId: string }>; +}; + describe("dynamicZone field", () => { const manageOpts = { path: "manage/en-US" }; const previewOpts = { path: "preview/en-US" }; - const manage = usePageManageHandler(manageOpts); + const eventEntryContent: { + beforeCreate: CmsEntry | undefined; + afterCreate: CmsEntry | undefined; + beforeUpdate: CmsEntry | undefined; + afterUpdate: CmsEntry | undefined; + } = { + beforeCreate: undefined, + afterCreate: undefined, + beforeUpdate: undefined, + afterUpdate: undefined + }; + + const lifecycleEvents = new ContextPlugin(async (context: CmsContext) => { + if (!context.cms) { + throw new Error("Missing cms on context."); + } + context.cms.onEntryBeforeCreate.subscribe(async params => { + eventEntryContent.beforeCreate = structuredClone(params.entry) as CmsEntry; + }); + context.cms.onEntryAfterCreate.subscribe(async params => { + eventEntryContent.afterCreate = structuredClone(params.entry) as CmsEntry; + }); + context.cms.onEntryBeforeUpdate.subscribe(async params => { + eventEntryContent.beforeUpdate = structuredClone(params.entry) as CmsEntry; + }); + context.cms.onEntryAfterUpdate.subscribe(async params => { + eventEntryContent.afterUpdate = structuredClone(params.entry) as CmsEntry; + }); + }); + + const manage = usePageManageHandler({ ...manageOpts, bottomPlugins: [lifecycleEvents] }); const authorManager = useAuthorManageHandler({ ...manageOpts @@ -443,5 +479,12 @@ describe("dynamicZone field", () => { } } }); + + const tplIsConverted = (tpl: T) => "_templateId" in tpl; + + expect(eventEntryContent.beforeCreate?.values.content.every(tplIsConverted)).toEqual(true); + expect(eventEntryContent.afterCreate?.values.content.every(tplIsConverted)).toEqual(true); + expect(eventEntryContent.beforeUpdate?.values.content.every(tplIsConverted)).toEqual(true); + expect(eventEntryContent.afterUpdate?.values.content.every(tplIsConverted)).toEqual(true); }); }); diff --git a/packages/api-headless-cms/__tests__/contentAPI/multipleValues.test.ts b/packages/api-headless-cms/__tests__/contentAPI/multipleValues.test.ts index 939690de3d0..3a9234ea968 100644 --- a/packages/api-headless-cms/__tests__/contentAPI/multipleValues.test.ts +++ b/packages/api-headless-cms/__tests__/contentAPI/multipleValues.test.ts @@ -135,20 +135,13 @@ describe("multiple values in field", () => { } }); - expect(response).toEqual({ + expect(response).toMatchObject({ data: { updateContentModel: { - data: null, - error: { - code: "ENTRY_TITLE_FIELD_TYPE", - message: - "Fields that accept multiple values cannot be used as the entry title.", - data: { - storageId: expect.stringMatching("text@"), - fieldId: "availableSizes", - type: "text" - } - } + data: { + titleFieldId: "title" + }, + error: null } } }); diff --git a/packages/api-headless-cms/__tests__/contentAPI/predefinedValues.test.ts b/packages/api-headless-cms/__tests__/contentAPI/predefinedValues.test.ts index dbc18751959..226a524c110 100644 --- a/packages/api-headless-cms/__tests__/contentAPI/predefinedValues.test.ts +++ b/packages/api-headless-cms/__tests__/contentAPI/predefinedValues.test.ts @@ -26,7 +26,7 @@ describe("predefined values", () => { const setupBugModel = async ( contentModelGroup: CmsGroup, - overrides: Record = {} + overrides: (model: CmsModel) => Partial = () => ({}) ): Promise => { const model = models.find(m => m.modelId === "bug"); if (!model) { @@ -53,7 +53,7 @@ describe("predefined values", () => { data: { fields: model.fields, layout: model.layout, - ...overrides + ...(overrides ? overrides(model) : {}) } }); return update.data.updateContentModel.data; @@ -61,7 +61,7 @@ describe("predefined values", () => { test("should create an entry with predefined values selected", async () => { const contentModelGroup = await setupContentModelGroup(); - await setupBugModel(contentModelGroup, {}); + await setupBugModel(contentModelGroup); const { createBug } = useBugManageHandler({ ...manageOpts @@ -111,7 +111,7 @@ describe("predefined values", () => { test("should fail creating an entry with wrong predefined text value selected", async () => { const contentModelGroup = await setupContentModelGroup(); - await setupBugModel(contentModelGroup, {}); + await setupBugModel(contentModelGroup); const { createBug } = useBugManageHandler({ ...manageOpts @@ -150,7 +150,7 @@ describe("predefined values", () => { test("should fail creating an entry with wrong predefined number value selected", async () => { const contentModelGroup = await setupContentModelGroup(); - await setupBugModel(contentModelGroup, {}); + await setupBugModel(contentModelGroup); const { createBug } = useBugManageHandler({ ...manageOpts @@ -189,7 +189,7 @@ describe("predefined values", () => { test("should fail creating an entry with wrong predefined number and text values selected", async () => { const contentModelGroup = await setupContentModelGroup(); - await setupBugModel(contentModelGroup, {}); + await setupBugModel(contentModelGroup); const { createBug } = useBugManageHandler({ ...manageOpts @@ -233,115 +233,11 @@ describe("predefined values", () => { }); }); - test("title should be a selected predefined text value label", async () => { - const contentModelGroup = await setupContentModelGroup(); - await setupBugModel(contentModelGroup, { - titleFieldId: "bugType" - }); - - const { createBug } = useBugManageHandler({ - ...manageOpts - }); - - const [response] = await createBug({ - data: { - name: "A hard debuggable bug", - bugType: "critical", - bugValue: 2, - bugFixed: 3 - } - }); - - expect(response).toEqual({ - data: { - createBug: { - data: { - id: expect.any(String), - createdOn: expect.stringMatching(/^20/), - modifiedOn: null, - savedOn: expect.stringMatching(/^20/), - createdBy: { - id: "id-12345678", - displayName: "John Doe", - type: "admin" - }, - lastPublishedOn: null, - firstPublishedOn: null, - meta: { - locked: false, - modelId: "bug", - status: "draft", - title: "Critical bug!", - version: 1 - }, - name: "A hard debuggable bug", - bugType: "critical", - bugValue: 2, - bugFixed: 3 - }, - error: null - } - } - }); - }); - - test("title should be a selected predefined number value label", async () => { - const contentModelGroup = await setupContentModelGroup(); - await setupBugModel(contentModelGroup, { - titleFieldId: "bugValue" - }); - - const { createBug } = useBugManageHandler({ - ...manageOpts - }); - - const [response] = await createBug({ - data: { - name: "A hard debuggable bug", - bugType: "critical", - bugValue: 3, - bugFixed: 3 - } - }); - - expect(response).toEqual({ - data: { - createBug: { - data: { - id: expect.any(String), - createdOn: expect.stringMatching(/^20/), - modifiedOn: null, - savedOn: expect.stringMatching(/^20/), - createdBy: { - id: "id-12345678", - displayName: "John Doe", - type: "admin" - }, - lastPublishedOn: null, - firstPublishedOn: null, - meta: { - locked: false, - modelId: "bug", - status: "draft", - title: "High bug value", - version: 1 - }, - name: "A hard debuggable bug", - bugType: "critical", - bugValue: 3, - bugFixed: 3 - }, - error: null - } - } - }); - }); - it("should be able to create an entry with default bug type value", async () => { const contentModelGroup = await setupContentModelGroup(); - const bugModel = await setupBugModel(contentModelGroup, { + const bugModel = await setupBugModel(contentModelGroup, () => ({ titleFieldId: "bugValue" - }); + })); const { createBug } = useBugManageHandler({ ...manageOpts @@ -377,7 +273,7 @@ describe("predefined values", () => { locked: false, modelId: "bug", status: "draft", - title: "High bug value", + title: "A hard debuggable bug - none", version: 1 }, name: "A hard debuggable bug - none", @@ -456,7 +352,7 @@ describe("predefined values", () => { locked: false, modelId: "bug", status: "draft", - title: "High bug value", + title: "A hard debuggable bug - undefined", version: 1 }, name: "A hard debuggable bug - undefined", diff --git a/packages/api-headless-cms/__tests__/contentTraverser/mocks/article.entry.ts b/packages/api-headless-cms/__tests__/contentTraverser/mocks/article.entry.ts deleted file mode 100644 index 928fca58cf1..00000000000 --- a/packages/api-headless-cms/__tests__/contentTraverser/mocks/article.entry.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { richTextValue } from "./richTextValue"; - -export const articleEntry = { - title: "Article #1", - body: richTextValue, - categories: [{ modelId: "category", entryId: "12345678" }], - content: [ - { - title: "Hero #1", - _templateId: "cv2zf965v324ivdc7e1vt" - }, - { - _templateId: "9ht43gurhegkbdfsaafyads", - settings: { - title: "Title", - seo: [ - { - title: "title-0" - }, - { - title: "title-1" - } - ] - } - } - ] -}; diff --git a/packages/api-headless-cms/__tests__/contentTraverser/mocks/page.entry.ts b/packages/api-headless-cms/__tests__/contentTraverser/mocks/page.entry.ts new file mode 100644 index 00000000000..dd1a5ff992d --- /dev/null +++ b/packages/api-headless-cms/__tests__/contentTraverser/mocks/page.entry.ts @@ -0,0 +1,313 @@ +export const pageEntry = { + modelId: "page", + revisionCreatedOn: "2024-06-27T12:45:56.795Z", + status: "draft", + meta: {}, + revisionCreatedBy: { + type: "admin", + displayName: "John Doe", + id: "667d2515df36ec000a8c8072" + }, + revisionModifiedBy: { + type: "admin", + displayName: "John Doe", + id: "667d2515df36ec000a8c8072" + }, + createdBy: { + type: "admin", + displayName: "John Doe", + id: "667d2515df36ec000a8c8072" + }, + entryId: "667d5f049718b800089a41f8", + id: "667d5f049718b800089a41f8#0001", + savedBy: { + type: "admin", + displayName: "John Doe", + id: "667d2515df36ec000a8c8072" + }, + version: 1, + location: { + folderId: "667d2ca4fcae6a000ac38af5#0001" + }, + revisionSavedOn: "2024-07-05T09:18:51.860Z", + locale: "en-US", + savedOn: "2024-07-05T09:18:51.860Z", + values: { + pageTitle: "From the Playground", + pageType: "BasicPageTemplate", + pageSettings: { + generalPageSettings: { + pageSlug: "from-the-playground", + deliveryDomain: "acme.com", + layout: "dark", + pageClass: null, + pageCategory: null, + redirectUrl: null, + browserTabTitle: "John was here", + description: "the description", + customCanonicalUrl: null, + contentOwner: "ulf@acme.com", + organisation: "acme", + navTitle: null, + hideInNavigation: false, + hideInBreadcrumb: false, + noFollow: "inherited", + noIndex: "inherited", + publishTime: null, + unPublishTime: null, + headerContactLink: null, + copyRightText: null, + inheritFooterLinks: null, + footerLinkList: [], + inheritSocialMediaLinks: null, + socialMediaLinkList: [], + uuid: "acme:Ma3wHp4Vb1n" + }, + pageTeaserSettings: { + pageTeaserMedia: { + file: null, + altText: null, + seoName: null, + crop: null + }, + pageTeaserTitle: null, + pageTeaserText: "", + pageTeaserSocialMediaTitle: null, + pageTeaserSocialMediaText: "", + pageTeaserFakePublishDate: null, + pageTeaserExpiryDate: null, + pageTeaserFilterTags: null, + pageTeaserVisualTag1: null, + pageTeaserVisualTag2: null, + pageTeaserEventLocation: null, + pageTeaserEventStartDate: null, + pageTeaserEventEndDate: null + } + }, + pageTemplate: { + _templateId: "basicPageTemplate", + introZone: [ + { + _templateId: "stageTemplate", + layout: "imageLeft", + title: { + title: "my playground", + headingRank: null + }, + stageText: { + root: { + format: null, + type: "root", + children: [ + { + children: [ + { + mode: "normal", + format: 0, + style: null, + detail: 0, + text: "Hello Here is some text", + type: "text", + version: 1 + } + ], + indent: 0, + format: null, + styles: [ + { + type: "typography", + styleId: "paragraph1" + } + ], + type: "paragraph-element", + version: 1, + direction: "ltr" + } + ], + indent: 0, + version: 1, + direction: "ltr" + } + }, + button: { + buttonText: "Click me", + linkpicker: "https://www.acme.com" + }, + stageMedia: { + file: "https://acme.com/assets/api/uuid:52e1aa7b-9f0d-4437-80e8-910e7a34e2b6/width:1036/image_small.jpeg", + altText: "Heat map of the world", + seoName: "seo name", + crop: "0.1248:0:0.7503:1" + }, + uuid: "acme:playGroundXYZ" + } + ], + mainZone: [ + { + _templateId: "quoteTemplate", + title: { + title: "my Quote", + headingRank: null + }, + layout: "imageRight", + focusOn: "image", + quoteMedia: { + file: "https://acme.com/assets/api/uuid:4ae336d1-19c3-4ac4-b755-0cc25644eac4/no-text_original.png", + altText: "alt", + seoName: "seo-name" + }, + quoteText: "so what", + quoteSource: "John", + uuid: "acme:098MyQuote77" + }, + { + _templateId: "mediaRichtextTemplate", + layout: "imageRight", + uuid: "acme:ttJcRRPR0JP", + title: { + title: "my MRT", + headingRank: "h3" + }, + subtitle: "The MRT subtitle", + text: { + root: { + format: null, + type: "root", + children: [ + { + children: [ + { + mode: "normal", + format: 0, + style: null, + detail: 0, + text: "some nice words", + type: "text", + version: 1 + } + ], + indent: 0, + format: null, + styles: [ + { + type: "typography", + styleId: "paragraph1" + } + ], + type: "paragraph-element", + version: 1, + direction: "ltr" + } + ], + indent: 0, + version: 1, + direction: "ltr" + } + }, + mrtMedia: [ + { + file: "https://acme.com/assets/api/uuid:4ae336d1-19c3-4ac4-b755-0cc25644eac4/sf-no-text_original.png", + altText: "alternative text", + seoName: "seo-optimized-name", + caption: "Hä? ", + captionLink: "caption Link " + }, + { + file: "https://acme.com/assets/api/uuid:b3bddd2b-553a-483a-8bc1-20f02471ed1e/vegas-toureiffel_original.mp4", + altText: null, + seoName: null, + caption: null, + captionLink: null + } + ], + button: { + buttonText: "Click me", + linkpicker: "https://www.acme.com" + }, + linklist: [ + { + text: "my first link ", + linkpicker: "http://www.domain.com" + } + ] + }, + { + _templateId: "contentTeaserRowTemplate", + layout: null, + title: { + title: "CTR title", + headingRank: null + }, + contentTeaserRowCards: [ + { + _templateId: "contentTeaserRowCardTemplate", + contentTeaserRowMediaMedia: { + file: "https://acme.com/assets/api/uuid:fca831bb-373a-4b2c-91d3-c3284f16b613/width:1036/image_small.png", + altText: "asd", + seoName: "wdfb" + }, + title: { + title: "inner teaser title", + headingRank: "h3" + }, + text: { + root: { + format: null, + type: "root", + children: [ + { + children: [ + { + mode: "normal", + format: 0, + style: null, + detail: 0, + text: "with som etext ", + type: "text", + version: 1 + } + ], + indent: 0, + format: null, + styles: [ + { + type: "typography", + styleId: "paragraph1" + } + ], + type: "paragraph-element", + version: 1, + direction: "ltr" + } + ], + indent: 0, + version: 1, + direction: "ltr" + } + }, + linklist: [], + uuid: "acme:hmAHkQsvr5q" + } + ], + uuid: "acme:LyEFKwkutww" + } + ] + } + }, + revisionSavedBy: { + type: "admin", + displayName: "John Doe", + id: "667d2515df36ec000a8c8072" + }, + tenant: "root", + revisionModifiedOn: "2024-07-05T09:18:51.860Z", + createdOn: "2024-06-27T12:45:56.795Z", + modifiedOn: "2024-07-05T09:18:51.860Z", + locked: false, + webinyVersion: "5.40.0", + modifiedBy: { + type: "admin", + displayName: "John Doe", + id: "667d2515df36ec000a8c8072" + } +}; diff --git a/packages/api-headless-cms/__tests__/contentTraverser/mocks/page.model.ts b/packages/api-headless-cms/__tests__/contentTraverser/mocks/page.model.ts new file mode 100644 index 00000000000..341f7e75b78 --- /dev/null +++ b/packages/api-headless-cms/__tests__/contentTraverser/mocks/page.model.ts @@ -0,0 +1,6108 @@ +import { createPrivateModel } from "~/plugins"; + +export const pageModel = createPrivateModel({ + modelId: "page", + name: "Page", + titleFieldId: "pageTitle", + tags: ["type:model"], + fields: [ + { + id: "pageTitle", + fieldId: "pageTitle", + type: "text", + label: "Page Title", + helpText: "Title of the page", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "required", + message: "Please insert a page title." + }, + { + name: "maxLength", + message: "Max length is 255.", + settings: { + value: 255 + } + } + ], + storageId: "text@pageTitle" + }, + { + id: "pageType", + fieldId: "pageType", + type: "text", + label: "Page Type", + helpText: "Type of the page", + renderer: { + name: "disabled-text-input" + }, + storageId: "text@pageType" + }, + { + id: "pageSettings", + fieldId: "pageSettings", + multipleValues: false, + type: "object", + label: "Page Settings", + renderer: { + name: "page-settings-object" + }, + settings: { + fields: [ + { + id: "generalPageSettings", + fieldId: "generalPageSettings", + multipleValues: false, + type: "object", + label: "General", + renderer: { + name: "general-page-settings-object" + }, + settings: { + fields: [ + { + id: "pageSlug", + fieldId: "pageSlug", + type: "text", + label: "Slug*", + helpText: + "Live name of this page. The field only allows latin lower-case letters, numbers, dashes. It must not be duplicating currently existing URL in the same folder. ", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "required", + settings: {}, + message: "Value is required." + }, + { + name: "pattern", + settings: { + preset: "custom", + regex: "^[a-z0-9-]+$" + }, + message: + "Only latin letters, numbers and dashes are allowed" + }, + { + name: "maxLength", + message: "Max length is 255.", + settings: { + value: 255 + } + } + ], + storageId: "text@pageSlug" + }, + { + id: "deliveryDomain", + fieldId: "deliveryDomain", + type: "text", + label: "Delivery Domain", + helpText: + "With inherited the page gets the domain of the parent page.If Xcelerator is selected you have to fill in defined extra mandatory properties to ensure a smooth integration into this portfolio.", + renderer: { + name: "select-box" + }, + predefinedValues: { + enabled: true, + values: [ + { + label: "Inherited", + value: "inherited", + selected: true + }, + { + label: "acme.com", + value: "acme.com" + }, + { + label: "xcelerator.acme.com", + value: "xcelerator.acme.com" + } + ] + }, + settings: { + defaultValue: "inherited" + }, + storageId: "text@deliveryDomain" + }, + { + id: "layout", + fieldId: "layout", + type: "text", + label: "Layout", + helpText: + "Employer brand design is only allowed for this campaign.", + renderer: { + name: "select-box" + }, + predefinedValues: { + enabled: true, + values: [ + { + label: "Dark", + value: "dark", + selected: true + }, + { + label: "Employer Brand", + value: "employerbrand" + } + ] + }, + settings: { + defaultValue: "dark" + }, + storageId: "text@layout" + }, + { + id: "pageClass", + fieldId: "pageClass", + type: "text", + label: "Page Class*", + placeholderText: "Please select", + renderer: { + name: "select-box" + }, + predefinedValues: { + enabled: true, + values: [ + { + label: "Inspirative", + value: "Inspirative" + }, + { + label: "Informative", + value: "Informative" + }, + { + label: "Basic", + value: "Basic" + }, + { + label: "Mandatory", + value: "Mandatory" + } + ] + }, + validation: [ + { + name: "required", + settings: {}, + message: "Value is required." + } + ], + storageId: "text@pageClass" + }, + { + id: "pageCategory", + fieldId: "pageCategory", + type: "text", + label: "Page Category*", + placeholderText: "Please select", + renderer: { + name: "select-box" + }, + predefinedValues: { + enabled: true, + values: [ + { + label: "Family page", + value: "family-page" + }, + { + label: "Detail page", + value: "detail-page" + }, + { + label: "Info page", + value: "info-page" + }, + { + label: "Event page", + value: "event-page" + }, + { + label: "Campaign page", + value: "campaign-page" + }, + { + label: "Press page", + value: "press-page" + }, + { + label: "Functional only", + value: "functional-only" + } + ] + }, + validation: [ + { + name: "required", + settings: {}, + message: "Value is required." + } + ], + storageId: "text@pageCategory" + }, + { + id: "redirectUrl", + fieldId: "redirectUrl", + type: "text", + label: "Redirect (302)", + helpText: + "If redirected you can use tags and a filled Page teaser to appear in filter results but not in search results. This redirect is defined as “temporarily” (302) to inform search engines that the URL could come back so that they try to crawl again and again. So, if the page is deleted for the current eternity, please create a 301 redirect in our Redirect tool.", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "pattern", + settings: { + preset: "custom", + regex: "^(?:https?:\\/\\/(?:\\w+\\.)+\\w+(\\/\\S*)?)|^mailto?:.+|^#.+|^(\\/\\S*)(?:\\?[^#\\s]*)?(?:#[^\\s]*)?", + flag: "i" + }, + message: "The url is invalid" + } + ], + storageId: "text@redirectUrl" + }, + { + id: "browserTabTitle", + fieldId: "browserTabTitle", + type: "text", + label: "Browser Tab Title*", + helpText: + "Defines the title of this page that is used in the browser's tab, favorite links and most importantly on search engine results pages.Max length is 60 characters - and our brand and your country name occupy some of them by default. ", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "required", + settings: {}, + message: "Value is required." + } + ], + storageId: "text@browserTabTitle" + }, + { + id: "description", + fieldId: "description", + type: "text", + label: "Description*", + helpText: + "Used as part of the search snippet in search engine results page (SERP) incl. ACME search and is meant to give the user an idea of the content that exists within the page. \nLength should be between 140…160 characters incl. spaces - this can be ignored for the non-Latin characters.", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "required", + settings: {}, + message: "Value is required." + } + ], + storageId: "text@description" + }, + { + id: "customCanonicalUrl", + fieldId: "customCanonicalUrl", + type: "text", + label: "Custom Canonical Url", + helpText: + "If not filled in, the canonical URL will be created automatically in page source code.", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "pattern", + settings: { + preset: "custom", + regex: "^(?:https?:\\/\\/(?:\\w+\\.)+\\w+(\\/\\S*)?)|^mailto?:.+|^#.+|^(\\/\\S*)(?:\\?[^#\\s]*)?(?:#[^\\s]*)?", + flag: "i" + }, + message: "The url is invalid" + } + ], + storageId: "text@customCanonicalUrl" + }, + { + id: "contentOwner", + fieldId: "contentOwner", + type: "text", + label: "Content responsible*", + helpText: + "SCD-connected email address of the employee we need to contact if there are issues with this page or content questions.", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "required", + settings: {}, + message: "Value is required." + }, + { + name: "pattern", + settings: { + preset: "custom", + regex: "^\\w[\\+\\w.-]*@acme.com$", + flags: "i" + }, + message: "Email must be a @acme-com address" + } + ], + storageId: "text@contentOwner" + }, + { + id: "organisation", + fieldId: "organisation", + type: "text", + label: "Organisation*", + helpText: + "Select the content responsible org unit for correct internal analytics data.", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "required", + settings: {}, + message: "Value is required." + } + ], + storageId: "text@organisation" + }, + { + id: "navTitle", + fieldId: "navTitle", + type: "text", + label: "Navigation and breadcrumb title", + helpText: + "Page name to be displayed in the navigation and breadcrumb. Avoid to use “ACME”, it should be clear for the user where he is.", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "maxLength", + message: "Max length is 255.", + settings: { + value: 255 + } + } + ], + storageId: "text@navTitle" + }, + { + id: "hideInNavigation", + fieldId: "hideInNavigation", + type: "boolean", + label: "Hide in navigation", + renderer: { + name: "boolean-input" + }, + settings: { + defaultValue: false + }, + storageId: "boolean@hideInNavigation" + }, + { + id: "hideInBreadcrumb", + fieldId: "hideInBreadcrumb", + type: "boolean", + label: "Hide in breadcrumb", + renderer: { + name: "boolean-input" + }, + settings: { + defaultValue: false + }, + storageId: "boolean@hideInBreadcrumb" + }, + { + id: "noFollow", + fieldId: "noFollow", + type: "text", + label: "Follow", + helpText: + "Prevents search engines to follow the links on this page. Use carefully and with competence.", + renderer: { + name: "select-box" + }, + predefinedValues: { + enabled: true, + values: [ + { + label: "Inherited", + value: "inherited", + selected: true + }, + { + label: "Follow", + value: "follow" + }, + { + label: "No Follow", + value: "no-follow" + } + ] + }, + settings: { + defaultValue: "inherited" + }, + storageId: "text@noFollow" + }, + { + id: "noIndex", + fieldId: "noIndex", + type: "text", + label: "Index", + helpText: + "Prevents search engines incl. ACME internal search from indexing this page. Do not use for silent go live.", + renderer: { + name: "select-box" + }, + predefinedValues: { + enabled: true, + values: [ + { + label: "Inherited", + value: "inherited", + selected: true + }, + { + label: "Index", + value: "index" + }, + { + label: "No Index", + value: "no-index" + } + ] + }, + settings: { + defaultValue: "inherited" + }, + storageId: "text@noIndex" + }, + { + id: "publishTime", + fieldId: "publishTime", + type: "datetime", + label: "Publish", + helpText: + "Date an time this page will be published automatically. Leave empty for normal publishing process.", + renderer: { + name: "date-time-input" + }, + settings: { + type: "dateTimeWithoutTimezone" + }, + storageId: "datetime@publishTime" + }, + { + id: "unPublishTime", + fieldId: "unPublishTime", + type: "datetime", + label: "Unpublish", + helpText: + "Date an time this page will be published automatically. Please be aware of possible 404 errors - better leave empty for normal unpublishing process.", + renderer: { + name: "date-time-input" + }, + settings: { + type: "dateTimeWithoutTimezone" + }, + storageId: "datetime@unPublishTime" + }, + { + id: "headerContactLink", + fieldId: "headerContactLink", + label: "Header contact link", + type: "text", + placeholderText: "Inherited from parent", + helpText: + "If not filled in, inherited from parent page, if filled in, it inherits to child pages.The displayed text is pulled from an i18n list.", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "pattern", + settings: { + preset: "custom", + regex: "^(?:https?:\\/\\/(?:\\w+\\.)+\\w+(\\/\\S*)?)|^mailto?:.+|^#.+|^(\\/\\S*)(?:\\?[^#\\s]*)?(?:#[^\\s]*)?", + flag: "i" + }, + message: "The url is invalid" + } + ], + storageId: "text@headerContactLink" + }, + { + id: "copyRightText", + fieldId: "copyRightText", + label: "Copyright text", + type: "text", + placeholderText: "Inherited from parent", + renderer: { + name: "text-input" + }, + storageId: "text@copyRightText" + }, + { + id: "inheritFooterLinks", + fieldId: "inheritFooterLinks", + label: "Inherit Footer links", + type: "boolean", + validation: [], + renderer: { + name: "boolean-input" + }, + settings: { + defaultValue: true + }, + predefinedValues: { + enabled: false, + values: [] + }, + storageId: "boolean@inheritFooterLinks" + }, + { + id: "footerLinkList", + fieldId: "footerLinkList", + label: "Footer Links", + type: "object", + multipleValues: true, + renderer: { + name: "objects" + }, + settings: { + fields: [ + { + type: "text", + validation: [ + { + name: "required", + message: "Value is required." + } + ], + renderer: { + name: "text-input" + }, + label: "Link Text", + helpText: + "Mandatory. For SEO avoid terms like “More” or “Click here”.", + fieldId: "footerLinkText", + id: "footerLinkText", + storageId: "text@footerLinkText" + }, + { + type: "text", + validation: [ + { + name: "required", + message: "Value is required." + }, + { + name: "pattern", + settings: { + preset: "url" + }, + message: "URL Format is required" + } + ], + renderer: { + name: "text-input" + }, + label: "Link", + helpText: + "If link target is SmartCMS internal, create link relative via to avoid 404 errors.", + fieldId: "footerLinkLink", + id: "footerLinkLink", + storageId: "text@footerLinkLink" + } + ], + layout: [["footerLinkText"], ["footerLinkLink"]] + }, + storageId: "object@footerLinkList" + }, + { + id: "inheritSocialMediaLinks", + fieldId: "inheritSocialMediaLinks", + label: "Inherit Social Media links", + type: "boolean", + validation: [], + renderer: { + name: "boolean-input" + }, + settings: { + defaultValue: true + }, + predefinedValues: { + enabled: false, + values: [] + }, + storageId: "boolean@inheritSocialMediaLinks" + }, + { + id: "socialMediaLinkList", + fieldId: "socialMediaLinkList", + label: "Social Media Links", + type: "object", + multipleValues: true, + renderer: { + name: "objects" + }, + settings: { + fields: [ + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "Link", + helpText: + "The links are inherited to all child pages up to the moment, when a child page has its own entry.", + fieldId: "socialMediaLinkLink", + id: "socialMediaLinkLink", + storageId: "text@socialMediaLinkLink" + } + ], + layout: [["socialMediaLinkLink"]] + }, + storageId: "object@socialMediaLinkList" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: "The technical ID of this element.", + fieldId: "uuid", + id: "pageUuid", + storageId: "text@pageUuid" + } + ], + layout: [ + ["pageSlug", "deliveryDomain", "layout"], + ["pageClass", "pageCategory"], + ["redirectUrl"], + ["browserTabTitle", "description"], + ["customCanonicalUrl"], + ["contentOwner", "organisation"], + ["navTitle", "hideInNavigation", "hideInBreadcrumb"], + ["noIndex", "noFollow"], + ["publishTime", "unPublishTime"], + ["headerContactLink"], + ["copyRightText"], + ["inheritFooterLinks", "footerLinkList"], + ["inheritSocialMediaLinks", "socialMediaLinkList"], + ["pageUuid"] + ] + }, + storageId: "object@generalPageSettings" + }, + { + id: "pageTeaserSettings", + fieldId: "pageTeaserSettings", + multipleValues: false, + type: "object", + label: "Page Teaser", + renderer: { + name: "page-teaser-settings-object" + }, + settings: { + fields: [ + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "asset-input" + }, + label: "Media", + fieldId: "pageTeaserMedia", + id: "pageTeaserMedia", + storageId: "object@pageTeaserMedia", + settings: { + fields: [ + { + type: "file", + multipleValues: false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: "file", + id: "pageTeaserMediaFile", + storageId: "file@pageTeaserMediaFile" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: "altText", + id: "pageTeaserMediaAltText", + storageId: "text@pageTeaserMediaAltText" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: "seoName", + id: "pageTeaserMediaSeoName", + storageId: "text@pageTeaserMediaSeoName" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: "The value used to crop this media.", + fieldId: "crop", + id: "pageTeaserMediaCrop", + storageId: "text@pageTeaserMediaCrop", + settings: { + disabled: true + } + } + ], + layout: [ + ["pageTeaserMediaFile"], + ["pageTeaserMediaAltText"], + ["pageTeaserMediaSeoName"], + ["pageTeaserMediaCrop"] + ] + } + }, + { + id: "pageTeaserTitle", + fieldId: "pageTeaserTitle", + type: "text", + label: "Teaser title on acme.com", + helpText: + "If you use more than 150 characters incl. spaces it could be that the text will be shortened by the destination page. Please avoid the word “ACME”: teasers appear only on acme.com", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "maxLength", + message: "Max length is 255.", + settings: { + value: 255 + } + } + ], + storageId: "text@pageTeaserTitle" + }, + { + id: "pageTeaserText", + fieldId: "pageTeaserText", + type: "long-text", + label: "Teaser text on acme.com", + helpText: + "If you use more than 150 characters incl. spaces it could be that the text will be shortened by the destination page.Please write in the first person: teasers appear only on acme.com.", + renderer: { + name: "long-text-text-area" + }, + storageId: "long-text@pageTeaserText" + }, + { + id: "pageTeaserSocialMediaTitle", + fieldId: "pageTeaserSocialMediaTitle", + type: "text", + label: "Teaser title for social media", + helpText: "", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "maxLength", + message: "Max length is 255.", + settings: { + value: 255 + } + } + ], + storageId: "text@pageTeaserSocialMediaTitle" + }, + { + id: "pageTeaserSocialMediaText", + fieldId: "pageTeaserSocialMediaText", + type: "long-text", + label: "Teaser text for social media", + helpText: "", + renderer: { + name: "long-text-text-area" + }, + storageId: "long-text@pageTeaserSocialMediaText" + }, + { + id: "pageTeaserFakePublishDate", + fieldId: "pageTeaserFakePublishDate", + type: "datetime", + label: "Fake publish", + helpText: + "For filter results sorting or feeding the recommendation engine with the real age of the page.The source code and sitemap.xml date, read by search engines, shows the real publish date.", + renderer: { + name: "date-time-input" + }, + settings: { + type: "dateTimeWithoutTimezone" + }, + storageId: "datetime@pageTeaserFakePublishDate" + }, + { + id: "pageTeaserExpiryDate", + fieldId: "pageTeaserExpiryDate", + type: "datetime", + label: "Expire", + helpText: + "In Filter results the teaser will not be shown if a expire date is set. The page itself is not affected.", + renderer: { + name: "date-time-input" + }, + settings: { + type: "dateTimeWithoutTimezone" + }, + storageId: "datetime@pageTeaserExpiryDate" + }, + { + id: "pageTeaserFilterTags", + fieldId: "pageTeaserFilterTags", + type: "text", + label: "Filter Tag(s)", + helpText: + "Select the tags in English. They will be translated into the browser language during delivery.", + renderer: { + name: "text-input" + }, + storageId: "text@pageTeaserFilterTags" + }, + { + id: "pageTeaserVisualTag1", + fieldId: "pageTeaserVisualTag1", + type: "text", + label: "Visual Tag 1", + helpText: + "Not for filtering, only shown in the teasers' 1st topline.", + renderer: { + name: "text-input" + }, + storageId: "text@pageTeaserVisualTag1" + }, + { + id: "pageTeaserVisualTag2", + fieldId: "pageTeaserVisualTag2", + type: "text", + label: "Visual Tag 2", + renderer: { + name: "text-input" + }, + storageId: "text@pageTeaserVisualTag2" + }, + { + id: "pageTeaserEventLocation", + fieldId: "pageTeaserEventLocation", + type: "text", + label: "Event Location", + helpText: "Please type in an event location, if needed", + renderer: { + name: "text-input" + }, + storageId: "text@pageTeaserEventLocation" + }, + { + id: "pageTeaserEventStartDate", + fieldId: "pageTeaserEventStartDate", + type: "datetime", + label: "Event start", + renderer: { + name: "date-time-input" + }, + settings: { + type: "dateTimeWithoutTimezone" + }, + storageId: "datetime@pageTeaserEventStartDate" + }, + { + id: "pageTeaserEventEndDate", + fieldId: "pageTeaserEventEndDate", + type: "datetime", + label: "Event end", + renderer: { + name: "date-time-input" + }, + settings: { + type: "dateTimeWithoutTimezone" + }, + storageId: "datetime@pageTeaserEventEndDate" + } + ], + layout: [ + ["pageTeaserMedia"], + ["pageTeaserTitle"], + ["pageTeaserText"], + ["pageTeaserSocialMediaTitle"], + ["pageTeaserSocialMediaText"], + ["pageTeaserFakePublishDate"], + ["pageTeaserExpiryDate"], + ["pageTeaserFilterTags"], + ["pageTeaserVisualTag1"], + ["pageTeaserVisualTag2"], + ["pageTeaserEventLocation"], + ["pageTeaserEventStartDate"], + ["pageTeaserEventEndDate"] + ] + }, + storageId: "object@pageTeaserSettings" + } + ], + layout: [["generalPageSettings"], ["pageTeaserSettings"]] + }, + storageId: "object@pageSettings" + }, + { + id: "pageTemplate", + fieldId: "pageTemplate", + type: "dynamicZone", + label: "Page Template", + multipleValues: false, + renderer: { + name: "dynamicZone" + }, + settings: { + templates: [ + { + validation: [], + name: "Basic Page", + gqlTypeName: "BasicPageTemplate", + icon: "fas/home", + description: "Basic Page", + id: "basicPageTemplate", + fields: [ + { + id: "introZone", + fieldId: "introZone", + label: "Introduction Zone", + type: "dynamicZone", + multipleValues: true, + renderer: { + name: "dynamicZone" + }, + settings: { + templates: [ + { + name: "Stage", + gqlTypeName: "Stage", + icon: "fas/masks-theater", + description: + "1st element of every page, delivers a H1 and a short intro text.", + id: "stageTemplate", + validation: [], + fields: [ + { + type: "text", + validation: [], + renderer: { + name: "select-box" + }, + helpText: + "If used outside of Intro section the headline will be delivered as H2.", + label: "Layout", + predefinedValues: { + enabled: true, + values: [ + { + label: "Text only", + value: "textOnly" + }, + { + label: "Text with media left", + value: "imageLeft" + }, + { + label: "Text with media right", + value: "imageRight", + selected: true + }, + { + label: "Panorama", + value: "panoramaImage" + }, + { + label: "Full screen with background image", + value: "backgroundImageVideo" + } + ] + }, + fieldId: "layout", + id: "stageLayout", + storageId: "text@stageLayout" + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: "title", + id: "stageTitle", + storageId: "object@stageTitle", + settings: { + fields: [ + { + type: "text", + validation: [ + { + name: "required", + message: + "Title is required." + } + ], + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Max. 70 characters incl. spaces are allowed. If you selected layout “Text only”: unlimited.", + fieldId: "title", + id: "stageTitleTitle", + storageId: "text@stageTitleTitle", + settings: { + inputField: { + rows: 2 + } + } + }, + { + type: "text", + multipleValues: false, + validation: [], + predefinedValues: { + enabled: true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: "headingRank", + id: "stageTitleHeadingRank", + storageId: + "text@stageTitleHeadingRank" + } + ], + layout: [ + [ + "stageTitleTitle", + "stageTitleHeadingRank" + ] + ] + } + }, + { + type: "rich-text", + validation: [], + renderer: { + name: "enhanced-lexical-text-input" + }, + label: "Text", + helpText: + "For a good user experience it is recommended not to use more than 600 characters incl. spaces. If there is the need for more, it is recommended to split the content into separate elements.", + fieldId: "stageText", + placeholderText: + "Max. 400 characters incl. spaces are allowed. If you selected the “Text only”: unlimited.", + id: "stageText", + storageId: "rich-text@stageText" + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Button", + helpText: + "The button hierarchy and design is pre-defined per component. See the showroom for details.", + fieldId: "button", + id: "stageButton", + storageId: "object@stageButton", + settings: { + fields: [ + { + type: "text", + validation: [], + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Button Text", + helpText: + "About 30 characters per row, if delivered on desktop. On mobile devices please calculate with ~20.", + fieldId: "buttonText", + id: "stageButtonText", + storageId: "text@stageButtonText" + }, + { + type: "text", + renderer: { + name: "text-input" + }, + label: "Button Link", + fieldId: "linkpicker", + id: "stageButtonLink", + helpText: + "If link target is SmartCMS internal, create link relative via to avoid 404 errors.", + storageId: "text@stageButtonLink" + } + ], + layout: [ + ["stageButtonText", "stageButtonLink"] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "asset-input" + }, + label: "Media", + helpText: + "Image 16:9 or 4:3, video always 16:9. Gifs bigger that 6 MB might not be delivered for performance reasons.", + fieldId: "stageMedia", + id: "stageMedia", + storageId: "object@stageMedia", + settings: { + cropPresets: { + single: { + automatic: true, + defaultPreset: "4:3", + presetsList: ["4:3", "16:9"] + } + }, + fields: [ + { + type: "file", + multipleValues: false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: "file", + id: "stageMediaFile", + storageId: "file@stageMediaFile" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: "altText", + id: "stageMediaAltText", + storageId: "text@stageMediaAltText" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: "seoName", + id: "stageMediaSeoName", + storageId: "text@stageMediaSeoName" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: "crop", + id: "stageMediaCrop", + storageId: "text@stageMediaCrop", + settings: { + disabled: true + } + } + ], + layout: [ + ["stageMediaFile"], + ["stageMediaAltText"], + ["stageMediaSeoName"], + ["stageMediaCrop"] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: "The technical ID of this element.", + fieldId: "uuid", + id: "stageUuid", + storageId: "text@stageUuid" + } + ], + layout: [ + ["stageLayout"], + ["stageTitle"], + ["stageText"], + ["stageMedia"], + ["stageButton"], + ["stageUuid"] + ] + } + ] + }, + storageId: "dynamicZone@introZone" + }, + { + id: "mainZone", + fieldId: "mainZone", + label: "Main Zone", + type: "dynamicZone", + multipleValues: true, + renderer: { + name: "dynamicZone" + }, + settings: { + templates: [ + { + name: "Accordion/Tab", + gqlTypeName: "AccordionTab", + icon: "fas/stairs", + description: + "You can easily switch from tab to accordion with one click. To avoid creating inside an accordion/tab split too much content, the title of the embedded component isn’t delivered. Be aware that the content inside the splits cannot be seen by search engines.", + id: "accordionTabTemplate", + validation: [], + fields: [ + { + type: "text", + validation: [ + { + name: "required", + message: "Must select Accordion or Tab" + } + ], + renderer: { + name: "select-box" + }, + label: "Layout", + helpText: + "For UX reasons please limit the amount of accordion splits to six.", + placeholderText: "Please select", + predefinedValues: { + enabled: true, + values: [ + { + label: "Accordion", + value: "accordion", + selected: true + }, + { + label: "Tab", + value: "tab" + } + ] + }, + fieldId: "layout", + id: "accordionTabLayout", + storageId: "text@AccordionTabLayout" + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: "title", + id: "accordionTabTitle", + storageId: "object@accordionTabTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Titles aren’t delivered in Accordion/Tab components for UX reasons.", + fieldId: "title", + id: "accordionTabTitleTitle", + storageId: + "text@accordionTabTitleTitle", + settings: { + inputField: {} + } + }, + { + type: "text", + multipleValues: false, + validation: [], + predefinedValues: { + enabled: true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: "headingRank", + id: "accordionTabTitleHeadingRank", + storageId: + "text@accordionTabTitleHeadingRank" + } + ], + layout: [ + [ + "accordionTabTitleTitle", + "accordionTabTitleHeadingRank" + ] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: true, + renderer: { + name: "objects" + }, + label: "Splits", + fieldId: "split", + id: "accordionTabSplit", + storageId: "object@AccordionTabSplit", + settings: { + fields: [ + { + type: "text", + validation: [ + { + name: "required", + message: + "The field is required" + } + ], + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Split title", + helpText: + "Title, visible in tab field or closed accordion fold. Works as an anchor.", + fieldId: "splitTitle", + id: "accordionTabSplitTitle", + storageId: + "text@accordionTabSplitTitle" + }, + { + type: "dynamicZone", + multipleValues: true, + validation: [ + { + name: "required", + message: + "This field is required" + } + ], + renderer: { + name: "dynamicZone" + }, + settings: { + templates: [ + { + name: "Media Rich Text", + gqlTypeName: + "MediaRichText", + icon: "fas/align-left", + description: + "Media Rich Text Component : Text and image a/o video side-by-side. Enrich-able with title, subtitle link list or button.", + id: "mediaRichtextTemplate", + validation: [], + fields: [ + { + type: "text", + renderer: { + name: "select-box" + }, + helpText: + "If single image, the ratio is free. For more than one it is set to 16:9.", + label: "Layout", + predefinedValues: + { + enabled: + true, + values: [ + { + label: "Media position left", + value: "imageLeft", + selected: + true + }, + { + label: "Media position right", + value: "imageRight" + } + ] + }, + fieldId: + "layout", + id: "mrtLayout", + storageId: + "text@mrtLayout" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: + "The technical ID of this element.", + fieldId: "uuid", + id: "mrtUuid", + storageId: + "text@mrtUuid" + }, + { + type: "object", + validation: [], + multipleValues: + false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: + "title", + id: "mrtTitle", + storageId: + "object@mrtTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: + false, + renderer: + { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Titles aren’t delivered in Accordion/Tab components for UX reasons.", + fieldId: + "title", + id: "mrtTitleTitle", + storageId: + "text@mrtTitleTitle", + settings: + { + inputField: + {} + } + }, + { + type: "text", + multipleValues: + false, + validation: + [], + predefinedValues: + { + enabled: + true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: + true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: + { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: + "headingRank", + id: "mrtTitleHeadingRank", + storageId: + "text@mrtTitleHeadingRank" + } + ], + layout: [ + [ + "mrtTitleTitle", + "mrtTitleHeadingRank" + ] + ] + } + }, + { + type: "text", + renderer: { + name: "text-input" + }, + label: "Subtitle", + helpText: + "Plain text, max 150 characters.", + fieldId: + "subtitle", + id: "mrtSubtitle", + storageId: + "text@mrtSubtitle" + }, + { + type: "rich-text", + validation: [], + renderer: { + name: "enhanced-lexical-text-input" + }, + label: "Text", + helpText: + "For a good user experience it is recommended not to use more than 600 characters incl. spaces. If there is the need for more, it is recommended to split the content into separate elements.", + fieldId: "text", + id: "mrtRichText", + storageId: + "rich-text@mrtRichText" + }, + { + type: "object", + validation: [], + multipleValues: + true, + renderer: { + name: "asset-input" + }, + label: "Media", + helpText: + "The ratio is free for single images. For multiple images the ratio is fixed at 16:9.", + fieldId: + "mrtMedia", + id: "mrtMedia", + storageId: + "object@mrtMedia", + settings: { + cropPresets: + { + single: { + presetsList: + [ + "EMPTY" + ] + }, + multiple: + { + presetsList: + [ + "16:9" + ] + } + }, + fields: [ + { + type: "file", + multipleValues: + false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: + "file", + id: "mrtMediaFile", + storageId: + "file@mrtMediaFile" + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: + "altText", + id: "mrtMediaAltText", + storageId: + "text@mrtMediaAltText" + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: + "seoName", + id: "mrtMediaSeoName", + storageId: + "text@mrtMediaSeoName" + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "text-input" + }, + label: "Caption", + helpText: + "Text length is max. 300 characters incl. spaces.", + fieldId: + "caption", + id: "mrtMediaCaption", + storageId: + "text@mrtMediaCaption", + validation: + [ + { + name: "maxLength", + message: + "Caption is longer then 300 characters.", + settings: + { + value: 300 + } + } + ] + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "text-input" + }, + label: "Caption link", + helpText: + "The link affects the complete text, not single words.", + fieldId: + "captionLink", + id: "mrtMediaCaptionLink", + storageId: + "text@mrtMediaCaptionLink" + }, + { + type: "text", + validation: + [], + renderer: + { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: + "crop", + id: "mrtMediaCrop", + storageId: + "text@mrtMediaCrop", + settings: + { + disabled: + true + } + } + ], + layout: [ + [ + "mrtMediaFile" + ], + [ + "mrtMediaAltText" + ], + [ + "mrtMediaSeoName" + ], + [ + "mrtMediaCaption" + ], + [ + "mrtMediaCaptionLink" + ], + [ + "mrtMediaCrop" + ] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: + false, + renderer: { + name: "object" + }, + label: "Button", + helpText: + "The button hierarchy and design is pre-defined per component. See the showroom for details.", + fieldId: + "button", + id: "mrtButton", + storageId: + "object@mrtButton", + settings: { + fields: [ + { + type: "text", + validation: + [], + multipleValues: + false, + renderer: + { + name: "text-input" + }, + label: "Button Text", + helpText: + "About 30 characters per row, if delivered on desktop. On mobile devices please calculate with ~20.", + fieldId: + "buttonText", + id: "mrtButtonText", + storageId: + "text@mrtButtonText" + }, + { + type: "text", + renderer: + { + name: "text-input" + }, + label: "Button Link", + fieldId: + "linkpicker", + id: "mrtButtonLink", + helpText: + "If link target is SmartCMS internal, create link relative via to avoid 404 errors.", + storageId: + "text@mrtButtonLink" + } + ], + layout: [ + [ + "mrtButtonText", + "mrtButtonLink" + ] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: + true, + renderer: { + name: "objects" + }, + label: "LinkList", + fieldId: + "linklist", + id: "mrtLinkList", + storageId: + "object@mrtLinkList", + settings: { + fields: [ + { + type: "text", + multipleValues: + false, + validation: + [ + { + name: "required", + message: + "Value is required." + } + ], + renderer: + { + name: "text-input" + }, + label: "Link Text", + helpText: + "Mandatory. For SEO avoid terms like “More” or “Click here”.", + fieldId: + "text", + id: "mrtLinkListText", + storageId: + "text@mrtLinkListText" + }, + { + type: "text", + renderer: + { + name: "text-input" + }, + validation: + [ + { + name: "required", + message: + "Value is required." + } + ], + label: "Link", + fieldId: + "linkpicker", + id: "mrtLinkListLink", + helpText: + "If link is SmartCMS internal, create link relative via to avoid 404 errors", + storageId: + "text@mrtLinkListLink" + } + ], + layout: [ + [ + "mrtLinkListText" + ], + [ + "mrtLinkListLink" + ] + ] + } + } + ], + layout: [ + ["mrtLayout"], + ["mrtTitle"], + ["mrtSubtitle"], + ["mrtRichText"], + ["mrtMedia"], + ["mrtButton"], + ["mrtLinkList"], + ["mrtUuid"] + ] + }, + { + name: "Gallery", + gqlTypeName: "Gallery", + icon: "fas/file-video", + description: + "Image a/o video slider which fills the complete browser width. Linked caption optional.", + id: "galleryTemplate", + validation: [], + fields: [ + { + type: "object", + validation: [], + multipleValues: + false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: + "title", + id: "galleryTitle", + storageId: + "object@galleryTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: + false, + renderer: + { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Titles aren’t delivered in Accordion/Tab components for UX reasons.", + fieldId: + "title", + id: "galleryTitleTitle", + storageId: + "text@galleryTitleTitle", + settings: + { + inputField: + {} + } + }, + { + type: "text", + multipleValues: + false, + validation: + [], + predefinedValues: + { + enabled: + true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: + true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: + { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: + "headingRank", + id: "galleryTitleHeadingRank", + storageId: + "text@galleryTitleHeadingRank" + } + ], + layout: [ + [ + "galleryTitleTitle", + "galleryTitleHeadingRank" + ] + ] + } + }, + { + type: "object", + validation: [], + renderer: { + name: "object" + }, + label: "Show on all images", + helpText: + "You can switch off/on the magnifier and/or the download icon, but only for all images - and not for videos", + fieldId: + "showOnAllImages", + id: "galleryShowOnAllImage", + storageId: + "object@galleryShowOnAllImage", + settings: { + fields: [ + { + type: "boolean", + validation: + [], + renderer: + { + name: "boolean-input" + }, + label: "Magnifier", + fieldId: + "galleryMagnifier", + id: "galleryMagnifier", + storageId: + "text@galleryMagnifier" + }, + { + type: "boolean", + validation: + [], + renderer: + { + name: "boolean-input" + }, + label: "Download icon", + fieldId: + "galleryDownloadIcon", + id: "galleryDownloadIcon", + storageId: + "text@galleryDownloadIcon" + } + ], + layout: [ + [ + "galleryMagnifier", + "galleryDownloadIcon" + ] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: + true, + renderer: { + name: "asset-input" + }, + label: "Media", + helpText: + "The ratio is free for single images. For multiple images the ratio is fixed at 16:9.", + fieldId: + "galleryMedia", + id: "galleryMedia", + storageId: + "object@galleryMedia", + settings: { + contentType: + [ + "IMAGES", + "VIDEOS" + ], + cropPresets: + { + single: { + presetsList: + [ + "EMPTY" + ] + }, + multiple: + { + presetsList: + [ + "16:9" + ] + } + }, + fields: [ + { + type: "file", + multipleValues: + false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: + "file", + id: "galleryMediaFile", + storageId: + "file@galleryMediaFile" + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: + "altText", + id: "galleryMediaAltText", + storageId: + "text@galleryMediaAltText" + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: + "seoName", + id: "galleryMediaSeoName", + storageId: + "text@galleryMediaSeoName" + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "text-input" + }, + label: "Caption", + helpText: + "Text length is max. 300 characters incl. spaces.", + fieldId: + "caption", + id: "galleryMediaCaption", + storageId: + "text@galleryMediaCaption", + validation: + [ + { + name: "maxLength", + message: + "Caption is longer then 300 characters.", + settings: + { + value: 300 + } + } + ] + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "text-input" + }, + label: "Caption link", + helpText: + "The link affects the complete text, not single words.", + fieldId: + "captionLink", + id: "galleryMediaCaptionLink", + storageId: + "text@galleryMediaCaptionLink" + }, + { + type: "text", + validation: + [], + renderer: + { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: + "crop", + id: "galleryMediaCrop", + storageId: + "text@galleryMediaCrop", + settings: + { + disabled: + true + } + } + ], + layout: [ + [ + "galleryMediaFile" + ], + [ + "galleryMediaAltText" + ], + [ + "galleryMediaSeoName" + ], + [ + "galleryMediaCaption" + ], + [ + "galleryMediaCaptionLink" + ], + [ + "galleryMediaCrop" + ] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: + "The technical ID of this element.", + fieldId: "uuid", + id: "galleryUuid", + storageId: + "text@galleryUuid" + } + ], + layout: [ + ["galleryTitle"], + [ + "galleryShowOnAllImage" + ], + ["galleryMedia"], + ["galleryUuid"] + ] + }, + { + name: "Teaser Card", + gqlTypeName: + "ContentTeaserRowCard", + icon: "fas/receipt", + description: + "A teaser card with an image or video, rich text and link list or button.", + id: "contentTeaserRowCardTemplate", + validation: [], + fields: [ + { + type: "object", + validation: [], + multipleValues: + false, + renderer: { + name: "asset-input" + }, + label: "Media", + fieldId: + "contentTeaserRowMediaMedia", + id: "contentTeaserRowMedia", + storageId: + "object@contentTeaserRowMedia", + settings: { + cropPresets: + { + single: { + presetsList: + [ + "16:9" + ] + } + }, + fields: [ + { + type: "file", + multipleValues: + false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: + "file", + id: "contentTeaserRowMediaFile", + storageId: + "file@contentTeaserRowMediaFile" + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: + "altText", + id: "contentTeaserRowMediaAltText", + storageId: + "text@contentTeaserRowMediaAltText" + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: + "seoName", + id: "contentTeaserRowMediaSeoName", + storageId: + "text@contentTeaserRowMediaSeoName" + }, + { + type: "text", + validation: + [], + renderer: + { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: + "crop", + id: "contentTeaserRowMediaCrop", + storageId: + "text@contentTeaserRowMediaCrop", + settings: + { + disabled: + true + } + } + ], + layout: [ + [ + "contentTeaserRowMediaFile" + ], + [ + "contentTeaserRowMediaAltText" + ], + [ + "contentTeaserRowMediaSeoName" + ], + [ + "contentTeaserRowMediaCrop" + ] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: + false, + renderer: { + name: "object" + }, + label: "Teaser Title", + fieldId: + "title", + id: "contentTeaserRowTeaserTitle", + storageId: + "object@contentTeaserRowTeaserTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: + false, + renderer: + { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "If teaser title and text missing, the teaser will not be delivered.", + fieldId: + "title", + id: "contentTeaserRowTeaserTitleTitle", + storageId: + "text@contentTeaserRowTeaserTitleTitle", + settings: + { + inputField: + {} + } + }, + { + type: "text", + multipleValues: + false, + validation: + [], + predefinedValues: + { + enabled: + true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: + true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: + { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: + "headingRank", + id: "contentTeaserRowTeaserTitleHeadingRank", + storageId: + "text@contentTeaserRowTeaserTitleHeadingRank" + } + ], + layout: [ + [ + "contentTeaserRowTeaserTitleTitle", + "contentTeaserRowTeaserTitleHeadingRank" + ] + ] + } + }, + { + type: "rich-text", + validation: [], + renderer: { + name: "enhanced-lexical-text-input" + }, + label: "Text", + helpText: + "For a good user experience it is recommended not to use more than 600 characters incl. spaces. If there is the need for more, it is recommended to split the content into separate elements.", + fieldId: "text", + id: "contentTeaserRowRichText", + storageId: + "rich-text@contentTeaserRowRichText" + }, + { + type: "object", + validation: [], + multipleValues: + false, + renderer: { + name: "object" + }, + label: "Button", + helpText: + "The button hierarchy and design is pre-defined per component. See the showroom for details.", + fieldId: + "button", + id: "contentTeaserRowButton", + storageId: + "object@contentTeaserRowButton", + settings: { + fields: [ + { + type: "text", + validation: + [], + multipleValues: + false, + renderer: + { + name: "text-input" + }, + label: "Button Text", + helpText: + "About 30 characters per row, if delivered on desktop. On mobile devices please calculate with ~20.", + fieldId: + "buttonText", + id: "contentTeaserRowButtonText", + storageId: + "text@contentTeaserRowButtonText" + }, + { + type: "text", + renderer: + { + name: "text-input" + }, + label: "Button Link", + fieldId: + "linkpicker", + id: "contentTeaserRowButtonLink", + helpText: + "If link target is SmartCMS internal, create link relative via to avoid 404 errors.", + storageId: + "text@contentTeaserRowButtonLink" + } + ], + layout: [ + [ + "contentTeaserRowButtonText", + "contentTeaserRowButtonLink" + ] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: + true, + renderer: { + name: "objects" + }, + label: "LinkList", + fieldId: + "linklist", + id: "contentTeaserRowLinkList", + storageId: + "object@contentTeaserRowLinkList", + settings: { + fields: [ + { + type: "text", + multipleValues: + false, + validation: + [ + { + name: "required", + message: + "Value is required." + } + ], + renderer: + { + name: "text-input" + }, + label: "Link Text", + helpText: + "Mandatory. For SEO avoid terms like “More” or “Click here”.", + fieldId: + "text", + id: "contentTeaserRowLinkListText", + storageId: + "text@contentTeaserRowLinkListText" + }, + { + type: "text", + renderer: + { + name: "text-input" + }, + validation: + [ + { + name: "required", + message: + "Value is required." + } + ], + label: "Link", + fieldId: + "linkpicker", + id: "contentTeaserRowLinkListLink", + helpText: + "If link is SmartCMS internal, create link relative via to avoid 404 errors", + storageId: + "text@contentTeaserRowLinkListLink" + } + ], + layout: [ + [ + "contentTeaserRowLinkListText" + ], + [ + "contentTeaserRowLinkListLink" + ] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: + "The technical ID of this element.", + fieldId: "uuid", + id: "contentTeaserRowUuid", + storageId: + "text@contentTeaserRowUuid" + } + ], + layout: [ + [ + "contentTeaserRowMedia" + ], + [ + "contentTeaserRowTeaserTitle" + ], + [ + "contentTeaserRowRichText" + ], + [ + "contentTeaserRowButton" + ], + [ + "contentTeaserRowLinkList" + ], + [ + "contentTeaserRowUuid" + ] + ] + }, + { + name: "Teaser Routing", + gqlTypeName: + "TeaserRouting", + icon: "fas/table-columns", + description: + "Teaser with or w/o additional content flyout. Teaser content can be retrieved from the linked page or edited manually.", + id: "teaserRoutingTemplate", + validation: [], + fields: [ + { + type: "object", + validation: [], + multipleValues: + false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: + "title", + id: "teaserRoutingTitle", + storageId: + "object@teaserRoutingTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: + false, + renderer: + { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Titles aren’t delivered in Accordion/Tab components for UX reasons.", + fieldId: + "title", + id: "teaserRoutingTitleTitle", + storageId: + "text@teaserRoutingTitleTitle", + settings: + { + inputField: + {} + } + }, + { + type: "text", + multipleValues: + false, + validation: + [], + predefinedValues: + { + enabled: + true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: + true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: + { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: + "headingRank", + id: "teaserRoutingTitleHeadingRank", + storageId: + "text@teaserRoutingTitleHeadingRank" + } + ], + layout: [ + [ + "teaserRoutingTitleTitle", + "teaserRoutingTitleHeadingRank" + ] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: + "The technical ID of this element.", + fieldId: "uuid", + id: "teaserRoutingUuid", + storageId: + "text@teaserRoutingUuid" + }, + { + type: "text", + validation: [], + renderer: { + name: "select-box" + }, + label: "Layout", + helpText: + "When “with flyout” is selected, a flyout will only appear if in the flyout is in minimum one teaser: if there’s only the flyout title and/or text, it’s not shown due to UX reasons. In this case please use Accordion/Tab element.", + predefinedValues: + { + enabled: + true, + values: [ + { + label: "3 teaser per row", + value: "3-col", + selected: + true + }, + { + label: "3 teaser per row with flyout", + value: "3-col-flyout" + }, + { + label: "4 teaser per row with flyout", + value: "4-col-flyout" + } + ] + }, + fieldId: + "teaserRoutingLayout", + id: "teaserRoutingLayout", + storageId: + "text@teaserRoutingLayout" + }, + { + type: "text", + validation: [], + renderer: { + name: "select-box" + }, + label: "Variation", + predefinedValues: + { + enabled: + true, + values: [ + { + label: "All elements", + value: "teaser_card", + selected: + true + }, + { + label: "Teaser title and image", + value: "teaser_card_headline_image" + }, + { + label: "Teaser title and text", + value: "teaser_card_headline_text" + }, + { + label: "Teaser title only", + value: "teaser_card_headline" + } + ] + }, + fieldId: + "teaserRoutingVariation", + id: "teaserRoutingVariation", + storageId: + "text@teaserRoutingVariation" + }, + { + type: "dynamicZone", + renderer: { + name: "dynamicZone" + }, + multipleValues: + true, + settings: { + templates: [ + { + name: "Teaser Card", + gqlTypeName: + "TeaserRoutingCard", + icon: "fas/receipt", + description: + "Teaser Card for Teaser Routing", + id: "teaserRoutingCardTemplate", + validation: + [], + fields: [ + { + type: "object", + validation: + [], + multipleValues: + false, + renderer: + { + name: "asset-input" + }, + label: "Media", + fieldId: + "teaserRoutingCardMediaMedia", + id: "teaserRoutingCardMedia", + storageId: + "object@teaserRoutingCardMedia", + settings: + { + cropPresets: + { + single: { + presetsList: + [ + "16:9" + ] + } + }, + fields: [ + { + type: "file", + multipleValues: + false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: + "file", + id: "teaserRoutingCardMediaFile", + storageId: + "file@teaserRoutingCardMediaFile" + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: + "altText", + id: "teaserRoutingCardMediaAltText", + storageId: + "text@teaserRoutingCardMediaAltText" + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: + "seoName", + id: "teaserRoutingCardMediaSeoName", + storageId: + "text@teaserRoutingCardMediaSeoName" + }, + { + type: "text", + validation: + [], + renderer: + { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: + "crop", + id: "teaserRoutingCardMediaCrop", + storageId: + "text@teaserRoutingCardMediaCrop", + settings: + { + disabled: + true + } + } + ], + layout: [ + [ + "teaserRoutingCardMediaFile" + ], + [ + "teaserRoutingCardMediaAltText" + ], + [ + "teaserRoutingCardMediaSeoName" + ], + [ + "teaserRoutingCardMediaCrop" + ] + ] + } + }, + { + type: "text", + validation: + [], + renderer: + { + name: "select-box" + }, + label: "Background option", + predefinedValues: + { + enabled: + true, + values: [ + { + label: "Fixed Width", + value: "fixed", + selected: + true + }, + { + label: "Transparent Background", + value: "transparent" + }, + { + label: "White Background", + value: "white" + } + ] + }, + fieldId: + "backgroundOption", + id: "teaserRoutingCardBackgroundOption", + storageId: + "text@teaserRoutingBackgroundOption" + }, + { + type: "text", + validation: + [ + { + name: "required", + message: + "Value is required." + } + ], + multipleValues: + false, + renderer: + { + name: "enhanced-text-input" + }, + label: "Teaser title", + helpText: + "If empty, teaser title from relative linked page teaser content will be shown. Max. 70 characters recommended.", + fieldId: + "title", + id: "teaserRoutingCardTitle", + storageId: + "text@teaserTitle", + settings: + { + inputField: + { + rows: 2 + } + } + }, + { + type: "text", + multipleValues: + false, + renderer: + { + name: "enhanced-text-input" + }, + label: "Text", + helpText: + "It's recommended to not exceed a length of 150 characters.", + fieldId: + "text", + id: "teaserRoutingCardText", + storageId: + "text@teaserText", + settings: + { + inputField: + { + rows: 5 + } + } + }, + { + type: "text", + renderer: + { + name: "text-input" + }, + validation: + [ + { + name: "required", + message: + "Value is required." + }, + { + name: "pattern", + settings: + { + preset: "url" + }, + message: + "URL Format is required" + } + ], + label: "Link", + fieldId: + "linkpicker", + id: "teaserRoutingCardLink", + helpText: + "If link is SmartCMS internal, create link relative via to avoid 404 errors", + storageId: + "text@teaserRoutingCardLink" + }, + { + type: "text", + validation: + [], + renderer: + { + name: "text-input" + }, + label: "FragmentUUID", + helpText: + "The technical ID of this element.", + fieldId: + "uuid", + id: "teaserRoutingCardUuid", + storageId: + "text@teaserRoutingCardUuid" + } + ], + layout: [ + [ + "teaserRoutingCardMedia" + ], + [ + "teaserRoutingCardBackgroundOption" + ], + [ + "teaserRoutingCardTitle" + ], + [ + "teaserRoutingCardText" + ], + [ + "teaserRoutingCardLink" + ], + [ + "teaserRoutingCardUuid" + ] + ] + } + ] + }, + label: "Teaser Card", + helpText: + "Select one or more of the allowed elements or fragments. Be aware the title of the elements isn’t delivered live.", + fieldId: + "teaserRoutingCards", + id: "teaserRoutingCards", + storageId: + "text@teaserRoutingCards" + } + ], + layout: [ + [ + "teaserRoutingTitle" + ], + [ + "teaserRoutingLayout", + "teaserRoutingVariation" + ], + [ + "teaserRoutingCards" + ], + [ + "teaserRoutingUuid" + ] + ] + } + ] + }, + label: "Split content", + helpText: + "Select one or more of the allowed elements or fragments. Be aware the title of the elements isn’t delivered live.", + fieldId: "splitContent", + id: "accordionTabSplitContent", + storageId: + "text@accordionTabSplitContent" + } + ], + layout: [ + ["accordionTabSplitTitle"], + ["accordionTabSplitContent"] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: "The technical ID of this element.", + fieldId: "uuid", + id: "accordionTabUUID", + storageId: "text@accordionTabUUID" + } + ], + layout: [ + ["accordionTabLayout"], + ["accordionTabTitle"], + ["accordionTabSplit"], + ["accordionTabUUID"] + ] + }, + { + name: "Content Teaser Row", + gqlTypeName: "ContentTeaserRow", + icon: "fas/table-columns", + description: + "2 to 4 teasers per row with an image or video, rich text and link list or button.", + id: "contentTeaserRowTemplate", + validation: [], + fields: [ + { + type: "text", + validation: [], + renderer: { + name: "select-box" + }, + label: "Layout", + predefinedValues: { + enabled: true, + values: [ + { + label: "2 in a row", + value: "2-col", + selected: true + }, + { + label: "3 in a row", + value: "3-col" + }, + { + label: "4 in a row", + value: "4-col" + } + ] + }, + fieldId: "layout", + id: "contentTeaserRowLayout", + storageId: "text@contentTeaserRowLayout" + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: "title", + id: "contentTeaserRowTitle", + storageId: "object@contentTeaserRowTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Title is not shown in the frontend Accordion/Tab", + fieldId: "title", + id: "contentTeaserRowTitleTitle", + storageId: + "text@contentTeaserRowTitleTitle", + settings: { + inputField: {} + } + }, + { + type: "text", + multipleValues: false, + validation: [], + predefinedValues: { + enabled: true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: "headingRank", + id: "contentTeaserRowTitleHeadingRank", + storageId: + "text@contentTeaserRowTitleHeadingRank" + } + ], + layout: [ + [ + "contentTeaserRowTitleTitle", + "contentTeaserRowTitleHeadingRank" + ] + ] + } + }, + { + type: "object", + validation: [], + renderer: { + name: "object" + }, + label: "Show on all images", + helpText: + "You can switch off/on the magnifier and/or the download icon, but only for all images - and not for videos", + fieldId: "showOnAllImages", + id: "contentTeaserRowShowOnAllImage", + storageId: "object@contentTeaserShowOnAllImage", + settings: { + fields: [ + { + type: "boolean", + validation: [], + renderer: { + name: "boolean-input" + }, + label: "Magnifier", + fieldId: + "contentTeaserRowMagnifier", + id: "contentTeaserRowMagnifier", + storageId: + "boolean@contentTeaserRowMagnifier" + }, + { + type: "boolean", + validation: [], + renderer: { + name: "boolean-input" + }, + label: "Download icon", + fieldId: "contentTeaserRowDownload", + id: "contentTeaserRowDownload", + storageId: + "boolean@contentTeaserRowDownload" + } + ], + layout: [ + [ + "contentTeaserRowDownload", + "contentTeaserRowMagnifier" + ] + ] + } + }, + { + type: "dynamicZone", + renderer: { + name: "dynamicZone" + }, + multipleValues: true, + settings: { + templates: [ + { + name: "Teaser Card", + gqlTypeName: "ContentTeaserRowCard", + icon: "fas/receipt", + description: + "A teaser card with an image or video, rich text and link list or button.", + id: "contentTeaserRowCardTemplate", + validation: [], + fields: [ + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "asset-input" + }, + label: "Media", + fieldId: + "contentTeaserRowMediaMedia", + id: "contentTeaserRowMedia", + storageId: + "object@contentTeaserRowMedia", + settings: { + cropPresets: { + single: { + presetsList: [ + "16:9" + ] + } + }, + fields: [ + { + type: "file", + multipleValues: + false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: "file", + id: "contentTeaserRowMediaFile", + storageId: + "file@contentTeaserRowMediaFile" + }, + { + type: "text", + multipleValues: + false, + renderer: { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: + "altText", + id: "contentTeaserRowMediaAltText", + storageId: + "text@contentTeaserRowMediaAltText" + }, + { + type: "text", + multipleValues: + false, + renderer: { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: + "seoName", + id: "contentTeaserRowMediaSeoName", + storageId: + "text@contentTeaserRowMediaSeoName" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: "crop", + id: "contentTeaserRowMediaCrop", + storageId: + "text@contentTeaserRowMediaCrop", + settings: { + disabled: + true + } + } + ], + layout: [ + [ + "contentTeaserRowMediaFile" + ], + [ + "contentTeaserRowMediaAltText" + ], + [ + "contentTeaserRowMediaSeoName" + ], + [ + "contentTeaserRowMediaCrop" + ] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Teaser Title", + fieldId: "title", + id: "contentTeaserRowTeaserTitle", + storageId: + "object@contentTeaserRowTeaserTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: + false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "If teaser title and text missing, the teaser will not be delivered.", + fieldId: + "title", + id: "contentTeaserRowTeaserTitleTitle", + storageId: + "text@contentTeaserRowTeaserTitleTitle", + settings: { + inputField: + {} + } + }, + { + type: "text", + multipleValues: + false, + validation: [], + predefinedValues: + { + enabled: + true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: + true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: + "headingRank", + id: "contentTeaserRowTeaserTitleHeadingRank", + storageId: + "text@contentTeaserRowTeaserTitleHeadingRank" + } + ], + layout: [ + [ + "contentTeaserRowTeaserTitleTitle", + "contentTeaserRowTeaserTitleHeadingRank" + ] + ] + } + }, + { + type: "rich-text", + validation: [], + renderer: { + name: "enhanced-lexical-text-input" + }, + label: "Text", + helpText: + "For a good user experience it is recommended not to use more than 600 characters incl. spaces. If there is the need for more, it is recommended to split the content into separate elements.", + fieldId: "text", + id: "contentTeaserRowRichText", + storageId: + "rich-text@contentTeaserRowRichText" + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Button", + helpText: + "The button hierarchy and design is pre-defined per component. See the showroom for details.", + fieldId: "button", + id: "contentTeaserRowButton", + storageId: + "object@contentTeaserRowButton", + settings: { + fields: [ + { + type: "text", + validation: [], + multipleValues: + false, + renderer: { + name: "text-input" + }, + label: "Button Text", + helpText: + "About 30 characters per row, if delivered on desktop. On mobile devices please calculate with ~20.", + fieldId: + "buttonText", + id: "contentTeaserRowButtonText", + storageId: + "text@contentTeaserRowButtonText" + }, + { + type: "text", + renderer: { + name: "text-input" + }, + label: "Button Link", + fieldId: + "linkpicker", + id: "contentTeaserRowButtonLink", + helpText: + "If link target is SmartCMS internal, create link relative via to avoid 404 errors.", + storageId: + "text@contentTeaserRowButtonLink" + } + ], + layout: [ + [ + "contentTeaserRowButtonText", + "contentTeaserRowButtonLink" + ] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: true, + renderer: { + name: "objects" + }, + label: "LinkList", + fieldId: "linklist", + id: "contentTeaserRowLinkList", + storageId: + "object@contentTeaserRowLinkList", + settings: { + fields: [ + { + type: "text", + multipleValues: + false, + validation: [ + { + name: "required", + message: + "Value is required." + } + ], + renderer: { + name: "text-input" + }, + label: "Link Text", + helpText: + "Mandatory. For SEO avoid terms like “More” or “Click here”.", + fieldId: "text", + id: "contentTeaserRowLinkListText", + storageId: + "text@contentTeaserRowLinkListText" + }, + { + type: "text", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "required", + message: + "Value is required." + } + ], + label: "Link", + fieldId: + "linkpicker", + id: "contentTeaserRowLinkListLink", + helpText: + "If link is SmartCMS internal, create link relative via to avoid 404 errors", + storageId: + "text@contentTeaserRowLinkListLink" + } + ], + layout: [ + [ + "contentTeaserRowLinkListText" + ], + [ + "contentTeaserRowLinkListLink" + ] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: + "The technical ID of this element.", + fieldId: "uuid", + id: "contentTeaserRowUuid", + storageId: + "text@contentTeaserRowUuid" + } + ], + layout: [ + ["contentTeaserRowMedia"], + ["contentTeaserRowTeaserTitle"], + ["contentTeaserRowRichText"], + ["contentTeaserRowButton"], + ["contentTeaserRowLinkList"], + ["contentTeaserRowUuid"] + ] + } + ] + }, + label: "Cards content", + helpText: + "Select one or more of the allowed elements or fragments. Be aware the title of the elements isn’t delivered live.", + fieldId: "contentTeaserRowCards", + id: "contentTeaserRowCards", + storageId: "text@contentTeaserRowCards" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: "The technical ID of this element.", + fieldId: "uuid", + id: "contentTeaserRowUuid", + storageId: "text@contentTeaserRowUuid" + } + ], + layout: [ + ["contentTeaserRowTitle"], + ["contentTeaserRowLayout"], + ["contentTeaserRowShowOnAllImage"], + ["contentTeaserRowCards"], + ["contentTeaserRowUuid"] + ] + }, + { + name: "Gallery", + gqlTypeName: "Gallery", + icon: "fas/file-video", + description: + "Image a/o video slider which fills the complete browser width. Linked caption optional.", + id: "galleryTemplate", + validation: [], + fields: [ + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: "title", + id: "galleryTitle", + storageId: "object@galleryTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Titles aren’t delivered in Accordion/Tab components for UX reasons.", + fieldId: "title", + id: "galleryTitleTitle", + storageId: "text@galleryTitleTitle", + settings: { + inputField: {} + } + }, + { + type: "text", + multipleValues: false, + validation: [], + predefinedValues: { + enabled: true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: "headingRank", + id: "galleryTitleHeadingRank", + storageId: + "text@galleryTitleHeadingRank" + } + ], + layout: [ + [ + "galleryTitleTitle", + "galleryTitleHeadingRank" + ] + ] + } + }, + { + type: "object", + validation: [], + renderer: { + name: "object" + }, + label: "Show on all images", + helpText: + "You can switch off/on the magnifier and/or the download icon, but only for all images - and not for videos", + fieldId: "showOnAllImages", + id: "galleryShowOnAllImage", + storageId: "object@galleryShowOnAllImage", + settings: { + fields: [ + { + type: "boolean", + validation: [], + renderer: { + name: "boolean-input" + }, + label: "Magnifier", + fieldId: "galleryMagnifier", + id: "galleryMagnifier", + storageId: "text@galleryMagnifier" + }, + { + type: "boolean", + validation: [], + renderer: { + name: "boolean-input" + }, + label: "Download icon", + fieldId: "galleryDownloadIcon", + id: "galleryDownloadIcon", + storageId: + "text@galleryDownloadIcon" + } + ], + layout: [ + [ + "galleryMagnifier", + "galleryDownloadIcon" + ] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: true, + renderer: { + name: "asset-input" + }, + label: "Media", + helpText: + "The ratio is free for single images. For multiple images the ratio is fixed at 16:9.", + fieldId: "galleryMedia", + id: "galleryMedia", + storageId: "object@galleryMedia", + settings: { + contentType: ["IMAGES", "VIDEOS"], + cropPresets: { + single: { + presetsList: ["EMPTY"] + }, + multiple: { + presetsList: ["16:9"] + } + }, + fields: [ + { + type: "file", + multipleValues: false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: "file", + id: "galleryMediaFile", + storageId: "file@galleryMediaFile" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: "altText", + id: "galleryMediaAltText", + storageId: + "text@galleryMediaAltText" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: "seoName", + id: "galleryMediaSeoName", + storageId: + "text@galleryMediaSeoName" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Caption", + helpText: + "Text length is max. 300 characters incl. spaces.", + fieldId: "caption", + id: "galleryMediaCaption", + storageId: + "text@galleryMediaCaption", + validation: [ + { + name: "maxLength", + message: + "Caption is longer then 300 characters.", + settings: { + value: 300 + } + } + ] + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Caption link", + helpText: + "The link affects the complete text, not single words.", + fieldId: "captionLink", + id: "galleryMediaCaptionLink", + storageId: + "text@galleryMediaCaptionLink" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: "crop", + id: "galleryMediaCrop", + storageId: "text@galleryMediaCrop", + settings: { + disabled: true + } + } + ], + layout: [ + ["galleryMediaFile"], + ["galleryMediaAltText"], + ["galleryMediaSeoName"], + ["galleryMediaCaption"], + ["galleryMediaCaptionLink"], + ["galleryMediaCrop"] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: "The technical ID of this element.", + fieldId: "uuid", + id: "galleryUuid", + storageId: "text@galleryUuid" + } + ], + layout: [ + ["galleryTitle"], + ["galleryShowOnAllImage"], + ["galleryMedia"], + ["galleryUuid"] + ] + }, + { + name: "Media Rich Text", + gqlTypeName: "MediaRichText", + icon: "fas/align-left", + description: + "Media Rich Text Component : Text and image a/o video side-by-side. Enrich-able with title, subtitle link list or button.", + id: "mediaRichtextTemplate", + validation: [], + fields: [ + { + type: "text", + renderer: { + name: "select-box" + }, + helpText: + "If single image, the ratio is free. For more than one it is set to 16:9.", + label: "Layout", + predefinedValues: { + enabled: true, + values: [ + { + label: "Media position left", + value: "imageLeft", + selected: true + }, + { + label: "Media position right", + value: "imageRight" + } + ] + }, + fieldId: "layout", + id: "mrtLayout", + storageId: "text@mrtLayout" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: "The technical ID of this element.", + fieldId: "uuid", + id: "mrtUuid", + storageId: "text@mrtUuid" + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: "title", + id: "mrtTitle", + storageId: "object@mrtTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Titles aren’t delivered in Accordion/Tab components for UX reasons.", + fieldId: "title", + id: "mrtTitleTitle", + storageId: "text@mrtTitleTitle", + settings: { + inputField: {} + } + }, + { + type: "text", + multipleValues: false, + validation: [], + predefinedValues: { + enabled: true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: "headingRank", + id: "mrtTitleHeadingRank", + storageId: + "text@mrtTitleHeadingRank" + } + ], + layout: [ + ["mrtTitleTitle", "mrtTitleHeadingRank"] + ] + } + }, + { + type: "text", + renderer: { + name: "text-input" + }, + label: "Subtitle", + helpText: "Plain text, max 150 characters.", + fieldId: "subtitle", + id: "mrtSubtitle", + storageId: "text@mrtSubtitle" + }, + { + type: "rich-text", + validation: [], + renderer: { + name: "enhanced-lexical-text-input" + }, + label: "Text", + helpText: + "For a good user experience it is recommended not to use more than 600 characters incl. spaces. If there is the need for more, it is recommended to split the content into separate elements.", + fieldId: "text", + id: "mrtRichText", + storageId: "rich-text@mrtRichText" + }, + { + type: "object", + validation: [], + multipleValues: true, + renderer: { + name: "asset-input" + }, + label: "Media", + helpText: + "The ratio is free for single images. For multiple images the ratio is fixed at 16:9.", + fieldId: "mrtMedia", + id: "mrtMedia", + storageId: "object@mrtMedia", + settings: { + cropPresets: { + single: { + presetsList: ["EMPTY"] + }, + multiple: { + presetsList: ["16:9"] + } + }, + fields: [ + { + type: "file", + multipleValues: false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: "file", + id: "mrtMediaFile", + storageId: "file@mrtMediaFile" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: "altText", + id: "mrtMediaAltText", + storageId: "text@mrtMediaAltText" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: "seoName", + id: "mrtMediaSeoName", + storageId: "text@mrtMediaSeoName" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Caption", + helpText: + "Text length is max. 300 characters incl. spaces.", + fieldId: "caption", + id: "mrtMediaCaption", + storageId: "text@mrtMediaCaption", + validation: [ + { + name: "maxLength", + message: + "Caption is longer then 300 characters.", + settings: { + value: 300 + } + } + ] + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Caption link", + helpText: + "The link affects the complete text, not single words.", + fieldId: "captionLink", + id: "mrtMediaCaptionLink", + storageId: + "text@mrtMediaCaptionLink" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: "crop", + id: "mrtMediaCrop", + storageId: "text@mrtMediaCrop", + settings: { + disabled: true + } + } + ], + layout: [ + ["mrtMediaFile"], + ["mrtMediaAltText"], + ["mrtMediaSeoName"], + ["mrtMediaCaption"], + ["mrtMediaCaptionLink"], + ["mrtMediaCrop"] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Button", + helpText: + "The button hierarchy and design is pre-defined per component. See the showroom for details.", + fieldId: "button", + id: "mrtButton", + storageId: "object@mrtButton", + settings: { + fields: [ + { + type: "text", + validation: [], + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Button Text", + helpText: + "About 30 characters per row, if delivered on desktop. On mobile devices please calculate with ~20.", + fieldId: "buttonText", + id: "mrtButtonText", + storageId: "text@mrtButtonText" + }, + { + type: "text", + renderer: { + name: "text-input" + }, + label: "Button Link", + fieldId: "linkpicker", + id: "mrtButtonLink", + helpText: + "If link target is SmartCMS internal, create link relative via to avoid 404 errors.", + storageId: "text@mrtButtonLink" + } + ], + layout: [["mrtButtonText", "mrtButtonLink"]] + } + }, + { + type: "object", + validation: [], + multipleValues: true, + renderer: { + name: "objects" + }, + label: "LinkList", + fieldId: "linklist", + id: "mrtLinkList", + storageId: "object@mrtLinkList", + settings: { + fields: [ + { + type: "text", + multipleValues: false, + validation: [ + { + name: "required", + message: + "Value is required." + } + ], + renderer: { + name: "text-input" + }, + label: "Link Text", + helpText: + "Mandatory. For SEO avoid terms like “More” or “Click here”.", + fieldId: "text", + id: "mrtLinkListText", + storageId: "text@mrtLinkListText" + }, + { + type: "text", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "required", + message: + "Value is required." + } + ], + label: "Link", + fieldId: "linkpicker", + id: "mrtLinkListLink", + helpText: + "If link is SmartCMS internal, create link relative via to avoid 404 errors", + storageId: "text@mrtLinkListLink" + } + ], + layout: [ + ["mrtLinkListText"], + ["mrtLinkListLink"] + ] + } + } + ], + layout: [ + ["mrtLayout"], + ["mrtTitle"], + ["mrtSubtitle"], + ["mrtRichText"], + ["mrtMedia"], + ["mrtButton"], + ["mrtLinkList"], + ["mrtUuid"] + ] + }, + { + name: "Quote", + gqlTypeName: "Quote", + icon: "fas/quote-right", + description: "Quote with source and optional image.", + id: "quoteTemplate", + validation: [], + fields: [ + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: "title", + id: "quoteTitle", + storageId: "object@quoteTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Titles aren’t delivered in Accordion/Tab components for UX reasons.", + fieldId: "title", + id: "quoteTitleTitle", + storageId: "text@quoteTitleTitle", + settings: { + inputField: {} + } + }, + { + type: "text", + multipleValues: false, + validation: [], + predefinedValues: { + enabled: true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: "headingRank", + id: "quoteTitleHeadingRank", + storageId: + "text@quoteTitleHeadingRank" + } + ], + layout: [ + [ + "quoteTitleTitle", + "quoteTitleHeadingRank" + ] + ] + } + }, + { + type: "text", + renderer: { + name: "select-box" + }, + label: "Layout", + predefinedValues: { + enabled: true, + values: [ + { + label: "Image position left", + value: "imageLeft", + selected: true + }, + { + label: "Image position right", + value: "imageRight" + } + ] + }, + settings: { + defaultValue: "imageLeft" + }, + fieldId: "layout", + id: "quoteLayout", + storageId: "text@quoteLayout" + }, + { + type: "text", + renderer: { + name: "select-box" + }, + label: "Focus On", + helpText: + "Which one should be in user’s focus: the image or the quote?", + predefinedValues: { + enabled: true, + values: [ + { + label: "Quote", + value: "quote", + selected: true + }, + { + label: "Image", + value: "image" + } + ] + }, + settings: { + defaultValue: "quote" + }, + fieldId: "focusOn", + id: "quoteFocusOn", + storageId: "text@quoteFocusOn" + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "asset-input" + }, + label: "Media", + fieldId: "quoteMedia", + id: "quoteMedia", + storageId: "object@quoteMedia", + settings: { + contentType: ["GIFS", "IMAGES"], + fields: [ + { + type: "file", + multipleValues: false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: "file", + id: "quoteMediaFile", + storageId: "file@quoteMediaFile" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: "altText", + id: "quoteMediaAltText", + storageId: "text@quoteMediaAltText" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: "seoName", + id: "quoteMediaSeoName", + storageId: "text@quoteMediaSeoName" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: "crop", + id: "quoteMediaCrop", + storageId: "text@quoteMediaCrop", + settings: { + disabled: true + } + } + ], + layout: [ + ["quoteMediaFile"], + ["quoteMediaAltText"], + ["quoteMediaSeoName"], + ["quoteMediaCrop"] + ] + } + }, + { + type: "text", + validation: [ + { + name: "required", + message: "Value is required." + } + ], + renderer: { + name: "enhanced-text-input" + }, + helpText: + "The recommended length is 160 characters, as longer quotes are often not read by users.", + label: "Quote", + fieldId: "quoteText", + id: "quoteText", + storageId: "text@quotetext", + settings: { + inputField: { + rows: 5 + } + } + }, + { + type: "text", + renderer: { + name: "enhanced-text-input" + }, + helpText: + "It's recommended to not exceed a length of 160 characters.", + label: "Source", + fieldId: "quoteSource", + id: "quoteSource", + storageId: "text@quotesource", + settings: { + inputField: { + rows: 5 + } + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: "The technical ID of this element.", + fieldId: "uuid", + id: "quoteUuid", + storageId: "text@quoteUuid" + } + ], + layout: [ + ["quoteTitle"], + ["quoteLayout", "quoteFocusOn"], + ["quoteMedia"], + ["quoteText", "quoteSource"], + ["quoteUuid"] + ] + }, + { + name: "Reference Slider", + gqlTypeName: "ReferenceSlider", + icon: "fas/receipt", + description: + "Up to 9 teasers in a row with an individual tag line, title, rich text in a maximum of 3 bullet points and a link button.", + id: "referenceSliderTemplate", + validation: [], + fields: [ + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: "title", + id: "referenceSliderTitle", + storageId: "object@referenceSliderTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Titles aren’t delivered in Accordion/Tab components for UX reasons.", + fieldId: "title", + id: "referenceSliderTitleTitle", + storageId: + "text@referenceSliderTitleTitle", + settings: { + inputField: {} + } + }, + { + type: "text", + multipleValues: false, + validation: [], + predefinedValues: { + enabled: true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: "headingRank", + id: "referenceSliderTitleHeadingRank", + storageId: + "text@referenceSliderTitleHeadingRank" + } + ], + layout: [ + [ + "referenceSliderTitleTitle", + "referenceSliderTitleHeadingRank" + ] + ] + } + }, + { + type: "dynamicZone", + renderer: { + name: "dynamicZone" + }, + multipleValues: true, + settings: { + templates: [ + { + name: "Reference Slider Card", + gqlTypeName: "ReferenceSliderCard", + icon: "fas/receipt", + description: + "It is recommended to use up to 3 cards per slider element.The ratio of the media elements is fixed at 16:9.", + id: "referenceSliderCardTemplate", + validation: [], + fields: [ + { + type: "object", + validation: [ + { + name: "required", + message: + "Must select a media" + } + ], + multipleValues: false, + renderer: { + name: "asset-input" + }, + label: "Media", + fieldId: + "referenceSliderCardMedia", + id: "referenceSliderCardMedia", + storageId: + "object@referenceSliderCardMedia", + settings: { + cropPresets: { + single: { + automatic: true, + defaultPreset: + "16:9", + presetsList: [ + "16:9" + ] + } + }, + fields: [ + { + type: "file", + multipleValues: + false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: "file", + id: "referenceSliderCardMediaFile", + storageId: + "file@referenceSliderCardMediaFile" + }, + { + type: "text", + multipleValues: + false, + renderer: { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: + "altText", + id: "referenceSliderCardMediaAltText", + storageId: + "text@referenceSliderCardMediaAltText" + }, + { + type: "text", + multipleValues: + false, + renderer: { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: + "seoName", + id: "referenceSliderCardMediaSeoName", + storageId: + "text@referenceSliderCardMediaSeoName" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: "crop", + id: "referenceSliderCardMediaCrop", + storageId: + "text@referenceSliderCardMediaCrop", + settings: { + disabled: + true + } + } + ], + layout: [ + [ + "referenceSliderCardMediaFile" + ], + [ + "referenceSliderCardMediaAltText" + ], + [ + "referenceSliderCardMediaSeoName" + ], + [ + "referenceSliderCardMediaCrop" + ] + ] + } + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Customer name", + helpText: + "Appears like a Tag above the headline, optional", + fieldId: + "referenceSliderCardCustomerName", + id: "referenceSliderCardCustomerName", + storageId: + "text@referenceSliderCardCustomerName" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Location", + helpText: + "Appears like a Tag above the headline, optional", + fieldId: + "referenceSliderCardLocation", + id: "referenceSliderCardLocation", + storageId: + "text@referenceSliderCardLocation" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Market", + helpText: + "Appears like a Tag above the headline, optional", + fieldId: + "referenceSliderCardMarket", + id: "referenceSliderCardMarket", + storageId: + "text@referenceSliderCardMarket" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Mandatory, max. 70 characters recommended", + fieldId: + "referenceSliderCardTitle", + id: "referenceSliderCardTitle", + storageId: + "text@referenceSliderCardTitle", + validation: [ + { + name: "required", + message: + "The field is required" + } + ], + settings: { + inputField: { + rows: 2 + } + } + }, + { + type: "rich-text", + validation: [], + renderer: { + name: "enhanced-lexical-text-input" + }, + label: "Bullet point 1", + helpText: + "For a good user experience it is recommended not to use more than 600 characters incl. spaces. If there is the need for more, it is recommended to split the content into separate elements.", + fieldId: + "referenceSliderCardBulletPoint1", + placeholderText: + "Max. 140 characters recommended, optional", + id: "referenceSliderCardBulletPoint1", + storageId: + "rich-text@referenceSliderCardBulletPoint1" + }, + { + type: "rich-text", + validation: [], + renderer: { + name: "enhanced-lexical-text-input" + }, + label: "Bullet point 2", + helpText: + "For a good user experience it is recommended not to use more than 600 characters incl. spaces. If there is the need for more, it is recommended to split the content into separate elements.", + fieldId: + "referenceSliderCardBulletPoint2", + placeholderText: + "Max. 140 characters recommended, optional", + id: "referenceSliderCardBulletPoint2", + storageId: + "rich-text@referenceSliderCardBulletPoint2" + }, + { + type: "rich-text", + validation: [], + renderer: { + name: "enhanced-lexical-text-input" + }, + label: "Bullet point 3", + helpText: + "For a good user experience it is recommended not to use more than 600 characters incl. spaces. If there is the need for more, it is recommended to split the content into separate elements.", + fieldId: + "referenceSliderCardBulletPoint3", + placeholderText: + "Max. 140 characters recommended, optional", + id: "referenceSliderCardBulletPoint3", + storageId: + "rich-text@referenceSliderCardBulletPoint3" + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Button", + helpText: + "The button hierarchy and design is pre-defined per component. See the showroom for details.", + fieldId: "button", + id: "referenceSliderCardButton", + storageId: + "object@referenceSliderCardButton", + settings: { + fields: [ + { + type: "text", + validation: [], + multipleValues: + false, + renderer: { + name: "text-input" + }, + label: "Button Text", + helpText: + "About 30 characters per row, if delivered on desktop. On mobile devices please calculate with ~20.", + fieldId: + "buttonText", + id: "referenceSliderCardButtonText", + storageId: + "text@referenceSliderCardButtonText" + }, + { + type: "text", + renderer: { + name: "text-input" + }, + label: "Button Link", + fieldId: + "linkpicker", + id: "referenceSliderCardButtonLink", + helpText: + "If link target is SmartCMS internal, create link relative via to avoid 404 errors.", + storageId: + "text@referenceSliderCardButtonLink" + } + ], + layout: [ + [ + "referenceSliderCardButtonText", + "referenceSliderCardButtonLink" + ] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: + "The technical ID of this element.", + fieldId: "uuid", + id: "referenceSliderCardUuid", + storageId: + "text@referenceSliderCardUuid" + } + ], + layout: [ + ["referenceSliderCardMedia"], + [ + "referenceSliderCardCustomerName" + ], + ["referenceSliderCardLocation"], + ["referenceSliderCardMarket"], + ["referenceSliderCardTitle"], + [ + "referenceSliderCardBulletPoint1" + ], + [ + "referenceSliderCardBulletPoint2" + ], + [ + "referenceSliderCardBulletPoint3" + ], + ["referenceSliderCardButton"], + ["referenceSliderCardUuid"] + ] + } + ] + }, + label: "Cards content", + helpText: + "Select one or more of the allowed elements or fragments. Be aware the title of the elements isn’t delivered live.", + fieldId: "referenceSliderCards", + id: "referenceSliderCards", + storageId: "text@referenceSliderCards" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: "The technical ID of this element.", + fieldId: "uuid", + id: "referenceSliderUuid", + storageId: "text@referenceSliderUuid" + } + ], + layout: [ + ["referenceSliderTitle"], + ["referenceSliderCards"], + ["referenceSliderUuid"] + ] + }, + { + name: "Stage", + gqlTypeName: "Stage", + icon: "fas/masks-theater", + description: + "1st element of every page, delivers a H1 and a short intro text.", + id: "stageTemplate", + validation: [], + fields: [ + { + type: "text", + validation: [], + renderer: { + name: "select-box" + }, + helpText: + "If used outside of Intro section the headline will be delivered as H2.", + label: "Layout", + predefinedValues: { + enabled: true, + values: [ + { + label: "Text only", + value: "textOnly" + }, + { + label: "Text with media left", + value: "imageLeft" + }, + { + label: "Text with media right", + value: "imageRight", + selected: true + }, + { + label: "Panorama", + value: "panoramaImage" + }, + { + label: "Full screen with background image", + value: "backgroundImageVideo" + } + ] + }, + fieldId: "layout", + id: "stageLayout", + storageId: "text@stageLayout" + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: "title", + id: "stageTitle", + storageId: "object@stageTitle", + settings: { + fields: [ + { + type: "text", + validation: [ + { + name: "required", + message: + "Title is required." + } + ], + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Max. 70 characters incl. spaces are allowed. If you selected layout “Text only”: unlimited.", + fieldId: "title", + id: "stageTitleTitle", + storageId: "text@stageTitleTitle", + settings: { + inputField: { + rows: 2 + } + } + }, + { + type: "text", + multipleValues: false, + validation: [], + predefinedValues: { + enabled: true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: "headingRank", + id: "stageTitleHeadingRank", + storageId: + "text@stageTitleHeadingRank" + } + ], + layout: [ + [ + "stageTitleTitle", + "stageTitleHeadingRank" + ] + ] + } + }, + { + type: "rich-text", + validation: [], + renderer: { + name: "enhanced-lexical-text-input" + }, + label: "Text", + helpText: + "For a good user experience it is recommended not to use more than 600 characters incl. spaces. If there is the need for more, it is recommended to split the content into separate elements.", + fieldId: "stageText", + placeholderText: + "Max. 400 characters incl. spaces are allowed. If you selected the “Text only”: unlimited.", + id: "stageText", + storageId: "rich-text@stageText" + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Button", + helpText: + "The button hierarchy and design is pre-defined per component. See the showroom for details.", + fieldId: "button", + id: "stageButton", + storageId: "object@stageButton", + settings: { + fields: [ + { + type: "text", + validation: [], + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Button Text", + helpText: + "About 30 characters per row, if delivered on desktop. On mobile devices please calculate with ~20.", + fieldId: "buttonText", + id: "stageButtonText", + storageId: "text@stageButtonText" + }, + { + type: "text", + renderer: { + name: "text-input" + }, + label: "Button Link", + fieldId: "linkpicker", + id: "stageButtonLink", + helpText: + "If link target is SmartCMS internal, create link relative via to avoid 404 errors.", + storageId: "text@stageButtonLink" + } + ], + layout: [ + ["stageButtonText", "stageButtonLink"] + ] + } + }, + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "asset-input" + }, + label: "Media", + helpText: + "Image 16:9 or 4:3, video always 16:9. Gifs bigger that 6 MB might not be delivered for performance reasons.", + fieldId: "stageMedia", + id: "stageMedia", + storageId: "object@stageMedia", + settings: { + cropPresets: { + single: { + automatic: true, + defaultPreset: "4:3", + presetsList: ["4:3", "16:9"] + } + }, + fields: [ + { + type: "file", + multipleValues: false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: "file", + id: "stageMediaFile", + storageId: "file@stageMediaFile" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: "altText", + id: "stageMediaAltText", + storageId: "text@stageMediaAltText" + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: "seoName", + id: "stageMediaSeoName", + storageId: "text@stageMediaSeoName" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: "crop", + id: "stageMediaCrop", + storageId: "text@stageMediaCrop", + settings: { + disabled: true + } + } + ], + layout: [ + ["stageMediaFile"], + ["stageMediaAltText"], + ["stageMediaSeoName"], + ["stageMediaCrop"] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: "The technical ID of this element.", + fieldId: "uuid", + id: "stageUuid", + storageId: "text@stageUuid" + } + ], + layout: [ + ["stageLayout"], + ["stageTitle"], + ["stageText"], + ["stageMedia"], + ["stageButton"], + ["stageUuid"] + ] + }, + { + name: "Teaser Routing", + gqlTypeName: "TeaserRouting", + icon: "fas/table-columns", + description: + "Teaser with or w/o additional content flyout. Teaser content can be retrieved from the linked page or edited manually.", + id: "teaserRoutingTemplate", + validation: [], + fields: [ + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "object" + }, + label: "Title", + fieldId: "title", + id: "teaserRoutingTitle", + storageId: "object@teaserRoutingTitle", + settings: { + fields: [ + { + type: "text", + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Title", + helpText: + "Titles aren’t delivered in Accordion/Tab components for UX reasons.", + fieldId: "title", + id: "teaserRoutingTitleTitle", + storageId: + "text@teaserRoutingTitleTitle", + settings: { + inputField: {} + } + }, + { + type: "text", + multipleValues: false, + validation: [], + predefinedValues: { + enabled: true, + values: [ + { + label: "Auto generated", + value: "auto", + selected: true + }, + { + label: "H2", + value: "h2" + }, + { + label: "H3", + value: "h3" + }, + { + label: "H4", + value: "h4" + }, + { + label: "H5", + value: "h5" + }, + { + label: "H6", + value: "h6" + } + ] + }, + renderer: { + name: "select-box" + }, + label: "Heading Rank", + helpText: + "The heading rank is a page structure element needed for SEO, calculated by SmartCMS. To change the structure of the page you can choose another rank, following subtitles will be recalculated automatically.", + fieldId: "headingRank", + id: "teaserRoutingTitleHeadingRank", + storageId: + "text@teaserRoutingTitleHeadingRank" + } + ], + layout: [ + [ + "teaserRoutingTitleTitle", + "teaserRoutingTitleHeadingRank" + ] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: "The technical ID of this element.", + fieldId: "uuid", + id: "teaserRoutingUuid", + storageId: "text@teaserRoutingUuid" + }, + { + type: "text", + validation: [], + renderer: { + name: "select-box" + }, + label: "Layout", + helpText: + "When “with flyout” is selected, a flyout will only appear if in the flyout is in minimum one teaser: if there’s only the flyout title and/or text, it’s not shown due to UX reasons. In this case please use Accordion/Tab element.", + predefinedValues: { + enabled: true, + values: [ + { + label: "3 teaser per row", + value: "3-col", + selected: true + }, + { + label: "3 teaser per row with flyout", + value: "3-col-flyout" + }, + { + label: "4 teaser per row with flyout", + value: "4-col-flyout" + } + ] + }, + fieldId: "teaserRoutingLayout", + id: "teaserRoutingLayout", + storageId: "text@teaserRoutingLayout" + }, + { + type: "text", + validation: [], + renderer: { + name: "select-box" + }, + label: "Variation", + predefinedValues: { + enabled: true, + values: [ + { + label: "All elements", + value: "teaser_card", + selected: true + }, + { + label: "Teaser title and image", + value: "teaser_card_headline_image" + }, + { + label: "Teaser title and text", + value: "teaser_card_headline_text" + }, + { + label: "Teaser title only", + value: "teaser_card_headline" + } + ] + }, + fieldId: "teaserRoutingVariation", + id: "teaserRoutingVariation", + storageId: "text@teaserRoutingVariation" + }, + { + type: "dynamicZone", + renderer: { + name: "dynamicZone" + }, + multipleValues: true, + settings: { + templates: [ + { + name: "Teaser Card", + gqlTypeName: "TeaserRoutingCard", + icon: "fas/receipt", + description: + "Teaser Card for Teaser Routing", + id: "teaserRoutingCardTemplate", + validation: [], + fields: [ + { + type: "object", + validation: [], + multipleValues: false, + renderer: { + name: "asset-input" + }, + label: "Media", + fieldId: + "teaserRoutingCardMediaMedia", + id: "teaserRoutingCardMedia", + storageId: + "object@teaserRoutingCardMedia", + settings: { + cropPresets: { + single: { + presetsList: [ + "16:9" + ] + } + }, + fields: [ + { + type: "file", + multipleValues: + false, + label: "File", + helpText: + "How to change the start image of a video please see http://acme.com/dam FAQ", + fieldId: "file", + id: "teaserRoutingCardMediaFile", + storageId: + "file@teaserRoutingCardMediaFile" + }, + { + type: "text", + multipleValues: + false, + renderer: { + name: "text-input" + }, + label: "Alternative text", + helpText: + "If not selected then image is marked as decorative. Please refer to Showroom, topic “WCAG” to learn more.", + fieldId: + "altText", + id: "teaserRoutingCardMediaAltText", + storageId: + "text@teaserRoutingCardMediaAltText" + }, + { + type: "text", + multipleValues: + false, + renderer: { + name: "slug-field-input" + }, + label: "SEO name", + helpText: + "Example: My selfie will be delivered as my-selfie.jpg. Used for SEO.", + fieldId: + "seoName", + id: "teaserRoutingCardMediaSeoName", + storageId: + "text@teaserRoutingCardMediaSeoName" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-and-copy-input" + }, + label: "Crop values", + helpText: + "The value used to crop this media.", + fieldId: "crop", + id: "teaserRoutingCardMediaCrop", + storageId: + "text@teaserRoutingCardMediaCrop", + settings: { + disabled: + true + } + } + ], + layout: [ + [ + "teaserRoutingCardMediaFile" + ], + [ + "teaserRoutingCardMediaAltText" + ], + [ + "teaserRoutingCardMediaSeoName" + ], + [ + "teaserRoutingCardMediaCrop" + ] + ] + } + }, + { + type: "text", + validation: [], + renderer: { + name: "select-box" + }, + label: "Background option", + predefinedValues: { + enabled: true, + values: [ + { + label: "Fixed Width", + value: "fixed", + selected: true + }, + { + label: "Transparent Background", + value: "transparent" + }, + { + label: "White Background", + value: "white" + } + ] + }, + fieldId: "backgroundOption", + id: "teaserRoutingCardBackgroundOption", + storageId: + "text@teaserRoutingBackgroundOption" + }, + { + type: "text", + validation: [ + { + name: "required", + message: + "Value is required." + } + ], + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Teaser title", + helpText: + "If empty, teaser title from relative linked page teaser content will be shown. Max. 70 characters recommended.", + fieldId: "title", + id: "teaserRoutingCardTitle", + storageId: + "text@teaserTitle", + settings: { + inputField: { + rows: 2 + } + } + }, + { + type: "text", + multipleValues: false, + renderer: { + name: "enhanced-text-input" + }, + label: "Text", + helpText: + "It's recommended to not exceed a length of 150 characters.", + fieldId: "text", + id: "teaserRoutingCardText", + storageId: + "text@teaserText", + settings: { + inputField: { + rows: 5 + } + } + }, + { + type: "text", + renderer: { + name: "text-input" + }, + validation: [ + { + name: "required", + message: + "Value is required." + }, + { + name: "pattern", + settings: { + preset: "url" + }, + message: + "URL Format is required" + } + ], + label: "Link", + fieldId: "linkpicker", + id: "teaserRoutingCardLink", + helpText: + "If link is SmartCMS internal, create link relative via to avoid 404 errors", + storageId: + "text@teaserRoutingCardLink" + }, + { + type: "text", + validation: [], + renderer: { + name: "text-input" + }, + label: "FragmentUUID", + helpText: + "The technical ID of this element.", + fieldId: "uuid", + id: "teaserRoutingCardUuid", + storageId: + "text@teaserRoutingCardUuid" + } + ], + layout: [ + ["teaserRoutingCardMedia"], + [ + "teaserRoutingCardBackgroundOption" + ], + ["teaserRoutingCardTitle"], + ["teaserRoutingCardText"], + ["teaserRoutingCardLink"], + ["teaserRoutingCardUuid"] + ] + } + ] + }, + label: "Teaser Card", + helpText: + "Select one or more of the allowed elements or fragments. Be aware the title of the elements isn’t delivered live.", + fieldId: "teaserRoutingCards", + id: "teaserRoutingCards", + storageId: "text@teaserRoutingCards" + } + ], + layout: [ + ["teaserRoutingTitle"], + ["teaserRoutingLayout", "teaserRoutingVariation"], + ["teaserRoutingCards"], + ["teaserRoutingUuid"] + ] + } + ] + }, + storageId: "dynamicZone@mainZone" + } + ], + layout: [["introZone"], ["mainZone"]] + }, + { + name: "Press Release", + gqlTypeName: "PressReleasePageTemplate", + icon: "fas/camera", + description: "Press Release Page", + id: "pressReleasePageTemplate", + fields: [], + layout: [] + } + ] + }, + predefinedValues: { + enabled: false, + values: [] + }, + storageId: "dynamicZone@pageTemplate" + } + ] +}); diff --git a/packages/api-headless-cms/__tests__/contentTraverser/mocks/richTextValue.ts b/packages/api-headless-cms/__tests__/contentTraverser/mocks/richTextValue.ts deleted file mode 100644 index b43d6f0e278..00000000000 --- a/packages/api-headless-cms/__tests__/contentTraverser/mocks/richTextValue.ts +++ /dev/null @@ -1,275 +0,0 @@ -export const richTextValue = { - root: { - children: [ - { - children: [ - { - detail: 0, - format: 0, - mode: "normal", - style: "", - text: "Test CMS Title", - type: "text", - version: 1 - } - ], - direction: "ltr", - format: "", - indent: 0, - type: "heading-element", - version: 1, - tag: "h1", - styles: [ - { - styleId: "heading1", - type: "typography" - } - ] - }, - { - children: [], - direction: "ltr", - format: "", - indent: 0, - type: "paragraph-element", - version: 1, - styles: [ - { - styleId: "paragraph1", - type: "typography" - } - ] - }, - { - children: [ - { - detail: 0, - format: 0, - mode: "normal", - style: "", - text: "Testing a ", - type: "text", - version: 1 - }, - { - children: [ - { - detail: 0, - format: 0, - mode: "normal", - style: "", - text: "link", - type: "text", - version: 1 - } - ], - direction: "ltr", - format: "", - indent: 0, - type: "link", - version: 1, - rel: "noreferrer", - target: null, - title: null, - url: "https://space.com" - }, - { - detail: 0, - format: 0, - mode: "normal", - style: "", - text: " for parsing", - type: "text", - version: 1 - } - ], - direction: "ltr", - format: "", - indent: 0, - type: "paragraph-element", - version: 1, - styles: [ - { - styleId: "paragraph1", - type: "typography" - } - ] - }, - { - children: [ - { - detail: 0, - format: 0, - mode: "normal", - style: "", - text: "Test CMS Paragraph", - type: "text", - version: 1 - } - ], - direction: "ltr", - format: "", - indent: 0, - type: "paragraph-element", - version: 1, - styles: [ - { - styleId: "paragraph1", - type: "typography" - } - ] - }, - { - children: [], - direction: "ltr", - format: "", - indent: 0, - type: "paragraph-element", - version: 1, - styles: [ - { - styleId: "paragraph1", - type: "typography" - } - ] - }, - { - children: [ - { - detail: 0, - format: 0, - mode: "normal", - style: "", - text: "Test quote from lexical ", - type: "text", - version: 1 - }, - { - detail: 0, - format: 1, - mode: "normal", - style: "", - text: "CMS", - type: "text", - version: 1 - } - ], - direction: "ltr", - format: "", - indent: 0, - type: "webiny-quote", - version: 1, - styles: [ - { - styleId: "quote", - type: "typography" - } - ], - styleId: "quote" - }, - { - children: [], - direction: "ltr", - format: "", - indent: 0, - type: "paragraph-element", - version: 1, - styles: [ - { - styleId: "paragraph1", - type: "typography" - } - ] - }, - { - children: [ - { - children: [ - { - detail: 0, - format: 0, - mode: "normal", - style: "", - text: "List item 1", - type: "text", - version: 1 - } - ], - direction: "ltr", - format: "", - indent: 0, - type: "webiny-listitem", - version: 1, - value: 1 - }, - { - children: [ - { - detail: 0, - format: 0, - mode: "normal", - style: "", - text: "List item 2", - type: "text", - version: 1 - } - ], - direction: "ltr", - format: "", - indent: 0, - type: "webiny-listitem", - version: 1, - value: 2 - }, - { - children: [ - { - detail: 0, - format: 0, - mode: "normal", - style: "", - text: "List item 3", - type: "text", - version: 1 - } - ], - direction: "ltr", - format: "", - indent: 0, - type: "webiny-listitem", - version: 1, - value: 3 - } - ], - direction: "ltr", - format: "", - indent: 0, - type: "webiny-list", - version: 1, - themeStyleId: "list", - listType: "bullet", - start: 1, - tag: "ul" - }, - { - children: [], - direction: null, - format: "", - indent: 0, - type: "paragraph-element", - version: 1, - styles: [ - { - styleId: "paragraph1", - type: "typography" - } - ] - } - ], - direction: "ltr", - format: "", - indent: 0, - type: "root", - version: 1 - } -}; diff --git a/packages/api-headless-cms/__tests__/contentTraverser/modelAst.test.ts b/packages/api-headless-cms/__tests__/contentTraverser/modelAst.test.ts index ddc70fffd4b..a7947af3f1e 100644 --- a/packages/api-headless-cms/__tests__/contentTraverser/modelAst.test.ts +++ b/packages/api-headless-cms/__tests__/contentTraverser/modelAst.test.ts @@ -78,7 +78,7 @@ describe("Model to AST", () => { type: "dynamicZone", label: "Content", multipleValues: true, - settings: {} + settings: expect.toBeObject() }, children: [ { @@ -145,7 +145,7 @@ describe("Model to AST", () => { fieldId: "settings", label: "Settings", type: "object", - settings: {} + settings: expect.toBeObject() }, children: [ { @@ -166,7 +166,7 @@ describe("Model to AST", () => { type: "object", label: "SEO", multipleValues: true, - settings: {} + settings: expect.toBeObject() }, children: [ { @@ -190,7 +190,7 @@ describe("Model to AST", () => { fieldId: "dynamicZone", label: "DynamicZone", type: "dynamicZone", - settings: {} + settings: expect.toBeObject() }, children: [ { @@ -233,7 +233,7 @@ describe("Model to AST", () => { fieldId: "emptyDynamicZone", label: "DynamicZone", type: "dynamicZone", - settings: {} + settings: expect.toBeObject() }, children: [] } diff --git a/packages/api-headless-cms/__tests__/contentTraverser/traverser.test.ts b/packages/api-headless-cms/__tests__/contentTraverser/traverser.test.ts index 9e69bc7b91f..7966e8ae077 100644 --- a/packages/api-headless-cms/__tests__/contentTraverser/traverser.test.ts +++ b/packages/api-headless-cms/__tests__/contentTraverser/traverser.test.ts @@ -1,13 +1,12 @@ import { useHandler } from "~tests/testHelpers/useHandler"; import { CmsModelPlugin } from "~/plugins"; -import { articleModel } from "./mocks/article.model"; -import { articleEntry } from "./mocks/article.entry"; -import { richTextValue } from "~tests/contentTraverser/mocks/richTextValue"; +import { pageModel } from "./mocks/page.model"; +import { pageEntry } from "./mocks/page.entry"; describe("Content Traverser", () => { it("should traverse model AST and build flat object with entry values", async () => { const { handler, tenant } = useHandler({ - plugins: [new CmsModelPlugin(articleModel)] + plugins: [new CmsModelPlugin(pageModel)] }); const context = await handler({ @@ -19,16 +18,16 @@ describe("Content Traverser", () => { } }); - const traverser = await context.cms.getEntryTraverser("article"); + const traverser = await context.cms.getEntryTraverser("page"); const output: Record = {}; const skipFieldTypes = ["object", "dynamicZone"]; - traverser.traverse(articleEntry, ({ field, value, path }) => { + await traverser.traverse(pageEntry.values, ({ field, value, path }) => { /** * Most of the time you won't care about complex fields like "object" and "dynamicZone", but only their child fields. - * The traverser will still go into the child fields, but this way you can + * The traverser will still go into the child fields, but this way you can control which fields you want to process. */ if (skipFieldTypes.includes(field.type)) { return; @@ -38,13 +37,208 @@ describe("Content Traverser", () => { }); expect(output).toEqual({ - title: "Article #1", - body: richTextValue, - categories: [{ modelId: "category", entryId: "12345678" }], - "content.0.title": "Hero #1", - "content.1.settings.title": "Title", - "content.1.settings.seo.0.title": "title-0", - "content.1.settings.seo.1.title": "title-1" + pageTitle: "From the Playground", + pageType: "BasicPageTemplate", + "pageSettings.generalPageSettings.pageSlug": "from-the-playground", + "pageSettings.generalPageSettings.deliveryDomain": "acme.com", + "pageSettings.generalPageSettings.layout": "dark", + "pageSettings.generalPageSettings.pageClass": null, + "pageSettings.generalPageSettings.pageCategory": null, + "pageSettings.generalPageSettings.redirectUrl": null, + "pageSettings.generalPageSettings.browserTabTitle": "John was here", + "pageSettings.generalPageSettings.description": "the description", + "pageSettings.generalPageSettings.customCanonicalUrl": null, + "pageSettings.generalPageSettings.contentOwner": "ulf@acme.com", + "pageSettings.generalPageSettings.organisation": "acme", + "pageSettings.generalPageSettings.navTitle": null, + "pageSettings.generalPageSettings.hideInNavigation": false, + "pageSettings.generalPageSettings.hideInBreadcrumb": false, + "pageSettings.generalPageSettings.noFollow": "inherited", + "pageSettings.generalPageSettings.noIndex": "inherited", + "pageSettings.generalPageSettings.publishTime": null, + "pageSettings.generalPageSettings.unPublishTime": null, + "pageSettings.generalPageSettings.headerContactLink": null, + "pageSettings.generalPageSettings.copyRightText": null, + "pageSettings.generalPageSettings.inheritFooterLinks": null, + "pageSettings.generalPageSettings.inheritSocialMediaLinks": null, + "pageSettings.generalPageSettings.uuid": "acme:Ma3wHp4Vb1n", + "pageSettings.pageTeaserSettings.pageTeaserMedia.file": null, + "pageSettings.pageTeaserSettings.pageTeaserMedia.altText": null, + "pageSettings.pageTeaserSettings.pageTeaserMedia.seoName": null, + "pageSettings.pageTeaserSettings.pageTeaserMedia.crop": null, + "pageSettings.pageTeaserSettings.pageTeaserTitle": null, + "pageSettings.pageTeaserSettings.pageTeaserText": "", + "pageSettings.pageTeaserSettings.pageTeaserSocialMediaTitle": null, + "pageSettings.pageTeaserSettings.pageTeaserSocialMediaText": "", + "pageSettings.pageTeaserSettings.pageTeaserFakePublishDate": null, + "pageSettings.pageTeaserSettings.pageTeaserExpiryDate": null, + "pageSettings.pageTeaserSettings.pageTeaserFilterTags": null, + "pageSettings.pageTeaserSettings.pageTeaserVisualTag1": null, + "pageSettings.pageTeaserSettings.pageTeaserVisualTag2": null, + "pageSettings.pageTeaserSettings.pageTeaserEventLocation": null, + "pageSettings.pageTeaserSettings.pageTeaserEventStartDate": null, + "pageSettings.pageTeaserSettings.pageTeaserEventEndDate": null, + "pageTemplate.introZone.0.layout": "imageLeft", + "pageTemplate.introZone.0.title.title": "my playground", + "pageTemplate.introZone.0.title.headingRank": null, + "pageTemplate.introZone.0.stageText": { + root: { + format: null, + type: "root", + children: [ + { + children: [ + { + mode: "normal", + format: 0, + style: null, + detail: 0, + text: "Hello Here is some text", + type: "text", + version: 1 + } + ], + indent: 0, + format: null, + styles: [ + { + type: "typography", + styleId: "paragraph1" + } + ], + type: "paragraph-element", + version: 1, + direction: "ltr" + } + ], + indent: 0, + version: 1, + direction: "ltr" + } + }, + "pageTemplate.introZone.0.button.buttonText": "Click me", + "pageTemplate.introZone.0.button.linkpicker": "https://www.acme.com", + "pageTemplate.introZone.0.stageMedia.file": + "https://acme.com/assets/api/uuid:52e1aa7b-9f0d-4437-80e8-910e7a34e2b6/width:1036/image_small.jpeg", + "pageTemplate.introZone.0.stageMedia.altText": "Heat map of the world", + "pageTemplate.introZone.0.stageMedia.seoName": "seo name", + "pageTemplate.introZone.0.stageMedia.crop": "0.1248:0:0.7503:1", + "pageTemplate.introZone.0.uuid": "acme:playGroundXYZ", + "pageTemplate.mainZone.0.title.title": "my Quote", + "pageTemplate.mainZone.0.title.headingRank": null, + "pageTemplate.mainZone.0.layout": "imageRight", + "pageTemplate.mainZone.0.focusOn": "image", + "pageTemplate.mainZone.0.quoteMedia.file": + "https://acme.com/assets/api/uuid:4ae336d1-19c3-4ac4-b755-0cc25644eac4/no-text_original.png", + "pageTemplate.mainZone.0.quoteMedia.altText": "alt", + "pageTemplate.mainZone.0.quoteMedia.seoName": "seo-name", + "pageTemplate.mainZone.0.quoteText": "so what", + "pageTemplate.mainZone.0.quoteSource": "John", + "pageTemplate.mainZone.0.uuid": "acme:098MyQuote77", + "pageTemplate.mainZone.1.layout": "imageRight", + "pageTemplate.mainZone.1.uuid": "acme:ttJcRRPR0JP", + "pageTemplate.mainZone.1.title.title": "my MRT", + "pageTemplate.mainZone.1.title.headingRank": "h3", + "pageTemplate.mainZone.1.subtitle": "The MRT subtitle", + "pageTemplate.mainZone.1.text": { + root: { + format: null, + type: "root", + children: [ + { + children: [ + { + mode: "normal", + format: 0, + style: null, + detail: 0, + text: "some nice words", + type: "text", + version: 1 + } + ], + indent: 0, + format: null, + styles: [ + { + type: "typography", + styleId: "paragraph1" + } + ], + type: "paragraph-element", + version: 1, + direction: "ltr" + } + ], + indent: 0, + version: 1, + direction: "ltr" + } + }, + "pageTemplate.mainZone.1.mrtMedia.0.file": + "https://acme.com/assets/api/uuid:4ae336d1-19c3-4ac4-b755-0cc25644eac4/sf-no-text_original.png", + "pageTemplate.mainZone.1.mrtMedia.0.altText": "alternative text", + "pageTemplate.mainZone.1.mrtMedia.0.seoName": "seo-optimized-name", + "pageTemplate.mainZone.1.mrtMedia.0.caption": "Hä? ", + "pageTemplate.mainZone.1.mrtMedia.0.captionLink": "caption Link ", + "pageTemplate.mainZone.1.mrtMedia.1.file": + "https://acme.com/assets/api/uuid:b3bddd2b-553a-483a-8bc1-20f02471ed1e/vegas-toureiffel_original.mp4", + "pageTemplate.mainZone.1.mrtMedia.1.altText": null, + "pageTemplate.mainZone.1.mrtMedia.1.caption": null, + "pageTemplate.mainZone.1.mrtMedia.1.captionLink": null, + "pageTemplate.mainZone.1.mrtMedia.1.seoName": null, + "pageTemplate.mainZone.1.button.buttonText": "Click me", + "pageTemplate.mainZone.1.button.linkpicker": "https://www.acme.com", + "pageTemplate.mainZone.1.linklist.0.text": "my first link ", + "pageTemplate.mainZone.1.linklist.0.linkpicker": "http://www.domain.com", + "pageTemplate.mainZone.2.layout": null, + "pageTemplate.mainZone.2.title.title": "CTR title", + "pageTemplate.mainZone.2.title.headingRank": null, + "pageTemplate.mainZone.2.contentTeaserRowCards.0.contentTeaserRowMediaMedia.file": + "https://acme.com/assets/api/uuid:fca831bb-373a-4b2c-91d3-c3284f16b613/width:1036/image_small.png", + "pageTemplate.mainZone.2.contentTeaserRowCards.0.contentTeaserRowMediaMedia.altText": + "asd", + "pageTemplate.mainZone.2.contentTeaserRowCards.0.contentTeaserRowMediaMedia.seoName": + "wdfb", + "pageTemplate.mainZone.2.contentTeaserRowCards.0.title.title": "inner teaser title", + "pageTemplate.mainZone.2.contentTeaserRowCards.0.title.headingRank": "h3", + "pageTemplate.mainZone.2.contentTeaserRowCards.0.text": { + root: { + format: null, + type: "root", + children: [ + { + children: [ + { + mode: "normal", + format: 0, + style: null, + detail: 0, + text: "with som etext ", + type: "text", + version: 1 + } + ], + indent: 0, + format: null, + styles: [ + { + type: "typography", + styleId: "paragraph1" + } + ], + type: "paragraph-element", + version: 1, + direction: "ltr" + } + ], + indent: 0, + version: 1, + direction: "ltr" + } + }, + "pageTemplate.mainZone.2.contentTeaserRowCards.0.uuid": "acme:hmAHkQsvr5q", + "pageTemplate.mainZone.2.uuid": "acme:LyEFKwkutww" }); }); }); diff --git a/packages/api-headless-cms/__tests__/plugins/storage/container.ts b/packages/api-headless-cms/__tests__/plugins/storage/container.ts index 3f364db5681..f3e7f780b9e 100644 --- a/packages/api-headless-cms/__tests__/plugins/storage/container.ts +++ b/packages/api-headless-cms/__tests__/plugins/storage/container.ts @@ -1,7 +1,6 @@ import { PluginsContainer } from "@webiny/plugins"; import { createDefaultStorageTransform } from "~/storage/default"; import { createObjectStorageTransform } from "~/storage/object"; -import { createDynamicZoneStorageTransform } from "~/graphqlFields/dynamicZone/dynamicZoneStorage"; import { StorageTransformPlugin } from "~/plugins"; const createCustomPlugin = () => { @@ -22,7 +21,6 @@ export const createStoragePluginsContainer = () => { return new PluginsContainer([ createDefaultStorageTransform(), createObjectStorageTransform(), - createDynamicZoneStorageTransform(), createCustomPlugin() ]); }; diff --git a/packages/api-headless-cms/src/crud/contentEntry/referenceFieldsMapping.ts b/packages/api-headless-cms/src/crud/contentEntry/referenceFieldsMapping.ts index ae2be9fc2d8..17fa9a78d72 100644 --- a/packages/api-headless-cms/src/crud/contentEntry/referenceFieldsMapping.ts +++ b/packages/api-headless-cms/src/crud/contentEntry/referenceFieldsMapping.ts @@ -84,20 +84,15 @@ const buildReferenceFieldPaths = (params: BuildReferenceFieldPaths): string[] => } values.forEach((value, index) => { - const valueTemplate = Object.keys(value)[0]; - const template = templates.find(tpl => tpl.gqlTypeName === valueTemplate); + const template = templates.find(tpl => tpl.id === value["_templateId"]); if (!template) { return; } const result = buildReferenceFieldPaths({ fields: template.fields, - input: value[valueTemplate], - parentPaths: parentPaths.concat([ - field.fieldId, - String(index), - template.gqlTypeName - ]) + input: value, + parentPaths: parentPaths.concat([field.fieldId, String(index)]) }); collection.push(...result); @@ -111,8 +106,8 @@ const buildReferenceFieldPaths = (params: BuildReferenceFieldPaths): string[] => return collection; } - const valueTemplate = Object.keys(value)[0]; - const template = templates.find(tpl => tpl.gqlTypeName === valueTemplate); + // @ts-expect-error We're sure that a template value contains a _templateId property. + const template = templates.find(tpl => tpl.id === value["_templateId"]); if (!template) { return collection; @@ -120,8 +115,8 @@ const buildReferenceFieldPaths = (params: BuildReferenceFieldPaths): string[] => const result = buildReferenceFieldPaths({ fields: template.fields, - input: dotProp.get(value, valueTemplate, {}), - parentPaths: parentPaths.concat([field.fieldId, template.gqlTypeName]) + input: value ?? {}, + parentPaths: parentPaths.concat([field.fieldId]) }); collection.push(...result); diff --git a/packages/api-headless-cms/src/crud/contentModel/fields/descriptionField.ts b/packages/api-headless-cms/src/crud/contentModel/fields/descriptionField.ts index 387771930f4..980ebffb9c6 100644 --- a/packages/api-headless-cms/src/crud/contentModel/fields/descriptionField.ts +++ b/packages/api-headless-cms/src/crud/contentModel/fields/descriptionField.ts @@ -1,50 +1,29 @@ import { CmsModelField } from "~/types"; import { getBaseFieldType } from "~/utils/getBaseFieldType"; -import WebinyError from "@webiny/error"; +import { getApplicableFieldById } from "./getApplicableFieldById"; +const isFieldApplicable = (field: CmsModelField) => { + return getBaseFieldType(field) === "long-text" && !field.multipleValues; +}; + +/** + * Try finding the requested field, and return its `fieldId`. + * If not defined, or not applicable, fall back to the first applicable field. + */ export const getContentModelDescriptionFieldId = ( fields: CmsModelField[], descriptionFieldId?: string | null -): string | null | undefined => { - /** - * If there are no fields defined, we will just set as null. - */ +) => { if (fields.length === 0) { return null; } - /** - * If description field is not defined, let us find possible one. - */ - if (!descriptionFieldId) { - const descriptionField = fields.find(field => { - return getBaseFieldType(field) === "long-text" && !field.multipleValues; - }); - return descriptionField?.fieldId || null; - } - const target = fields.find( - field => field.fieldId === descriptionFieldId && getBaseFieldType(field) === "long-text" - ); - if (!target) { - throw new WebinyError( - `Field selected for the description field does not exist in the model.`, - "VALIDATION_ERROR", - { - fieldId: descriptionFieldId, - fields - } - ); - } - if (target.multipleValues) { - throw new WebinyError( - `Fields that accept multiple values cannot be used as the entry description.`, - "ENTRY_TITLE_FIELD_TYPE", - { - storageId: target.storageId, - fieldId: target.fieldId, - type: target.type - } - ); + + const target = getApplicableFieldById(fields, descriptionFieldId, isFieldApplicable); + + if (target) { + return target.fieldId; } - return target.fieldId; + const descriptionField = fields.find(isFieldApplicable); + return descriptionField ? descriptionField.fieldId : null; }; diff --git a/packages/api-headless-cms/src/crud/contentModel/fields/getApplicableFieldById.ts b/packages/api-headless-cms/src/crud/contentModel/fields/getApplicableFieldById.ts new file mode 100644 index 00000000000..6f54ec22d58 --- /dev/null +++ b/packages/api-headless-cms/src/crud/contentModel/fields/getApplicableFieldById.ts @@ -0,0 +1,13 @@ +import { CmsModelField } from "~/types"; + +export const getApplicableFieldById = ( + fields: CmsModelField[], + id: string | null | undefined, + isApplicable: (field: CmsModelField) => boolean +) => { + if (!id) { + return undefined; + } + + return fields.find(field => field.fieldId === id && isApplicable(field)); +}; diff --git a/packages/api-headless-cms/src/crud/contentModel/fields/imageField.ts b/packages/api-headless-cms/src/crud/contentModel/fields/imageField.ts index f35bcdea2ec..f8dfa576cf9 100644 --- a/packages/api-headless-cms/src/crud/contentModel/fields/imageField.ts +++ b/packages/api-headless-cms/src/crud/contentModel/fields/imageField.ts @@ -1,57 +1,27 @@ import { CmsModelField } from "~/types"; import { getBaseFieldType } from "~/utils/getBaseFieldType"; -import WebinyError from "@webiny/error"; +import { getApplicableFieldById } from "./getApplicableFieldById"; + +const isFieldApplicable = (field: CmsModelField) => { + return Boolean( + getBaseFieldType(field) === "file" && !field.multipleValues && field.settings?.imagesOnly + ); +}; export const getContentModelImageFieldId = ( fields: CmsModelField[], imageFieldId?: string | null -): string | null | undefined => { - /** - * If there are no fields defined, we will just set as null. - */ +) => { if (fields.length === 0) { return null; } - /** - * If image field is not defined, let us find possible one. - */ - if (!imageFieldId) { - const imageField = fields.find(field => { - return ( - getBaseFieldType(field) === "file" && - !field.multipleValues && - field.settings?.imagesOnly - ); - }); - return imageField?.fieldId || null; - } - const target = fields.find( - field => - field.fieldId === imageFieldId && - getBaseFieldType(field) === "file" && - field.settings?.imagesOnly - ); - if (!target) { - throw new WebinyError( - `Field selected for the image field does not exist in the model.`, - "VALIDATION_ERROR", - { - fieldId: imageFieldId, - fields - } - ); - } - if (target.multipleValues) { - throw new WebinyError( - `Fields that accept multiple values cannot be used as the entry image.`, - "ENTRY_TITLE_FIELD_TYPE", - { - storageId: target.storageId, - fieldId: target.fieldId, - type: target.type - } - ); + + const target = getApplicableFieldById(fields, imageFieldId, isFieldApplicable); + + if (target) { + return target.fieldId; } - return target.fieldId; + const imageField = fields.find(isFieldApplicable); + return imageField ? imageField.fieldId : null; }; diff --git a/packages/api-headless-cms/src/crud/contentModel/fields/titleField.ts b/packages/api-headless-cms/src/crud/contentModel/fields/titleField.ts index 20b33acb1fc..30fc63f28b9 100644 --- a/packages/api-headless-cms/src/crud/contentModel/fields/titleField.ts +++ b/packages/api-headless-cms/src/crud/contentModel/fields/titleField.ts @@ -1,74 +1,31 @@ import { CmsModelField } from "~/types"; import { getBaseFieldType } from "~/utils/getBaseFieldType"; -import WebinyError from "@webiny/error"; +import { getApplicableFieldById } from "~/crud/contentModel/fields/getApplicableFieldById"; const defaultTitleFieldId = "id"; -const allowedTitleFieldTypes = ["text", "number"]; +const isFieldApplicable = (field: CmsModelField) => { + return getBaseFieldType(field) === "text" && !field.multipleValues; +}; +/** + * Try finding the requested field, and return its `fieldId`. + * If not defined, or not applicable, fall back to the first applicable field. + */ export const getContentModelTitleFieldId = ( fields: CmsModelField[], - titleFieldId?: string -): string => { - /** - * If there are no fields defined, we will return the default field - */ + titleFieldId?: string | null +) => { if (fields.length === 0) { return defaultTitleFieldId; } - /** - * if there is no title field defined either in input data or existing content model data - * we will take first text field that has no multiple values enabled - * or if initial titleFieldId is the default one also try to find first available text field - */ - if (!titleFieldId || titleFieldId === defaultTitleFieldId) { - const titleField = fields.find(field => { - return getBaseFieldType(field) === "text" && !field.multipleValues; - }); - return titleField?.fieldId || defaultTitleFieldId; - } - /** - * check existing titleFieldId for existence in the model - * for correct type - * and that it is not multiple values field - */ - const target = fields.find(f => f.fieldId === titleFieldId); - if (!target) { - throw new WebinyError( - `Field selected for the title field does not exist in the model.`, - "VALIDATION_ERROR", - { - fieldId: titleFieldId, - fields - } - ); - } - if (allowedTitleFieldTypes.includes(target.type) === false) { - throw new WebinyError( - `Only ${allowedTitleFieldTypes.join( - ", " - )} and id fields can be used as an entry title.`, - "ENTRY_TITLE_FIELD_TYPE", - { - storageId: target.storageId, - fieldId: target.fieldId, - type: target.type - } - ); - } + const target = getApplicableFieldById(fields, titleFieldId, isFieldApplicable); - if (target.multipleValues) { - throw new WebinyError( - `Fields that accept multiple values cannot be used as the entry title.`, - "ENTRY_TITLE_FIELD_TYPE", - { - storageId: target.storageId, - fieldId: target.fieldId, - type: target.type - } - ); + if (target) { + return target.fieldId; } - return target.fieldId; + const textField = fields.find(isFieldApplicable); + return textField ? textField.fieldId : defaultTitleFieldId; }; diff --git a/packages/api-headless-cms/src/crud/contentModel/validation.ts b/packages/api-headless-cms/src/crud/contentModel/validation.ts index 817ca4c09c1..dc7a72d5c1b 100644 --- a/packages/api-headless-cms/src/crud/contentModel/validation.ts +++ b/packages/api-headless-cms/src/crud/contentModel/validation.ts @@ -4,18 +4,38 @@ import camelCase from "lodash/camelCase"; const fieldSystemFields: string[] = [ "id", - "fieldId", - "storageId", - "label", - "helpText", - "placeholderText", - "type", - "multipleValues", - "predefinedValues", - "renderer", - "validation", - "listValidation", - "settings" + "entryId", + "createdOn", + "modifiedOn", + "publishedOn", + "savedOn", + "deletedOn", + "restoredOn", + "firstPublishedOn", + "lastPublishedOn", + "createdBy", + "modifiedBy", + "savedBy", + "deletedBy", + "restoredBy", + "firstPublishedBy", + "lastPublishedBy", + "revisionCreatedOn", + "revisionModifiedOn", + "revisionSavedOn", + "revisionDeletedOn", + "revisionRestoredOn", + "revisionFirstPublishedOn", + "revisionLastPublishedOn", + "revisionCreatedBy", + "revisionModifiedBy", + "revisionSavedBy", + "revisionDeletedBy", + "revisionRestoredBy", + "revisionFirstPublishedBy", + "revisionLastPublishedBy", + "meta", + "wbyAco_location" ]; const str = zod.string().trim(); @@ -43,8 +63,7 @@ const fieldSchema = zod.object({ if (fieldSystemFields.includes(value)) { return ctx.addIssue({ code: zod.ZodIssueCode.custom, - message: `Provided ${value} is not valid - "${value}" is an auto-generated field.`, - path: ["fieldId"] + message: `Field ID "${value}" is a reserved keyword, and is not allowed.` }); } }), @@ -82,7 +101,7 @@ const fieldSchema = zod.object({ renderer: zod .object({ name: shortString, - settings: zod.object({}).passthrough().optional() + settings: zod.object({}).passthrough().nullish().optional() }) .optional() .nullable() diff --git a/packages/api-headless-cms/src/fieldConverters/CmsModelDynamicZoneFieldConverterPlugin.ts b/packages/api-headless-cms/src/fieldConverters/CmsModelDynamicZoneFieldConverterPlugin.ts index 1b2a474cb52..2e74d384a09 100644 --- a/packages/api-headless-cms/src/fieldConverters/CmsModelDynamicZoneFieldConverterPlugin.ts +++ b/packages/api-headless-cms/src/fieldConverters/CmsModelDynamicZoneFieldConverterPlugin.ts @@ -39,27 +39,25 @@ export class CmsModelDynamicZoneFieldConverterPlugin extends CmsModelFieldConver } if (field.multipleValues) { - const arrayValue = Array.isArray(value) ? value : []; + if (Array.isArray(value)) { + return { + [field.storageId]: value.map(item => { + return this.processToStorage({ + templates, + converterCollection, + value: item + }); + }) + }; + } - return { - [field.storageId]: arrayValue.map(item => { - return this.processToStorage({ - templates, - converterCollection, - value: item - }); - }) - }; + // If a multi-value dynamic zone receives anything other than an array, ignore the value. + return {}; } + + // If a single-value dynamic zone receives an array, ignore the value. if (Array.isArray(value)) { - throw new WebinyError( - `Dynamic zone field "${field.fieldId}" is expecting a non-array value.`, - "DYNAMIC_ZONE_EXPECTING_NON_ARRAY_VALUE", - { - field, - value - } - ); + return {}; } const processedValue = this.processToStorage({ @@ -67,6 +65,7 @@ export class CmsModelDynamicZoneFieldConverterPlugin extends CmsModelFieldConver converterCollection, value }); + return { [field.storageId]: processedValue }; @@ -74,56 +73,18 @@ export class CmsModelDynamicZoneFieldConverterPlugin extends CmsModelFieldConver private processToStorage(params: ProcessValue) { const { templates, converterCollection } = params; - let { value } = params; + const { value } = params; if (value === null || value === undefined) { return undefined; } - /** - * There are two ways converter needs to work: - * 1. when there is a _templateId - * 2. when there is a key which identifies which template is the data for - */ - - /** - * When we have a template key, everything is simple. - */ + const templateId = value._templateId; - let graphQlName: string | undefined = undefined; - let template: CmsDynamicZoneTemplate | undefined = undefined; - if (templateId) { - template = templates.find(t => { - return templateId === t.id; - }); - } - /** - * When we do not have a templateId, then the template identifier is the key of the value object. - * But at that point, values under that key become the value we are working with later on. - */ - // - else { - const keys = Object.keys(value); - if (keys.length === 0) { - return undefined; - } else if (keys.length > 1) { - throw new WebinyError( - "There cannot be more than one dynamic zone template in a single dynamic zone field.", - "DYNAMIC_ZONE_TOO_MANY_TEMPLATES", - { - templates: keys - } - ); - } - graphQlName = keys[0] as string; - template = templates.find(t => t.gqlTypeName === graphQlName); - } + const template = templates.find(t => { + return templateId === t.id; + }); if (!template) { - throw new WebinyError("Unknown template - converting to storage.", "UNKNOWN_TEMPLATE", { - templateId, - graphQlName - }); - } else if (graphQlName) { - value = value[graphQlName]; + return undefined; } return template.fields.reduce>( @@ -166,6 +127,7 @@ export class CmsModelDynamicZoneFieldConverterPlugin extends CmsModelFieldConver }) }; } + if (Array.isArray(value)) { throw new WebinyError( `Dynamic zone field "${field.fieldId}" is expecting a non-array value.`, @@ -182,6 +144,7 @@ export class CmsModelDynamicZoneFieldConverterPlugin extends CmsModelFieldConver converterCollection, value }); + return { [field.fieldId]: processedValue }; diff --git a/packages/api-headless-cms/src/graphql/schema/createManageResolvers.ts b/packages/api-headless-cms/src/graphql/schema/createManageResolvers.ts index d4f51f7cd0f..9a603a17f3b 100644 --- a/packages/api-headless-cms/src/graphql/schema/createManageResolvers.ts +++ b/packages/api-headless-cms/src/graphql/schema/createManageResolvers.ts @@ -15,6 +15,7 @@ import { resolvePublish } from "./resolvers/manage/resolvePublish"; import { resolveRepublish } from "./resolvers/manage/resolveRepublish"; import { resolveUnpublish } from "./resolvers/manage/resolveUnpublish"; import { resolveCreateFrom } from "./resolvers/manage/resolveCreateFrom"; +import { normalizeGraphQlInput } from "./resolvers/manage/normalizeGraphQlInput"; import { createFieldResolversFactory } from "./createFieldResolvers"; import { getEntryTitle } from "~/utils/getEntryTitle"; import { getEntryImage } from "~/utils/getEntryImage"; @@ -69,26 +70,32 @@ export const createManageResolvers: CreateManageResolvers = ({ } }); + const resolverFactoryParams = { model, fieldTypePlugins }; + return { Query: { - [`get${model.singularApiName}`]: resolveGet({ model }), - [`get${model.singularApiName}Revisions`]: resolveGetRevisions({ model }), - [`get${model.pluralApiName}ByIds`]: resolveGetByIds({ model }), - [`list${model.pluralApiName}`]: resolveList({ model }), - [`listDeleted${model.pluralApiName}`]: resolveListDeleted({ model }) + [`get${model.singularApiName}`]: resolveGet(resolverFactoryParams), + [`get${model.singularApiName}Revisions`]: resolveGetRevisions(resolverFactoryParams), + [`get${model.pluralApiName}ByIds`]: resolveGetByIds(resolverFactoryParams), + [`list${model.pluralApiName}`]: resolveList(resolverFactoryParams), + [`listDeleted${model.pluralApiName}`]: resolveListDeleted(resolverFactoryParams) }, Mutation: { - [`create${model.singularApiName}`]: resolveCreate({ model }), - [`update${model.singularApiName}`]: resolveUpdate({ model }), - [`validate${model.singularApiName}`]: resolveValidate({ model }), - [`move${model.singularApiName}`]: resolveMove({ model }), - [`delete${model.singularApiName}`]: resolveDelete({ model }), - [`restore${model.singularApiName}FromBin`]: resolveRestoreFromBin({ model }), - [`deleteMultiple${model.pluralApiName}`]: resolveDeleteMultiple({ model }), - [`publish${model.singularApiName}`]: resolvePublish({ model }), - [`republish${model.singularApiName}`]: resolveRepublish({ model }), - [`unpublish${model.singularApiName}`]: resolveUnpublish({ model }), - [`create${model.singularApiName}From`]: resolveCreateFrom({ model }) + [`create${model.singularApiName}`]: + normalizeGraphQlInput(resolveCreate)(resolverFactoryParams), + [`update${model.singularApiName}`]: + normalizeGraphQlInput(resolveUpdate)(resolverFactoryParams), + [`validate${model.singularApiName}`]: resolveValidate(resolverFactoryParams), + [`move${model.singularApiName}`]: resolveMove(resolverFactoryParams), + [`delete${model.singularApiName}`]: resolveDelete(resolverFactoryParams), + [`restore${model.singularApiName}FromBin`]: + resolveRestoreFromBin(resolverFactoryParams), + [`deleteMultiple${model.pluralApiName}`]: resolveDeleteMultiple(resolverFactoryParams), + [`publish${model.singularApiName}`]: resolvePublish(resolverFactoryParams), + [`republish${model.singularApiName}`]: resolveRepublish(resolverFactoryParams), + [`unpublish${model.singularApiName}`]: resolveUnpublish(resolverFactoryParams), + [`create${model.singularApiName}From`]: + normalizeGraphQlInput(resolveCreateFrom)(resolverFactoryParams) }, ...fieldResolvers, [`${model.singularApiName}Meta`]: { diff --git a/packages/api-headless-cms/src/graphql/schema/createPreviewResolvers.ts b/packages/api-headless-cms/src/graphql/schema/createPreviewResolvers.ts index ebdcad626c8..bd9265107b0 100644 --- a/packages/api-headless-cms/src/graphql/schema/createPreviewResolvers.ts +++ b/packages/api-headless-cms/src/graphql/schema/createPreviewResolvers.ts @@ -41,8 +41,8 @@ export const createPreviewResolvers: CreateReadResolvers = ({ return { Query: { - [`get${model.singularApiName}`]: resolveGet({ model }), - [`list${model.pluralApiName}`]: resolveList({ model }) + [`get${model.singularApiName}`]: resolveGet({ model, fieldTypePlugins }), + [`list${model.pluralApiName}`]: resolveList({ model, fieldTypePlugins }) }, ...fieldResolvers }; diff --git a/packages/api-headless-cms/src/graphql/schema/createReadResolvers.ts b/packages/api-headless-cms/src/graphql/schema/createReadResolvers.ts index 356bd1a986f..a050aa9371a 100644 --- a/packages/api-headless-cms/src/graphql/schema/createReadResolvers.ts +++ b/packages/api-headless-cms/src/graphql/schema/createReadResolvers.ts @@ -37,8 +37,8 @@ export const createReadResolvers: CreateReadResolvers = ({ models, model, fieldT return { Query: { - [`get${model.singularApiName}`]: resolveGet({ model }), - [`list${model.pluralApiName}`]: resolveList({ model }) + [`get${model.singularApiName}`]: resolveGet({ model, fieldTypePlugins }), + [`list${model.pluralApiName}`]: resolveList({ model, fieldTypePlugins }) }, [model.singularApiName]: { modelId: () => { diff --git a/packages/api-headless-cms/src/graphql/schema/resolvers/manage/normalizeGraphQlInput.ts b/packages/api-headless-cms/src/graphql/schema/resolvers/manage/normalizeGraphQlInput.ts new file mode 100644 index 00000000000..be0cdeeb3cd --- /dev/null +++ b/packages/api-headless-cms/src/graphql/schema/resolvers/manage/normalizeGraphQlInput.ts @@ -0,0 +1,60 @@ +import set from "lodash/set"; +import { GenericRecord } from "@webiny/api/types"; +import { CmsEntryResolverFactory, CmsFieldTypePlugins, CmsModel } from "~/types"; +import { ContentEntryTraverser } from "~/utils/contentEntryTraverser/ContentEntryTraverser"; + +/** + * This decorates a resolver factory, and normalizes `args.data`. + * This is necessary to separate GraphQL related hacks (like lack of support for union input type) + * from our own programmatic API. We want the input into our domain logic to be free of GraphQL hacks. + */ +export const normalizeGraphQlInput = ( + resolverFactory: CmsEntryResolverFactory +): CmsEntryResolverFactory => { + return params => { + const resolver = resolverFactory(params); + + return async (parent, args, context, info) => { + const input = args.data; + + if (!input) { + return resolver(parent, args, context, info); + } + + const traverser = await context.cms.getEntryTraverser(params.model.modelId); + const normalizer = new GraphQlInputNormalizer(traverser, params.fieldTypePlugins); + const normalizedInput = await normalizer.normalize(params.model, input); + + return resolver(parent, { ...args, data: normalizedInput }, context, info); + }; + }; +}; + +class GraphQlInputNormalizer { + private readonly traverser: ContentEntryTraverser; + private readonly fieldTypePlugins: CmsFieldTypePlugins; + + constructor(traverser: ContentEntryTraverser, fieldTypePlugins: CmsFieldTypePlugins) { + this.traverser = traverser; + this.fieldTypePlugins = fieldTypePlugins; + } + + async normalize(model: CmsModel, data: GenericRecord) { + const output = structuredClone(data); + + await this.traverser.traverse(output, async ({ path, value, field }) => { + const fieldPlugin = this.fieldTypePlugins[field.type]; + if (fieldPlugin && typeof fieldPlugin.manage.normalizeInput === "function") { + const normalizedValue = await fieldPlugin.manage.normalizeInput({ + model, + field, + input: value + }); + + set(output, path, normalizedValue); + } + }); + + return output; + } +} diff --git a/packages/api-headless-cms/src/graphqlFields/dynamicZone/dynamicZoneField.ts b/packages/api-headless-cms/src/graphqlFields/dynamicZone/dynamicZoneField.ts index 48514291f6f..42c89efcd39 100644 --- a/packages/api-headless-cms/src/graphqlFields/dynamicZone/dynamicZoneField.ts +++ b/packages/api-headless-cms/src/graphqlFields/dynamicZone/dynamicZoneField.ts @@ -12,6 +12,7 @@ import { createTypeName } from "~/utils/createTypeName"; import { createTypeFromFields } from "~/utils/createTypeFromFields"; import { createGraphQLInputField } from "../helpers"; import { GraphQLFieldResolver } from "@webiny/handler-graphql/types"; +import { GenericRecord } from "@webiny/api/types"; const createUnionTypeName = (model: CmsModel, field: CmsModelField) => { return `${model.singularApiName}_${createTypeName(field.fieldId)}`; @@ -75,9 +76,7 @@ const createTypeDefsForTemplates = ({ }; const remapTemplateValue = (value: any, typeName: string) => { - const templateType = Object.keys(value)[0]; - - return { ...value[templateType], __typename: `${typeName}_${templateType}` }; + return { ...value, __typename: typeName }; }; const createResolver = ( @@ -93,21 +92,28 @@ const createResolver = ( const resolver = (parent: any) => { const value = parent[field.fieldId]; if (!value) { - return field.multipleValues ? [] : value; + return value; } const typeName = `${graphQLType}_${createTypeName(field.fieldId)}`; - // const typeName = `${model.singularApiName}_${createTypeName(field.fieldId)}`; if (field.multipleValues && Array.isArray(value)) { const remappedValues = value.map(v => { - return remapTemplateValue(v, typeName); + const template = templates.find(tpl => tpl.id === v._templateId); + if (!template) { + return undefined; + } + return remapTemplateValue(v, `${typeName}_${template.gqlTypeName}`); }); return remappedValues; } - return remapTemplateValue(value, typeName); + const template = templates.find(tpl => tpl.id === value._templateId); + if (!template) { + return undefined; + } + return remapTemplateValue(value, `${typeName}_${template.gqlTypeName}`); }; const { templateTypes } = createTypeDefsForTemplates({ @@ -175,14 +181,11 @@ export const createDynamicZoneField = } }, getFieldAst: (field, converter) => { - const { templates = [], ...settings } = field.settings; + const { templates = [] } = field.settings; return { type: "field", - field: { - ...field, - settings - }, + field, children: templates.map(({ fields, ...template }) => { return { type: "collection", @@ -307,7 +310,38 @@ export const createDynamicZoneField = typeDefs: typeDefs.join("\n") }; }, - createResolver: createResolver("manage") + createResolver: createResolver("manage"), + /** + * In `createInputField`, we generate an input type supported by GraphQL, to work around the + * limitation of not being able to have a union input type. That shape of data is only needed for GraphQL, + * so before passing that to our domain logic, we need to normalize it. + */ + normalizeInput: ({ field, input }) => { + const templates = field.settings?.templates || []; + + if (Array.isArray(input) && field.multipleValues) { + return input + .map(value => normalizeDynamicZoneInput(value, templates)) + .filter(Boolean); + } + + return normalizeDynamicZoneInput(input, templates); + } } }; }; + +const normalizeDynamicZoneInput = ( + value: GenericRecord, + templates: CmsDynamicZoneTemplate[] +) => { + // Only one key is allowed in the input object. + const inputType = Object.keys(value)[0]; + const template = templates.find(tpl => tpl.gqlTypeName === inputType); + + if (template) { + return { ...value[inputType], _templateId: template.id }; + } + + return undefined; +}; diff --git a/packages/api-headless-cms/src/graphqlFields/dynamicZone/dynamicZoneStorage.ts b/packages/api-headless-cms/src/graphqlFields/dynamicZone/dynamicZoneStorage.ts deleted file mode 100644 index 9da0a6a7036..00000000000 --- a/packages/api-headless-cms/src/graphqlFields/dynamicZone/dynamicZoneStorage.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { CmsDynamicZoneTemplate, CmsModelDynamicZoneField } from "~/types"; -import { StorageTransformPlugin } from "~/plugins"; - -function valueWithTemplateId( - value: Record, - { id, gqlTypeName }: CmsDynamicZoneTemplate -) { - return { [gqlTypeName]: { ...value[gqlTypeName], _templateId: id } }; -} - -const convertToStorage = (value: Record, templates: CmsDynamicZoneTemplate[]) => { - // Only one key is allowed in the input object. - const inputType = Object.keys(value)[0]; - const template = templates.find(tpl => tpl.gqlTypeName === inputType); - if (template) { - return { ...value[inputType], _templateId: template.id }; - } - /** - * There is a possibility that the value is already in the storage format, so there is no need to transform it again. - * We are going to check: - * 1. value is an object - * 2. it contains a _templateId key - * 3. the key is a valid template id - at this point we know it is already converted - */ - if (!value || typeof value !== "object") { - return undefined; - } else if (!value._templateId) { - return undefined; - } - const tpl = templates.find(tpl => tpl.id === value._templateId); - return tpl ? value : undefined; -}; - -interface TemplateValueFromStorage { - _templateId: string; - [key: string]: any; -} - -const convertFromStorage = ( - value: TemplateValueFromStorage, - templates: CmsDynamicZoneTemplate[] -) => { - const template = templates.find(tpl => value._templateId === tpl.id); - - if (template) { - // We keep the `_templateId` property, to simplify further processing. - return { [template.gqlTypeName]: value }; - } - - /** - * When the `value` is in the original input format (during GraphQL mutations), `_templateId` will not be present - * in the `value` object (because this internal property is added by `toStorage` storage transform method, and since - * we simply return the input from the CRUD methods, this property will be missing). - * For that reason, we need to run some extra logic, to acquire the `_templateId`. - */ - - if (!value || typeof value !== "object") { - return undefined; - } - - /** - * `value` object must have exactly one none-empty key. - */ - const keys = Object.keys(value); - if (keys.length !== 1 || !keys[0]) { - return undefined; - } - - /** - * Find a template that matches the first (and only) key of the `value` object by template's `gqlTypeName`. - */ - const tpl = templates.find(tpl => tpl.gqlTypeName === keys[0]); - return tpl ? valueWithTemplateId(value, tpl) : undefined; -}; - -export const createDynamicZoneStorageTransform = () => { - return new StorageTransformPlugin({ - fieldType: "dynamicZone", - fromStorage: async ({ value, field }) => { - if (!value) { - return null; - } - - const templates = field.settings.templates; - - if (Array.isArray(value) && field.multipleValues) { - return value.map(value => convertFromStorage(value, templates)).filter(Boolean); - } - - return convertFromStorage(value, templates); - }, - toStorage: async ({ value, field }) => { - if (!value) { - return value; - } - - const templates = field.settings.templates; - - if (Array.isArray(value) && field.multipleValues) { - return value.map(value => convertToStorage(value, templates)).filter(Boolean); - } - - return convertToStorage(value, templates); - } - }); -}; diff --git a/packages/api-headless-cms/src/graphqlFields/dynamicZone/index.ts b/packages/api-headless-cms/src/graphqlFields/dynamicZone/index.ts index a9d2fb0d2df..e6ca789a097 100644 --- a/packages/api-headless-cms/src/graphqlFields/dynamicZone/index.ts +++ b/packages/api-headless-cms/src/graphqlFields/dynamicZone/index.ts @@ -1,2 +1 @@ export { createDynamicZoneField } from "./dynamicZoneField"; -export { createDynamicZoneStorageTransform } from "./dynamicZoneStorage"; diff --git a/packages/api-headless-cms/src/index.ts b/packages/api-headless-cms/src/index.ts index 167abeb0df7..86f635b82ce 100644 --- a/packages/api-headless-cms/src/index.ts +++ b/packages/api-headless-cms/src/index.ts @@ -2,7 +2,6 @@ import { createGraphQL as baseCreateGraphQL, CreateGraphQLParams } from "~/graph import { createDefaultModelManager } from "~/modelManager"; import { createGraphQLFields } from "~/graphqlFields"; import { createValidators } from "~/validators"; -import { createDynamicZoneStorageTransform } from "~/graphqlFields/dynamicZone/dynamicZoneStorage"; import { createContextParameterPlugin, createHeaderParameterPlugin, @@ -22,6 +21,7 @@ import { createRevisionIdScalarPlugin } from "~/graphql/scalars/RevisionIdScalar export * from "./utils/isHeadlessCmsReady"; export * from "./utils/createModelField"; +export * from "./graphql/schema/resolvers/manage/normalizeGraphQlInput"; export type CreateHeadlessCmsGraphQLParams = CreateGraphQLParams; export const createHeadlessCmsGraphQL = (params: CreateHeadlessCmsGraphQLParams = {}) => { @@ -53,8 +53,7 @@ export const createHeadlessCmsContext = (params: ContentContextParams) => { createGraphQLFields(), createFieldConverters(), createValidators(), - ...createStorageTransform(), - createDynamicZoneStorageTransform() + ...createStorageTransform() ]; }; export * from "~/graphqlFields"; diff --git a/packages/api-headless-cms/src/types/model.ts b/packages/api-headless-cms/src/types/model.ts index 7ba3b0d6349..0c45f4300b6 100644 --- a/packages/api-headless-cms/src/types/model.ts +++ b/packages/api-headless-cms/src/types/model.ts @@ -91,18 +91,18 @@ export interface CmsModel { */ lockedFields?: LockedField[]; /** - * The field that is being displayed as entry title. - * It is picked as first available text field. Or user can select own field. + * The field that is used as an entry title. + * If not specified by the user, the system tries to assign the first available `text` field. */ titleFieldId: string; /** - * The field which is displayed as the description one. - * Only way this is null or undefined is that there are no long-text fields to be set as description. + * The field that is used as an entry description. + * If not set by the user, the system will try to assign the first available `long-text` field. */ descriptionFieldId?: string | null; /** - * The field which is displayed as the image. - * Only way this is null or undefined is that there are no file fields, with images only set, to be set as image. + * The field that is used as an entry image. + * If not set by the user, the system will try to assign a `file` field which has `imagesOnly` enabled. */ imageFieldId?: string | null; /** diff --git a/packages/api-headless-cms/src/types/modelAst.ts b/packages/api-headless-cms/src/types/modelAst.ts index b546782630d..1b967b5bfb5 100644 --- a/packages/api-headless-cms/src/types/modelAst.ts +++ b/packages/api-headless-cms/src/types/modelAst.ts @@ -44,5 +44,8 @@ export interface ContentEntryNodeContext { } export interface ContentEntryValueVisitor { - (params: ContentEntryNode, context: ContentEntryNodeContext): Promise | void; + (params: ContentEntryNode, context: ContentEntryNodeContext): + | Promise + | void + | unknown; } diff --git a/packages/api-headless-cms/src/types/modelField.ts b/packages/api-headless-cms/src/types/modelField.ts index 2d50ed84a5e..66bce079b23 100644 --- a/packages/api-headless-cms/src/types/modelField.ts +++ b/packages/api-headless-cms/src/types/modelField.ts @@ -1,4 +1,5 @@ import { CmsModel } from "./model"; +import { GenericRecord } from "@webiny/api/types"; export type CmsModelFieldType = | "boolean" @@ -258,7 +259,7 @@ interface CmsModelFieldRenderer { /** * Renderer settings allow you to configure field renderer on a field level. */ - settings?: Record; + settings?: GenericRecord | null; } /** @@ -272,7 +273,7 @@ export interface CmsModelFieldSettings { * Predefined values (text, number) * The default value for the field in case it is not predefined values field. */ - defaultValue?: string | number | null | undefined; + defaultValue?: string | boolean | number | null | undefined; /** * Object field has child fields. */ diff --git a/packages/api-headless-cms/src/types/plugins.ts b/packages/api-headless-cms/src/types/plugins.ts index f0fdba6899f..66b0888761d 100644 --- a/packages/api-headless-cms/src/types/plugins.ts +++ b/packages/api-headless-cms/src/types/plugins.ts @@ -5,6 +5,7 @@ import { CmsFieldTypePlugins, CmsModelFieldDefinition, CmsModelFieldToGraphQLCreateResolver, + CmsModelFieldToGraphQLNormalizeInputParams, CmsModelFieldToGraphQLPluginValidateChildFields, CmsModelFieldValidatorValidateParams } from "./types"; @@ -265,6 +266,9 @@ export interface CmsModelFieldToGraphQLPlugin; + normalizeInput?: ( + params: CmsModelFieldToGraphQLNormalizeInputParams + ) => Promise; }; /** * diff --git a/packages/api-headless-cms/src/types/types.ts b/packages/api-headless-cms/src/types/types.ts index 45b4725654b..41e05096bef 100644 --- a/packages/api-headless-cms/src/types/types.ts +++ b/packages/api-headless-cms/src/types/types.ts @@ -171,6 +171,12 @@ export interface CmsModelFieldDefinition { typeDefs?: string; } +export interface CmsModelFieldToGraphQLNormalizeInputParams { + model: CmsModel; + field: TField; + input: GenericRecord | Array>; +} + interface CmsModelFieldToGraphQLCreateResolverParams { models: CmsModel[]; model: CmsModel; @@ -1561,6 +1567,7 @@ export interface CmsEntryValidateResponse { */ interface CmsEntryResolverFactoryParams { model: CmsModel; + fieldTypePlugins: CmsFieldTypePlugins; } /** diff --git a/packages/api-headless-cms/src/utils/contentEntryTraverser/ContentEntryTraverser.ts b/packages/api-headless-cms/src/utils/contentEntryTraverser/ContentEntryTraverser.ts index dad198f34b9..d96e674b617 100644 --- a/packages/api-headless-cms/src/utils/contentEntryTraverser/ContentEntryTraverser.ts +++ b/packages/api-headless-cms/src/utils/contentEntryTraverser/ContentEntryTraverser.ts @@ -26,6 +26,8 @@ const childrenAreCollections = (node: CmsModelFieldAstNode): node is NodeWithCol return node.children.every(node => node.type === "collection"); }; +const emptyValues = [null, undefined]; + export class ContentEntryTraverser { private readonly modelAst: CmsModelAst; @@ -33,11 +35,11 @@ export class ContentEntryTraverser { this.modelAst = modelAst; } - traverse(values: CmsEntryValues, visitor: ContentEntryValueVisitor) { - this.visitTree(this.modelAst, values, [], visitor); + async traverse(values: CmsEntryValues, visitor: ContentEntryValueVisitor) { + await this.visitTree(this.modelAst, values, [], visitor); } - private visitTree( + private async visitTree( root: CmsModelAst | CmsModelFieldAstNode, values: CmsEntryValues, path: string[], @@ -46,15 +48,21 @@ export class ContentEntryTraverser { for (const node of root.children) { const context: VisitorContext = { node, parent: root }; const field = this.getFieldFromNode(context); - const value = values[field.fieldId]; + let value = values[field.fieldId]; + + // We do not descend into nodes if they're `null` or `undefined`. + if (nodeHasChildren(node) && emptyValues.includes(value)) { + continue; + } - if (!value) { + // We do not visit leaf nodes that are `undefined`. + if (!nodeHasChildren(node) && value === undefined) { continue; } const fieldPath = [...path, field.fieldId]; - visitor( + await visitor( { field, value, @@ -63,30 +71,40 @@ export class ContentEntryTraverser { context ); + // Refetch the value from the original input, in case the value changed within the visitor. + value = values[field.fieldId]; + if (nodeHasChildren(node) && childrenAreCollections(node)) { if (field.multipleValues) { - this.ensureArray(value).forEach((value, index) => { - this.findCollectionAndVisit( + const arrayValue = this.ensureArray(value); + for (let i = 0; i < arrayValue.length; i++) { + await this.findCollectionAndVisit( node, - value, - [...fieldPath, index.toString()], + arrayValue[i], + [...fieldPath, i.toString()], visitor ); - }); + } } else { - this.findCollectionAndVisit(node, value, path, visitor); + await this.findCollectionAndVisit(node, value, fieldPath, visitor); } continue; } if (field.multipleValues) { - this.ensureArray(value).forEach((value, index) => { - this.visitTree(node, value, [...fieldPath, index.toString()], visitor); - }); + const arrayValue = this.ensureArray(value); + for (let i = 0; i < arrayValue.length; i++) { + await this.visitTree( + node, + arrayValue[i], + [...fieldPath, i.toString()], + visitor + ); + } continue; } - this.visitTree(node, value, fieldPath, visitor); + await this.visitTree(node, value, fieldPath, visitor); } } @@ -113,7 +131,7 @@ export class ContentEntryTraverser { return; } - this.visitTree(collection, values, path, visitor); + return this.visitTree(collection, values, path, visitor); } private getFieldFromNode({ node, parent }: VisitorContext) { diff --git a/packages/api-page-builder-import-export/package.json b/packages/api-page-builder-import-export/package.json index a0a954f9bd5..497b20f6e58 100644 --- a/packages/api-page-builder-import-export/package.json +++ b/packages/api-page-builder-import-export/package.json @@ -34,7 +34,7 @@ "archiver": "^7.0.1", "commodo-fields-object": "^1.0.6", "dot-prop-immutable": "^2.1.0", - "fs-extra": "^9.1.0", + "fs-extra": "^11.2.0", "load-json-file": "^6.2.0", "lodash": "^4.17.21", "node-fetch": "^2.6.13", diff --git a/packages/api-page-builder/package.json b/packages/api-page-builder/package.json index db907d2359f..3ddb8ade0b6 100644 --- a/packages/api-page-builder/package.json +++ b/packages/api-page-builder/package.json @@ -33,7 +33,7 @@ "archiver": "^7.0.1", "dataloader": "^2.0.0", "extract-zip": "^1.6.7", - "fs-extra": "^9.1.0", + "fs-extra": "^11.2.0", "jsonpack": "^1.1.5", "load-json-file": "^6.2.0", "lodash": "^4.17.21", diff --git a/packages/app-admin/src/components/LexicalEditor/LexicalEditor.tsx b/packages/app-admin/src/components/LexicalEditor/LexicalEditor.tsx index dde1e40a864..696024c9784 100644 --- a/packages/app-admin/src/components/LexicalEditor/LexicalEditor.tsx +++ b/packages/app-admin/src/components/LexicalEditor/LexicalEditor.tsx @@ -9,11 +9,13 @@ interface LexicalEditorProps extends Omit { theme?: Theme; } +const imagesOnly = ["image/*"]; + export const LexicalEditor = (props: LexicalEditorProps) => { const { theme } = useTheme(); return ( - + {({ showFileManager }) => ( { setState({ checkingUser: false }); } } catch (e) { - console.log("error", e); setState({ checkingUser: false }); } }; diff --git a/packages/app-file-manager/src/modules/FileManagerApiProvider/graphql.ts b/packages/app-file-manager/src/modules/FileManagerApiProvider/graphql.ts index 48da25ea3f0..cb14d6bf8bf 100644 --- a/packages/app-file-manager/src/modules/FileManagerApiProvider/graphql.ts +++ b/packages/app-file-manager/src/modules/FileManagerApiProvider/graphql.ts @@ -53,9 +53,9 @@ export interface ListFilesWhereQueryVariables { tags_in?: string[]; tags_startsWith?: string; tags_not_startsWith?: string; - type_in?: string[]; createdBy?: string; AND?: ListFilesWhereQueryVariables[]; + [key: string]: any; } export interface ListFilesQueryVariables { diff --git a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/useListFiles.ts b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/useListFiles.ts index 2a8843727e9..a28a45b6629 100644 --- a/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/useListFiles.ts +++ b/packages/app-file-manager/src/modules/FileManagerRenderer/FileManagerViewProvider/useListFiles.ts @@ -16,9 +16,13 @@ import { useFileManagerApi } from "~/modules/FileManagerApiProvider/FileManagerA import { getScopeWhereParams, State } from "./state"; import { ROOT_FOLDER } from "~/constants"; +const toTypeInput = (value: string) => { + return value.replace("*", ""); +}; + function nonEmptyArray(value: string[] | undefined, fallback: string[] | undefined = undefined) { if (Array.isArray(value)) { - return value.length ? value : undefined; + return value.length ? value.map(toTypeInput) : undefined; } return fallback; @@ -98,6 +102,15 @@ export function useListFiles({ modifiers, folderId, state }: UseListFilesParams) const AND: ListFilesWhereQueryVariables[] = []; + if (modifiers.accept.length) { + const types = nonEmptyArray(modifiers.accept); + if (types) { + AND.push({ + OR: types.map(type => ({ type_startsWith: type })) + }); + } + } + if (state.filters) { AND.push(state.filters); } @@ -130,7 +143,6 @@ export function useListFiles({ modifiers, folderId, state }: UseListFilesParams) ...getScopeWhereParams(modifiers.scope), location: locationWhere, createdBy: modifiers.own ? identity!.id : undefined, - type_in: nonEmptyArray(modifiers.accept), AND: AND.length > 0 ? AND : undefined } }; diff --git a/packages/app-headless-cms/src/admin/components/ContentEntryForm/ContentEntryForm.tsx b/packages/app-headless-cms/src/admin/components/ContentEntryForm/ContentEntryForm.tsx index 2f816b874ca..a911e28068c 100644 --- a/packages/app-headless-cms/src/admin/components/ContentEntryForm/ContentEntryForm.tsx +++ b/packages/app-headless-cms/src/admin/components/ContentEntryForm/ContentEntryForm.tsx @@ -4,7 +4,6 @@ import { CmsContentEntry } from "~/types"; import { makeDecoratable } from "@webiny/app-admin"; import { ModelProvider, useModel } from "~/admin/components/ModelProvider"; import { Header } from "~/admin/components/ContentEntryForm/Header"; -import { useDefaultValues } from "~/admin/components/ContentEntryForm/useDefaultValues"; import { useFormRenderer } from "~/admin/components/ContentEntryForm/useFormRenderer"; import { ContentEntryFormContext, ContentEntryFormProvider } from "./ContentEntryFormProvider"; import { CustomLayout } from "./CustomLayout"; @@ -53,16 +52,12 @@ export const ContentEntryForm = makeDecoratable( const formElementRef = useRef(null); const { model } = useModel(); const { goToRevision } = useGoToRevision(); - const defaultValues = useDefaultValues(model); const formRenderer = useFormRenderer(model); const defaultOnAfterCreate = (entry: CmsContentEntry) => { goToRevision(entry.id); }; - // Determine initial entry. - const initialData = entry && entry.id ? entry : defaultValues; - // When entry changes, scroll to the top of the form. useEffect(() => { if (!formElementRef.current) { @@ -72,12 +67,12 @@ export const ContentEntryForm = makeDecoratable( setTimeout(() => { formElementRef.current?.scrollTo(0, 0); }, 20); - }, [initialData.id, formElementRef.current]); + }, [entry.id, formElementRef.current]); return ( { @@ -53,12 +54,16 @@ export function useBind({ Bind, field }: UseBindProps) { const validators = createValidators(field, field.validation || emptyValidators); const listValidators = createValidators(field, field.listValidation || emptyValidators); - const defaultValue: string[] | undefined = undefined; const isMultipleValues = index === -1 && field.multipleValues; const inputValidators = isMultipleValues ? listValidators : validators; memoizedBindComponents.current[componentId] = function UseBind(params: UseBindParams) { - const { name: childName, validators: childValidators, children } = params; + const { + name: childName, + validators: childValidators, + children, + defaultValue + } = params; return ( { + return field.type === "number" ? Number(value) : value; +}; + const plugin: CmsModelFieldRendererPlugin = { type: "cms-editor-field-renderer", name: "cms-editor-field-renderer-checkboxes-buttons", @@ -19,42 +23,39 @@ const plugin: CmsModelFieldRendererPlugin = { render({ field, getBind }) { const Bind = getBind(); - const { values: options = [] } = field.predefinedValues || { + const { values: predefinedOptions = [] } = field.predefinedValues || { values: [] }; + // For `number` field, we want to convert the value to actual Number. + const options = predefinedOptions.map(opt => ({ + ...opt, + value: adaptToField(field, opt.value) + })); + + const defaults = options.filter(option => option.selected); + const defaultValue = defaults.length > 0 ? defaults.map(opt => opt.value) : undefined; + return ( - - {bind => { - return ( - - {({ onChange, getValue }) => ( - - {options.map((option, index) => { - const value = - field.type === "number" - ? Number(option.value) - : option.value; - return ( -
- -
- ); - })} -
- )} -
- ); - }} + + + {({ onChange, getValue }) => ( + + {options.map((option, index) => { + return ( +
+ +
+ ); + })} +
+ )} +
); } diff --git a/packages/app-headless-cms/src/admin/plugins/fieldRenderers/radioButtons.tsx b/packages/app-headless-cms/src/admin/plugins/fieldRenderers/radioButtons.tsx index 41323cb2ade..c61b30602ee 100644 --- a/packages/app-headless-cms/src/admin/plugins/fieldRenderers/radioButtons.tsx +++ b/packages/app-headless-cms/src/admin/plugins/fieldRenderers/radioButtons.tsx @@ -23,8 +23,10 @@ const plugin: CmsModelFieldRendererPlugin = { options: [] }; + const defaultOption = options.find(opt => opt.selected === true); + return ( - + {({ onChange, getValue }) => ( diff --git a/packages/app-headless-cms/src/admin/plugins/fieldRenderers/select.tsx b/packages/app-headless-cms/src/admin/plugins/fieldRenderers/select.tsx index bb8b467c5fd..025d2f766fa 100644 --- a/packages/app-headless-cms/src/admin/plugins/fieldRenderers/select.tsx +++ b/packages/app-headless-cms/src/admin/plugins/fieldRenderers/select.tsx @@ -1,24 +1,11 @@ import React from "react"; import get from "lodash/get"; import { i18n } from "@webiny/app/i18n"; -import { - CmsEditorFieldPredefinedValuesEntry as Option, - CmsModelFieldRendererPlugin -} from "~/types"; +import { CmsModelFieldRendererPlugin } from "~/types"; import { Select } from "@webiny/ui/Select"; const t = i18n.ns("app-headless-cms/admin/fields/text"); -const getDefaultValue = (initialValue?: string | null, options?: Option[]): string | undefined => { - if (initialValue) { - return initialValue || undefined; - } else if (!options) { - return undefined; - } - const selected = options.find(option => !!option.selected); - return selected ? selected.value : undefined; -}; - const plugin: CmsModelFieldRendererPlugin = { type: "cms-editor-field-renderer", name: "cms-editor-field-renderer-select-box", @@ -32,23 +19,17 @@ const plugin: CmsModelFieldRendererPlugin = { render({ field, getBind }) { const Bind = getBind(); - const { values: options } = field.predefinedValues || {}; + const { values: options = [] } = field.predefinedValues || {}; + const defaultOption = options.find(option => !!option.selected); return ( - - {bind => { - const value = getDefaultValue(bind.value, options); - return ( - ); } diff --git a/packages/app-page-builder-elements/src/renderers/tabs.tsx b/packages/app-page-builder-elements/src/renderers/tabs.tsx index 227749c8cbf..937489b9284 100644 --- a/packages/app-page-builder-elements/src/renderers/tabs.tsx +++ b/packages/app-page-builder-elements/src/renderers/tabs.tsx @@ -3,6 +3,7 @@ import styled from "@emotion/styled"; import { Elements } from "~/components/Elements"; import { createRenderer } from "~/createRenderer"; import { useRenderer } from "~/hooks/useRenderer"; +import { ClassNames } from "@emotion/react"; const TabsHeader = styled.div` display: flex; @@ -44,17 +45,24 @@ export const createTabs = () => { return ( <> - {element.elements.map((tab, index) => ( - { - setSelectedTabElement(tab); - }} - active={tab.id === selectedTabElement.id} - > - {tab.data?.settings?.tab?.label || ""} - - ))} + {element.elements.map((tab, index) => { + const active = tab.id === selectedTabElement.id; + return ( + + {({ cx }) => ( + { + setSelectedTabElement(tab); + }} + > + {tab.data?.settings?.tab?.label || ""} + + )} + + ); + })} diff --git a/packages/app-page-builder/src/editor/plugins/elements/tabs/PeTabs.tsx b/packages/app-page-builder/src/editor/plugins/elements/tabs/PeTabs.tsx index 535e18b4882..87b56cec421 100644 --- a/packages/app-page-builder/src/editor/plugins/elements/tabs/PeTabs.tsx +++ b/packages/app-page-builder/src/editor/plugins/elements/tabs/PeTabs.tsx @@ -5,6 +5,7 @@ import { createRenderer, useRenderer, Elements } from "@webiny/app-page-builder- import { Element as ElementType } from "@webiny/app-page-builder-elements/types"; import { useActiveElementId } from "~/editor/hooks/useActiveElementId"; import { elementWithChildrenByIdSelector } from "~/editor/recoil/modules"; +import { ClassNames } from "@emotion/react"; const TabsContainer = styled.div` width: 100%; @@ -62,18 +63,25 @@ const PeTabs = createRenderer(() => { return ( - {childrenElements.map((tab, index) => ( - { - setSelectedTabElement(tab); - setActiveElementId(tab.id); - }} - active={tab.id === selectedTabElement.id} - > - {tab.data?.settings?.tab?.label || ""} - - ))} + {childrenElements.map((tab, index) => { + const active = tab.id === selectedTabElement.id; + return ( + + {({ cx }) => ( + { + setSelectedTabElement(tab); + setActiveElementId(tab.id); + }} + > + {tab.data?.settings?.tab?.label || ""} + + )} + + ); + })} {querySelection ? ( void; + onError?: (errors: FileError[], files: SelectedFile[]) => void; +}; + +export type RenderPropParams = { + browseFiles: (params: BrowseFilesParams) => void; + getDropZoneProps: (additionalProps: any) => any; + getLabelProps: (additionalProps: any) => any; + validateFiles: (files: SelectedFile[] | File[]) => FileError[]; +}; + +export type FilesRules = { + accept: string[]; + multiple: boolean; + maxSize: string; + multipleMaxSize: string; + multipleMaxCount: number | null; + convertToBase64: boolean; + onSuccess?: (files: SelectedFile[]) => void; + onError?: (errors: FileError[], files: SelectedFile[]) => void; +}; + +export type Props = FilesRules & { + children: (params: RenderPropParams) => React.ReactNode; + id?: string; +}; + +export class Files extends React.Component { + static defaultProps = { + accept: [], + multiple: false, + maxSize: "2mb", + multipleMaxSize: "10mb", + multipleMaxCount: null, + convertToBase64: false + }; + + input: HTMLInputElement | null = null; + browseFilesPassedParams: BrowseFilesParams | null = null; + id: string = generateId(); + + validateFiles = (files: SelectedFile[] | File[]): FileError[] => { + const { multiple, multipleMaxSize, multipleMaxCount, accept, maxSize } = this.props; + + const errors: FileError[] = []; + let multipleFileSize = 0; + + if (!multiple && files.length > 1) { + errors.push({ + id: generateId(), + type: "multipleNotAllowed" + }); + + return errors; + } + + for (let index = 0; index < files.length; index++) { + const file = files[index]; + + if ( + Array.isArray(accept) && + accept.length && + !accept.some(type => minimatch(file.type, type)) + ) { + errors.push({ + id: generateId(), + index, + file, + type: "unsupportedFileType" + }); + } else if (maxSize) { + if (file.size > bytes(maxSize)) { + errors.push({ + id: generateId(), + index, + file, + type: "maxSizeExceeded" + }); + } + } + + if (multiple) { + multipleFileSize += file.size; + } + } + + if (multiple) { + if (multipleMaxSize && multipleFileSize > bytes(multipleMaxSize)) { + errors.push({ + id: generateId(), + type: "multipleMaxSizeExceeded", + multipleFileSize, + multipleMaxSize: bytes(multipleMaxSize) + }); + } + + if (multipleMaxCount && files.length > multipleMaxCount) { + errors.push({ + id: generateId(), + type: "multipleMaxCountExceeded", + multipleCount: files.length, + multipleMaxCount + }); + } + } + + return errors; + }; + + processSelectedFiles = async (eventFiles: Array) => { + if (eventFiles.length === 0) { + return; + } + + const { convertToBase64, onSuccess, onError } = this.props; + const { browseFilesPassedParams } = this; + const callbacks = { + onSuccess, + onError + }; + + if (browseFilesPassedParams && browseFilesPassedParams.onSuccess) { + callbacks.onSuccess = browseFilesPassedParams.onSuccess; + } + + if (browseFilesPassedParams && browseFilesPassedParams.onError) { + callbacks.onError = browseFilesPassedParams.onError; + } + + const files: SelectedFile[] = [...eventFiles].map(file => { + return { + id: generateId(), + name: file.name, + type: file.type, + size: file.size, + src: { + file, + base64: null + } + }; + }); + + const errors = this.validateFiles(files); + + if (errors.length) { + callbacks.onError && callbacks.onError(errors, files); + } else { + if (convertToBase64) { + for (let i = 0; i < files.length; i++) { + const file = files[i].src.file; + files[i].src.base64 = await readFileContent(file); + } + } + + callbacks.onSuccess && callbacks.onSuccess(files); + } + + // Reset the browseFiles arguments. + if (this.input) { + this.input.value = ""; + } + this.browseFilesPassedParams = null; + }; + + /** + * Extracted into a separate method just for testing purposes. + */ + onDropFilesHandler = async ({ e, onSuccess, onError }: any) => { + this.browseFilesPassedParams = { onSuccess, onError }; + e.dataTransfer && + e.dataTransfer.files && + (await this.processSelectedFiles(e.dataTransfer.files)); + }; + + /** + * Extracted into a separate method just for testing purposes. + */ + browseFilesHandler = ({ onSuccess, onError }: any) => { + this.browseFilesPassedParams = { onSuccess, onError }; + this.input && this.input.click(); + }; + + override render() { + const { multiple, accept, id } = this.props; + return ( + + {this.props.children({ + getLabelProps: (props: any) => { + return { + ...props, + htmlFor: id || this.id + }; + }, + validateFiles: this.validateFiles, + browseFiles: ({ onSuccess, onError }: BrowseFilesParams = {}) => { + this.browseFilesHandler({ onSuccess, onError }); + }, + getDropZoneProps: ({ + onSuccess, + onError, + onDragOver, + onDrop, + ...rest + }: any = {}) => { + return { + ...rest, + onDragOver: (e: DragEvent) => { + e.preventDefault(); + typeof onDragOver === "function" && onDragOver(); + }, + onDrop: async (e: DragEvent) => { + e.preventDefault(); + typeof onDrop === "function" && onDrop(); + this.onDropFilesHandler({ e, onSuccess, onError }); + } + }; + } + })} + + { + if (ref) { + this.input = ref; + } + }} + accept={accept.join(",")} + style={{ display: "none" }} + type="file" + multiple={multiple} + onChange={e => + this.processSelectedFiles((e.target.files as any as Array) ?? []) + } + /> + + ); + } +} diff --git a/packages/app/src/react-butterfiles/index.ts b/packages/app/src/react-butterfiles/index.ts new file mode 100644 index 00000000000..c69f9dff0b6 --- /dev/null +++ b/packages/app/src/react-butterfiles/index.ts @@ -0,0 +1,3 @@ +import { Files } from "./Files"; + +export default Files; diff --git a/packages/app/src/react-butterfiles/utils/generateId.ts b/packages/app/src/react-butterfiles/utils/generateId.ts new file mode 100644 index 00000000000..b4187fc34cc --- /dev/null +++ b/packages/app/src/react-butterfiles/utils/generateId.ts @@ -0,0 +1,3 @@ +export const generateId = () => { + return "_" + Math.random().toString(36).substr(2, 9); +}; diff --git a/packages/app/src/react-butterfiles/utils/readFileContent.ts b/packages/app/src/react-butterfiles/utils/readFileContent.ts new file mode 100644 index 00000000000..ec645d3a45d --- /dev/null +++ b/packages/app/src/react-butterfiles/utils/readFileContent.ts @@ -0,0 +1,14 @@ +export const readFileContent = async (file: File) => { + return new Promise((resolve, reject) => { + const reader = new window.FileReader(); + reader.onload = function (e) { + if (e.target) { + resolve(e.target.result as string); + } else { + reject(`Unable to read file contents!`); + } + }; + + reader.readAsDataURL(file); + }); +}; diff --git a/packages/cli-plugin-deploy-pulumi/utils/createPulumiCommand.js b/packages/cli-plugin-deploy-pulumi/utils/createPulumiCommand.js index 33f557fa130..0aeadfe0b40 100644 --- a/packages/cli-plugin-deploy-pulumi/utils/createPulumiCommand.js +++ b/packages/cli-plugin-deploy-pulumi/utils/createPulumiCommand.js @@ -54,7 +54,7 @@ const createPulumiCommand = ({ } const sendTelemetryEvents = telemetry === true && params.telemetry !== false; - const getTelemetryEventName = stage => `pulumi-command-${name}-${stage}`; + const getTelemetryEventName = stage => `cli-pulumi-command-${name}-${stage}`; const telemetryProperties = { env: params.env || "unknown", commandParams: JSON.stringify(params) diff --git a/packages/cli-plugin-scaffold-extensions/package.json b/packages/cli-plugin-scaffold-extensions/package.json index 6b3ee68229a..e3a34a68e47 100644 --- a/packages/cli-plugin-scaffold-extensions/package.json +++ b/packages/cli-plugin-scaffold-extensions/package.json @@ -26,6 +26,7 @@ "execa": "^5.0.0", "glob": "^7.1.2", "load-json-file": "^6.2.0", + "lodash": "^4.17.21", "ncp": "^2.0.0", "replace-in-path": "^1.1.0", "ts-morph": "^11.0.0", diff --git a/packages/cli-plugin-scaffold-extensions/src/generators/utils/generateAdminExtensions.ts b/packages/cli-plugin-scaffold-extensions/src/generators/utils/generateAdminExtensions.ts index 32a48991e0b..f188fe59652 100644 --- a/packages/cli-plugin-scaffold-extensions/src/generators/utils/generateAdminExtensions.ts +++ b/packages/cli-plugin-scaffold-extensions/src/generators/utils/generateAdminExtensions.ts @@ -1,5 +1,6 @@ import fs from "fs"; import path from "path"; +import camelCase from "lodash/camelCase"; import { formatCode } from "@webiny/cli-plugin-scaffold/utils"; import { ExtensionWorkspace } from "./getExtensionsFromFilesystem"; @@ -9,7 +10,7 @@ export const generateAdminExtensions = async (extensions: ExtensionWorkspace[]) const code: string[][] = []; extensions.forEach(extension => { - const name = path.basename(extension.path); + const name = camelCase(path.basename(extension.path)); const ucFirstName = name.charAt(0).toUpperCase() + name.slice(1); const componentName = ucFirstName + "Extension"; const importStatement = `import { Extension as ${componentName}} from "${extension.packageJson.name}";`; diff --git a/packages/cli-plugin-scaffold-graphql-api/template/pulumi/dev/graphql.ts b/packages/cli-plugin-scaffold-graphql-api/template/pulumi/dev/graphql.ts index 900577eae3c..a9df31740bb 100644 --- a/packages/cli-plugin-scaffold-graphql-api/template/pulumi/dev/graphql.ts +++ b/packages/cli-plugin-scaffold-graphql-api/template/pulumi/dev/graphql.ts @@ -72,7 +72,7 @@ class Graphql { description: "Project application name - GraphQL API Lambda function.", role: role.arn, timeout: 30, - memorySize: 512, + memorySize: 1024, code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive("../code/graphql/build") }), diff --git a/packages/cli-plugin-scaffold-graphql-api/template/pulumi/prod/graphql.ts b/packages/cli-plugin-scaffold-graphql-api/template/pulumi/prod/graphql.ts index eda76085abf..c67aff2922c 100644 --- a/packages/cli-plugin-scaffold-graphql-api/template/pulumi/prod/graphql.ts +++ b/packages/cli-plugin-scaffold-graphql-api/template/pulumi/prod/graphql.ts @@ -74,7 +74,7 @@ class Graphql { description: "Project application name - GraphQL API Lambda function.", role: this.role.arn, timeout: 30, - memorySize: 512, + memorySize: 1024, code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive("../code/graphql/build") }), diff --git a/packages/cli/package.json b/packages/cli/package.json index 07d7a090d96..d9f63dbef6f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -22,7 +22,7 @@ "execa": "^5.0.0", "fast-glob": "^3.2.7", "find-up": "5.0.0", - "fs-extra": "^9.1.0", + "fs-extra": "^11.2.0", "graphql-request": "^3.7.0", "inquirer": "^7.3.3", "is-ci": "^3.0.0", diff --git a/packages/create-webiny-project/package.json b/packages/create-webiny-project/package.json index 14ac70d341e..fc5b698e0a7 100644 --- a/packages/create-webiny-project/package.json +++ b/packages/create-webiny-project/package.json @@ -17,7 +17,7 @@ "chalk": "^4.1.0", "execa": "^5.0.0", "find-up": "5.0.0", - "fs-extra": "^9.0.1", + "fs-extra": "^11.2.0", "js-yaml": "3.14.1", "listr": "0.14.3", "load-json-file": "6.2.0", @@ -29,7 +29,8 @@ "uuid": "8.3.2", "validate-npm-package-name": "3.0.0", "write-json-file": "4.3.0", - "yargs": "15.4.1" + "yargs": "15.4.1", + "yesno": "^0.4.0" }, "publishConfig": { "access": "public", diff --git a/packages/create-webiny-project/utils/createProject.js b/packages/create-webiny-project/utils/createProject.js index 33b7435fb19..ca59e81d1a2 100644 --- a/packages/create-webiny-project/utils/createProject.js +++ b/packages/create-webiny-project/utils/createProject.js @@ -12,6 +12,7 @@ const validateProjectName = require("./validateProjectName"); const yaml = require("js-yaml"); const findUp = require("find-up"); const { GracefulError } = require("./GracefulError"); +const yesno = require("yesno"); const NOT_APPLICABLE = gray("N/A"); const HL = bold(gray("—")).repeat(30); @@ -23,6 +24,8 @@ const sleep = () => }, 500); }); +const getTelemetryEventName = stage => `cli-create-webiny-project-${stage}`; + module.exports = async function createProject({ projectName, force, @@ -105,7 +108,7 @@ module.exports = async function createProject({ console.log(`Initializing a new Webiny project in ${green(projectRoot)}...`); - await sendEvent({ event: "create-webiny-project-start" }); + await sendEvent({ event: getTelemetryEventName("start") }); let isGitAvailable = false; try { @@ -258,7 +261,8 @@ module.exports = async function createProject({ console.log(); - await require(templatePath)({ + const setupTemplate = require(templatePath); + await setupTemplate({ log, isGitAvailable, projectName, @@ -268,25 +272,21 @@ module.exports = async function createProject({ templateOptions: parsedTemplateOptions }); - await sendEvent({ event: "create-webiny-project-end" }); + await sendEvent({ event: getTelemetryEventName("end") }); } catch (err) { + let event = getTelemetryEventName("error"); if (err instanceof GracefulError) { - await sendEvent({ - event: "create-webiny-project-error-graceful", - properties: { - errorMessage: err.message, - errorStack: err.stack - } - }); - } else { - await sendEvent({ - event: "create-webiny-project-error", - properties: { - errorMessage: err.message, - errorStack: err.stack - } - }); + event = getTelemetryEventName("error-graceful"); } + + await sendEvent({ + event, + properties: { + errorMessage: err.cause?.message || err.message, + errorStack: err.cause?.stack || err.stack + } + }); + const node = process.versions.node; const os = process.platform; @@ -367,4 +367,61 @@ module.exports = async function createProject({ process.exit(1); } + + console.log(); + console.log( + `🎉 Your new Webiny project ${green( + projectName + )} has been created and is ready to be deployed for the first time!` + ); + console.log(); + + const ok = await yesno({ + question: bold(`${green("?")} Would you like to deploy your project now (Y/n)?`), + defaultValue: true + }); + + console.log(); + + if (ok) { + console.log("🚀 Deploying your new Webiny project..."); + console.log(); + + try { + const command = ["webiny", "deploy"]; + if (debug) { + command.push("--debug"); + } + + await execa("yarn", command, { + cwd: projectRoot, + stdio: "inherit" + }); + } catch { + // Don't do anything. This is because the `webiny deploy` command has its own + // error handling and will print the error message. As far as this setup script + // is concerned, it succeeded, and it doesn't need to do anything else. + } + + return; + } + + console.log( + [ + `Finish the setup by running the following command: ${green( + `cd ${projectName} && yarn webiny deploy` + )}`, + "", + `To see all of the available CLI commands, run ${green( + "yarn webiny --help" + )} in your ${green(projectName)} directory.`, + "", + "Want to dive deeper into Webiny? Check out https://webiny.com/docs/!", + "Like the project? Star us on https://github.com/webiny/webiny-js!", + "", + "Need help? Join our Slack community! https://www.webiny.com/slack", + "", + "🚀 Happy coding!" + ].join("\n") + ); }; diff --git a/packages/cwp-template-aws/package.json b/packages/cwp-template-aws/package.json index c94659df493..1cb1bb0fb91 100644 --- a/packages/cwp-template-aws/package.json +++ b/packages/cwp-template-aws/package.json @@ -17,15 +17,14 @@ "chalk": "^4.1.0", "execa": "^5.0.0", "fast-glob": "^3.2.7", - "fs-extra": "^9.0.1", + "fs-extra": "^11.2.0", "get-yarn-workspaces": "1.0.2", "inquirer": "7.3.3", "load-json-file": "6.2.0", "lodash": "^4.17.21", "open": "^8.4.0", "ora": "4.1.1", - "write-json-file": "4.3.0", - "yesno": "^0.4.0" + "write-json-file": "4.3.0" }, "devDependencies": { "dotenv": "^8.2.0" diff --git a/packages/cwp-template-aws/setup.js b/packages/cwp-template-aws/setup.js index 657ec891b5a..914bb267a61 100644 --- a/packages/cwp-template-aws/setup.js +++ b/packages/cwp-template-aws/setup.js @@ -7,8 +7,7 @@ const merge = require("lodash/merge"); const writeJsonFile = require("write-json-file"); const loadJsonFile = require("load-json-file"); const getPackages = require("get-yarn-workspaces"); -const { green, yellow, bold } = require("chalk"); -const yesno = require("yesno"); +const { yellow } = require("chalk"); const ora = require("ora"); const IS_TEST = process.env.NODE_ENV === "test"; @@ -125,88 +124,30 @@ const setup = async args => { await writeJsonFile(packageJsonPath, packageJson); } - if (!IS_TEST) { - // Install dependencies. - console.log(); - const spinner = ora("Installing packages...").start(); - try { - const subprocess = execa("yarn", [], { - cwd: projectRoot, - maxBuffer: "500_000_000" - }); - await subprocess; - spinner.succeed("Packages installed successfully."); - } catch (e) { - spinner.fail("Failed to install packages."); - - console.log(e.message); - - throw new Error( - "Failed while installing project dependencies. Please check the above Yarn logs for more information." - ); - } - } - if (IS_TEST) { return; } + // Install dependencies. console.log(); - console.log( - `🎉 Your new Webiny project ${green( - projectName - )} has been created and is ready to be deployed for the first time!` - ); - console.log(); - - const ok = await yesno({ - question: bold(`${green("?")} Would you like to deploy your project now (Y/n)?`), - defaultValue: true - }); - - console.log(); - - if (ok) { - console.log("🚀 Deploying your new Webiny project..."); - console.log(); + const spinner = ora("Installing packages...").start(); + try { + const subprocess = execa("yarn", [], { + cwd: projectRoot, + maxBuffer: "500_000_000" + }); + await subprocess; + spinner.succeed("Packages installed successfully."); + } catch (e) { + spinner.fail("Failed to install packages."); - try { - const command = ["webiny", "deploy"]; - if (args.debug) { - command.push("--debug"); - } + console.log(e.message); - await execa("yarn", command, { - cwd: projectRoot, - stdio: "inherit" - }); - } catch { - // Don't do anything. This is because the `webiny deploy` command has its own - // error handling and will print the error message. As far as this setup script - // is concerned, it succeeded, and it doesn't need to do anything else. - } - - return; + throw new Error( + "Failed while installing project dependencies. Please check the above Yarn logs for more information.", + { cause: e } + ); } - - console.log( - [ - `Finish the setup by running the following command: ${green( - `cd ${projectName} && yarn webiny deploy` - )}`, - "", - `To see all of the available CLI commands, run ${green( - "yarn webiny --help" - )} in your ${green(projectName)} directory.`, - "", - "Want to dive deeper into Webiny? Check out https://webiny.com/docs/!", - "Like the project? Star us on https://github.com/webiny/webiny-js!", - "", - "Need help? Join our Slack community! https://www.webiny.com/slack", - "", - "🚀 Happy coding!" - ].join("\n") - ); }; module.exports = setup; diff --git a/packages/form/src/FormPresenter.ts b/packages/form/src/FormPresenter.ts index d7d04d69d29..d485ab68697 100644 --- a/packages/form/src/FormPresenter.ts +++ b/packages/form/src/FormPresenter.ts @@ -75,7 +75,7 @@ export class FormPresenter { } getFieldValue(name: string) { - return lodashGet(this.data, name) as unknown; + return toJS(lodashGet(this.data, name)) as unknown; } getFieldValidation(name: string): FieldValidationResult { diff --git a/packages/lexical-editor/src/components/Editor/RichTextEditor.tsx b/packages/lexical-editor/src/components/Editor/RichTextEditor.tsx index e0d03102f63..8b119cbc134 100644 --- a/packages/lexical-editor/src/components/Editor/RichTextEditor.tsx +++ b/packages/lexical-editor/src/components/Editor/RichTextEditor.tsx @@ -8,7 +8,7 @@ import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin"; import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin"; import { ClearEditorPlugin } from "@lexical/react/LexicalClearEditorPlugin"; import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin"; -import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary"; +import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary"; import { makeDecoratable } from "@webiny/react-composition"; import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin"; import { ContentEditable } from "@lexical/react/LexicalContentEditable"; @@ -120,7 +120,10 @@ const BaseRichTextEditor = ({ editorState.read(() => { if (typeof onChange === "function") { const editorState = editor.getEditorState(); - onChange(JSON.stringify(editorState.toJSON())); + // The timeout is necessary to prevent the `flushSync` warning by React. + setTimeout(() => { + onChange(JSON.stringify(editorState.toJSON())); + }, 0); } }); } diff --git a/packages/lexical-editor/src/utils/files.ts b/packages/lexical-editor/src/utils/files.ts index 90b5d4a56b6..8957c8f491d 100644 --- a/packages/lexical-editor/src/utils/files.ts +++ b/packages/lexical-editor/src/utils/files.ts @@ -11,43 +11,24 @@ export interface FileManagerFileItemMetaItem { value: any; } -export const isImageType = (file: FileManagerFileItem): boolean => { - if (!file?.meta) { - return false; - } - - for (const metaItem of file.meta) { - if (metaItem.key === "type") { - return metaItem.value.includes("image/"); - } - } - - return false; -}; - export const fileToImagePayload = (file: FileManagerFileItem): ImagePayload | null => { - if (!file?.meta) { - return null; - } - - if (!isImageType(file)) { - return null; - } - const imagePayload = {} as ImagePayload; imagePayload["id"] = file.id; imagePayload["src"] = file.src; imagePayload["showCaption"] = true; imagePayload["captionsEnabled"] = true; - for (const metaValue of file.meta) { - if (metaValue.key === "name") { - imagePayload["altText"] = metaValue.value; - } else if (metaValue.key === "width") { - imagePayload["width"] = metaValue.value; - } else if (metaValue.key === "height") { - imagePayload["height"] = metaValue.value; + if (file?.meta) { + for (const metaValue of file.meta) { + if (metaValue.key === "name") { + imagePayload["altText"] = metaValue.value; + } else if (metaValue.key === "width") { + imagePayload["width"] = metaValue.value; + } else if (metaValue.key === "height") { + imagePayload["height"] = metaValue.value; + } } } + return imagePayload; }; diff --git a/packages/project-utils/bundling/app/config/webpack.config.js b/packages/project-utils/bundling/app/config/webpack.config.js index 2771beec31a..90d2b74d8e3 100644 --- a/packages/project-utils/bundling/app/config/webpack.config.js +++ b/packages/project-utils/bundling/app/config/webpack.config.js @@ -223,6 +223,8 @@ module.exports = function (webpackEnv, { paths, options }) { "react-dom$": require.resolve("react-dom/profiling"), "scheduler/tracing": require.resolve("scheduler/tracing-profiling") }), + // This is a temporary fix, until we sort out the `react-butterfiles` dependency. + "react-butterfiles": require.resolve("@webiny/app/react-butterfiles"), ...(modules.webpackAliases || {}) }, fallback: { diff --git a/packages/project-utils/bundling/function/buildHandler.js b/packages/project-utils/bundling/function/buildHandler.js index 21043eeac11..57743d31533 100644 --- a/packages/project-utils/bundling/function/buildHandler.js +++ b/packages/project-utils/bundling/function/buildHandler.js @@ -10,7 +10,7 @@ module.exports = async options => { options.logs !== false && console.log("Deleting existing build files..."); rimraf.sync(join(cwd, "./dist")); - rimraf.sync(join(cwd, "*.tsbuildinfo")); + rimraf.sync(join(cwd, "*.tsbuildinfo"), { glob: true }); await createBuildFunction({ ...options, diff --git a/packages/project-utils/package.json b/packages/project-utils/package.json index 3fcda75483c..b8a96f6b931 100644 --- a/packages/project-utils/package.json +++ b/packages/project-utils/package.json @@ -42,7 +42,7 @@ "eslint-webpack-plugin": "^3.1.1", "file-loader": "6.2.0", "fork-ts-checker-webpack-plugin": "^9.0.2", - "fs-extra": "^9.1.0", + "fs-extra": "^11.2.0", "get-yarn-workspaces": "1.0.2", "glob": "^7.1.2", "html-webpack-plugin": "5.5.0", @@ -98,6 +98,7 @@ "src": [ "!!raw-loader!", "@material/base", + "@webiny/app", "@webiny/api", "@webiny/tasks", "@webiny/handler", diff --git a/packages/project-utils/packages/buildPackage.js b/packages/project-utils/packages/buildPackage.js index cac526df40e..b4d2669d786 100644 --- a/packages/project-utils/packages/buildPackage.js +++ b/packages/project-utils/packages/buildPackage.js @@ -12,7 +12,7 @@ module.exports = async options => { const { cwd } = options; options.logs !== false && console.log("Deleting existing build files..."); rimraf.sync(join(cwd, "./dist")); - rimraf.sync(join(cwd, "*.tsbuildinfo")); + rimraf.sync(join(cwd, "*.tsbuildinfo"), { glob: true }); options.logs !== false && console.log("Building..."); diff --git a/packages/pulumi-aws/src/apps/api/ApiApwScheduler.ts b/packages/pulumi-aws/src/apps/api/ApiApwScheduler.ts index 3422a194fe8..23e60bc0a54 100644 --- a/packages/pulumi-aws/src/apps/api/ApiApwScheduler.ts +++ b/packages/pulumi-aws/src/apps/api/ApiApwScheduler.ts @@ -108,7 +108,7 @@ function createExecuteActionLambda(app: PulumiApp, params: ScheduleActionParams) runtime: LAMBDA_RUNTIME, handler: "handler.handler", timeout: 60, - memorySize: 128, + memorySize: 512, description: "Handle execute action workflow in apw scheduler", code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive( @@ -211,7 +211,7 @@ function createScheduleActionLambda( runtime: LAMBDA_RUNTIME, handler: "handler.handler", timeout: 60, - memorySize: 128, + memorySize: 512, description: "Handle schedule action workflow in apw scheduler", code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive( diff --git a/packages/pulumi-aws/src/apps/api/ApiBackgroundTask.ts b/packages/pulumi-aws/src/apps/api/ApiBackgroundTask.ts index 69b9e815f04..e91506fc27d 100644 --- a/packages/pulumi-aws/src/apps/api/ApiBackgroundTask.ts +++ b/packages/pulumi-aws/src/apps/api/ApiBackgroundTask.ts @@ -26,7 +26,7 @@ export const ApiBackgroundTask = createAppModule({ return Array.from(new Set([...(arns || []), getLayerArn("sharp")])); }), timeout: 900, - memorySize: 512, + memorySize: 1024, description: "Performs background tasks." } }); diff --git a/packages/pulumi-aws/src/apps/api/ApiFileManager.ts b/packages/pulumi-aws/src/apps/api/ApiFileManager.ts index cd7d10092f3..c80a7b99350 100644 --- a/packages/pulumi-aws/src/apps/api/ApiFileManager.ts +++ b/packages/pulumi-aws/src/apps/api/ApiFileManager.ts @@ -35,7 +35,7 @@ export const ApiFileManager = createAppModule({ runtime: LAMBDA_RUNTIME, handler: "handler.handler", timeout: 30, - memorySize: 512, + memorySize: 1024, description: "Triggered when a file is deleted.", code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive( diff --git a/packages/pulumi-aws/src/apps/api/ApiGraphql.ts b/packages/pulumi-aws/src/apps/api/ApiGraphql.ts index eb340e600c4..fb0957b8eb1 100644 --- a/packages/pulumi-aws/src/apps/api/ApiGraphql.ts +++ b/packages/pulumi-aws/src/apps/api/ApiGraphql.ts @@ -48,7 +48,7 @@ export const ApiGraphql = createAppModule({ handler: "handler.handler", role: role.output.arn, timeout: 30, - memorySize: 512, + memorySize: 1024, code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive( path.join(app.paths.workspace, "graphql/build") diff --git a/packages/pulumi-aws/src/apps/api/ApiPageBuilder.ts b/packages/pulumi-aws/src/apps/api/ApiPageBuilder.ts index 9e4319b4113..4222b0dc934 100644 --- a/packages/pulumi-aws/src/apps/api/ApiPageBuilder.ts +++ b/packages/pulumi-aws/src/apps/api/ApiPageBuilder.ts @@ -58,7 +58,7 @@ function createExportResources(app: PulumiApp, params: PageBuilderParams) { runtime: LAMBDA_RUNTIME, handler: "handler.handler", timeout: 60, - memorySize: 512, + memorySize: 1024, description: "Handle export's combine workflow", code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive( @@ -82,7 +82,7 @@ function createExportResources(app: PulumiApp, params: PageBuilderParams) { runtime: LAMBDA_RUNTIME, handler: "handler.handler", timeout: 60, - memorySize: 512, + memorySize: 1024, description: "Handle export's process workflow", code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive( @@ -199,7 +199,7 @@ function createImportResources(app: PulumiApp, params: PageBuilderParams) { runtime: LAMBDA_RUNTIME, handler: "handler.handler", timeout: 60, - memorySize: 512, + memorySize: 1024, description: "Handle import queue process workflow", code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive( @@ -223,7 +223,7 @@ function createImportResources(app: PulumiApp, params: PageBuilderParams) { runtime: LAMBDA_RUNTIME, handler: "handler.handler", timeout: 60, - memorySize: 512, + memorySize: 1024, description: "Handle import queue create workflow", code: new pulumi.asset.AssetArchive({ ".": new pulumi.asset.FileArchive( diff --git a/packages/pulumi-aws/src/apps/core/CoreCognito.ts b/packages/pulumi-aws/src/apps/core/CoreCognito.ts index 934d6c8e91e..508c6550cfb 100644 --- a/packages/pulumi-aws/src/apps/core/CoreCognito.ts +++ b/packages/pulumi-aws/src/apps/core/CoreCognito.ts @@ -100,7 +100,15 @@ export const CoreCognito = createAppModule({ const userPoolClient = app.addResource(aws.cognito.UserPoolClient, { name: "user-pool-client", config: { - userPoolId: userPool.output.id + userPoolId: userPool.output.id, + accessTokenValidity: 60, + idTokenValidity: 60, + refreshTokenValidity: 30, + tokenValidityUnits: { + accessToken: "minutes", + idToken: "minutes", + refreshToken: "days" + } } }); diff --git a/packages/pulumi-aws/src/apps/website/WebsitePrerendering.ts b/packages/pulumi-aws/src/apps/website/WebsitePrerendering.ts index a18bec6b9cb..ac93fba2ab6 100644 --- a/packages/pulumi-aws/src/apps/website/WebsitePrerendering.ts +++ b/packages/pulumi-aws/src/apps/website/WebsitePrerendering.ts @@ -100,7 +100,7 @@ function createRenderSubscriber( runtime: LAMBDA_RUNTIME, handler: "handler.handler", timeout: 30, - memorySize: 512, + memorySize: 1024, environment: { variables: getCommonLambdaEnvVariables().apply(value => ({ ...value, @@ -235,7 +235,7 @@ function createFlushService( runtime: LAMBDA_RUNTIME, handler: "handler.handler", timeout: 30, - memorySize: 512, + memorySize: 1024, environment: { variables: getCommonLambdaEnvVariables().apply(value => ({ ...value, diff --git a/packages/pulumi-sdk/package.json b/packages/pulumi-sdk/package.json index 89920bcf092..b95c9b1ac90 100644 --- a/packages/pulumi-sdk/package.json +++ b/packages/pulumi-sdk/package.json @@ -18,7 +18,7 @@ "@pulumi/pulumi": "^3.113.3", "decompress": "^4.2.1", "execa": "^5.0.0", - "fs-extra": "^9.1.0", + "fs-extra": "^11.2.0", "lodash": "^4.17.21", "node-fetch": "^2.6.9", "semver": "^7.3.5", diff --git a/packages/react-properties/src/createConfigurableComponent.tsx b/packages/react-properties/src/createConfigurableComponent.tsx index 5a353f979a4..8742e79941e 100644 --- a/packages/react-properties/src/createConfigurableComponent.tsx +++ b/packages/react-properties/src/createConfigurableComponent.tsx @@ -1,7 +1,8 @@ import React, { useContext, useEffect, useMemo, useState } from "react"; import { Compose, Decorator, makeDecoratable } from "@webiny/react-composition"; -import { Property, Properties, toObject } from "~/index"; import { GenericComponent } from "@webiny/react-composition/types"; +import { Property, Properties, toObject } from "~/index"; +import { useDebugConfig } from "./useDebugConfig"; const createHOC = (newChildren: React.ReactNode): Decorator> => @@ -68,6 +69,7 @@ export function createConfigurableComponent(name: string) { const WithConfig = ({ onProperties, children }: WithConfigProps) => { const [properties, setProperties] = useState([]); + useDebugConfig(name, properties); const context = { properties }; useEffect(() => { diff --git a/packages/react-properties/src/useDebugConfig.ts b/packages/react-properties/src/useDebugConfig.ts new file mode 100644 index 00000000000..679b918e4bd --- /dev/null +++ b/packages/react-properties/src/useDebugConfig.ts @@ -0,0 +1,27 @@ +import { useEffect } from "react"; +import { Property } from "./Properties"; +import { toObject } from "./utils"; + +declare global { + interface Window { + __debugConfigs: Record void>; + } +} + +export function useDebugConfig(name: string, properties: Property[]) { + useEffect(() => { + if (process.env.NODE_ENV !== "development") { + return; + } + + const configs = window.__debugConfigs ?? {}; + configs[name] = () => console.log(toObject(properties)); + window.__debugConfigs = configs; + + return () => { + const configs = window.__debugConfigs ?? {}; + delete configs[name]; + window.__debugConfigs = configs; + }; + }, [properties]); +} diff --git a/scripts/buildPackages/package.json b/scripts/buildPackages/package.json index 96e16f2a3c2..8dac93e9d9f 100644 --- a/scripts/buildPackages/package.json +++ b/scripts/buildPackages/package.json @@ -9,7 +9,7 @@ "chalk": "^4.1.0", "execa": "^5.1.1", "folder-hash": "^4.0.4", - "fs-extra": "^7.0.1", + "fs-extra": "^11.2.0", "listr2": "^5.0.8", "load-json-file": "^6.2.0", "write-json-file": "^4.3.0", diff --git a/scripts/prepublishOnly/package.json b/scripts/prepublishOnly/package.json index 9fa9b46a8ba..4c57adb5bad 100644 --- a/scripts/prepublishOnly/package.json +++ b/scripts/prepublishOnly/package.json @@ -8,7 +8,7 @@ "dependencies": { "chalk": "^4.1.0", "find-up": "5.0.0", - "fs-extra": "^7.0.1", + "fs-extra": "^11.2.0", "get-yarn-workspaces": "1.0.2", "load-json-file": "^6.2.0", "lodash": "^4.17.21", diff --git a/scripts/release/Release.js b/scripts/release/Release.js index 133551d31cb..f575bba76d9 100644 --- a/scripts/release/Release.js +++ b/scripts/release/Release.js @@ -13,6 +13,7 @@ class Release { resetAllChanges = true; mostRecentVersion = undefined; createGithubRelease = false; + npmTags = []; constructor(logger) { if (!logger) { @@ -61,9 +62,12 @@ class Release { // Generate `lerna.json` using `example.lerna.json`. { // Determine current version - const tags = await this.__getTags(); + this.npmTags = await this.__getTags(); this.mostRecentVersion = this.__getMostRecentVersion( - [tags["latest"], tags[this.tag === "latest" ? "beta" : this.tag]].filter(Boolean) + [ + this.npmTags["latest"], + this.npmTags[this.tag === "latest" ? "beta" : this.tag] + ].filter(Boolean) ); this.logger.info("Most recent version is %s", this.mostRecentVersion); @@ -117,7 +121,15 @@ class Release { ]; this.logger.debug(lernaPublishArgs.join(" ")); - await execa("yarn", lernaPublishArgs, { stdio: "inherit" }); + try { + await execa("yarn", lernaPublishArgs, { stdio: "inherit" }); + } catch (err) { + this.logger.debug("Failed to publish packages to NPM!", err); + this.logger.info("Retrying publishing..."); + // Rerun `lerna publish` ignoring lifecycle scripts, as packages are already built and ready to go. + await execa("yarn", [...lernaPublishArgs, "--ignore-scripts"], { stdio: "inherit" }); + } + this.logger.info(`Packages were published to NPM under %s dist-tag`, this.tag); if (this.createGithubRelease !== false) { @@ -131,10 +143,10 @@ class Release { this.logger.info("Created Git tag %s", versionTag); // Changelog and Github release. - const changelog = await this.__getChangelog(lernaJSON.version); - this.logger.log("Changelog:\n\n%s\n\n", changelog); - try { + const changelog = await this.__getChangelog(lernaJSON.version); + this.logger.log("Changelog:\n\n%s\n\n", changelog); + const { data: release } = await this.__createGithubRelease(versionTag, changelog); this.logger.info("Created Github release: %s", release.html_url); } catch (err) { @@ -181,7 +193,7 @@ class Release { } async __getChangelog(currentlyPublishedVersion) { - const from = `v${this.mostRecentVersion}`; + const from = `v${this.npmTags["latest"]}`; const to = `v${currentlyPublishedVersion}`; this.logger.info(`Generating changelog ${from}..${to}`); diff --git a/yarn.lock b/yarn.lock index 3244b0e431c..6ed129b9a2a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -224,6 +224,21 @@ __metadata: languageName: node linkType: hard +"@aws-crypto/sha256-browser@npm:5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/sha256-browser@npm:5.2.0" + dependencies: + "@aws-crypto/sha256-js": ^5.2.0 + "@aws-crypto/supports-web-crypto": ^5.2.0 + "@aws-crypto/util": ^5.2.0 + "@aws-sdk/types": ^3.222.0 + "@aws-sdk/util-locate-window": ^3.0.0 + "@smithy/util-utf8": ^2.0.0 + tslib: ^2.6.2 + checksum: 773f12f2026d82a6bb4a23a8f491894a6d32525bd9b8bfbc12896526cf11882a7607a671c478c45f9cd7d6ba1caaed48a62b67c6f725244bd83a1275108f46c7 + languageName: node + linkType: hard + "@aws-crypto/sha256-browser@npm:^1.0.0": version: 1.2.2 resolution: "@aws-crypto/sha256-browser@npm:1.2.2" @@ -261,6 +276,17 @@ __metadata: languageName: node linkType: hard +"@aws-crypto/sha256-js@npm:5.2.0, @aws-crypto/sha256-js@npm:^5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/sha256-js@npm:5.2.0" + dependencies: + "@aws-crypto/util": ^5.2.0 + "@aws-sdk/types": ^3.222.0 + tslib: ^2.6.2 + checksum: 007fbe0436d714d0d0d282e2b61c90e45adcb9ad75eac9ac7ba03d32b56624afd09b2a9ceb4d659661cf17c51d74d1900ab6b00eacafc002da1101664955ca53 + languageName: node + linkType: hard + "@aws-crypto/supports-web-crypto@npm:^1.0.0": version: 1.0.0 resolution: "@aws-crypto/supports-web-crypto@npm:1.0.0" @@ -279,6 +305,15 @@ __metadata: languageName: node linkType: hard +"@aws-crypto/supports-web-crypto@npm:^5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/supports-web-crypto@npm:5.2.0" + dependencies: + tslib: ^2.6.2 + checksum: 6ffc21de48b2b2c3e918193101d7e8fe949d47b37688892e1c39eaedaa938be80c0f404fe1c874c30cce16781026777a53bf47d5d90143ca91d0feb7c4a6f830 + languageName: node + linkType: hard + "@aws-crypto/util@npm:^1.2.2": version: 1.2.2 resolution: "@aws-crypto/util@npm:1.2.2" @@ -301,6 +336,17 @@ __metadata: languageName: node linkType: hard +"@aws-crypto/util@npm:^5.2.0": + version: 5.2.0 + resolution: "@aws-crypto/util@npm:5.2.0" + dependencies: + "@aws-sdk/types": ^3.222.0 + "@smithy/util-utf8": ^2.0.0 + tslib: ^2.6.2 + checksum: f0f81d9d2771c59946cfec48b86cb23d39f78a966c4a1f89d4753abdc3cb38de06f907d1e6450059b121d48ac65d612ab88bdb70014553a077fc3dabddfbf8d6 + languageName: node + linkType: hard + "@aws-sdk/abort-controller@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/abort-controller@npm:3.6.1" @@ -881,52 +927,52 @@ __metadata: linkType: hard "@aws-sdk/client-iot@npm:^3.540.0": - version: 3.596.0 - resolution: "@aws-sdk/client-iot@npm:3.596.0" - dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sso-oidc": 3.596.0 - "@aws-sdk/client-sts": 3.596.0 - "@aws-sdk/core": 3.592.0 - "@aws-sdk/credential-provider-node": 3.596.0 - "@aws-sdk/middleware-host-header": 3.577.0 - "@aws-sdk/middleware-logger": 3.577.0 - "@aws-sdk/middleware-recursion-detection": 3.577.0 - "@aws-sdk/middleware-user-agent": 3.587.0 - "@aws-sdk/region-config-resolver": 3.587.0 - "@aws-sdk/types": 3.577.0 - "@aws-sdk/util-endpoints": 3.587.0 - "@aws-sdk/util-user-agent-browser": 3.577.0 - "@aws-sdk/util-user-agent-node": 3.587.0 - "@smithy/config-resolver": ^3.0.1 - "@smithy/core": ^2.2.0 - "@smithy/fetch-http-handler": ^3.0.1 - "@smithy/hash-node": ^3.0.0 - "@smithy/invalid-dependency": ^3.0.0 - "@smithy/middleware-content-length": ^3.0.0 - "@smithy/middleware-endpoint": ^3.0.1 - "@smithy/middleware-retry": ^3.0.3 - "@smithy/middleware-serde": ^3.0.0 - "@smithy/middleware-stack": ^3.0.0 - "@smithy/node-config-provider": ^3.1.0 - "@smithy/node-http-handler": ^3.0.0 - "@smithy/protocol-http": ^4.0.0 - "@smithy/smithy-client": ^3.1.1 - "@smithy/types": ^3.0.0 - "@smithy/url-parser": ^3.0.0 + version: 3.614.0 + resolution: "@aws-sdk/client-iot@npm:3.614.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.614.0 + "@aws-sdk/client-sts": 3.614.0 + "@aws-sdk/core": 3.614.0 + "@aws-sdk/credential-provider-node": 3.614.0 + "@aws-sdk/middleware-host-header": 3.609.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.609.0 + "@aws-sdk/middleware-user-agent": 3.614.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.2.6 + "@smithy/fetch-http-handler": ^3.2.1 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.3 + "@smithy/middleware-endpoint": ^3.0.5 + "@smithy/middleware-retry": ^3.0.9 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.2 + "@smithy/protocol-http": ^4.0.3 + "@smithy/smithy-client": ^3.1.7 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@smithy/util-base64": ^3.0.0 "@smithy/util-body-length-browser": ^3.0.0 "@smithy/util-body-length-node": ^3.0.0 - "@smithy/util-defaults-mode-browser": ^3.0.3 - "@smithy/util-defaults-mode-node": ^3.0.3 - "@smithy/util-endpoints": ^2.0.1 - "@smithy/util-middleware": ^3.0.0 - "@smithy/util-retry": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.9 + "@smithy/util-defaults-mode-node": ^3.0.9 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 uuid: ^9.0.1 - checksum: 1ac428d7d9f84ede02dd5589f35c47eb4daa049cc8382004d16edc044e6b2f4b93bf3630a238bb648765b6baf63318bf86c5dd28decc0437c1dddf7691ae7448 + checksum: 2d075f43a017b1106a91d2f7d6d10e54f4d7bdefe3d9c134106b75711d27aaf063f6b462ccc63e1c45d0298fbc6c469cc46c854a00bd9fd74f90208e13e690a2 languageName: node linkType: hard @@ -1196,51 +1242,52 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-sso-oidc@npm:3.596.0": - version: 3.596.0 - resolution: "@aws-sdk/client-sso-oidc@npm:3.596.0" - dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sts": 3.596.0 - "@aws-sdk/core": 3.592.0 - "@aws-sdk/credential-provider-node": 3.596.0 - "@aws-sdk/middleware-host-header": 3.577.0 - "@aws-sdk/middleware-logger": 3.577.0 - "@aws-sdk/middleware-recursion-detection": 3.577.0 - "@aws-sdk/middleware-user-agent": 3.587.0 - "@aws-sdk/region-config-resolver": 3.587.0 - "@aws-sdk/types": 3.577.0 - "@aws-sdk/util-endpoints": 3.587.0 - "@aws-sdk/util-user-agent-browser": 3.577.0 - "@aws-sdk/util-user-agent-node": 3.587.0 - "@smithy/config-resolver": ^3.0.1 - "@smithy/core": ^2.2.0 - "@smithy/fetch-http-handler": ^3.0.1 - "@smithy/hash-node": ^3.0.0 - "@smithy/invalid-dependency": ^3.0.0 - "@smithy/middleware-content-length": ^3.0.0 - "@smithy/middleware-endpoint": ^3.0.1 - "@smithy/middleware-retry": ^3.0.3 - "@smithy/middleware-serde": ^3.0.0 - "@smithy/middleware-stack": ^3.0.0 - "@smithy/node-config-provider": ^3.1.0 - "@smithy/node-http-handler": ^3.0.0 - "@smithy/protocol-http": ^4.0.0 - "@smithy/smithy-client": ^3.1.1 - "@smithy/types": ^3.0.0 - "@smithy/url-parser": ^3.0.0 +"@aws-sdk/client-sso-oidc@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/client-sso-oidc@npm:3.614.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/core": 3.614.0 + "@aws-sdk/credential-provider-node": 3.614.0 + "@aws-sdk/middleware-host-header": 3.609.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.609.0 + "@aws-sdk/middleware-user-agent": 3.614.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.2.6 + "@smithy/fetch-http-handler": ^3.2.1 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.3 + "@smithy/middleware-endpoint": ^3.0.5 + "@smithy/middleware-retry": ^3.0.9 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.2 + "@smithy/protocol-http": ^4.0.3 + "@smithy/smithy-client": ^3.1.7 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@smithy/util-base64": ^3.0.0 "@smithy/util-body-length-browser": ^3.0.0 "@smithy/util-body-length-node": ^3.0.0 - "@smithy/util-defaults-mode-browser": ^3.0.3 - "@smithy/util-defaults-mode-node": ^3.0.3 - "@smithy/util-endpoints": ^2.0.1 - "@smithy/util-middleware": ^3.0.0 - "@smithy/util-retry": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.9 + "@smithy/util-defaults-mode-node": ^3.0.9 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: ae2e6f60eec488b62c34aab4cec770c89c0b8922ee23771f40a1fd407900b97a466196f261bad9696d187d3c8dccccc734d256d6686a71c9c5ac8c6373c2df22 + peerDependencies: + "@aws-sdk/client-sts": ^3.614.0 + checksum: fb82b2e4c9e352bfd3d5578b6e0827e957895f7dddcde19a9af1713f796806d27ebf9f08d9c9f86f0b5319dfdbe580b0e9facacfe85b918de6ca8ac6bdd48950 languageName: node linkType: hard @@ -1290,49 +1337,49 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-sso@npm:3.592.0": - version: 3.592.0 - resolution: "@aws-sdk/client-sso@npm:3.592.0" - dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/core": 3.592.0 - "@aws-sdk/middleware-host-header": 3.577.0 - "@aws-sdk/middleware-logger": 3.577.0 - "@aws-sdk/middleware-recursion-detection": 3.577.0 - "@aws-sdk/middleware-user-agent": 3.587.0 - "@aws-sdk/region-config-resolver": 3.587.0 - "@aws-sdk/types": 3.577.0 - "@aws-sdk/util-endpoints": 3.587.0 - "@aws-sdk/util-user-agent-browser": 3.577.0 - "@aws-sdk/util-user-agent-node": 3.587.0 - "@smithy/config-resolver": ^3.0.1 - "@smithy/core": ^2.2.0 - "@smithy/fetch-http-handler": ^3.0.1 - "@smithy/hash-node": ^3.0.0 - "@smithy/invalid-dependency": ^3.0.0 - "@smithy/middleware-content-length": ^3.0.0 - "@smithy/middleware-endpoint": ^3.0.1 - "@smithy/middleware-retry": ^3.0.3 - "@smithy/middleware-serde": ^3.0.0 - "@smithy/middleware-stack": ^3.0.0 - "@smithy/node-config-provider": ^3.1.0 - "@smithy/node-http-handler": ^3.0.0 - "@smithy/protocol-http": ^4.0.0 - "@smithy/smithy-client": ^3.1.1 - "@smithy/types": ^3.0.0 - "@smithy/url-parser": ^3.0.0 +"@aws-sdk/client-sso@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/client-sso@npm:3.614.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/core": 3.614.0 + "@aws-sdk/middleware-host-header": 3.609.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.609.0 + "@aws-sdk/middleware-user-agent": 3.614.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.2.6 + "@smithy/fetch-http-handler": ^3.2.1 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.3 + "@smithy/middleware-endpoint": ^3.0.5 + "@smithy/middleware-retry": ^3.0.9 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.2 + "@smithy/protocol-http": ^4.0.3 + "@smithy/smithy-client": ^3.1.7 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@smithy/util-base64": ^3.0.0 "@smithy/util-body-length-browser": ^3.0.0 "@smithy/util-body-length-node": ^3.0.0 - "@smithy/util-defaults-mode-browser": ^3.0.3 - "@smithy/util-defaults-mode-node": ^3.0.3 - "@smithy/util-endpoints": ^2.0.1 - "@smithy/util-middleware": ^3.0.0 - "@smithy/util-retry": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.9 + "@smithy/util-defaults-mode-node": ^3.0.9 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: e993043e8438e1cc0445b61de485951e957f0889135b3e34f79b7080852f369b13d516dc6c027f8d3c8ad95cc41666f63f0543e04c10ec9e120b3e025a34367e + checksum: f6ec0be51a1fb657f8c058506460b50a853aaf0b1801ece88002eb3a53a6723c7245dffcfd1761e95dcdfd330667c0d0948518c3fa1e99c57d807938d8a035ef languageName: node linkType: hard @@ -1384,51 +1431,51 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/client-sts@npm:3.596.0": - version: 3.596.0 - resolution: "@aws-sdk/client-sts@npm:3.596.0" - dependencies: - "@aws-crypto/sha256-browser": 3.0.0 - "@aws-crypto/sha256-js": 3.0.0 - "@aws-sdk/client-sso-oidc": 3.596.0 - "@aws-sdk/core": 3.592.0 - "@aws-sdk/credential-provider-node": 3.596.0 - "@aws-sdk/middleware-host-header": 3.577.0 - "@aws-sdk/middleware-logger": 3.577.0 - "@aws-sdk/middleware-recursion-detection": 3.577.0 - "@aws-sdk/middleware-user-agent": 3.587.0 - "@aws-sdk/region-config-resolver": 3.587.0 - "@aws-sdk/types": 3.577.0 - "@aws-sdk/util-endpoints": 3.587.0 - "@aws-sdk/util-user-agent-browser": 3.577.0 - "@aws-sdk/util-user-agent-node": 3.587.0 - "@smithy/config-resolver": ^3.0.1 - "@smithy/core": ^2.2.0 - "@smithy/fetch-http-handler": ^3.0.1 - "@smithy/hash-node": ^3.0.0 - "@smithy/invalid-dependency": ^3.0.0 - "@smithy/middleware-content-length": ^3.0.0 - "@smithy/middleware-endpoint": ^3.0.1 - "@smithy/middleware-retry": ^3.0.3 - "@smithy/middleware-serde": ^3.0.0 - "@smithy/middleware-stack": ^3.0.0 - "@smithy/node-config-provider": ^3.1.0 - "@smithy/node-http-handler": ^3.0.0 - "@smithy/protocol-http": ^4.0.0 - "@smithy/smithy-client": ^3.1.1 - "@smithy/types": ^3.0.0 - "@smithy/url-parser": ^3.0.0 +"@aws-sdk/client-sts@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/client-sts@npm:3.614.0" + dependencies: + "@aws-crypto/sha256-browser": 5.2.0 + "@aws-crypto/sha256-js": 5.2.0 + "@aws-sdk/client-sso-oidc": 3.614.0 + "@aws-sdk/core": 3.614.0 + "@aws-sdk/credential-provider-node": 3.614.0 + "@aws-sdk/middleware-host-header": 3.609.0 + "@aws-sdk/middleware-logger": 3.609.0 + "@aws-sdk/middleware-recursion-detection": 3.609.0 + "@aws-sdk/middleware-user-agent": 3.614.0 + "@aws-sdk/region-config-resolver": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@aws-sdk/util-user-agent-browser": 3.609.0 + "@aws-sdk/util-user-agent-node": 3.614.0 + "@smithy/config-resolver": ^3.0.5 + "@smithy/core": ^2.2.6 + "@smithy/fetch-http-handler": ^3.2.1 + "@smithy/hash-node": ^3.0.3 + "@smithy/invalid-dependency": ^3.0.3 + "@smithy/middleware-content-length": ^3.0.3 + "@smithy/middleware-endpoint": ^3.0.5 + "@smithy/middleware-retry": ^3.0.9 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/node-http-handler": ^3.1.2 + "@smithy/protocol-http": ^4.0.3 + "@smithy/smithy-client": ^3.1.7 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 "@smithy/util-base64": ^3.0.0 "@smithy/util-body-length-browser": ^3.0.0 "@smithy/util-body-length-node": ^3.0.0 - "@smithy/util-defaults-mode-browser": ^3.0.3 - "@smithy/util-defaults-mode-node": ^3.0.3 - "@smithy/util-endpoints": ^2.0.1 - "@smithy/util-middleware": ^3.0.0 - "@smithy/util-retry": ^3.0.0 + "@smithy/util-defaults-mode-browser": ^3.0.9 + "@smithy/util-defaults-mode-node": ^3.0.9 + "@smithy/util-endpoints": ^2.0.5 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 49dcdfbc9df1012a48f1c0eb83d9ccfd172612369d3cfe6ef16d29fcd5123b4379bf53535f7cacb7bc88ff2a8c461b698d22cda1421e6050eef3db25eb1f7f81 + checksum: 86a6845e912d5d12e7ee936519d439e1c38234bfd9b09c563c3a73a99b2046b72fc16c781eec02a3513e64dddc6bbe12e133a9ca1d9d76159808af85e5c8c9d0 languageName: node linkType: hard @@ -1458,18 +1505,18 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/core@npm:3.592.0": - version: 3.592.0 - resolution: "@aws-sdk/core@npm:3.592.0" +"@aws-sdk/core@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/core@npm:3.614.0" dependencies: - "@smithy/core": ^2.2.0 - "@smithy/protocol-http": ^4.0.0 - "@smithy/signature-v4": ^3.0.0 - "@smithy/smithy-client": ^3.1.1 - "@smithy/types": ^3.0.0 + "@smithy/core": ^2.2.6 + "@smithy/protocol-http": ^4.0.3 + "@smithy/signature-v4": ^3.1.2 + "@smithy/smithy-client": ^3.1.7 + "@smithy/types": ^3.3.0 fast-xml-parser: 4.2.5 tslib: ^2.6.2 - checksum: 10ebbf695358e7bc3d2a84a7add3f52f479605c1ab6d2bd6970aa5846daebff2febf5156fbc5b275e0593c32d973a9f88f528df8280377557a48b87d1b9be5a3 + checksum: cf0f019d647ed8903ebba8b02830385ab3d9ea5efc4b86e9ccf5a6b662cda214c2666084518e8d16855e3ee63228c06d62811ef272eb98247125cf6629f64024 languageName: node linkType: hard @@ -1510,18 +1557,6 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-env@npm:3.587.0": - version: 3.587.0 - resolution: "@aws-sdk/credential-provider-env@npm:3.587.0" - dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/property-provider": ^3.1.0 - "@smithy/types": ^3.0.0 - tslib: ^2.6.2 - checksum: 3062e39c2b0e15eafea50fc2d182de41cba0c4845714b941dd7fb0b75605d7bae51d1919b2b1fdade0c3ec1e470d57ccb00d939898152ed1fbc2c2d265d400b1 - languageName: node - linkType: hard - "@aws-sdk/credential-provider-env@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/credential-provider-env@npm:3.6.1" @@ -1533,6 +1568,18 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/credential-provider-env@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/credential-provider-env@npm:3.609.0" + dependencies: + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: eda20122740481d04f5110fb9349df339562da1e1d5217e6c47e5f80ed0cce1b3bea01081272487bf04e402fcecc2734a352b0b57ae80b090dd8a0b3547ad185 + languageName: node + linkType: hard + "@aws-sdk/credential-provider-http@npm:3.535.0": version: 3.535.0 resolution: "@aws-sdk/credential-provider-http@npm:3.535.0" @@ -1550,20 +1597,20 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-http@npm:3.596.0": - version: 3.596.0 - resolution: "@aws-sdk/credential-provider-http@npm:3.596.0" +"@aws-sdk/credential-provider-http@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/credential-provider-http@npm:3.614.0" dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/fetch-http-handler": ^3.0.1 - "@smithy/node-http-handler": ^3.0.0 - "@smithy/property-provider": ^3.1.0 - "@smithy/protocol-http": ^4.0.0 - "@smithy/smithy-client": ^3.1.1 - "@smithy/types": ^3.0.0 - "@smithy/util-stream": ^3.0.1 + "@aws-sdk/types": 3.609.0 + "@smithy/fetch-http-handler": ^3.2.1 + "@smithy/node-http-handler": ^3.1.2 + "@smithy/property-provider": ^3.1.3 + "@smithy/protocol-http": ^4.0.3 + "@smithy/smithy-client": ^3.1.7 + "@smithy/types": ^3.3.0 + "@smithy/util-stream": ^3.0.6 tslib: ^2.6.2 - checksum: 8c83fb7bb6110e43c9bacb94cabf5db23475cbdf7267d1929c3537996ffcc92e9c434df38fd873662d6b148f2c137bc2401647f031d07ffa32f208f5c92d81c8 + checksum: ab8ca065261bd4c2f53d706e36224575f316546174d2fd2926476ddca5a55aa04ef2e7eadc57e110af37d53b591f8d77c4c546bd38dbd6f46973303db4b293f9 languageName: node linkType: hard @@ -1597,27 +1644,6 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-ini@npm:3.596.0": - version: 3.596.0 - resolution: "@aws-sdk/credential-provider-ini@npm:3.596.0" - dependencies: - "@aws-sdk/credential-provider-env": 3.587.0 - "@aws-sdk/credential-provider-http": 3.596.0 - "@aws-sdk/credential-provider-process": 3.587.0 - "@aws-sdk/credential-provider-sso": 3.592.0 - "@aws-sdk/credential-provider-web-identity": 3.587.0 - "@aws-sdk/types": 3.577.0 - "@smithy/credential-provider-imds": ^3.1.0 - "@smithy/property-provider": ^3.1.0 - "@smithy/shared-ini-file-loader": ^3.1.0 - "@smithy/types": ^3.0.0 - tslib: ^2.6.2 - peerDependencies: - "@aws-sdk/client-sts": ^3.596.0 - checksum: 24e3e1bd6ad295803d729cd36b871ee750d1498c2e1a1480eee1a15ec56e6d79fe1effc827c044900161b23521ca518903ea24ddb4e66a546a65c1d82d6f75bb - languageName: node - linkType: hard - "@aws-sdk/credential-provider-ini@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/credential-provider-ini@npm:3.6.1" @@ -1630,6 +1656,27 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/credential-provider-ini@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/credential-provider-ini@npm:3.614.0" + dependencies: + "@aws-sdk/credential-provider-env": 3.609.0 + "@aws-sdk/credential-provider-http": 3.614.0 + "@aws-sdk/credential-provider-process": 3.614.0 + "@aws-sdk/credential-provider-sso": 3.614.0 + "@aws-sdk/credential-provider-web-identity": 3.609.0 + "@aws-sdk/types": 3.609.0 + "@smithy/credential-provider-imds": ^3.1.4 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + peerDependencies: + "@aws-sdk/client-sts": ^3.614.0 + checksum: 5de5ad57de883eec96dbaa09f27ad58566c59fdb5ae925d4cc51fc7ff1add5bb67b2d455f8b97c0b10c1294f6822ffd32dd99e5412c06d4c5e04bbbf4d3a4d21 + languageName: node + linkType: hard + "@aws-sdk/credential-provider-node@npm:3.540.0": version: 3.540.0 resolution: "@aws-sdk/credential-provider-node@npm:3.540.0" @@ -1650,26 +1697,6 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-node@npm:3.596.0": - version: 3.596.0 - resolution: "@aws-sdk/credential-provider-node@npm:3.596.0" - dependencies: - "@aws-sdk/credential-provider-env": 3.587.0 - "@aws-sdk/credential-provider-http": 3.596.0 - "@aws-sdk/credential-provider-ini": 3.596.0 - "@aws-sdk/credential-provider-process": 3.587.0 - "@aws-sdk/credential-provider-sso": 3.592.0 - "@aws-sdk/credential-provider-web-identity": 3.587.0 - "@aws-sdk/types": 3.577.0 - "@smithy/credential-provider-imds": ^3.1.0 - "@smithy/property-provider": ^3.1.0 - "@smithy/shared-ini-file-loader": ^3.1.0 - "@smithy/types": ^3.0.0 - tslib: ^2.6.2 - checksum: 21ef971a7ff304ed9ab9b52e46f4296ea4c2bca0a5973a1e7044dfab4e74a5b1e3c0f45cf541789e02f177677464973920abcd9cdecd3e13ff10b493cfd99869 - languageName: node - linkType: hard - "@aws-sdk/credential-provider-node@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/credential-provider-node@npm:3.6.1" @@ -1686,6 +1713,26 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/credential-provider-node@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/credential-provider-node@npm:3.614.0" + dependencies: + "@aws-sdk/credential-provider-env": 3.609.0 + "@aws-sdk/credential-provider-http": 3.614.0 + "@aws-sdk/credential-provider-ini": 3.614.0 + "@aws-sdk/credential-provider-process": 3.614.0 + "@aws-sdk/credential-provider-sso": 3.614.0 + "@aws-sdk/credential-provider-web-identity": 3.609.0 + "@aws-sdk/types": 3.609.0 + "@smithy/credential-provider-imds": ^3.1.4 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: 4859cf4a50d83cfb538aa899a7884c6f6371f555ee3e451f426bfadf7d312240439dafdf73eebf4a471f6ba87dc6cdf86d02190625a16874c168fdd812e7bf46 + languageName: node + linkType: hard + "@aws-sdk/credential-provider-process@npm:3.535.0": version: 3.535.0 resolution: "@aws-sdk/credential-provider-process@npm:3.535.0" @@ -1699,19 +1746,6 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-process@npm:3.587.0": - version: 3.587.0 - resolution: "@aws-sdk/credential-provider-process@npm:3.587.0" - dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/property-provider": ^3.1.0 - "@smithy/shared-ini-file-loader": ^3.1.0 - "@smithy/types": ^3.0.0 - tslib: ^2.6.2 - checksum: 20add2fa4ecb513a8f7c376284248bf16601af52d56f30a20b9cb6c77ed811162b2d1d0c364fe27bba50bc6ac1a395c50057351c1d2107837358ef3974d7ff9a - languageName: node - linkType: hard - "@aws-sdk/credential-provider-process@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/credential-provider-process@npm:3.6.1" @@ -1725,6 +1759,19 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/credential-provider-process@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/credential-provider-process@npm:3.614.0" + dependencies: + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: 8bbbbf66911f38818e801187ae8df000e92b4e1c0dbe6d6b9afae81e08fb771302d2dc86c459653a2ed71acc10b9773885ae28d6fbce0031e082e9a6e61c85ee + languageName: node + linkType: hard + "@aws-sdk/credential-provider-sso@npm:3.540.0": version: 3.540.0 resolution: "@aws-sdk/credential-provider-sso@npm:3.540.0" @@ -1740,18 +1787,18 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-sso@npm:3.592.0": - version: 3.592.0 - resolution: "@aws-sdk/credential-provider-sso@npm:3.592.0" +"@aws-sdk/credential-provider-sso@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/credential-provider-sso@npm:3.614.0" dependencies: - "@aws-sdk/client-sso": 3.592.0 - "@aws-sdk/token-providers": 3.587.0 - "@aws-sdk/types": 3.577.0 - "@smithy/property-provider": ^3.1.0 - "@smithy/shared-ini-file-loader": ^3.1.0 - "@smithy/types": ^3.0.0 + "@aws-sdk/client-sso": 3.614.0 + "@aws-sdk/token-providers": 3.614.0 + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 5bc46040e521789a091b06d2d09931bd4254a3ece63f3370ec448cd58d0185821a39369efe47478cd6a0cd8911c4d93e52414ecca91ff72ed95b8813b619d93d + checksum: bf48b244d7e1727d8b1547e53b5ea2843d165c609ae394c305cd0166ceb1aecee787ae83a39880ce9c558daf1e0def5d5e043d9e418890b63c47f2680f1edd9a languageName: node linkType: hard @@ -1768,17 +1815,17 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/credential-provider-web-identity@npm:3.587.0": - version: 3.587.0 - resolution: "@aws-sdk/credential-provider-web-identity@npm:3.587.0" +"@aws-sdk/credential-provider-web-identity@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/credential-provider-web-identity@npm:3.609.0" dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/property-provider": ^3.1.0 - "@smithy/types": ^3.0.0 + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 peerDependencies: - "@aws-sdk/client-sts": ^3.587.0 - checksum: bfade039dcf35041fc020832363840e8fd6d7e21afbab35945852f62bb718bc954a59cb78911ea3ce6f9aaca4184f4934ba269f713ff811d06fcef1332af8cba + "@aws-sdk/client-sts": ^3.609.0 + checksum: 7a95a6c4792491122677fab6f01a9a46c8aa2f94d95255430bbd3fdcd514ab05ecf92c0ab169c8b30215b6b9181165f8d009774ba5a39cdd633162ef30879e56 languageName: node linkType: hard @@ -1970,18 +2017,6 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-host-header@npm:3.577.0": - version: 3.577.0 - resolution: "@aws-sdk/middleware-host-header@npm:3.577.0" - dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/protocol-http": ^4.0.0 - "@smithy/types": ^3.0.0 - tslib: ^2.6.2 - checksum: f325612558d8d56a13e0593a78a1807c55dac5913313ed53d0a09a1c4bc771976e74e1738bd46068adeea755c35f72b19c2f902ecad1ff1ae52290972cf9fe88 - languageName: node - linkType: hard - "@aws-sdk/middleware-host-header@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/middleware-host-header@npm:3.6.1" @@ -1993,6 +2028,18 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/middleware-host-header@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/middleware-host-header@npm:3.609.0" + dependencies: + "@aws-sdk/types": 3.609.0 + "@smithy/protocol-http": ^4.0.3 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: 19eda952c9d1a8ab34e820d26306034bd98ea4e4330cda39b881cb9d71bd64064a75eef27a51c2c38ba4beef18c53b4f21619ce1598c10cc7fe7831ab5dd4698 + languageName: node + linkType: hard + "@aws-sdk/middleware-location-constraint@npm:3.535.0": version: 3.535.0 resolution: "@aws-sdk/middleware-location-constraint@npm:3.535.0" @@ -2015,17 +2062,6 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-logger@npm:3.577.0": - version: 3.577.0 - resolution: "@aws-sdk/middleware-logger@npm:3.577.0" - dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/types": ^3.0.0 - tslib: ^2.6.2 - checksum: 142e993c82997391fb9c66244f2add15ad71e626b9aacf36a81ea369d33e3a1375ece09dd6315bf8fcaf4d8dcbaae340237088f1091f12a8f56740eddb32090a - languageName: node - linkType: hard - "@aws-sdk/middleware-logger@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/middleware-logger@npm:3.6.1" @@ -2036,6 +2072,17 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/middleware-logger@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/middleware-logger@npm:3.609.0" + dependencies: + "@aws-sdk/types": 3.609.0 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: b6f67a2e9ba082c8aec9d45905ae45ea5a95896f1beecb0c2d7fecfe17dd8fad99513f43b11ed7fd6ca9ff7764a0fc1ce63af91b1baed92b36f7b4b5390be5c6 + languageName: node + linkType: hard + "@aws-sdk/middleware-recursion-detection@npm:3.535.0": version: 3.535.0 resolution: "@aws-sdk/middleware-recursion-detection@npm:3.535.0" @@ -2048,15 +2095,15 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-recursion-detection@npm:3.577.0": - version: 3.577.0 - resolution: "@aws-sdk/middleware-recursion-detection@npm:3.577.0" +"@aws-sdk/middleware-recursion-detection@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/middleware-recursion-detection@npm:3.609.0" dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/protocol-http": ^4.0.0 - "@smithy/types": ^3.0.0 + "@aws-sdk/types": 3.609.0 + "@smithy/protocol-http": ^4.0.3 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 9655fe7b9a071a9a62397871a7bc529ebfff372a2cd1997b78c22ff320b0cdf0224881c122375e0b97e7307a167d437f438f6c414db71c882afb66a0510a519e + checksum: ec16809a501bd2182d87411fa96c409a91c166566370281c14c023ae169542c27f75f3e8e4167e538b4ce3a3e0e30cd082a3f9df24fdb6a2fb09c78c7824eda8 languageName: node linkType: hard @@ -2175,19 +2222,6 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/middleware-user-agent@npm:3.587.0": - version: 3.587.0 - resolution: "@aws-sdk/middleware-user-agent@npm:3.587.0" - dependencies: - "@aws-sdk/types": 3.577.0 - "@aws-sdk/util-endpoints": 3.587.0 - "@smithy/protocol-http": ^4.0.0 - "@smithy/types": ^3.0.0 - tslib: ^2.6.2 - checksum: 0a01579c20dc3e574e58578cf255169b7a8fc8cb2f38cd5d0d6ed282131d953d0ccd578d137a8d39c617b7722de7e194fce9647b662490935d5c8da01354ba5e - languageName: node - linkType: hard - "@aws-sdk/middleware-user-agent@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/middleware-user-agent@npm:3.6.1" @@ -2199,6 +2233,19 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/middleware-user-agent@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/middleware-user-agent@npm:3.614.0" + dependencies: + "@aws-sdk/types": 3.609.0 + "@aws-sdk/util-endpoints": 3.614.0 + "@smithy/protocol-http": ^4.0.3 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: ff8f1fdfadf87efd1582d15db439aa3b1c266cab985f66da7d57c8dbc275b67d0c959490cb6376981059babc3067e5e6f29dfe470ddbac8ddac6ebc806302b39 + languageName: node + linkType: hard + "@aws-sdk/node-config-provider@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/node-config-provider@npm:3.6.1" @@ -2279,17 +2326,17 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/region-config-resolver@npm:3.587.0": - version: 3.587.0 - resolution: "@aws-sdk/region-config-resolver@npm:3.587.0" +"@aws-sdk/region-config-resolver@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/region-config-resolver@npm:3.614.0" dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/node-config-provider": ^3.1.0 - "@smithy/types": ^3.0.0 + "@aws-sdk/types": 3.609.0 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/types": ^3.3.0 "@smithy/util-config-provider": ^3.0.0 - "@smithy/util-middleware": ^3.0.0 + "@smithy/util-middleware": ^3.0.3 tslib: ^2.6.2 - checksum: aa9bae8d88a7d3dc45017b8a6391942f70e95b4e16c4a6907048088f5eb49c9b77b81f084f4ed6d057eb4785ac182ee99dafa9cf3072d5aba3d19c02005abd8a + checksum: dbaca50792c99685845b21dd4a53228613e0458ee517a21db941890ee521d91eff80704f08e9ee71b6f04e70fb86362c4823750bb0b3727240af68d78d8fa4be languageName: node linkType: hard @@ -2394,18 +2441,18 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/token-providers@npm:3.587.0": - version: 3.587.0 - resolution: "@aws-sdk/token-providers@npm:3.587.0" +"@aws-sdk/token-providers@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/token-providers@npm:3.614.0" dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/property-provider": ^3.1.0 - "@smithy/shared-ini-file-loader": ^3.1.0 - "@smithy/types": ^3.0.0 + "@aws-sdk/types": 3.609.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 peerDependencies: - "@aws-sdk/client-sso-oidc": ^3.587.0 - checksum: 7a4d44bc413b88b933b439c2b26ac7d55a0ad26ede6b774fc659e8fb7b7f4dee555c7e478aa304983c1f4cd696825b5c47171ec5b918d54bce0146849274088c + "@aws-sdk/client-sso-oidc": ^3.614.0 + checksum: 2901b8428afc3b76ff1df9ac29a2698db6bf65d1d2afcd8424b9bf187313d2a3ca747c3b205afeb5c132068b5a5a94d84ce82710f775fa0cbb79499d7fea2d64 languageName: node linkType: hard @@ -2419,16 +2466,6 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/types@npm:3.577.0": - version: 3.577.0 - resolution: "@aws-sdk/types@npm:3.577.0" - dependencies: - "@smithy/types": ^3.0.0 - tslib: ^2.6.2 - checksum: d10fe1d720adf3d8b17d5c23787611e336509569df7526efa96e8901100b9279a68e30a207eff60dc5cfa011abd68d47b81e40f2d4d1a9ddfd2d3653c20e1734 - languageName: node - linkType: hard - "@aws-sdk/types@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/types@npm:3.6.1" @@ -2436,6 +2473,16 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/types@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/types@npm:3.609.0" + dependencies: + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + checksum: 522768d08f104065b0ff6a37eddaa7803186014acee1c0011b3dbd3ef841e47ae694e58f608aeec8a39d22d644d759ade996fe51d18b880617778dc2dbbe1ede + languageName: node + linkType: hard + "@aws-sdk/types@npm:^3.1.0, @aws-sdk/types@npm:^3.222.0": version: 3.266.0 resolution: "@aws-sdk/types@npm:3.266.0" @@ -2547,15 +2594,15 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-endpoints@npm:3.587.0": - version: 3.587.0 - resolution: "@aws-sdk/util-endpoints@npm:3.587.0" +"@aws-sdk/util-endpoints@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/util-endpoints@npm:3.614.0" dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/types": ^3.0.0 - "@smithy/util-endpoints": ^2.0.1 + "@aws-sdk/types": 3.609.0 + "@smithy/types": ^3.3.0 + "@smithy/util-endpoints": ^2.0.5 tslib: ^2.6.2 - checksum: 4b1cbfc49129b414144ad94cc947b78c6c3c061f5a39b4365d85c8a2d5e21b83ac85ab1add95b8eb64c48aed58792a486faa74887ff3a56a7a0f381bb1cbbce9 + checksum: 9d9973ceee59bf30af85c7f4328083daea033a987ec396dcb89eb7649f470ceb19c6b96635e121f3557e726f7ec7453236c956cf43f22128883c277f17d2a13f languageName: node linkType: hard @@ -2610,18 +2657,6 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-user-agent-browser@npm:3.577.0": - version: 3.577.0 - resolution: "@aws-sdk/util-user-agent-browser@npm:3.577.0" - dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/types": ^3.0.0 - bowser: ^2.11.0 - tslib: ^2.6.2 - checksum: 48b29b186f9d59c7ee272568cb0752834527aeccf122e4794313f84fb4c72dc65edf4bbf22f07aa7e2dde7da288e6d7ba20633edd9dbc853aca1b170bdfe1532 - languageName: node - linkType: hard - "@aws-sdk/util-user-agent-browser@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/util-user-agent-browser@npm:3.6.1" @@ -2633,6 +2668,18 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/util-user-agent-browser@npm:3.609.0": + version: 3.609.0 + resolution: "@aws-sdk/util-user-agent-browser@npm:3.609.0" + dependencies: + "@aws-sdk/types": 3.609.0 + "@smithy/types": ^3.3.0 + bowser: ^2.11.0 + tslib: ^2.6.2 + checksum: 75ba1ae74dd1001f47870766d92b66ac02a0a488efcf42c1a368962a7978a778d99536e880f07f7db1c2ca66cc9b1863fd3342957a22dcf78bf2f4398265a7a5 + languageName: node + linkType: hard + "@aws-sdk/util-user-agent-node@npm:3.535.0": version: 3.535.0 resolution: "@aws-sdk/util-user-agent-node@npm:3.535.0" @@ -2650,23 +2697,6 @@ __metadata: languageName: node linkType: hard -"@aws-sdk/util-user-agent-node@npm:3.587.0": - version: 3.587.0 - resolution: "@aws-sdk/util-user-agent-node@npm:3.587.0" - dependencies: - "@aws-sdk/types": 3.577.0 - "@smithy/node-config-provider": ^3.1.0 - "@smithy/types": ^3.0.0 - tslib: ^2.6.2 - peerDependencies: - aws-crt: ">=1.0.0" - peerDependenciesMeta: - aws-crt: - optional: true - checksum: 6f963c5371de04144fbd2ed893d823bc7c9f9a9e6e40bde3a1bab82274213110b7e2542d7da0798ffa7d24031ff63b385b08799a07800a816f4c85b0c2e44abe - languageName: node - linkType: hard - "@aws-sdk/util-user-agent-node@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/util-user-agent-node@npm:3.6.1" @@ -2678,6 +2708,23 @@ __metadata: languageName: node linkType: hard +"@aws-sdk/util-user-agent-node@npm:3.614.0": + version: 3.614.0 + resolution: "@aws-sdk/util-user-agent-node@npm:3.614.0" + dependencies: + "@aws-sdk/types": 3.609.0 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/types": ^3.3.0 + tslib: ^2.6.2 + peerDependencies: + aws-crt: ">=1.0.0" + peerDependenciesMeta: + aws-crt: + optional: true + checksum: 1f010080c2301fd836908963a235ef39e597d959e27461d15d4958fa582ab20795022f8cb7429c183c386f558a5c125cb254a0c4e844dbc6422169f4884be34a + languageName: node + linkType: hard + "@aws-sdk/util-utf8-browser@npm:3.6.1": version: 3.6.1 resolution: "@aws-sdk/util-utf8-browser@npm:3.6.1" @@ -12238,13 +12285,13 @@ __metadata: languageName: node linkType: hard -"@smithy/abort-controller@npm:^3.0.1": - version: 3.0.1 - resolution: "@smithy/abort-controller@npm:3.0.1" +"@smithy/abort-controller@npm:^3.1.1": + version: 3.1.1 + resolution: "@smithy/abort-controller@npm:3.1.1" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: a95ac89a3d8ecb98486a02895fbbd6d45f13cc00e886b7543ea09e294df2fdba8ae86805a8d9feb6b48cf3e59351fb7cdde0005e78959096f26da09c986d6b96 + checksum: 7b7497f49d58787cad858f8c5ea9931ccd44d39536db4abdd531a5abf37784469522e41d9ad1d541892caa0ed3bea750447809a0a18f4689a9543d672aa61d48 languageName: node linkType: hard @@ -12280,16 +12327,16 @@ __metadata: languageName: node linkType: hard -"@smithy/config-resolver@npm:^3.0.1, @smithy/config-resolver@npm:^3.0.2": - version: 3.0.2 - resolution: "@smithy/config-resolver@npm:3.0.2" +"@smithy/config-resolver@npm:^3.0.5": + version: 3.0.5 + resolution: "@smithy/config-resolver@npm:3.0.5" dependencies: - "@smithy/node-config-provider": ^3.1.1 - "@smithy/types": ^3.1.0 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/types": ^3.3.0 "@smithy/util-config-provider": ^3.0.0 - "@smithy/util-middleware": ^3.0.1 + "@smithy/util-middleware": ^3.0.3 tslib: ^2.6.2 - checksum: 088a9dc444e1e8ac184a490814a560107f731a0e87cd9a3e8293b506c082a93b9f2fe2b9142cdccf0766c4a4d81fe921b3938899b37971e1fcf4954760efddfb + checksum: 96895ae0622a229655fa08f009d29a20157043020125014e84cb5ca33a10171c9724c309491214c2422d9c4c6681e7f5ec5f7faa8f45e11250449cf07f3552ec languageName: node linkType: hard @@ -12309,19 +12356,19 @@ __metadata: languageName: node linkType: hard -"@smithy/core@npm:^2.2.0": - version: 2.2.1 - resolution: "@smithy/core@npm:2.2.1" - dependencies: - "@smithy/middleware-endpoint": ^3.0.2 - "@smithy/middleware-retry": ^3.0.4 - "@smithy/middleware-serde": ^3.0.1 - "@smithy/protocol-http": ^4.0.1 - "@smithy/smithy-client": ^3.1.2 - "@smithy/types": ^3.1.0 - "@smithy/util-middleware": ^3.0.1 +"@smithy/core@npm:^2.2.6": + version: 2.2.6 + resolution: "@smithy/core@npm:2.2.6" + dependencies: + "@smithy/middleware-endpoint": ^3.0.5 + "@smithy/middleware-retry": ^3.0.9 + "@smithy/middleware-serde": ^3.0.3 + "@smithy/protocol-http": ^4.0.3 + "@smithy/smithy-client": ^3.1.7 + "@smithy/types": ^3.3.0 + "@smithy/util-middleware": ^3.0.3 tslib: ^2.6.2 - checksum: 107510a1304edd2341909a085ec676df172fbfe8df81cf5f20ce2e227956dc37ccc5484699af5cc53d199a1dc86cfd80a36c760f1955b4086da0bd9a1f9a6d9c + checksum: e07c7ba38b92f7e96760736fae16db2eb24b4ff454181db563b98a7b73f7eb80ad17192c3b3a241f0db718076bbb56b0d9f0662dfd64c00d71729293b29d2362 languageName: node linkType: hard @@ -12338,16 +12385,16 @@ __metadata: languageName: node linkType: hard -"@smithy/credential-provider-imds@npm:^3.1.0, @smithy/credential-provider-imds@npm:^3.1.1": - version: 3.1.1 - resolution: "@smithy/credential-provider-imds@npm:3.1.1" +"@smithy/credential-provider-imds@npm:^3.1.4": + version: 3.1.4 + resolution: "@smithy/credential-provider-imds@npm:3.1.4" dependencies: - "@smithy/node-config-provider": ^3.1.1 - "@smithy/property-provider": ^3.1.1 - "@smithy/types": ^3.1.0 - "@smithy/url-parser": ^3.0.1 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/property-provider": ^3.1.3 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 tslib: ^2.6.2 - checksum: 5da3bce01557c19cc3d52a92aa33c6cbbbcbacc0d67a48d61193a8c1251702b5168af9b538313a54c4dea6bf0a07f8a00dffb3b10430a06ce3a25461eca0c018 + checksum: c75a653970f5e7b888dddbcb916fadd2c45fe59b1a776de9b44f39771b3941fb536684d2407aef88ce376afa6024f38759290db966b07e9213c49a9427ea4a7c languageName: node linkType: hard @@ -12419,16 +12466,16 @@ __metadata: languageName: node linkType: hard -"@smithy/fetch-http-handler@npm:^3.0.1, @smithy/fetch-http-handler@npm:^3.0.2": - version: 3.0.2 - resolution: "@smithy/fetch-http-handler@npm:3.0.2" +"@smithy/fetch-http-handler@npm:^3.2.1": + version: 3.2.1 + resolution: "@smithy/fetch-http-handler@npm:3.2.1" dependencies: - "@smithy/protocol-http": ^4.0.1 - "@smithy/querystring-builder": ^3.0.1 - "@smithy/types": ^3.1.0 + "@smithy/protocol-http": ^4.0.3 + "@smithy/querystring-builder": ^3.0.3 + "@smithy/types": ^3.3.0 "@smithy/util-base64": ^3.0.0 tslib: ^2.6.2 - checksum: ae4d93ee07dc02c77524b5f6218c53853a39db144e862b4fb92c918ce1e21d8ad5b43c6535121b8a13ada06f2d2874b9556689903452e8286c228c618075861f + checksum: 45754a06a1f2fd9d602b0759adc1d5a720ade398e70e239a7ac61dc9fc38e77a90077c7e141bf88051a8158a01f622825bec64dce642b73ba2b4c4268d2517d1 languageName: node linkType: hard @@ -12456,15 +12503,15 @@ __metadata: languageName: node linkType: hard -"@smithy/hash-node@npm:^3.0.0": - version: 3.0.1 - resolution: "@smithy/hash-node@npm:3.0.1" +"@smithy/hash-node@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/hash-node@npm:3.0.3" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 "@smithy/util-buffer-from": ^3.0.0 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 2ee4d3509d0c947d7c4c2a18c3315a608504c4fe2cb68bf2d9bfc0d0c02d59463ae1550d0d47e4f97b75e5a95bf309b966c9290f18b9719f53c6ff9f9819d933 + checksum: 203a3581bec5373e63d42e03f62129022f03d17390e9358a4e25fc1d44c43962ea80ab5bcbb91605e3025e22136bed059665a3b16835f66316f43ed391df9548 languageName: node linkType: hard @@ -12489,13 +12536,13 @@ __metadata: languageName: node linkType: hard -"@smithy/invalid-dependency@npm:^3.0.0": - version: 3.0.1 - resolution: "@smithy/invalid-dependency@npm:3.0.1" +"@smithy/invalid-dependency@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/invalid-dependency@npm:3.0.3" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 2a74c585e8a9bd84a1b9e4c78412921944024d8647e0b7d7f38ea64e3e7e3ed6391679a61ffc4a8d0e43cd6ac1e6aca607246f5cccbd791b37a527a72f4530df + checksum: 459b4ae4e47595e8a675ff2e8bfea7f58a41f77138416ea310c89e29312e08963a701cdc354324da9dd578a7995158b4421695365070d74b0276ddff7f701bba languageName: node linkType: hard @@ -12539,14 +12586,14 @@ __metadata: languageName: node linkType: hard -"@smithy/middleware-content-length@npm:^3.0.0": - version: 3.0.1 - resolution: "@smithy/middleware-content-length@npm:3.0.1" +"@smithy/middleware-content-length@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/middleware-content-length@npm:3.0.3" dependencies: - "@smithy/protocol-http": ^4.0.1 - "@smithy/types": ^3.1.0 + "@smithy/protocol-http": ^4.0.3 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 5b7374abe716eb95aa1f102a5d3c2570f637d92611dc7cc44140692689e0b37e81dab00b95aa4ee97a774a07fadae0a055fc03baa3f3f2b6cb4fe4ee3b189368 + checksum: 9ecc734ec64eff8a031c5eccacc8085eb78ed4ee94f2a62e781ac805b788a84ec1dfc5acf0b10bad59263f09e2a8185babf3b9ac0f4abe86466ccdac833d9fa5 languageName: node linkType: hard @@ -12565,18 +12612,18 @@ __metadata: languageName: node linkType: hard -"@smithy/middleware-endpoint@npm:^3.0.1, @smithy/middleware-endpoint@npm:^3.0.2": - version: 3.0.2 - resolution: "@smithy/middleware-endpoint@npm:3.0.2" - dependencies: - "@smithy/middleware-serde": ^3.0.1 - "@smithy/node-config-provider": ^3.1.1 - "@smithy/shared-ini-file-loader": ^3.1.1 - "@smithy/types": ^3.1.0 - "@smithy/url-parser": ^3.0.1 - "@smithy/util-middleware": ^3.0.1 +"@smithy/middleware-endpoint@npm:^3.0.5": + version: 3.0.5 + resolution: "@smithy/middleware-endpoint@npm:3.0.5" + dependencies: + "@smithy/middleware-serde": ^3.0.3 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 + "@smithy/url-parser": ^3.0.3 + "@smithy/util-middleware": ^3.0.3 tslib: ^2.6.2 - checksum: 711ab19d75271a542afd35b7e91a9d42f937d2bf9c547b6e40f50b0999af9811086493c6e48c113a2445a56fe49f909220f4866fc0affe370c28801dd6ba1050 + checksum: 4ab0272efd47baa528a04c5413fb224e41be144902680239fffc83cf1fb7e9b5342e8b627a4149136efa2b29baacc84baa4dbcef5fd2fa55c70e169c7f4ba750 languageName: node linkType: hard @@ -12597,20 +12644,20 @@ __metadata: languageName: node linkType: hard -"@smithy/middleware-retry@npm:^3.0.3, @smithy/middleware-retry@npm:^3.0.4": - version: 3.0.4 - resolution: "@smithy/middleware-retry@npm:3.0.4" - dependencies: - "@smithy/node-config-provider": ^3.1.1 - "@smithy/protocol-http": ^4.0.1 - "@smithy/service-error-classification": ^3.0.1 - "@smithy/smithy-client": ^3.1.2 - "@smithy/types": ^3.1.0 - "@smithy/util-middleware": ^3.0.1 - "@smithy/util-retry": ^3.0.1 +"@smithy/middleware-retry@npm:^3.0.9": + version: 3.0.9 + resolution: "@smithy/middleware-retry@npm:3.0.9" + dependencies: + "@smithy/node-config-provider": ^3.1.4 + "@smithy/protocol-http": ^4.0.3 + "@smithy/service-error-classification": ^3.0.3 + "@smithy/smithy-client": ^3.1.7 + "@smithy/types": ^3.3.0 + "@smithy/util-middleware": ^3.0.3 + "@smithy/util-retry": ^3.0.3 tslib: ^2.6.2 uuid: ^9.0.1 - checksum: 96e93df1b757b06f45729969ff094d24f840c69ac411a5cc4972e0b5c51626cb3ce4e1dee312796c67f6bbef2523d7da352c006d562abe1d74f881f49487f1b7 + checksum: 500af971d63fc628a0e362e17222d1ec332d6159ff89c94ca5ab0f16b55ded2ab927a5a60d8bbc26afa487ebf8576677ef0112a786c477149e8493da9ca6fbea languageName: node linkType: hard @@ -12624,13 +12671,13 @@ __metadata: languageName: node linkType: hard -"@smithy/middleware-serde@npm:^3.0.0, @smithy/middleware-serde@npm:^3.0.1": - version: 3.0.1 - resolution: "@smithy/middleware-serde@npm:3.0.1" +"@smithy/middleware-serde@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/middleware-serde@npm:3.0.3" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 7d869849d3bf5ae0615dc7927dacb9a7c8e9d0a75b9f8b6d3bd6a72e4a8eb626d6d37bea2dfd34aa76d87b5d9ed3d5067ea9bc028851eb01e230e8bebd0de96e + checksum: 6c633bb8957e078d480888bd33d5a8c269a483a1358c2b28c62daecfd442c711c509d9e69302e6b19fc298139ee67cdda63a604e7da0e4ef9005117d8e0897cc languageName: node linkType: hard @@ -12644,13 +12691,13 @@ __metadata: languageName: node linkType: hard -"@smithy/middleware-stack@npm:^3.0.0, @smithy/middleware-stack@npm:^3.0.1": - version: 3.0.1 - resolution: "@smithy/middleware-stack@npm:3.0.1" +"@smithy/middleware-stack@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/middleware-stack@npm:3.0.3" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 96ea38e6aa8760af2ac6f7fd4e2538d7481ee84b60a7e993803524ccd3192c8c47a06cc0b09a6d309069a879aa76c095e7c7d15c94863fc89ab2333848172005 + checksum: f4a450e2ebca0a8a3b4e1bbfad7d7e9c45edccbe1c984a22f2228092a526120748365e8964b478357249675d8bbc28fdaa8a4a19643a3c1d86bd74e1499327c5 languageName: node linkType: hard @@ -12666,15 +12713,15 @@ __metadata: languageName: node linkType: hard -"@smithy/node-config-provider@npm:^3.1.0, @smithy/node-config-provider@npm:^3.1.1": - version: 3.1.1 - resolution: "@smithy/node-config-provider@npm:3.1.1" +"@smithy/node-config-provider@npm:^3.1.4": + version: 3.1.4 + resolution: "@smithy/node-config-provider@npm:3.1.4" dependencies: - "@smithy/property-provider": ^3.1.1 - "@smithy/shared-ini-file-loader": ^3.1.1 - "@smithy/types": ^3.1.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/shared-ini-file-loader": ^3.1.4 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 0e9d68cdd9f83b975392d4f9c74a385bb0bce0f5b5549f69bd6e1563d2a9bd10b073d528b0a3a484be25eafb7b8fde912576377329655dac90790d9e479e5085 + checksum: 7ea4e7cea93ab154ab89a9d6b2453c8f96b96db18883070d287bc5fa9cfd10091bb00006a15bb7e6ed25810fd1a133d458e45310a8eaa1727a55d4ce2be3ba09 languageName: node linkType: hard @@ -12704,16 +12751,16 @@ __metadata: languageName: node linkType: hard -"@smithy/node-http-handler@npm:^3.0.0, @smithy/node-http-handler@npm:^3.0.1": - version: 3.0.1 - resolution: "@smithy/node-http-handler@npm:3.0.1" +"@smithy/node-http-handler@npm:^3.1.2": + version: 3.1.2 + resolution: "@smithy/node-http-handler@npm:3.1.2" dependencies: - "@smithy/abort-controller": ^3.0.1 - "@smithy/protocol-http": ^4.0.1 - "@smithy/querystring-builder": ^3.0.1 - "@smithy/types": ^3.1.0 + "@smithy/abort-controller": ^3.1.1 + "@smithy/protocol-http": ^4.0.3 + "@smithy/querystring-builder": ^3.0.3 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 35a3e022f85b4236792dc8f320193d4fafa91613ca313485a60f57f4d656a3547aa5d7ea0e47b9d764cdb374ed51fab5a738adb5fd58fb29b24cbca1c67b70d3 + checksum: d0b910218ba51a1d1a2e4c232e435c0a39cf728b8578e62746eecb059dada71a32cb285c0b908c72e97c93dd51cb7255a6d13d8e6991ed8ee91f050587cc129e languageName: node linkType: hard @@ -12727,13 +12774,13 @@ __metadata: languageName: node linkType: hard -"@smithy/property-provider@npm:^3.1.0, @smithy/property-provider@npm:^3.1.1": - version: 3.1.1 - resolution: "@smithy/property-provider@npm:3.1.1" +"@smithy/property-provider@npm:^3.1.3": + version: 3.1.3 + resolution: "@smithy/property-provider@npm:3.1.3" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: c17b5e2f0307f8086c6e271e4c6f2f95096a09aea3334a386ae2c9e2da44462d3ae0d3f853c67c4bf08ec3544c033947b507629f5a24e5d9e31a3b0a6162f749 + checksum: 37a3d92267a2a32c2cc17fd1f0ab2b336f75fb7807db88f6194efede9d6a66068658a7effb7773451404fca990924393dbbf3d57e2aca67ef2e489a85666e225 languageName: node linkType: hard @@ -12757,13 +12804,13 @@ __metadata: languageName: node linkType: hard -"@smithy/protocol-http@npm:^4.0.0, @smithy/protocol-http@npm:^4.0.1": - version: 4.0.1 - resolution: "@smithy/protocol-http@npm:4.0.1" +"@smithy/protocol-http@npm:^4.0.3": + version: 4.0.3 + resolution: "@smithy/protocol-http@npm:4.0.3" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: bf6c972eda49f786657177a5e2c9be037dec665b97f7e62000e57cbc5dc8cefb08988841f807ef28b8300e271ca26e82702248410e6f12d3a3dee390632e56d1 + checksum: 8869db000d94c7e788cff6eb26b5081aef78f4db8f5ab586a2b179d16db8b33e9df5e6e8fd26f5517c01507a4de3446a598b0575e04334e023d07f00f9af3df8 languageName: node linkType: hard @@ -12789,14 +12836,14 @@ __metadata: languageName: node linkType: hard -"@smithy/querystring-builder@npm:^3.0.1": - version: 3.0.1 - resolution: "@smithy/querystring-builder@npm:3.0.1" +"@smithy/querystring-builder@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/querystring-builder@npm:3.0.3" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 "@smithy/util-uri-escape": ^3.0.0 tslib: ^2.6.2 - checksum: cada00dbca2d605484377582cd1f2937dc615c9eea326d6ea4275bb28da55719e5653c53366e019e7a0b3b8ab73e0bfafd3c640e7f313693fd71dab88be18888 + checksum: 5c46c620d87f9b4e67b8eb543667b0160fb05bbec01d62d45adb94305369dca9e82daba47d81e840fdc399fa47f9b5930ce668d65fe83ee278a1b27d59d0b5d3 languageName: node linkType: hard @@ -12810,13 +12857,13 @@ __metadata: languageName: node linkType: hard -"@smithy/querystring-parser@npm:^3.0.1": - version: 3.0.1 - resolution: "@smithy/querystring-parser@npm:3.0.1" +"@smithy/querystring-parser@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/querystring-parser@npm:3.0.3" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 2697162eae53c70a38da7afb246092d641d66c12a5bf042201650560c511ee68f4908b404b4e6ded871c7c748b42e6317de6b7ea2ad4313b1663bcf0a1f8be67 + checksum: 1de11cbc4325578b243a0e3e89b46371f4705d3df41ea51b37e8efa655d3b75253180b0fca9ceed8b3955a2d458689f551cd24fd904d0f65647c62c6b08795bf languageName: node linkType: hard @@ -12829,12 +12876,12 @@ __metadata: languageName: node linkType: hard -"@smithy/service-error-classification@npm:^3.0.1": - version: 3.0.1 - resolution: "@smithy/service-error-classification@npm:3.0.1" +"@smithy/service-error-classification@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/service-error-classification@npm:3.0.3" dependencies: - "@smithy/types": ^3.1.0 - checksum: b210d5b77ca200db1197aa8015501c5c69727eee12e84b7595b5596953a10bfc18ee37e54609ae1546d00bbb81c2dbd9d54828d5fc63af895b3c3be942c01f26 + "@smithy/types": ^3.3.0 + checksum: 5bef710f5698c929c97865cba41f36b0c59100b9a1c4478a2d47caeb5e3a1a18077b870b365efaa45c94666f2075bc8978f7a6e8b964afbba3a4e490eb6c13eb languageName: node linkType: hard @@ -12848,13 +12895,13 @@ __metadata: languageName: node linkType: hard -"@smithy/shared-ini-file-loader@npm:^3.1.0, @smithy/shared-ini-file-loader@npm:^3.1.1": - version: 3.1.1 - resolution: "@smithy/shared-ini-file-loader@npm:3.1.1" +"@smithy/shared-ini-file-loader@npm:^3.1.4": + version: 3.1.4 + resolution: "@smithy/shared-ini-file-loader@npm:3.1.4" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: ea05a372dfce029af363014886274cb4ecc1a466a65c72370abf9964855647741a5deb6aee417c90fe744f61091670efa06989ebb37202ff52c4630b46a682dc + checksum: c5321635f3be34e424009fc9045454a9ceec543ec20b3b9719bf3a48bbfc03b794f4545546e9c2dcb0a987de2ca5ff8999df9bf7c166c6fc7685c1fa1f068bc1 languageName: node linkType: hard @@ -12874,18 +12921,18 @@ __metadata: languageName: node linkType: hard -"@smithy/signature-v4@npm:^3.0.0": - version: 3.0.1 - resolution: "@smithy/signature-v4@npm:3.0.1" +"@smithy/signature-v4@npm:^3.1.2": + version: 3.1.2 + resolution: "@smithy/signature-v4@npm:3.1.2" dependencies: "@smithy/is-array-buffer": ^3.0.0 - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 "@smithy/util-hex-encoding": ^3.0.0 - "@smithy/util-middleware": ^3.0.1 + "@smithy/util-middleware": ^3.0.3 "@smithy/util-uri-escape": ^3.0.0 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 23f8a1e47c8d452af5e1a7c9f02a7a764c6e7316c10592dfd57f87204851c0927278f87d9ecc23b9f0e8778ef28e4508eb00b267dceb68fd634dacf08d292f0e + checksum: 5d10bfe89116a79ea13fe159b05d7fc10f7f67f11333cad6b96990b862cae9ed6c7c7a466d0bf296368610a43e34730feab0ec62f214019f18c61115d4dc8923 languageName: node linkType: hard @@ -12903,17 +12950,17 @@ __metadata: languageName: node linkType: hard -"@smithy/smithy-client@npm:^3.1.1, @smithy/smithy-client@npm:^3.1.2": - version: 3.1.2 - resolution: "@smithy/smithy-client@npm:3.1.2" +"@smithy/smithy-client@npm:^3.1.7": + version: 3.1.7 + resolution: "@smithy/smithy-client@npm:3.1.7" dependencies: - "@smithy/middleware-endpoint": ^3.0.2 - "@smithy/middleware-stack": ^3.0.1 - "@smithy/protocol-http": ^4.0.1 - "@smithy/types": ^3.1.0 - "@smithy/util-stream": ^3.0.2 + "@smithy/middleware-endpoint": ^3.0.5 + "@smithy/middleware-stack": ^3.0.3 + "@smithy/protocol-http": ^4.0.3 + "@smithy/types": ^3.3.0 + "@smithy/util-stream": ^3.0.6 tslib: ^2.6.2 - checksum: 0ac896c1ae5cb8e6f044f74df37f458bf6a18faabdb9aea3b8aa0a70710bb0109f3f744d5bfd5c75dcb52da40167cd0b1521c85af356d37a60aefcc60a750238 + checksum: ce644e23dafaade96bd00f1d80d3dce54b72e7c2ef22bb9c504c4b237fad2df2f91da0780c26e7a44936dbd73e8cfee3cb423f6db48a56d52c9c3218454be575 languageName: node linkType: hard @@ -12935,12 +12982,12 @@ __metadata: languageName: node linkType: hard -"@smithy/types@npm:^3.0.0, @smithy/types@npm:^3.1.0": - version: 3.1.0 - resolution: "@smithy/types@npm:3.1.0" +"@smithy/types@npm:^3.3.0": + version: 3.3.0 + resolution: "@smithy/types@npm:3.3.0" dependencies: tslib: ^2.6.2 - checksum: 8bb0934cfdc16e41ebd519196ba0d1574bd70d7006dae17117a1b40a19ac40e98f00c8f7b695abbc90fec14e8b8252a274ad54a9bbd4aa706c65b89b89142f25 + checksum: 29bb5f83c41e32f8d4094a2aba2d3dfbd763ab5943784a700f3fa22df0dcf0ccac1b1907f7a87fbb9f6f2269fcd4750524bcb48f892249e200ffe397c0981309 languageName: node linkType: hard @@ -12955,14 +13002,14 @@ __metadata: languageName: node linkType: hard -"@smithy/url-parser@npm:^3.0.0, @smithy/url-parser@npm:^3.0.1": - version: 3.0.1 - resolution: "@smithy/url-parser@npm:3.0.1" +"@smithy/url-parser@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/url-parser@npm:3.0.3" dependencies: - "@smithy/querystring-parser": ^3.0.1 - "@smithy/types": ^3.1.0 + "@smithy/querystring-parser": ^3.0.3 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 9ad3dd58a1ad4e11a3ecf3b97411ac5577e72057f7590964e425ecdbe558614959d4c6ed403fb38aea29361193c78283f9c337fe111af0692f16ac96105c3ab3 + checksum: 86b4bc8e6c176b56076c30233ca4cfeb98d162fe27a348ddfda5f163ce7d173b8e684aa26202bbf4e0b5695b0ad43c0cb40170ca6793652d0ea6edb00443c036 languageName: node linkType: hard @@ -13075,16 +13122,16 @@ __metadata: languageName: node linkType: hard -"@smithy/util-defaults-mode-browser@npm:^3.0.3": - version: 3.0.4 - resolution: "@smithy/util-defaults-mode-browser@npm:3.0.4" +"@smithy/util-defaults-mode-browser@npm:^3.0.9": + version: 3.0.9 + resolution: "@smithy/util-defaults-mode-browser@npm:3.0.9" dependencies: - "@smithy/property-provider": ^3.1.1 - "@smithy/smithy-client": ^3.1.2 - "@smithy/types": ^3.1.0 + "@smithy/property-provider": ^3.1.3 + "@smithy/smithy-client": ^3.1.7 + "@smithy/types": ^3.3.0 bowser: ^2.11.0 tslib: ^2.6.2 - checksum: bd86e24d831d64fd9d5f267ab8c42508b4b0252f0fe5f2333d4c28e47bbf407b9e3790df071325cad6b25977c6b449055fade579163ea1d954b19eabab0a78fa + checksum: e8e7b414af4dc0b66782cf92bd103ebae66431025069768f8f5df0794a337843d51bd8c7f6a620a895cc0923f8f054a57aca7340083fec9732da48f414d75ba7 languageName: node linkType: hard @@ -13103,18 +13150,18 @@ __metadata: languageName: node linkType: hard -"@smithy/util-defaults-mode-node@npm:^3.0.3": - version: 3.0.4 - resolution: "@smithy/util-defaults-mode-node@npm:3.0.4" - dependencies: - "@smithy/config-resolver": ^3.0.2 - "@smithy/credential-provider-imds": ^3.1.1 - "@smithy/node-config-provider": ^3.1.1 - "@smithy/property-provider": ^3.1.1 - "@smithy/smithy-client": ^3.1.2 - "@smithy/types": ^3.1.0 +"@smithy/util-defaults-mode-node@npm:^3.0.9": + version: 3.0.9 + resolution: "@smithy/util-defaults-mode-node@npm:3.0.9" + dependencies: + "@smithy/config-resolver": ^3.0.5 + "@smithy/credential-provider-imds": ^3.1.4 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/property-provider": ^3.1.3 + "@smithy/smithy-client": ^3.1.7 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: e9be558d2371db5d568456a824aa5348abaf3f1c828f805e9a8eb4c5df6e4c1c37fda217ef860988b1b65855e9a4f162bcdd6e56a96fa5fcfab0bbb53690115f + checksum: e0159856f22f5bb1825e16e263e19e4a16cd29c04d81a88c4aad90cb36d4f1733f8fe43298751e8bfda9f00f16951860c7a9f84833e948b28002349cee454162 languageName: node linkType: hard @@ -13129,14 +13176,14 @@ __metadata: languageName: node linkType: hard -"@smithy/util-endpoints@npm:^2.0.1": - version: 2.0.2 - resolution: "@smithy/util-endpoints@npm:2.0.2" +"@smithy/util-endpoints@npm:^2.0.5": + version: 2.0.5 + resolution: "@smithy/util-endpoints@npm:2.0.5" dependencies: - "@smithy/node-config-provider": ^3.1.1 - "@smithy/types": ^3.1.0 + "@smithy/node-config-provider": ^3.1.4 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: a3eab500202f8f855d9a7b0d4580a1968006b9a92c298c54d44cfb15f5abfdfe88be5cfec9dfba0365682ba00c863cd317054a26646e25bdeeb695bd16cf9786 + checksum: bb2a96323f52beaf2820f4e5764c865cff3ac5bca0c0df6923bb4582b0f87faf1606110cd4e36005ac43f41e9673ebdca4bbb8b913880fc2a4e0ff3301250da8 languageName: node linkType: hard @@ -13168,13 +13215,13 @@ __metadata: languageName: node linkType: hard -"@smithy/util-middleware@npm:^3.0.0, @smithy/util-middleware@npm:^3.0.1": - version: 3.0.1 - resolution: "@smithy/util-middleware@npm:3.0.1" +"@smithy/util-middleware@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/util-middleware@npm:3.0.3" dependencies: - "@smithy/types": ^3.1.0 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 5bb4befb5cb5385fe7089c2574ff1f9bb920f6d03b56a881666d9f6d0b6611b6108046bb6638061cd73cb4aef8701515be55f94b713259aaadd7594474b266f9 + checksum: f37f25d65595af5ff4c3f69fa7e66545ac1651f77979e15ffbc9047e18fc668dae90458ee76add85a49ea3729c49d317e40542d5430e81e2eafe8dcae2ddb3bc languageName: node linkType: hard @@ -13189,14 +13236,14 @@ __metadata: languageName: node linkType: hard -"@smithy/util-retry@npm:^3.0.0, @smithy/util-retry@npm:^3.0.1": - version: 3.0.1 - resolution: "@smithy/util-retry@npm:3.0.1" +"@smithy/util-retry@npm:^3.0.3": + version: 3.0.3 + resolution: "@smithy/util-retry@npm:3.0.3" dependencies: - "@smithy/service-error-classification": ^3.0.1 - "@smithy/types": ^3.1.0 + "@smithy/service-error-classification": ^3.0.3 + "@smithy/types": ^3.3.0 tslib: ^2.6.2 - checksum: 677f1a71c5f0aa69a4a60f184e44d41b0b22951789e74dd540bb3213de8ef380321777c8e1fde85e4c61a784cd4bc7d773eeae02ab6408dfafc5ed3655f46674 + checksum: c760595376154be67414083aa6f76094022df72987521469b124ef3ef5848c0536757dcd2006520580380db6a4d7b597a05569470c3151f71d5e678df63f4c13 languageName: node linkType: hard @@ -13216,19 +13263,19 @@ __metadata: languageName: node linkType: hard -"@smithy/util-stream@npm:^3.0.1, @smithy/util-stream@npm:^3.0.2": - version: 3.0.2 - resolution: "@smithy/util-stream@npm:3.0.2" +"@smithy/util-stream@npm:^3.0.6": + version: 3.0.6 + resolution: "@smithy/util-stream@npm:3.0.6" dependencies: - "@smithy/fetch-http-handler": ^3.0.2 - "@smithy/node-http-handler": ^3.0.1 - "@smithy/types": ^3.1.0 + "@smithy/fetch-http-handler": ^3.2.1 + "@smithy/node-http-handler": ^3.1.2 + "@smithy/types": ^3.3.0 "@smithy/util-base64": ^3.0.0 "@smithy/util-buffer-from": ^3.0.0 "@smithy/util-hex-encoding": ^3.0.0 "@smithy/util-utf8": ^3.0.0 tslib: ^2.6.2 - checksum: 9e9449b2d4c30fca4d01a1721a4097ed170fa79399287cddb32cf44e60a0fda1470c9fcba025013975c6fbf7b95d9546aa3588fef1c8640f8c82f1061c1fdc1e + checksum: 17b303d8bbc085975ba84d3acd3ac01dd1d88734e01462ab078614799c28cac6c4476ecd98411a3b9de325b4b03a5fa11050bcc13a845d3812883c371f0b6b5e languageName: node linkType: hard @@ -13259,7 +13306,7 @@ __metadata: languageName: node linkType: hard -"@smithy/util-utf8@npm:^2.3.0": +"@smithy/util-utf8@npm:^2.0.0, @smithy/util-utf8@npm:^2.3.0": version: 2.3.0 resolution: "@smithy/util-utf8@npm:2.3.0" dependencies: @@ -13915,12 +13962,13 @@ __metadata: languageName: node linkType: hard -"@types/fs-extra@npm:^8.0.1": - version: 8.1.2 - resolution: "@types/fs-extra@npm:8.1.2" +"@types/fs-extra@npm:^11.0.4": + version: 11.0.4 + resolution: "@types/fs-extra@npm:11.0.4" dependencies: + "@types/jsonfile": "*" "@types/node": "*" - checksum: 7277198ded9caea5750c82e569ba1e6fbac28cdb4a95e5d52d24e7c4c2ac90bf45fbe89e08fc21de8f9d3c9b302e30680566eb04e460c30ceac66ad24c161b37 + checksum: 242cb84157631f057f76495c8220707541882c00a00195b603d937fb55e471afecebcb089bab50233ed3a59c69fd68bf65c1f69dd7fafe2347e139cc15b9b0e5 languageName: node linkType: hard @@ -14120,6 +14168,15 @@ __metadata: languageName: node linkType: hard +"@types/jsonfile@npm:*": + version: 6.1.4 + resolution: "@types/jsonfile@npm:6.1.4" + dependencies: + "@types/node": "*" + checksum: 309fda20eb5f1cf68f2df28931afdf189c5e7e6bec64ac783ce737bb98908d57f6f58757ad5da9be37b815645a6f914e2d4f3ac66c574b8fe1ba6616284d0e97 + languageName: node + linkType: hard + "@types/jsonpack@npm:^1.1.0": version: 1.1.2 resolution: "@types/jsonpack@npm:1.1.2" @@ -14528,12 +14585,12 @@ __metadata: linkType: hard "@types/readable-stream@npm:^4.0.0, @types/readable-stream@npm:^4.0.5": - version: 4.0.14 - resolution: "@types/readable-stream@npm:4.0.14" + version: 4.0.15 + resolution: "@types/readable-stream@npm:4.0.15" dependencies: "@types/node": "*" safe-buffer: ~5.1.1 - checksum: 3b95cfbeb797ea480a3a3a80ddaac1b8ac065fdd000120a8379bcf2817795b61724823a90acdd3868ed60829d0630a6aa492e2302ecab182f25cffaf60e8826f + checksum: 1822760640a032064a98a1adb9d46e0ca74754394cb78e7cbec4e5f7900576e615b7fc374753addb80cbb75907ac9c21d955b7f20d29a7698a0d83525d87bb41 languageName: node linkType: hard @@ -15270,7 +15327,7 @@ __metadata: chalk: ^4.1.0 execa: ^5.1.1 folder-hash: ^4.0.4 - fs-extra: ^7.0.1 + fs-extra: ^11.2.0 listr2: ^5.0.8 load-json-file: ^6.2.0 ts-node: ^10.5.0 @@ -15287,7 +15344,7 @@ __metadata: dependencies: chalk: ^4.1.0 find-up: 5.0.0 - fs-extra: ^7.0.1 + fs-extra: ^11.2.0 get-yarn-workspaces: 1.0.2 load-json-file: ^6.2.0 lodash: ^4.17.21 @@ -15915,7 +15972,7 @@ __metadata: commodo-fields-object: ^1.0.6 csvtojson: ^2.0.10 date-fns: ^2.22.1 - fs-extra: ^9.1.0 + fs-extra: ^11.2.0 jest: ^29.7.0 jest-dynalite: ^3.2.0 json2csv: ^4.5.2 @@ -16361,7 +16418,7 @@ __metadata: archiver: ^7.0.1 commodo-fields-object: ^1.0.6 dot-prop-immutable: ^2.1.0 - fs-extra: ^9.1.0 + fs-extra: ^11.2.0 jest: ^29.7.0 jest-dynalite: ^3.2.0 load-json-file: ^6.2.0 @@ -16495,7 +16552,7 @@ __metadata: bytes: ^3.1.0 dataloader: ^2.0.0 extract-zip: ^1.6.7 - fs-extra: ^9.1.0 + fs-extra: ^11.2.0 jest: ^29.7.0 jsonpack: ^1.1.5 load-json-file: ^6.2.0 @@ -18499,9 +18556,11 @@ __metadata: apollo-link-http-common: ^0.2.16 apollo-utilities: ^1.3.4 boolean: ^3.0.1 + bytes: ^3.0.0 graphql: ^15.7.2 invariant: ^2.2.4 lodash: ^4.17.21 + minimatch: ^5.1.0 nanoid: ^3.3.7 react: 18.2.0 react-dom: 18.2.0 @@ -18673,6 +18732,7 @@ __metadata: execa: ^5.0.0 glob: ^7.1.2 load-json-file: ^6.2.0 + lodash: ^4.17.21 ncp: ^2.0.0 replace-in-path: ^1.1.0 rimraf: ^5.0.5 @@ -18906,7 +18966,7 @@ __metadata: execa: ^5.0.0 fast-glob: ^3.2.7 find-up: 5.0.0 - fs-extra: ^9.1.0 + fs-extra: ^11.2.0 graphql-request: ^3.7.0 inquirer: ^7.3.3 is-ci: ^3.0.0 @@ -18934,7 +18994,7 @@ __metadata: dotenv: ^8.2.0 execa: ^5.0.0 fast-glob: ^3.2.7 - fs-extra: ^9.0.1 + fs-extra: ^11.2.0 get-yarn-workspaces: 1.0.2 inquirer: 7.3.3 load-json-file: 6.2.0 @@ -18942,7 +19002,6 @@ __metadata: open: ^8.4.0 ora: 4.1.1 write-json-file: 4.3.0 - yesno: ^0.4.0 languageName: unknown linkType: soft @@ -19512,7 +19571,7 @@ __metadata: eslint-webpack-plugin: ^3.1.1 file-loader: 6.2.0 fork-ts-checker-webpack-plugin: ^9.0.2 - fs-extra: ^9.1.0 + fs-extra: ^11.2.0 get-yarn-workspaces: 1.0.2 glob: ^7.1.2 html-webpack-plugin: 5.5.0 @@ -19622,7 +19681,7 @@ __metadata: "@webiny/project-utils": 0.0.0 decompress: ^4.2.1 execa: ^5.0.0 - fs-extra: ^9.1.0 + fs-extra: ^11.2.0 lodash: ^4.17.21 node-fetch: ^2.6.9 rimraf: ^5.0.5 @@ -21947,14 +22006,14 @@ __metadata: linkType: hard "bl@npm:^6.0.8": - version: 6.0.12 - resolution: "bl@npm:6.0.12" + version: 6.0.14 + resolution: "bl@npm:6.0.14" dependencies: "@types/readable-stream": ^4.0.0 buffer: ^6.0.3 inherits: ^2.0.4 readable-stream: ^4.2.0 - checksum: 10cdc8264a7f3c53f62ec6942ace2f9fa8c1437ea3d466606ad9dc2585f6f08405907875f7ab454af79453efaafa0e0f53e382dad95b7d4b288ef912e53e6125 + checksum: 689e1ebc3d3af51ca29fec93ef0b7e4112544a3aba451e1b93534dd293c816304400086e89709f2c215f232d0d2ac73cb6a322c1522dc11679e7807875d0cc19 languageName: node linkType: hard @@ -23983,7 +24042,7 @@ __metadata: chalk: ^4.1.0 execa: ^5.0.0 find-up: 5.0.0 - fs-extra: ^9.0.1 + fs-extra: ^11.2.0 js-yaml: 3.14.1 listr: 0.14.3 load-json-file: 6.2.0 @@ -23996,6 +24055,7 @@ __metadata: validate-npm-package-name: 3.0.0 write-json-file: 4.3.0 yargs: 15.4.1 + yesno: ^0.4.0 bin: create-webiny-project: ./bin.js languageName: unknown @@ -27609,7 +27669,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^7.0.0, fs-extra@npm:^7.0.1": +"fs-extra@npm:^7.0.1": version: 7.0.1 resolution: "fs-extra@npm:7.0.1" dependencies: @@ -27620,7 +27680,7 @@ __metadata: languageName: node linkType: hard -"fs-extra@npm:^9.0.0, fs-extra@npm:^9.0.1, fs-extra@npm:^9.1.0": +"fs-extra@npm:^9.0.0, fs-extra@npm:^9.1.0": version: 9.1.0 resolution: "fs-extra@npm:9.1.0" dependencies: @@ -33177,8 +33237,8 @@ __metadata: linkType: hard "mqtt@npm:^5.2.0, mqtt@npm:^5.5.2": - version: 5.7.0 - resolution: "mqtt@npm:5.7.0" + version: 5.8.0 + resolution: "mqtt@npm:5.8.0" dependencies: "@types/readable-stream": ^4.0.5 "@types/ws": ^8.5.9 @@ -33196,12 +33256,12 @@ __metadata: rfdc: ^1.3.0 split2: ^4.2.0 worker-timers: ^7.1.4 - ws: ^8.14.2 + ws: ^8.17.1 bin: mqtt: build/bin/mqtt.js mqtt_pub: build/bin/pub.js mqtt_sub: build/bin/sub.js - checksum: 65b3452a8db4414a76d779554e618a0e3bf27d342235cf3cb543635a44f5f2039d1f5f49c1bbb74f80da6192f3460c87ed27edcec31d299bd9618877743272bd + checksum: b44e4cc5086ff548bf240e5b7d9961ffaf028d608f935b95a7efd2b9c40601496ba1142cb41d421d0f31000840dc01165bcb1b1d6daa943072725396f566f0d3 languageName: node linkType: hard @@ -38520,7 +38580,7 @@ __metadata: "@commitlint/cli": ^11.0.0 "@commitlint/config-conventional": ^11.0.0 "@octokit/rest": ^20.0.2 - "@types/fs-extra": ^8.0.1 + "@types/fs-extra": ^11.0.4 "@types/hoist-non-react-statics": ^3.3.5 "@types/jest": ^29.5.11 "@types/node": ^18.0.0 @@ -38550,7 +38610,7 @@ __metadata: eslint-plugin-standard: ^5.0.0 execa: ^5.1.1 folder-hash: ^4.0.0 - fs-extra: ^7.0.0 + fs-extra: ^11.2.0 fsevents: ^2.0.7 get-stream: ^3.0.0 get-yarn-workspaces: ^1.0.2 @@ -42663,9 +42723,9 @@ __metadata: languageName: node linkType: hard -"ws@npm:^8.14.2": - version: 8.17.0 - resolution: "ws@npm:8.17.0" +"ws@npm:^8.17.1": + version: 8.18.0 + resolution: "ws@npm:8.18.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -42674,7 +42734,7 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 147ef9eab0251364e1d2c55338ad0efb15e6913923ccbfdf20f7a8a6cb8f88432bcd7f4d8f66977135bfad35575644f9983201c1a361019594a4e53977bf6d4e + checksum: 91d4d35bc99ff6df483bdf029b9ea4bfd7af1f16fc91231a96777a63d263e1eabf486e13a2353970efc534f9faa43bdbf9ee76525af22f4752cbc5ebda333975 languageName: node linkType: hard