Skip to content

Commit

Permalink
Update predefined pages (#2550)
Browse files Browse the repository at this point in the history
The predefined pages demo was in a bad shape: Loading/saving didn't work, the info tag didn't look right, etc. I've therefore updated the demo to reflect the latests changes/decisions made in the CRUD Generator. Notable changes:
- Use a GraphQL enum for `type`
- Add the save conflict check
  • Loading branch information
johnnyomair authored Oct 29, 2024
1 parent 979d5f4 commit a357ed1
Show file tree
Hide file tree
Showing 17 changed files with 241 additions and 232 deletions.
2 changes: 1 addition & 1 deletion demo/admin/src/common/MasterMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ 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";
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";
Expand Down
37 changes: 37 additions & 0 deletions demo/admin/src/documents/predefinedPages/EditPredefinedPage.gql.ts
Original file line number Diff line number Diff line change
@@ -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}
`;
127 changes: 127 additions & 0 deletions demo/admin/src/documents/predefinedPages/EditPredefinedPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { useApolloClient, useQuery } from "@apollo/client";
import {
FinalForm,
FinalFormSaveButton,
Loading,
MainContent,
SelectField,
Toolbar,
ToolbarFillSpace,
ToolbarItem,
useFormApiRef,
useStackApi,
} from "@comet/admin";
import { ArrowLeft } from "@comet/admin-icons";
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";
import { FormattedMessage } from "react-intl";
import { v4 as uuid } from "uuid";

import { predefinedPageQuery, savePredefinedPageMutation } from "./EditPredefinedPage.gql";
import {
GQLPredefinedPageQuery,
GQLPredefinedPageQueryVariables,
GQLSavePredefinedPageMutation,
GQLSavePredefinedPageMutationVariables,
} from "./EditPredefinedPage.gql.generated";
import { predefinedPageLabels } from "./predefinedPageLabels";

type FormValues = {
type?: GQLPredefinedPageType;
};

interface Props {
id: string;
}

export const EditPredefinedPage = ({ id: pageTreeNodeId }: Props) => {
const stackApi = useStackApi();
const client = useApolloClient();
const formApiRef = useFormApiRef<FormValues>();

const { data, error, loading, refetch } = useQuery<GQLPredefinedPageQuery, GQLPredefinedPageQueryVariables>(predefinedPageQuery, {
variables: { pageTreeNodeId },
});

const initialValues = useMemo<Partial<FormValues>>(() => {
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 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,
};

const id = data?.pageTreeNode?.document?.id ?? uuid();

await client.mutate<GQLSavePredefinedPageMutation, GQLSavePredefinedPageMutationVariables>({
mutation: savePredefinedPageMutation,
variables: { id, input: output, attachedPageTreeNodeId: pageTreeNodeId },
});
};

if (error) {
throw error;
}

if (loading) {
return <Loading behavior="fillPageHeight" />;
}

return (
<FinalForm apiRef={formApiRef} onSubmit={handleSubmit} mode="edit" initialValues={initialValues}>
{() => (
<>
{saveConflict.dialogs}
<Toolbar scopeIndicator={<ContentScopeIndicator />}>
<ToolbarItem>
<IconButton onClick={stackApi?.goBack}>
<ArrowLeft />
</IconButton>
</ToolbarItem>
<PageName pageId={pageTreeNodeId} />
<ToolbarFillSpace />
<ToolbarItem>
<FinalFormSaveButton hasConflict={saveConflict.hasConflict} />
</ToolbarItem>
</Toolbar>
<MainContent>
<SelectField
name="type"
label={<FormattedMessage id="predefinedPages.type.label" defaultMessage="Type" />}
options={[{ value: "News", label: predefinedPageLabels.News }]}
fullWidth
/>
</MainContent>
</>
)}
</FinalForm>
);
};
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
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";
import { FormattedMessage } from "react-intl";

import { EditPredefinedPage } from "./EditPredefinedPage";
import { GQLPredefinedPageInfoTagQuery, GQLPredefinedPageInfoTagQueryVariables } from "./PredefinedPage.generated";
import { predefinedPageLabels } from "./predefinedPageLabels";

const predefinedPageInfoTagQuery = gql`
query PredefinedPageInfoTag($id: ID!) {
Expand All @@ -23,7 +25,7 @@ const predefinedPageInfoTagQuery = gql`
`;

export const PredefinedPage: DocumentInterface<Pick<GQLPredefinedPage, "type">, GQLPredefinedPageInput> = {
displayName: <FormattedMessage id="predefinedPage" defaultMessage="Predefined Page" />,
displayName: <FormattedMessage id="predefinedPages.displayName" defaultMessage="Predefined Page" />,
editComponent: EditPredefinedPage,
getQuery: gql`
query PredefinedPageDocument($id: ID!) {
Expand Down Expand Up @@ -64,7 +66,7 @@ export const PredefinedPage: DocumentInterface<Pick<GQLPredefinedPage, "type">,

if (data?.page?.document != null) {
const { type } = data.page.document as GQLPredefinedPage;
return type ? <>{type}</> : null;
return type ? <Chip label={predefinedPageLabels[type]} /> : null;
} else {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { GQLPredefinedPageType } from "@src/graphql.generated";
import { ReactNode } from "react";
import { FormattedMessage } from "react-intl";

export const predefinedPageLabels: Record<GQLPredefinedPageType, ReactNode> = {
News: <FormattedMessage id="predefinedPages.news" defaultMessage="News" />,
};
104 changes: 0 additions & 104 deletions demo/admin/src/predefinedPage/EditPredefinedPage.tsx

This file was deleted.

23 changes: 13 additions & 10 deletions demo/api/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -338,13 +338,6 @@ enum UserGroup {

union PageContentUnion = Page | Link | PredefinedPage

type PredefinedPage implements DocumentInterface {
id: ID!
updatedAt: DateTime!
createdAt: DateTime!
type: String
}

type DamScope {
domain: String!
}
Expand Down Expand Up @@ -387,6 +380,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!
Expand Down Expand Up @@ -788,8 +792,7 @@ type Query {
topMenu(scope: PageTreeNodeScopeInput!): [PageTreeNode!]!
mainMenuItem(pageTreeNodeId: ID!): MainMenuItem!
footer(scope: FooterContentScopeInput!): Footer
predefinedPage(id: ID!): PredefinedPage
pageTreeNodeForPredefinedPage(type: String!, scope: PageTreeNodeScopeInput!): PageTreeNode
predefinedPage(id: ID!): PredefinedPage!
kubernetesCronJobs: [KubernetesCronJob!]!
kubernetesCronJob(name: String!): KubernetesCronJob!
kubernetesJobs(cronJobName: String!): [KubernetesJob!]!
Expand Down Expand Up @@ -1403,7 +1406,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 {
Expand Down
Loading

0 comments on commit a357ed1

Please sign in to comment.