From aefa45562157cdde768b5b122e2cf206fadc5cb1 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Thu, 19 Sep 2024 10:16:46 +0200 Subject: [PATCH 01/17] Remove unused `pageTreeNodeForPredefinedPage` query --- demo/api/schema.gql | 1 - .../predefined-page/predefined-page.module.ts | 4 +- .../predefined-page.resolver.ts | 24 +-------- .../predefined-page.service.ts | 50 ------------------- 4 files changed, 2 insertions(+), 77 deletions(-) delete mode 100644 demo/api/src/predefined-page/predefined-page.service.ts diff --git a/demo/api/schema.gql b/demo/api/schema.gql index 0e6cf3af7c..f1714b8fda 100644 --- a/demo/api/schema.gql +++ b/demo/api/schema.gql @@ -771,7 +771,6 @@ type Query { mainMenuItem(pageTreeNodeId: ID!): MainMenuItem! footer(scope: FooterContentScopeInput!): Footer predefinedPage(id: ID!): PredefinedPage - pageTreeNodeForPredefinedPage(type: String!, scope: PageTreeNodeScopeInput!): PageTreeNode kubernetesCronJobs: [KubernetesCronJob!]! kubernetesCronJob(name: String!): KubernetesCronJob! kubernetesJobs(cronJobName: String!): [KubernetesJob!]! diff --git a/demo/api/src/predefined-page/predefined-page.module.ts b/demo/api/src/predefined-page/predefined-page.module.ts index a9e8c495da..4bdd88da9f 100644 --- a/demo/api/src/predefined-page/predefined-page.module.ts +++ b/demo/api/src/predefined-page/predefined-page.module.ts @@ -4,11 +4,9 @@ import { PagesModule } from "@src/pages/pages.module"; import { PredefinedPage } from "./entities/predefined-page.entity"; import { PredefinedPageResolver } from "./predefined-page.resolver"; -import { PredefinedPageService } from "./predefined-page.service"; @Module({ imports: [PagesModule, MikroOrmModule.forFeature([PredefinedPage])], - providers: [PredefinedPageResolver, PredefinedPageService], - exports: [PredefinedPageService], + providers: [PredefinedPageResolver], }) export class PredefinedPageModule {} diff --git a/demo/api/src/predefined-page/predefined-page.resolver.ts b/demo/api/src/predefined-page/predefined-page.resolver.ts index aba37da466..9a30bc80f2 100644 --- a/demo/api/src/predefined-page/predefined-page.resolver.ts +++ b/demo/api/src/predefined-page/predefined-page.resolver.ts @@ -1,23 +1,11 @@ -import { - AffectedEntity, - PageTreeNodeInterface, - PageTreeNodeVisibility, - PageTreeService, - RequestContext, - RequestContextInterface, - RequiredPermission, - validateNotModified, -} from "@comet/cms-api"; +import { AffectedEntity, PageTreeNodeVisibility, PageTreeService, RequiredPermission, validateNotModified } from "@comet/cms-api"; import { InjectRepository } from "@mikro-orm/nestjs"; import { EntityRepository } from "@mikro-orm/postgresql"; import { UnauthorizedException } from "@nestjs/common"; import { Args, ID, Mutation, Query, Resolver } from "@nestjs/graphql"; -import { PageTreeNodeScope } from "@src/page-tree/dto/page-tree-node-scope"; -import { PageTreeNode } from "@src/page-tree/entities/page-tree-node.entity"; import { PredefinedPageInput } from "./dto/predefined-page.input"; import { PredefinedPage } from "./entities/predefined-page.entity"; -import { PredefinedPageService } from "./predefined-page.service"; @Resolver(() => PredefinedPage) @RequiredPermission("pageTree") @@ -25,7 +13,6 @@ export class PredefinedPageResolver { constructor( @InjectRepository(PredefinedPage) private readonly repository: EntityRepository, private readonly pageTreeService: PageTreeService, - private readonly predefinedPageService: PredefinedPageService, ) {} @Query(() => PredefinedPage, { nullable: true }) @@ -74,13 +61,4 @@ export class PredefinedPageResolver { return this.repository.findOneOrFail(id); } - - @Query(() => PageTreeNode, { nullable: true }) - async pageTreeNodeForPredefinedPage( - @Args("type") type: string, - @Args("scope", { type: () => PageTreeNodeScope }) scope: PageTreeNodeScope, - @RequestContext() { includeInvisiblePages }: RequestContextInterface, - ): Promise { - return this.predefinedPageService.pageTreeNodeForPredefinedPage(type, scope, includeInvisiblePages); - } } diff --git a/demo/api/src/predefined-page/predefined-page.service.ts b/demo/api/src/predefined-page/predefined-page.service.ts deleted file mode 100644 index 1fe0d38eb8..0000000000 --- a/demo/api/src/predefined-page/predefined-page.service.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { PageTreeNodeInterface, PageTreeNodeVisibility, PageTreeService } from "@comet/cms-api"; -import { InjectRepository } from "@mikro-orm/nestjs"; -import { EntityRepository } from "@mikro-orm/postgresql"; -import { Injectable } from "@nestjs/common"; -import { PageTreeNodeScope } from "@src/page-tree/dto/page-tree-node-scope"; - -import { PredefinedPage } from "./entities/predefined-page.entity"; - -@Injectable() -export class PredefinedPageService { - constructor( - @InjectRepository(PredefinedPage) private readonly repository: EntityRepository, - protected readonly pageTreeService: PageTreeService, - ) {} - - async pageTreeNodeForPredefinedPage( - type: string, - scope: PageTreeNodeScope, - includeInvisiblePages?: Array, - ): Promise { - const predefinedPageNodes = await this.pageTreeService - .createReadApi({ - visibility: [PageTreeNodeVisibility.Published, ...(includeInvisiblePages || [])], - }) - .getNodes({ scope, documentType: "PredefinedPage" }); - - for (const node of predefinedPageNodes) { - const attachedDocument = await this.pageTreeService.getActiveAttachedDocument(node.id, node.documentType); - - if (!attachedDocument) { - continue; - } - - const document = (await this.pageTreeService.resolveDocument( - attachedDocument.type, - attachedDocument.documentId, - )) as PredefinedPage | null; - - if (!document) { - continue; - } - - if (document.type === type) { - return node; - } - } - - return null; - } -} From 8f88982246a6da4b6183fb13a44ff0f7bb0fe086 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Thu, 19 Sep 2024 10:18:30 +0200 Subject: [PATCH 02/17] Fix `predefinedPage` query Return value isn't nullable due to using `findOneOrFail`. --- demo/api/schema.gql | 2 +- demo/api/src/predefined-page/predefined-page.resolver.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/demo/api/schema.gql b/demo/api/schema.gql index f1714b8fda..542ccf11d0 100644 --- a/demo/api/schema.gql +++ b/demo/api/schema.gql @@ -770,7 +770,7 @@ type Query { topMenu(scope: PageTreeNodeScopeInput!): [PageTreeNode!]! mainMenuItem(pageTreeNodeId: ID!): MainMenuItem! footer(scope: FooterContentScopeInput!): Footer - predefinedPage(id: ID!): PredefinedPage + predefinedPage(id: ID!): PredefinedPage! kubernetesCronJobs: [KubernetesCronJob!]! kubernetesCronJob(name: String!): KubernetesCronJob! kubernetesJobs(cronJobName: String!): [KubernetesJob!]! diff --git a/demo/api/src/predefined-page/predefined-page.resolver.ts b/demo/api/src/predefined-page/predefined-page.resolver.ts index 9a30bc80f2..a80ea61960 100644 --- a/demo/api/src/predefined-page/predefined-page.resolver.ts +++ b/demo/api/src/predefined-page/predefined-page.resolver.ts @@ -15,10 +15,11 @@ export class PredefinedPageResolver { private readonly pageTreeService: PageTreeService, ) {} - @Query(() => PredefinedPage, { nullable: true }) + @Query(() => PredefinedPage) @AffectedEntity(PredefinedPage) - async predefinedPage(@Args("id", { type: () => ID }) id: string): Promise { - return this.repository.findOneOrFail(id); + async predefinedPage(@Args("id", { type: () => ID }) id: string): Promise { + const predefinedPage = await this.repository.findOneOrFail(id); + return predefinedPage; } @Mutation(() => PredefinedPage) From 54e4f47a9d29ec8223983420983c02d176949d0d Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Mon, 23 Sep 2024 09:13:04 +0200 Subject: [PATCH 03/17] Fix `savePredefinedPage` mutation Make sure that saving a predefined page document actually works. --- .../src/predefinedPage/EditPredefinedPage.tsx | 66 +++++++++++++------ .../predefined-page.resolver.ts | 11 ++-- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx index bae0e57101..dd5c56c9dc 100644 --- a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx @@ -1,20 +1,22 @@ -import { gql, useMutation, useQuery } from "@apollo/client"; +import { gql, useApolloClient, useQuery } from "@apollo/client"; import { FinalForm, FinalFormSaveButton, Loading, MainContent, SelectField, Toolbar, ToolbarFillSpace, ToolbarItem, useStackApi } from "@comet/admin"; import { ArrowLeft } from "@comet/admin-icons"; import { PageName } from "@comet/cms-admin"; import { IconButton, MenuItem } from "@mui/material"; +import { useMemo } from "react"; import { FormattedMessage } from "react-intl"; +import { v4 as uuid } from "uuid"; import { GQLPredefinedPageQuery, GQLPredefinedPageQueryVariables, - GQLUpdatePredefinedPageMutation, - GQLUpdatePredefinedPageMutationVariables, + GQLSavePredefinedPageMutation, + GQLSavePredefinedPageMutationVariables, } from "./EditPredefinedPage.generated"; const getQuery = gql` - query PredefinedPage($id: ID!) { - page: pageTreeNode(id: $id) { + query PredefinedPage($pageTreeNodeId: ID!) { + pageTreeNode(id: $pageTreeNodeId) { id name slug @@ -34,42 +36,64 @@ const getQuery = gql` } `; -const updateMutation = gql` - mutation UpdatePredefinedPage($pageId: ID!, $input: PredefinedPageInput!, $lastUpdatedAt: DateTime, $attachedPageTreeNodeId: ID!) { - savePredefinedPage(id: $pageId, input: $input, lastUpdatedAt: $lastUpdatedAt, attachedPageTreeNodeId: $attachedPageTreeNodeId) { +const savePredefinedPageMutation = gql` + mutation SavePredefinedPage($id: ID!, $input: PredefinedPageInput!, $lastUpdatedAt: DateTime, $attachedPageTreeNodeId: ID!) { + savePredefinedPage(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt, attachedPageTreeNodeId: $attachedPageTreeNodeId) { id type } } `; +type FormValues = { + type?: string; +}; + interface Props { id: string; } -export const EditPredefinedPage = ({ id }: Props) => { +export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { const stackApi = useStackApi(); + const client = useApolloClient(); const { data, loading } = useQuery(getQuery, { - variables: { id }, + variables: { pageTreeNodeId }, }); - const [mutation] = useMutation(updateMutation, { - refetchQueries: ["PredefinedPage"], - }); + const initialValues = useMemo>(() => { + if (data?.pageTreeNode?.document) { + if (data.pageTreeNode.document.__typename !== "PredefinedPage") { + throw new Error(`Invalid document type: ${data.pageTreeNode.document.__typename}`); + } + + return { + type: data.pageTreeNode.document.type ?? undefined, + }; + } + + return {}; + }, [data]); + + const handleSubmit = async (formValues: FormValues) => { + const output = { + type: formValues.type ?? null, + }; + + const id = data?.pageTreeNode?.document?.id ?? uuid(); + + await client.mutate({ + mutation: savePredefinedPageMutation, + variables: { id, input: output, attachedPageTreeNodeId: pageTreeNodeId }, + }); + }; if (loading) { return ; } return ( - { - mutation({ variables: { pageId: id, input: { type: "News" }, attachedPageTreeNodeId: id } }); - }} - > + {({ pristine, hasValidationErrors, submitting, handleSubmit, hasSubmitErrors }) => { return ( <> @@ -79,7 +103,7 @@ export const EditPredefinedPage = ({ id }: Props) => { - + diff --git a/demo/api/src/predefined-page/predefined-page.resolver.ts b/demo/api/src/predefined-page/predefined-page.resolver.ts index a80ea61960..f5e5ed33c9 100644 --- a/demo/api/src/predefined-page/predefined-page.resolver.ts +++ b/demo/api/src/predefined-page/predefined-page.resolver.ts @@ -1,6 +1,6 @@ import { AffectedEntity, PageTreeNodeVisibility, PageTreeService, RequiredPermission, validateNotModified } from "@comet/cms-api"; import { InjectRepository } from "@mikro-orm/nestjs"; -import { EntityRepository } from "@mikro-orm/postgresql"; +import { EntityManager, EntityRepository } from "@mikro-orm/postgresql"; import { UnauthorizedException } from "@nestjs/common"; import { Args, ID, Mutation, Query, Resolver } from "@nestjs/graphql"; @@ -11,6 +11,7 @@ import { PredefinedPage } from "./entities/predefined-page.entity"; @RequiredPermission("pageTree") export class PredefinedPageResolver { constructor( + private readonly entityManager: EntityManager, @InjectRepository(PredefinedPage) private readonly repository: EntityRepository, private readonly pageTreeService: PageTreeService, ) {} @@ -29,7 +30,7 @@ export class PredefinedPageResolver { @Args("input", { type: () => PredefinedPageInput }) input: PredefinedPageInput, @Args("attachedPageTreeNodeId", { type: () => ID }) attachedPageTreeNodeId: string, @Args("lastUpdatedAt", { type: () => Date, nullable: true }) lastUpdatedAt?: Date, - ): Promise { + ): Promise { // all pageTypes need this is-archived-page-check // TODO: maybe implemented in a base-(document|page)-service which lives in @comet/cms-api const pageTreeNode = await this.pageTreeService.createReadApi({ visibility: "all" }).getNodeOrFail(attachedPageTreeNodeId); @@ -52,14 +53,12 @@ export class PredefinedPageResolver { id, type: input.type, }); - - this.repository.persist(predefinedPage); } await this.pageTreeService.attachDocument({ id, type: "PredefinedPage" }, attachedPageTreeNodeId); - await this.repository.flush(); + await this.entityManager.flush(); - return this.repository.findOneOrFail(id); + return predefinedPage; } } From 0536879aeb8004ae424b918a46f46dc9ec5f6c85 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Mon, 23 Sep 2024 09:17:39 +0200 Subject: [PATCH 04/17] Move GraphQL documents to .gql file We do this for the Admin Generator, so we should do it here as well. --- .../predefinedPage/EditPredefinedPage.gql.ts | 37 ++++++++++++++++++ .../src/predefinedPage/EditPredefinedPage.tsx | 38 ++----------------- 2 files changed, 41 insertions(+), 34 deletions(-) create mode 100644 demo/admin/src/predefinedPage/EditPredefinedPage.gql.ts diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.gql.ts b/demo/admin/src/predefinedPage/EditPredefinedPage.gql.ts new file mode 100644 index 0000000000..36e3ac58e0 --- /dev/null +++ b/demo/admin/src/predefinedPage/EditPredefinedPage.gql.ts @@ -0,0 +1,37 @@ +import { gql } from "@apollo/client"; + +export const predefinedPageFormFragment = gql` + fragment PredefinedPageForm on PredefinedPage { + type + } +`; + +export const predefinedPageQuery = gql` + query PredefinedPage($pageTreeNodeId: ID!) { + pageTreeNode(id: $pageTreeNodeId) { + id + document { + __typename + ... on DocumentInterface { + id + updatedAt + } + ... on PredefinedPage { + ...PredefinedPageForm + } + } + } + } + ${predefinedPageFormFragment} +`; + +export const savePredefinedPageMutation = gql` + mutation SavePredefinedPage($id: ID!, $input: PredefinedPageInput!, $lastUpdatedAt: DateTime, $attachedPageTreeNodeId: ID!) { + savePredefinedPage(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt, attachedPageTreeNodeId: $attachedPageTreeNodeId) { + id + updatedAt + ...PredefinedPageForm + } + } + ${predefinedPageFormFragment} +`; diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx index dd5c56c9dc..b56088d194 100644 --- a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx @@ -1,4 +1,4 @@ -import { gql, useApolloClient, useQuery } from "@apollo/client"; +import { useApolloClient, useQuery } from "@apollo/client"; import { FinalForm, FinalFormSaveButton, Loading, MainContent, SelectField, Toolbar, ToolbarFillSpace, ToolbarItem, useStackApi } from "@comet/admin"; import { ArrowLeft } from "@comet/admin-icons"; import { PageName } from "@comet/cms-admin"; @@ -7,43 +7,13 @@ import { useMemo } from "react"; import { FormattedMessage } from "react-intl"; import { v4 as uuid } from "uuid"; +import { predefinedPageQuery, savePredefinedPageMutation } from "./EditPredefinedPage.gql"; import { GQLPredefinedPageQuery, GQLPredefinedPageQueryVariables, GQLSavePredefinedPageMutation, GQLSavePredefinedPageMutationVariables, -} from "./EditPredefinedPage.generated"; - -const getQuery = gql` - query PredefinedPage($pageTreeNodeId: ID!) { - pageTreeNode(id: $pageTreeNodeId) { - id - name - slug - parentId - document { - __typename - ... on DocumentInterface { - id - updatedAt - } - ... on PredefinedPage { - id - type - } - } - } - } -`; - -const savePredefinedPageMutation = gql` - mutation SavePredefinedPage($id: ID!, $input: PredefinedPageInput!, $lastUpdatedAt: DateTime, $attachedPageTreeNodeId: ID!) { - savePredefinedPage(id: $id, input: $input, lastUpdatedAt: $lastUpdatedAt, attachedPageTreeNodeId: $attachedPageTreeNodeId) { - id - type - } - } -`; +} from "./EditPredefinedPage.gql.generated"; type FormValues = { type?: string; @@ -57,7 +27,7 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { const stackApi = useStackApi(); const client = useApolloClient(); - const { data, loading } = useQuery(getQuery, { + const { data, loading } = useQuery(predefinedPageQuery, { variables: { pageTreeNodeId }, }); From 5ba862bd057be0e7d96be8b5a01b935802c139b4 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Mon, 23 Sep 2024 09:18:25 +0200 Subject: [PATCH 05/17] Remove unused Final Form render props --- .../src/predefinedPage/EditPredefinedPage.tsx | 52 +++++++++---------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx index b56088d194..267a82feb0 100644 --- a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx @@ -64,33 +64,31 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { return ( - {({ pristine, hasValidationErrors, submitting, handleSubmit, hasSubmitErrors }) => { - return ( - <> - - - - - - - - - - - - - - } name="type" fullWidth> - {predefinedPageOptions.map((item, index) => ( - - {item.name} - - ))} - - - - ); - }} + {() => ( + <> + + + + + + + + + + + + + + } name="type" fullWidth> + {predefinedPageOptions.map((item, index) => ( + + {item.name} + + ))} + + + + )} ); }; From f6803a07e0722565e6640c88fb84348163d79bc3 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Mon, 23 Sep 2024 09:20:19 +0200 Subject: [PATCH 06/17] Fix message IDs Predefined pages aren't structured content. --- demo/admin/src/predefinedPage/EditPredefinedPage.tsx | 4 ++-- demo/admin/src/predefinedPage/PredefinedPage.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx index 267a82feb0..e7ba4d88d2 100644 --- a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx @@ -79,7 +79,7 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { - } name="type" fullWidth> + } name="type" fullWidth> {predefinedPageOptions.map((item, index) => ( {item.name} @@ -93,4 +93,4 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { ); }; -const predefinedPageOptions = [{ value: "News", name: }]; +const predefinedPageOptions = [{ value: "News", name: }]; diff --git a/demo/admin/src/predefinedPage/PredefinedPage.tsx b/demo/admin/src/predefinedPage/PredefinedPage.tsx index b99bf77906..9167daad6b 100644 --- a/demo/admin/src/predefinedPage/PredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/PredefinedPage.tsx @@ -23,7 +23,7 @@ const predefinedPageInfoTagQuery = gql` `; export const PredefinedPage: DocumentInterface, GQLPredefinedPageInput> = { - displayName: , + displayName: , editComponent: EditPredefinedPage, getQuery: gql` query PredefinedPageDocument($id: ID!) { From 90393ced76ae44b957c8872923b1a42a64b4d242 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Mon, 23 Sep 2024 09:23:01 +0200 Subject: [PATCH 07/17] Add missing chip in info tag --- demo/admin/src/predefinedPage/PredefinedPage.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/demo/admin/src/predefinedPage/PredefinedPage.tsx b/demo/admin/src/predefinedPage/PredefinedPage.tsx index 9167daad6b..afbfcdd829 100644 --- a/demo/admin/src/predefinedPage/PredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/PredefinedPage.tsx @@ -1,6 +1,7 @@ import { useQuery } from "@apollo/client"; import { FileData, FileDataNotMenu } from "@comet/admin-icons"; import { DocumentInterface } from "@comet/cms-admin"; +import { Chip } from "@mui/material"; import { GQLPredefinedPage, GQLPredefinedPageInput } from "@src/graphql.generated"; import { EditPredefinedPage } from "@src/predefinedPage/EditPredefinedPage"; import gql from "graphql-tag"; @@ -64,7 +65,7 @@ export const PredefinedPage: DocumentInterface, if (data?.page?.document != null) { const { type } = data.page.document as GQLPredefinedPage; - return type ? <>{type} : null; + return type ? : null; } else { return null; } From 23ef6d69d5bf5be6f8cae3770d181f6c50328398 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Mon, 23 Sep 2024 09:27:47 +0200 Subject: [PATCH 08/17] Move predefined page labels into separate file --- .../src/predefinedPage/EditPredefinedPage.tsx | 18 ++++++++---------- .../src/predefinedPage/PredefinedPage.tsx | 3 ++- .../predefinedPage/predefinedPageLabels.tsx | 6 ++++++ 3 files changed, 16 insertions(+), 11 deletions(-) create mode 100644 demo/admin/src/predefinedPage/predefinedPageLabels.tsx diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx index e7ba4d88d2..051c559108 100644 --- a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx @@ -2,7 +2,7 @@ import { useApolloClient, useQuery } from "@apollo/client"; import { FinalForm, FinalFormSaveButton, Loading, MainContent, SelectField, Toolbar, ToolbarFillSpace, ToolbarItem, useStackApi } from "@comet/admin"; import { ArrowLeft } from "@comet/admin-icons"; import { PageName } from "@comet/cms-admin"; -import { IconButton, MenuItem } from "@mui/material"; +import { IconButton } from "@mui/material"; import { useMemo } from "react"; import { FormattedMessage } from "react-intl"; import { v4 as uuid } from "uuid"; @@ -14,6 +14,7 @@ import { GQLSavePredefinedPageMutation, GQLSavePredefinedPageMutationVariables, } from "./EditPredefinedPage.gql.generated"; +import { predefinedPageLabels } from "./predefinedPageLabels"; type FormValues = { type?: string; @@ -79,18 +80,15 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { - } name="type" fullWidth> - {predefinedPageOptions.map((item, index) => ( - - {item.name} - - ))} - + } + options={[{ value: "News", label: predefinedPageLabels.News }]} + fullWidth + /> )} ); }; - -const predefinedPageOptions = [{ value: "News", name: }]; diff --git a/demo/admin/src/predefinedPage/PredefinedPage.tsx b/demo/admin/src/predefinedPage/PredefinedPage.tsx index afbfcdd829..02a45af1f8 100644 --- a/demo/admin/src/predefinedPage/PredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/PredefinedPage.tsx @@ -8,6 +8,7 @@ import gql from "graphql-tag"; import { FormattedMessage } from "react-intl"; import { GQLPredefinedPageInfoTagQuery, GQLPredefinedPageInfoTagQueryVariables } from "./PredefinedPage.generated"; +import { predefinedPageLabels } from "./predefinedPageLabels"; const predefinedPageInfoTagQuery = gql` query PredefinedPageInfoTag($id: ID!) { @@ -65,7 +66,7 @@ export const PredefinedPage: DocumentInterface, if (data?.page?.document != null) { const { type } = data.page.document as GQLPredefinedPage; - return type ? : null; + return type ? : null; } else { return null; } diff --git a/demo/admin/src/predefinedPage/predefinedPageLabels.tsx b/demo/admin/src/predefinedPage/predefinedPageLabels.tsx new file mode 100644 index 0000000000..342058f212 --- /dev/null +++ b/demo/admin/src/predefinedPage/predefinedPageLabels.tsx @@ -0,0 +1,6 @@ +import { ReactNode } from "react"; +import { FormattedMessage } from "react-intl"; + +export const predefinedPageLabels: Record = { + News: , +}; From 5d7b8643851b43e9b7f2ecc787a4bc479f2fd012 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Mon, 23 Sep 2024 09:32:35 +0200 Subject: [PATCH 09/17] Use GraphQL enum for predefined page type --- .../src/predefinedPage/EditPredefinedPage.tsx | 3 ++- .../src/predefinedPage/predefinedPageLabels.tsx | 3 ++- demo/api/schema.gql | 8 ++++++-- .../predefined-page/dto/predefined-page.input.ts | 10 ++++++---- .../entities/predefined-page.entity.ts | 14 +++++++++++--- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx index 051c559108..a7cf30c2d9 100644 --- a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx @@ -3,6 +3,7 @@ import { FinalForm, FinalFormSaveButton, Loading, MainContent, SelectField, Tool import { ArrowLeft } from "@comet/admin-icons"; import { PageName } from "@comet/cms-admin"; import { IconButton } from "@mui/material"; +import { GQLPredefinedPageType } from "@src/graphql.generated"; import { useMemo } from "react"; import { FormattedMessage } from "react-intl"; import { v4 as uuid } from "uuid"; @@ -17,7 +18,7 @@ import { import { predefinedPageLabels } from "./predefinedPageLabels"; type FormValues = { - type?: string; + type?: GQLPredefinedPageType; }; interface Props { diff --git a/demo/admin/src/predefinedPage/predefinedPageLabels.tsx b/demo/admin/src/predefinedPage/predefinedPageLabels.tsx index 342058f212..be97267332 100644 --- a/demo/admin/src/predefinedPage/predefinedPageLabels.tsx +++ b/demo/admin/src/predefinedPage/predefinedPageLabels.tsx @@ -1,6 +1,7 @@ +import { GQLPredefinedPageType } from "@src/graphql.generated"; import { ReactNode } from "react"; import { FormattedMessage } from "react-intl"; -export const predefinedPageLabels: Record = { +export const predefinedPageLabels: Record = { News: , }; diff --git a/demo/api/schema.gql b/demo/api/schema.gql index 542ccf11d0..10beb5f668 100644 --- a/demo/api/schema.gql +++ b/demo/api/schema.gql @@ -339,7 +339,11 @@ type PredefinedPage implements DocumentInterface { id: ID! updatedAt: DateTime! createdAt: DateTime! - type: String + type: PredefinedPageType +} + +enum PredefinedPageType { + News } type DamScope { @@ -1383,7 +1387,7 @@ input FooterInput { scalar FooterContentBlockInput @specifiedBy(url: "http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf") input PredefinedPageInput { - type: String + type: PredefinedPageType } input ProductInput { diff --git a/demo/api/src/predefined-page/dto/predefined-page.input.ts b/demo/api/src/predefined-page/dto/predefined-page.input.ts index 476f67d152..02fb03a703 100644 --- a/demo/api/src/predefined-page/dto/predefined-page.input.ts +++ b/demo/api/src/predefined-page/dto/predefined-page.input.ts @@ -1,10 +1,12 @@ import { Field, InputType } from "@nestjs/graphql"; -import { IsOptional, IsString } from "class-validator"; +import { IsEnum, IsOptional } from "class-validator"; + +import { PredefinedPageType } from "../entities/predefined-page.entity"; @InputType() export class PredefinedPageInput { - @Field(() => String, { nullable: true }) - @IsString() + @Field(() => PredefinedPageType, { nullable: true }) + @IsEnum(PredefinedPageType) @IsOptional() - type?: string; + type?: PredefinedPageType; } diff --git a/demo/api/src/predefined-page/entities/predefined-page.entity.ts b/demo/api/src/predefined-page/entities/predefined-page.entity.ts index 0221409cbb..ba47da29a7 100644 --- a/demo/api/src/predefined-page/entities/predefined-page.entity.ts +++ b/demo/api/src/predefined-page/entities/predefined-page.entity.ts @@ -1,8 +1,16 @@ import { DocumentInterface, PageTreeNodeDocumentEntityScopeService, ScopedEntity } from "@comet/cms-api"; import { BaseEntity, Entity, OptionalProps, PrimaryKey, Property } from "@mikro-orm/core"; -import { Field, ID, ObjectType } from "@nestjs/graphql"; +import { Field, ID, ObjectType, registerEnumType } from "@nestjs/graphql"; import { v4 as uuid } from "uuid"; +export enum PredefinedPageType { + News = "News", +} + +registerEnumType(PredefinedPageType, { + name: "PredefinedPageType", +}); + @Entity() @ObjectType({ implements: () => [DocumentInterface], @@ -29,6 +37,6 @@ export class PredefinedPage extends BaseEntity implements updatedAt: Date = new Date(); @Property({ columnType: "text", nullable: true }) - @Field({ nullable: true }) - type?: string; + @Field(() => PredefinedPageType, { nullable: true }) + type?: PredefinedPageType; } From bb7d5e4a8abe11444ee8f6613d78197bb0a2d4bf Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Mon, 23 Sep 2024 09:36:27 +0200 Subject: [PATCH 10/17] Add content scope indicator to toolbar --- demo/admin/src/predefinedPage/EditPredefinedPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx index a7cf30c2d9..4f7a1fb87d 100644 --- a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx @@ -1,7 +1,7 @@ import { useApolloClient, useQuery } from "@apollo/client"; import { FinalForm, FinalFormSaveButton, Loading, MainContent, SelectField, Toolbar, ToolbarFillSpace, ToolbarItem, useStackApi } from "@comet/admin"; import { ArrowLeft } from "@comet/admin-icons"; -import { PageName } from "@comet/cms-admin"; +import { ContentScopeIndicator, PageName } from "@comet/cms-admin"; import { IconButton } from "@mui/material"; import { GQLPredefinedPageType } from "@src/graphql.generated"; import { useMemo } from "react"; @@ -68,7 +68,7 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { {() => ( <> - + }> From e8853733bf0777f8e7c0f74cbd7263f5b01001f9 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Mon, 23 Sep 2024 10:13:06 +0200 Subject: [PATCH 11/17] Add save conflict check --- .../src/predefinedPage/EditPredefinedPage.tsx | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx index 4f7a1fb87d..9ae2fe98cd 100644 --- a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx @@ -1,7 +1,18 @@ import { useApolloClient, useQuery } from "@apollo/client"; -import { FinalForm, FinalFormSaveButton, Loading, MainContent, SelectField, Toolbar, ToolbarFillSpace, ToolbarItem, useStackApi } from "@comet/admin"; +import { + FinalForm, + FinalFormSaveButton, + Loading, + MainContent, + SelectField, + Toolbar, + ToolbarFillSpace, + ToolbarItem, + useFormApiRef, + useStackApi, +} from "@comet/admin"; import { ArrowLeft } from "@comet/admin-icons"; -import { ContentScopeIndicator, PageName } from "@comet/cms-admin"; +import { ContentScopeIndicator, PageName, queryUpdatedAt, resolveHasSaveConflict, useFormSaveConflict } from "@comet/cms-admin"; import { IconButton } from "@mui/material"; import { GQLPredefinedPageType } from "@src/graphql.generated"; import { useMemo } from "react"; @@ -28,8 +39,9 @@ interface Props { export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { const stackApi = useStackApi(); const client = useApolloClient(); + const formApiRef = useFormApiRef(); - const { data, loading } = useQuery(predefinedPageQuery, { + const { data, loading, refetch } = useQuery(predefinedPageQuery, { variables: { pageTreeNodeId }, }); @@ -47,7 +59,22 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { return {}; }, [data]); + const saveConflict = useFormSaveConflict({ + checkConflict: async () => { + const updatedAt = await queryUpdatedAt(client, "predefinedPage", data?.pageTreeNode?.document?.id); + return resolveHasSaveConflict(data?.pageTreeNode?.document?.updatedAt, updatedAt); + }, + formApiRef, + loadLatestVersion: async () => { + await refetch(); + }, + }); + const handleSubmit = async (formValues: FormValues) => { + if (await saveConflict.checkForConflicts()) { + throw new Error("Conflicts detected"); + } + const output = { type: formValues.type ?? null, }; @@ -65,9 +92,10 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { } return ( - + {() => ( <> + {saveConflict.dialogs} }> @@ -77,7 +105,7 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { - + From e81d1b3fdf2aed749219ef9f606dcff1cf642f06 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Mon, 23 Sep 2024 10:14:32 +0200 Subject: [PATCH 12/17] Re-throw error to nearest error boundary --- demo/admin/src/predefinedPage/EditPredefinedPage.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx index 9ae2fe98cd..a73c9a67e5 100644 --- a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx +++ b/demo/admin/src/predefinedPage/EditPredefinedPage.tsx @@ -41,7 +41,7 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { const client = useApolloClient(); const formApiRef = useFormApiRef(); - const { data, loading, refetch } = useQuery(predefinedPageQuery, { + const { data, error, loading, refetch } = useQuery(predefinedPageQuery, { variables: { pageTreeNodeId }, }); @@ -87,6 +87,10 @@ export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => { }); }; + if (error) { + throw error; + } + if (loading) { return ; } From 1c9a95433168f6d4a22e62c309d7442604a20d07 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Tue, 24 Sep 2024 10:50:31 +0200 Subject: [PATCH 13/17] Remove PagesModule import from PredefinedPageModule --- demo/api/src/predefined-page/predefined-page.module.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/demo/api/src/predefined-page/predefined-page.module.ts b/demo/api/src/predefined-page/predefined-page.module.ts index 4bdd88da9f..72af470091 100644 --- a/demo/api/src/predefined-page/predefined-page.module.ts +++ b/demo/api/src/predefined-page/predefined-page.module.ts @@ -1,12 +1,11 @@ import { MikroOrmModule } from "@mikro-orm/nestjs"; import { Module } from "@nestjs/common"; -import { PagesModule } from "@src/pages/pages.module"; import { PredefinedPage } from "./entities/predefined-page.entity"; import { PredefinedPageResolver } from "./predefined-page.resolver"; @Module({ - imports: [PagesModule, MikroOrmModule.forFeature([PredefinedPage])], + imports: [MikroOrmModule.forFeature([PredefinedPage])], providers: [PredefinedPageResolver], }) export class PredefinedPageModule {} From 6a368ff24697a351d08d69eedb4a7913c04df286 Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Tue, 24 Sep 2024 10:57:44 +0200 Subject: [PATCH 14/17] Rename and move module to match documents in the Starter --- demo/api/schema.gql | 22 +++++++++---------- demo/api/src/app.module.ts | 6 ++--- .../dto/predefined-page.input.ts | 0 .../entities/predefined-page.entity.ts | 0 .../predefined-pages.module.ts} | 6 ++--- .../predefined-pages.resolver.ts} | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) rename demo/api/src/{predefined-page => documents/predefined-pages}/dto/predefined-page.input.ts (100%) rename demo/api/src/{predefined-page => documents/predefined-pages}/entities/predefined-page.entity.ts (100%) rename demo/api/src/{predefined-page/predefined-page.module.ts => documents/predefined-pages/predefined-pages.module.ts} (60%) rename demo/api/src/{predefined-page/predefined-page.resolver.ts => documents/predefined-pages/predefined-pages.resolver.ts} (98%) diff --git a/demo/api/schema.gql b/demo/api/schema.gql index 8bd25c31cd..413c662542 100644 --- a/demo/api/schema.gql +++ b/demo/api/schema.gql @@ -335,17 +335,6 @@ enum UserGroup { union PageContentUnion = Page | Link | PredefinedPage -type PredefinedPage implements DocumentInterface { - id: ID! - updatedAt: DateTime! - createdAt: DateTime! - type: PredefinedPageType -} - -enum PredefinedPageType { - News -} - type DamScope { domain: String! } @@ -388,6 +377,17 @@ type DamFile { dependents(offset: Int! = 0, limit: Int! = 25, filter: DependentFilter, forceRefresh: Boolean! = false): PaginatedDependencies! } +type PredefinedPage implements DocumentInterface { + id: ID! + updatedAt: DateTime! + createdAt: DateTime! + type: PredefinedPageType +} + +enum PredefinedPageType { + News +} + type FooterContentScope { domain: String! language: String! diff --git a/demo/api/src/app.module.ts b/demo/api/src/app.module.ts index 53782f8909..a7ceb3f8bb 100644 --- a/demo/api/src/app.module.ts +++ b/demo/api/src/app.module.ts @@ -27,7 +27,6 @@ import { ContentGenerationService } from "@src/content-generation/content-genera import { DbModule } from "@src/db/db.module"; import { LinksModule } from "@src/links/links.module"; import { PagesModule } from "@src/pages/pages.module"; -import { PredefinedPage } from "@src/predefined-page/entities/predefined-page.entity"; import { ValidationError } from "apollo-server-express"; import { Request } from "express"; @@ -37,6 +36,8 @@ import { UserService } from "./auth/user.service"; import { DamScope } from "./dam/dto/dam-scope"; import { DamFile } from "./dam/entities/dam-file.entity"; import { DamFolder } from "./dam/entities/dam-folder.entity"; +import { PredefinedPage } from "./documents/predefined-pages/entities/predefined-page.entity"; +import { PredefinedPagesModule } from "./documents/predefined-pages/predefined-pages.module"; import { FooterModule } from "./footer/footer.module"; import { Link } from "./links/entities/link.entity"; import { MenusModule } from "./menus/menus.module"; @@ -46,7 +47,6 @@ import { PageTreeNodeCreateInput, PageTreeNodeUpdateInput } from "./page-tree/dt import { PageTreeNodeScope } from "./page-tree/dto/page-tree-node-scope"; import { PageTreeNode } from "./page-tree/entities/page-tree-node.entity"; import { Page } from "./pages/entities/page.entity"; -import { PredefinedPageModule } from "./predefined-page/predefined-page.module"; import { ProductsModule } from "./products/products.module"; import { RedirectScope } from "./redirects/dto/redirect-scope"; @@ -157,7 +157,7 @@ export class AppModule { NewsModule, MenusModule, FooterModule, - PredefinedPageModule, + PredefinedPagesModule, CronJobsModule, ProductsModule, ...(config.azureAiTranslator ? [AzureAiTranslatorModule.register(config.azureAiTranslator)] : []), diff --git a/demo/api/src/predefined-page/dto/predefined-page.input.ts b/demo/api/src/documents/predefined-pages/dto/predefined-page.input.ts similarity index 100% rename from demo/api/src/predefined-page/dto/predefined-page.input.ts rename to demo/api/src/documents/predefined-pages/dto/predefined-page.input.ts diff --git a/demo/api/src/predefined-page/entities/predefined-page.entity.ts b/demo/api/src/documents/predefined-pages/entities/predefined-page.entity.ts similarity index 100% rename from demo/api/src/predefined-page/entities/predefined-page.entity.ts rename to demo/api/src/documents/predefined-pages/entities/predefined-page.entity.ts diff --git a/demo/api/src/predefined-page/predefined-page.module.ts b/demo/api/src/documents/predefined-pages/predefined-pages.module.ts similarity index 60% rename from demo/api/src/predefined-page/predefined-page.module.ts rename to demo/api/src/documents/predefined-pages/predefined-pages.module.ts index 72af470091..55fcdd2b8e 100644 --- a/demo/api/src/predefined-page/predefined-page.module.ts +++ b/demo/api/src/documents/predefined-pages/predefined-pages.module.ts @@ -2,10 +2,10 @@ import { MikroOrmModule } from "@mikro-orm/nestjs"; import { Module } from "@nestjs/common"; import { PredefinedPage } from "./entities/predefined-page.entity"; -import { PredefinedPageResolver } from "./predefined-page.resolver"; +import { PredefinedPagesResolver } from "./predefined-pages.resolver"; @Module({ imports: [MikroOrmModule.forFeature([PredefinedPage])], - providers: [PredefinedPageResolver], + providers: [PredefinedPagesResolver], }) -export class PredefinedPageModule {} +export class PredefinedPagesModule {} diff --git a/demo/api/src/predefined-page/predefined-page.resolver.ts b/demo/api/src/documents/predefined-pages/predefined-pages.resolver.ts similarity index 98% rename from demo/api/src/predefined-page/predefined-page.resolver.ts rename to demo/api/src/documents/predefined-pages/predefined-pages.resolver.ts index f5e5ed33c9..cf898c816e 100644 --- a/demo/api/src/predefined-page/predefined-page.resolver.ts +++ b/demo/api/src/documents/predefined-pages/predefined-pages.resolver.ts @@ -9,7 +9,7 @@ import { PredefinedPage } from "./entities/predefined-page.entity"; @Resolver(() => PredefinedPage) @RequiredPermission("pageTree") -export class PredefinedPageResolver { +export class PredefinedPagesResolver { constructor( private readonly entityManager: EntityManager, @InjectRepository(PredefinedPage) private readonly repository: EntityRepository, From 01b89d721ddf8a4e0df2139a50deb19a0f49188a Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Tue, 24 Sep 2024 11:00:59 +0200 Subject: [PATCH 15/17] Move Admin files to match documents in the Starter --- demo/admin/src/common/MasterMenu.tsx | 2 +- .../predefinedPages}/EditPredefinedPage.gql.ts | 0 .../predefinedPages}/EditPredefinedPage.tsx | 0 .../predefinedPages}/PredefinedPage.tsx | 2 +- .../predefinedPages}/predefinedPageLabels.tsx | 0 5 files changed, 2 insertions(+), 2 deletions(-) rename demo/admin/src/{predefinedPage => documents/predefinedPages}/EditPredefinedPage.gql.ts (100%) rename demo/admin/src/{predefinedPage => documents/predefinedPages}/EditPredefinedPage.tsx (100%) rename demo/admin/src/{predefinedPage => documents/predefinedPages}/PredefinedPage.tsx (97%) rename demo/admin/src/{predefinedPage => documents/predefinedPages}/predefinedPageLabels.tsx (100%) diff --git a/demo/admin/src/common/MasterMenu.tsx b/demo/admin/src/common/MasterMenu.tsx index c832d3ccf6..9131820639 100644 --- a/demo/admin/src/common/MasterMenu.tsx +++ b/demo/admin/src/common/MasterMenu.tsx @@ -15,6 +15,7 @@ import { import { ContentScope } from "@src/common/ContentScopeProvider"; import { ImportFromUnsplash } from "@src/dam/ImportFromUnsplash"; import Dashboard from "@src/dashboard/Dashboard"; +import { PredefinedPage } from "@src/documents/predefinedPages/PredefinedPage"; import { GQLPageTreeNodeCategory } from "@src/graphql.generated"; import { Link } from "@src/links/Link"; import { NewsLinkBlock } from "@src/news/blocks/NewsLinkBlock"; @@ -22,7 +23,6 @@ import { NewsPage } from "@src/news/generated/NewsPage"; import MainMenu from "@src/pages/mainMenu/MainMenu"; import { Page } from "@src/pages/Page"; import { categoryToUrlParam, pageTreeCategories, urlParamToCategory } from "@src/pageTree/pageTreeCategories"; -import { PredefinedPage } from "@src/predefinedPage/PredefinedPage"; import ProductCategoriesPage from "@src/products/categories/ProductCategoriesPage"; import { CombinationFieldsTestProductsPage } from "@src/products/future/CombinationFieldsTestProductsPage"; import { CreateCapProductPage as FutureCreateCapProductPage } from "@src/products/future/CreateCapProductPage"; diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.gql.ts b/demo/admin/src/documents/predefinedPages/EditPredefinedPage.gql.ts similarity index 100% rename from demo/admin/src/predefinedPage/EditPredefinedPage.gql.ts rename to demo/admin/src/documents/predefinedPages/EditPredefinedPage.gql.ts diff --git a/demo/admin/src/predefinedPage/EditPredefinedPage.tsx b/demo/admin/src/documents/predefinedPages/EditPredefinedPage.tsx similarity index 100% rename from demo/admin/src/predefinedPage/EditPredefinedPage.tsx rename to demo/admin/src/documents/predefinedPages/EditPredefinedPage.tsx diff --git a/demo/admin/src/predefinedPage/PredefinedPage.tsx b/demo/admin/src/documents/predefinedPages/PredefinedPage.tsx similarity index 97% rename from demo/admin/src/predefinedPage/PredefinedPage.tsx rename to demo/admin/src/documents/predefinedPages/PredefinedPage.tsx index 02a45af1f8..0e4986c1d8 100644 --- a/demo/admin/src/predefinedPage/PredefinedPage.tsx +++ b/demo/admin/src/documents/predefinedPages/PredefinedPage.tsx @@ -3,10 +3,10 @@ import { FileData, FileDataNotMenu } from "@comet/admin-icons"; import { DocumentInterface } from "@comet/cms-admin"; import { Chip } from "@mui/material"; import { GQLPredefinedPage, GQLPredefinedPageInput } from "@src/graphql.generated"; -import { EditPredefinedPage } from "@src/predefinedPage/EditPredefinedPage"; import gql from "graphql-tag"; import { FormattedMessage } from "react-intl"; +import { EditPredefinedPage } from "./EditPredefinedPage"; import { GQLPredefinedPageInfoTagQuery, GQLPredefinedPageInfoTagQueryVariables } from "./PredefinedPage.generated"; import { predefinedPageLabels } from "./predefinedPageLabels"; diff --git a/demo/admin/src/predefinedPage/predefinedPageLabels.tsx b/demo/admin/src/documents/predefinedPages/predefinedPageLabels.tsx similarity index 100% rename from demo/admin/src/predefinedPage/predefinedPageLabels.tsx rename to demo/admin/src/documents/predefinedPages/predefinedPageLabels.tsx From 94db07429f554e562074dcbbee799d48b48f1ebd Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Wed, 25 Sep 2024 10:29:38 +0200 Subject: [PATCH 16/17] Move Site files to match documents in the Starter --- .../src/{ => documents}/predefinedPages/predefinedPagePaths.ts | 0 demo/site/src/middleware/predefinedPages.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename demo/site/src/{ => documents}/predefinedPages/predefinedPagePaths.ts (100%) diff --git a/demo/site/src/predefinedPages/predefinedPagePaths.ts b/demo/site/src/documents/predefinedPages/predefinedPagePaths.ts similarity index 100% rename from demo/site/src/predefinedPages/predefinedPagePaths.ts rename to demo/site/src/documents/predefinedPages/predefinedPagePaths.ts diff --git a/demo/site/src/middleware/predefinedPages.ts b/demo/site/src/middleware/predefinedPages.ts index d5926c00db..59033d7b97 100644 --- a/demo/site/src/middleware/predefinedPages.ts +++ b/demo/site/src/middleware/predefinedPages.ts @@ -1,6 +1,6 @@ import { gql } from "@comet/cms-site"; import { languages } from "@src/config"; -import { predefinedPagePaths } from "@src/predefinedPages/predefinedPagePaths"; +import { predefinedPagePaths } from "@src/documents/predefinedPages/predefinedPagePaths"; import { createGraphQLFetch } from "@src/util/graphQLClient"; import { memoryCache } from "./cache"; From be85243fe72f29738dff0ff4f5d45dfcc0b3043f Mon Sep 17 00:00:00 2001 From: Johannes Obermair Date: Thu, 17 Oct 2024 11:21:09 +0200 Subject: [PATCH 17/17] Use `@IsUndefinable()` and `@IsNullable()` instead of `@IsOptional()` --- .../predefined-pages/dto/predefined-page.input.ts | 8 +++++--- .../predefined-pages/entities/predefined-page.entity.ts | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/demo/api/src/documents/predefined-pages/dto/predefined-page.input.ts b/demo/api/src/documents/predefined-pages/dto/predefined-page.input.ts index 02fb03a703..6b4c959efb 100644 --- a/demo/api/src/documents/predefined-pages/dto/predefined-page.input.ts +++ b/demo/api/src/documents/predefined-pages/dto/predefined-page.input.ts @@ -1,5 +1,6 @@ +import { IsNullable, IsUndefinable } from "@comet/cms-api"; import { Field, InputType } from "@nestjs/graphql"; -import { IsEnum, IsOptional } from "class-validator"; +import { IsEnum } from "class-validator"; import { PredefinedPageType } from "../entities/predefined-page.entity"; @@ -7,6 +8,7 @@ import { PredefinedPageType } from "../entities/predefined-page.entity"; export class PredefinedPageInput { @Field(() => PredefinedPageType, { nullable: true }) @IsEnum(PredefinedPageType) - @IsOptional() - type?: PredefinedPageType; + @IsUndefinable() + @IsNullable() + type?: PredefinedPageType | null; } diff --git a/demo/api/src/documents/predefined-pages/entities/predefined-page.entity.ts b/demo/api/src/documents/predefined-pages/entities/predefined-page.entity.ts index ba47da29a7..f8f1a5b0c3 100644 --- a/demo/api/src/documents/predefined-pages/entities/predefined-page.entity.ts +++ b/demo/api/src/documents/predefined-pages/entities/predefined-page.entity.ts @@ -38,5 +38,5 @@ export class PredefinedPage extends BaseEntity implements @Property({ columnType: "text", nullable: true }) @Field(() => PredefinedPageType, { nullable: true }) - type?: PredefinedPageType; + type?: PredefinedPageType | null; }