Skip to content

Commit

Permalink
Make documentTypes prop of PagesPage also accept a function mappi…
Browse files Browse the repository at this point in the history
…ng categories to document types (#2116)

Previously, only the supported documentTypes of the current category
could be passed to the `PagesPage`.
That made it impossible to verify if a document can be moved to another
category.
If a document was moved to a category that didn't support its type, the
PageTree crashed.

If a mapping function is passed to `documentTypes`, documents can only
be moved to categories that support their type.

```diff
<PagesPage
-   documentTypes={pageTreeDocumentTypes}
+   documentTypes={(category): Record<DocumentType, DocumentInterface> => {
+       if (category === "TopMenu") {
+           return {
+               Page,
+               PredefinedPage,
+           };
+       }
+
+       return {
+           Page,
+           PredefinedPage,
+           Link,
+       };
+   }}
    // ...
/>
```

Note: If the move is valid is still only verified in the admin
interface. However, you have to work actively against the UI to make the
move.
  • Loading branch information
thomasdax98 authored Jun 17, 2024
1 parent 2085ff7 commit acfcef9
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 10 deletions.
32 changes: 32 additions & 0 deletions .changeset/little-bats-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
"@comet/cms-admin": minor
---

The `documentTypes` prop of `PagesPage` now also accepts a function mapping categories to document types

Previously, only the supported documentTypes of the current category could be passed to the `PagesPage`.
That made it impossible to verify if a document can be moved to another category.
If a document was moved to a category that didn't support its type, the PageTree crashed.

If a mapping function is passed to `documentTypes`, documents can only be moved to categories that support their type.

```diff
<PagesPage
- documentTypes={pageTreeDocumentTypes}
+ documentTypes={(category): Record<DocumentType, DocumentInterface> => {
+ if (category === "TopMenu") {
+ return {
+ Page,
+ PredefinedPage,
+ };
+ }
+
+ return {
+ Page,
+ PredefinedPage,
+ Link,
+ };
+ }}
// ...
/>
```
17 changes: 16 additions & 1 deletion demo/admin/src/common/MasterMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
createRedirectsPage,
CronJobsPage,
DamPage,
DocumentInterface,
DocumentType,
MasterMenu as CometMasterMenu,
MasterMenuData,
PagesPage,
Expand Down Expand Up @@ -68,7 +70,20 @@ export const masterMenuData: MasterMenuData = [
<PagesPage
path={`/pages/pagetree/${match.params.category}`}
allCategories={pageTreeCategories}
documentTypes={pageTreeDocumentTypes}
documentTypes={(category): Record<DocumentType, DocumentInterface> => {
if (category === "TopMenu") {
return {
Page,
PredefinedPage,
};
}

return {
Page,
PredefinedPage,
Link,
};
}}
editPageNode={EditPageNode}
category={category}
renderContentScopeIndicator={(scope) => <ContentScopeIndicator scope={scope} variant="toolbar" />}
Expand Down
39 changes: 33 additions & 6 deletions packages/admin/cms-admin/src/pages/pageTree/MovePageMenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as React from "react";
import { FormattedMessage } from "react-intl";

import { useContentScope } from "../../contentScope/Provider";
import { DocumentInterface, DocumentType } from "../../documents/types";
import { GQLUpdatePageTreeNodeCategoryMutation, GQLUpdatePageTreeNodeCategoryMutationVariables } from "./MovePageMenuItem.generated";
import { PageTreePage } from "./usePageTree";
import { usePageTreeContext } from "./usePageTreeContext";
Expand All @@ -26,13 +27,17 @@ export function MovePageMenuItem({ page }: Props): React.ReactElement | null {
}
`);
const { scope } = useContentScope();
const { allCategories, query } = usePageTreeContext();
const { allCategories, query, getDocumentTypesByCategory } = usePageTreeContext();

if (allCategories.length <= 1) {
return null;
}

const handleSubMenuItemClick = async (category: string) => {
if (!categorySupportsDocumentType(category, page.documentType, getDocumentTypesByCategory)) {
throw new Error(`Cannot move: Target category doesn't support documentType ${page.documentType}`);
}

const refetchQueries = [
{ query, variables: { contentScope: scope, category } },
{ query, variables: { contentScope: scope, category: page.category } },
Expand All @@ -46,11 +51,33 @@ export function MovePageMenuItem({ page }: Props): React.ReactElement | null {

return (
<RowActionsMenu icon={<MovePage />} text={<FormattedMessage id="comet.pages.pages.page.movePage" defaultMessage="Move page" />}>
{allCategories.map(({ category, label }) => (
<RowActionsItem key={category} disabled={category === page.category || submitting} onClick={() => handleSubMenuItemClick(category)}>
{label}
</RowActionsItem>
))}
{allCategories.map(({ category, label }) => {
const canMoveToTargetCategory = categorySupportsDocumentType(category, page.documentType, getDocumentTypesByCategory);

return (
<RowActionsItem
key={category}
disabled={category === page.category || !canMoveToTargetCategory || submitting}
onClick={() => handleSubMenuItemClick(category)}
>
{label}
</RowActionsItem>
);
})}
</RowActionsMenu>
);
}

const categorySupportsDocumentType = (
category: string,
documentType: string,
getDocumentTypesByCategory?: (category: string) => Record<DocumentType, DocumentInterface>,
) => {
if (getDocumentTypesByCategory === undefined) {
// fallback if no category->documentTypes mapping function was passed
return true;
}

const supportedDocumentTypes = Object.keys(getDocumentTypesByCategory(category));
return supportedDocumentTypes.includes(documentType);
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface PageTreeContext {
allCategories: AllCategories;
currentCategory: string;
documentTypes: Record<DocumentType, DocumentInterface>;
getDocumentTypesByCategory?: (category: string) => Record<DocumentType, DocumentInterface>;
tree: TreeMap<GQLPageTreePageFragment>;
query: DocumentNode;
}
Expand Down
16 changes: 13 additions & 3 deletions packages/admin/cms-admin/src/pages/pagesPage/PagesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ interface Props {
category: string;
path: string;
allCategories: AllCategories;
documentTypes: Record<DocumentType, DocumentInterface>;
documentTypes: Record<DocumentType, DocumentInterface> | ((category: string) => Record<DocumentType, DocumentInterface>);
editPageNode?: React.ComponentType<EditPageNodeProps>;
renderContentScopeIndicator: (scope: ContentScopeInterface) => React.ReactNode;
}
Expand All @@ -50,7 +50,7 @@ export function PagesPage({
category,
path,
allCategories,
documentTypes,
documentTypes: passedDocumentTypes,
editPageNode: EditPageNode = DefaultEditPageNode,
renderContentScopeIndicator,
}: Props): React.ReactElement {
Expand All @@ -61,6 +61,7 @@ export function PagesPage({

const siteConfig = useSiteConfig({ scope });
const pagesQuery = React.useMemo(() => createPagesQuery({ additionalPageTreeNodeFragment }), [additionalPageTreeNodeFragment]);
const documentTypes = typeof passedDocumentTypes === "function" ? passedDocumentTypes(category) : passedDocumentTypes;

React.useEffect(() => {
setRedirectPathAfterChange(path);
Expand Down Expand Up @@ -157,7 +158,16 @@ export function PagesPage({
</Button>
</ToolbarActions>
</Toolbar>
<PageTreeContext.Provider value={{ allCategories, currentCategory: category, documentTypes, tree, query: pagesQuery }}>
<PageTreeContext.Provider
value={{
allCategories,
currentCategory: category,
documentTypes,
getDocumentTypesByCategory: typeof passedDocumentTypes === "function" ? passedDocumentTypes : undefined,
tree,
query: pagesQuery,
}}
>
<PageTreeContent fullHeight>
<ActionToolbarBox>
<PagesPageActionToolbar
Expand Down

0 comments on commit acfcef9

Please sign in to comment.