@strapi/content-manager 5.53.0 → 5.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/components/ActionsDrawer.js +17 -6
- package/dist/admin/components/ActionsDrawer.js.map +1 -1
- package/dist/admin/components/ActionsDrawer.mjs +19 -8
- package/dist/admin/components/ActionsDrawer.mjs.map +1 -1
- package/dist/admin/components/LeftMenu.js +131 -52
- package/dist/admin/components/LeftMenu.js.map +1 -1
- package/dist/admin/components/LeftMenu.mjs +133 -54
- package/dist/admin/components/LeftMenu.mjs.map +1 -1
- package/dist/admin/history/components/VersionsList.js +37 -43
- package/dist/admin/history/components/VersionsList.js.map +1 -1
- package/dist/admin/history/components/VersionsList.mjs +37 -43
- package/dist/admin/history/components/VersionsList.mjs.map +1 -1
- package/dist/admin/hooks/useContentManagerInitData.js +3 -2
- package/dist/admin/hooks/useContentManagerInitData.js.map +1 -1
- package/dist/admin/hooks/useContentManagerInitData.mjs +3 -2
- package/dist/admin/hooks/useContentManagerInitData.mjs.map +1 -1
- package/dist/admin/hooks/useDocumentActions.js +3 -1
- package/dist/admin/hooks/useDocumentActions.js.map +1 -1
- package/dist/admin/hooks/useDocumentActions.mjs +4 -2
- package/dist/admin/hooks/useDocumentActions.mjs.map +1 -1
- package/dist/admin/layout.js +2 -4
- package/dist/admin/layout.js.map +1 -1
- package/dist/admin/layout.mjs +2 -4
- package/dist/admin/layout.mjs.map +1 -1
- package/dist/admin/modules/app.js +3 -1
- package/dist/admin/modules/app.js.map +1 -1
- package/dist/admin/modules/app.mjs +3 -1
- package/dist/admin/modules/app.mjs.map +1 -1
- package/dist/admin/pages/EditView/EditViewPage.js +15 -20
- package/dist/admin/pages/EditView/EditViewPage.js.map +1 -1
- package/dist/admin/pages/EditView/EditViewPage.mjs +15 -20
- package/dist/admin/pages/EditView/EditViewPage.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/DocumentActions.js +2 -0
- package/dist/admin/pages/EditView/components/DocumentActions.js.map +1 -1
- package/dist/admin/pages/EditView/components/DocumentActions.mjs +2 -0
- package/dist/admin/pages/EditView/components/DocumentActions.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/EditorToolbarObserver.js +74 -7
- package/dist/admin/pages/EditView/components/EditorToolbarObserver.js.map +1 -1
- package/dist/admin/pages/EditView/components/EditorToolbarObserver.mjs +74 -7
- package/dist/admin/pages/EditView/components/EditorToolbarObserver.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js +7 -2
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs +7 -2
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js +59 -2
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs +60 -3
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.js +4 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.mjs +4 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.js +4 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.mjs +4 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.js +2 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.mjs +2 -1
- package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js +58 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs +58 -2
- package/dist/admin/pages/EditView/components/FormInputs/Relations/RelationModal.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.js +25 -2
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.js.map +1 -1
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.mjs +5 -2
- package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.mjs.map +1 -1
- package/dist/admin/pages/EditView/components/InputRenderer.js +5 -1
- package/dist/admin/pages/EditView/components/InputRenderer.js.map +1 -1
- package/dist/admin/pages/EditView/components/InputRenderer.mjs +6 -2
- package/dist/admin/pages/EditView/components/InputRenderer.mjs.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.js +1 -0
- package/dist/admin/pages/ListView/ListViewPage.js.map +1 -1
- package/dist/admin/pages/ListView/ListViewPage.mjs +1 -0
- package/dist/admin/pages/ListView/ListViewPage.mjs.map +1 -1
- package/dist/admin/preview/components/InputPopover.js +64 -46
- package/dist/admin/preview/components/InputPopover.js.map +1 -1
- package/dist/admin/preview/components/InputPopover.mjs +66 -49
- package/dist/admin/preview/components/InputPopover.mjs.map +1 -1
- package/dist/admin/preview/hooks/usePreviewInputManager.js +23 -7
- package/dist/admin/preview/hooks/usePreviewInputManager.js.map +1 -1
- package/dist/admin/preview/hooks/usePreviewInputManager.mjs +25 -9
- package/dist/admin/preview/hooks/usePreviewInputManager.mjs.map +1 -1
- package/dist/admin/preview/pages/Preview.js +19 -0
- package/dist/admin/preview/pages/Preview.js.map +1 -1
- package/dist/admin/preview/pages/Preview.mjs +20 -1
- package/dist/admin/preview/pages/Preview.mjs.map +1 -1
- package/dist/admin/preview/utils/constants.js +9 -3
- package/dist/admin/preview/utils/constants.js.map +1 -1
- package/dist/admin/preview/utils/constants.mjs +9 -3
- package/dist/admin/preview/utils/constants.mjs.map +1 -1
- package/dist/admin/src/components/ActionsDrawer.d.ts +1 -0
- package/dist/admin/src/modules/app.d.ts +2 -0
- package/dist/admin/src/pages/EditView/components/EditorToolbarObserver.d.ts +2 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.d.ts +5 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.d.ts +5 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +5 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.d.ts +2 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations/RelationModal.d.ts +14 -1
- package/dist/admin/src/preview/components/InputPopover.d.ts +2 -1
- package/dist/admin/src/preview/pages/Preview.d.ts +1 -0
- package/dist/admin/src/preview/utils/constants.d.ts +8 -1
- package/dist/admin/src/services/init.d.ts +1 -0
- package/dist/admin/src/utils/contentStructure.d.ts +59 -0
- package/dist/admin/utils/contentStructure.js +136 -0
- package/dist/admin/utils/contentStructure.js.map +1 -0
- package/dist/admin/utils/contentStructure.mjs +130 -0
- package/dist/admin/utils/contentStructure.mjs.map +1 -0
- package/dist/server/controllers/init.js +7 -2
- package/dist/server/controllers/init.js.map +1 -1
- package/dist/server/controllers/init.mjs +7 -2
- package/dist/server/controllers/init.mjs.map +1 -1
- package/dist/server/preview/controllers/previewScript.js +548 -22
- package/dist/server/services/content-structure.js +53 -0
- package/dist/server/services/content-structure.js.map +1 -0
- package/dist/server/services/content-structure.mjs +51 -0
- package/dist/server/services/content-structure.mjs.map +1 -0
- package/dist/server/services/index.js +2 -0
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/index.mjs +2 -0
- package/dist/server/services/index.mjs.map +1 -1
- package/dist/server/src/controllers/index.d.ts +1 -1
- package/dist/server/src/controllers/init.d.ts +1 -1
- package/dist/server/src/controllers/init.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +6 -1
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/services/content-structure.d.ts +8 -0
- package/dist/server/src/services/content-structure.d.ts.map +1 -0
- package/dist/server/src/services/index.d.ts +5 -0
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/server/utils/index.js.map +1 -1
- package/dist/server/utils/index.mjs.map +1 -1
- package/dist/shared/contracts/init.d.ts +2 -0
- package/dist/shared/contracts/init.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -76,6 +76,11 @@ declare const normalizeBlocksState: (editor: Editor, value: Schema.Attribute.Blo
|
|
|
76
76
|
interface BlocksEditorProps extends Pick<FieldValue<Schema.Attribute.BlocksValue>, 'onChange' | 'value' | 'error'>, BlocksContentProps {
|
|
77
77
|
disabled?: boolean;
|
|
78
78
|
name: string;
|
|
79
|
+
/** When true, sync form state on every keystroke (Live Preview popover). */
|
|
80
|
+
livePreviewSync?: boolean;
|
|
81
|
+
/** Index of the block that was double-clicked in the live preview. When provided,
|
|
82
|
+
* the editor positions the Slate cursor at that block on mount instead of using autoFocus. */
|
|
83
|
+
blockIndex?: number | null;
|
|
79
84
|
}
|
|
80
85
|
declare const BlocksEditor: React.ForwardRefExoticComponent<BlocksEditorProps & React.RefAttributes<{
|
|
81
86
|
focus: () => void;
|
|
@@ -4,6 +4,11 @@ import type { Schema } from '@strapi/types';
|
|
|
4
4
|
interface BlocksInputProps extends Omit<InputProps, 'type'> {
|
|
5
5
|
labelAction?: React.ReactNode;
|
|
6
6
|
type: Schema.Attribute.Blocks['type'];
|
|
7
|
+
autoFocus?: boolean;
|
|
8
|
+
livePreviewSync?: boolean;
|
|
9
|
+
onFocus?: React.FocusEventHandler<HTMLElement>;
|
|
10
|
+
onBlur?: React.FocusEventHandler<HTMLElement>;
|
|
11
|
+
blockIndex?: number | null;
|
|
7
12
|
}
|
|
8
13
|
declare const MemoizedBlocksInput: React.MemoExoticComponent<React.ForwardRefExoticComponent<BlocksInputProps & React.RefAttributes<{
|
|
9
14
|
focus: () => void;
|
|
@@ -5,6 +5,7 @@ interface EditorLayoutProps {
|
|
|
5
5
|
onToggleExpand: () => void;
|
|
6
6
|
disabled: boolean;
|
|
7
7
|
ariaDescriptionId: string;
|
|
8
|
+
livePreviewSync?: boolean;
|
|
8
9
|
}
|
|
9
|
-
declare const EditorLayout: ({ children, error, disabled, onToggleExpand, ariaDescriptionId, }: EditorLayoutProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
declare const EditorLayout: ({ children, error, disabled, onToggleExpand, ariaDescriptionId, livePreviewSync, }: EditorLayoutProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
11
|
export { EditorLayout };
|
|
@@ -79,5 +79,18 @@ type RelationModalRendererProps = {
|
|
|
79
79
|
*/
|
|
80
80
|
declare const RelationModalRenderer: (props: RelationModalRendererProps) => import("react/jsx-runtime").JSX.Element;
|
|
81
81
|
declare const generateCreateUrl: (currentDocumentMeta: DocumentMeta) => string;
|
|
82
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Pre-fill the inverse relation with the parent that opened create-on-the-fly.
|
|
84
|
+
* One-way relations have no inverse; unsaved parents have no documentId.
|
|
85
|
+
*/
|
|
86
|
+
declare const prefillParentRelation: ({ initialValues, fieldToConnect, childSchema, parentDocument, parentModel, }: {
|
|
87
|
+
initialValues?: AnyData;
|
|
88
|
+
fieldToConnect?: string;
|
|
89
|
+
childSchema?: {
|
|
90
|
+
attributes?: Record<string, unknown>;
|
|
91
|
+
};
|
|
92
|
+
parentDocument?: Record<string, unknown>;
|
|
93
|
+
parentModel?: string;
|
|
94
|
+
}) => AnyData | undefined;
|
|
95
|
+
export { reducer, RelationModalRenderer, useRelationModal, getFullPageUrl, generateCreateUrl, prefillParentRelation, };
|
|
83
96
|
export type { State, Action, RelationOpenMode };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type UseDocument } from '../../hooks/useDocument';
|
|
2
2
|
declare function useHasInputPopoverParent(): boolean;
|
|
3
|
+
declare function usePreviewPopoverBlockIndex(): number | null;
|
|
3
4
|
declare const InputPopover: ({ documentResponse }: {
|
|
4
5
|
documentResponse: ReturnType<UseDocument>;
|
|
5
6
|
}) => import("react/jsx-runtime").JSX.Element | null;
|
|
6
|
-
export { InputPopover, useHasInputPopoverParent };
|
|
7
|
+
export { InputPopover, useHasInputPopoverParent, usePreviewPopoverBlockIndex };
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
export declare const INTERNAL_EVENTS: {
|
|
5
5
|
readonly STRAPI_FIELD_FOCUS: "strapiFieldFocus";
|
|
6
6
|
readonly STRAPI_FIELD_BLUR: "strapiFieldBlur";
|
|
7
|
-
readonly STRAPI_FIELD_CHANGE: "strapiFieldChange";
|
|
8
7
|
readonly STRAPI_FIELD_FOCUS_INTENT: "strapiFieldFocusIntent";
|
|
9
8
|
readonly STRAPI_FIELD_SINGLE_CLICK_HINT: "strapiFieldSingleClickHint";
|
|
9
|
+
readonly STRAPI_IFRAME_CLICK: "strapiIframeClick";
|
|
10
|
+
readonly STRAPI_RESCAN_HIGHLIGHTS: "strapiRescanHighlights";
|
|
10
11
|
};
|
|
11
12
|
/**
|
|
12
13
|
* These events are documented to users, and will be hardcoded in their frontends.
|
|
@@ -16,6 +17,12 @@ export declare const PUBLIC_EVENTS: {
|
|
|
16
17
|
readonly PREVIEW_READY: "previewReady";
|
|
17
18
|
readonly STRAPI_UPDATE: "strapiUpdate";
|
|
18
19
|
readonly STRAPI_SCRIPT: "strapiScript";
|
|
20
|
+
/**
|
|
21
|
+
* Dispatched as a CustomEvent on the iframe window when a blocks field changes.
|
|
22
|
+
* Host apps listen for this event to re-render their BlocksRenderer in real time.
|
|
23
|
+
* Also sent as a postMessage from the admin to the iframe (same event type).
|
|
24
|
+
*/
|
|
25
|
+
readonly STRAPI_FIELD_CHANGE: "strapiFieldChange";
|
|
19
26
|
};
|
|
20
27
|
/**
|
|
21
28
|
* Error messages for preview field operations.
|
|
@@ -5,5 +5,6 @@ declare const useGetInitialDataQuery: import("@reduxjs/toolkit/dist/query/react/
|
|
|
5
5
|
}>;
|
|
6
6
|
components: import("../../../shared/contracts/components").Component[];
|
|
7
7
|
contentTypes: import("../../../shared/contracts/content-types").ContentType[];
|
|
8
|
+
contentStructure?: import("@strapi/types/dist/modules/content-structure.js").ResolvedContentStructure;
|
|
8
9
|
}, "adminApi">>;
|
|
9
10
|
export { useGetInitialDataQuery };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ContentManagerLink } from '../hooks/useContentManagerInitData';
|
|
2
|
+
import type { Modules } from '@strapi/types';
|
|
3
|
+
type ResolvedGroupNode = Modules.ContentStructure.ResolvedGroupNode;
|
|
4
|
+
type VisibleTreeNode<TLink> = {
|
|
5
|
+
type: 'folder';
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
children: VisibleTreeNode<TLink>[];
|
|
9
|
+
} | {
|
|
10
|
+
type: 'link';
|
|
11
|
+
link: TLink;
|
|
12
|
+
};
|
|
13
|
+
export type LinkTreeNode = VisibleTreeNode<ContentManagerLink>;
|
|
14
|
+
/**
|
|
15
|
+
* Reconcile a resolved content-structure section (folder groups) with the set of links the user can
|
|
16
|
+
* actually see with respect to their RBAC permissions.
|
|
17
|
+
*/
|
|
18
|
+
export declare const deriveVisibleTree: <TLink extends {
|
|
19
|
+
uid: string;
|
|
20
|
+
}>(groups: ResolvedGroupNode[], links: TLink[], compareUngrouped?: (a: TLink, b: TLink) => number) => VisibleTreeNode<TLink>[];
|
|
21
|
+
export declare function flattenTreeLinks<TLink>(nodes: VisibleTreeNode<TLink>[], parentPath?: string[]): Array<{
|
|
22
|
+
link: TLink;
|
|
23
|
+
path: string[];
|
|
24
|
+
}>;
|
|
25
|
+
export declare function countTreeLinks<TLink>(nodes: VisibleTreeNode<TLink>[]): number;
|
|
26
|
+
type FilterTreeLinksParams<TLink> = {
|
|
27
|
+
matchFolderName: (name: string) => boolean;
|
|
28
|
+
matchLink: (link: TLink) => boolean;
|
|
29
|
+
nodes: VisibleTreeNode<TLink>[];
|
|
30
|
+
parentPath?: string[];
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Search the contentStructure tree, returning the matching links with their folder path.
|
|
34
|
+
*
|
|
35
|
+
* A **link** matches on whatever `matchLink` tests (display name and/or UID) and is returned with its ancestor folder path.
|
|
36
|
+
*
|
|
37
|
+
* A **folder** matches on its name and, when it does, surfaces *all* of its descendant content types (each with
|
|
38
|
+
* its own path).
|
|
39
|
+
*/
|
|
40
|
+
export declare function filterTreeLinks<TLink>({ matchFolderName, matchLink, nodes, parentPath, }: FilterTreeLinksParams<TLink>): Array<{
|
|
41
|
+
link: TLink;
|
|
42
|
+
path: string[];
|
|
43
|
+
}>;
|
|
44
|
+
type BuildContentStructureSectionParams = {
|
|
45
|
+
compareLinks: (a: ContentManagerLink, b: ContentManagerLink) => number;
|
|
46
|
+
groups: Modules.ContentStructure.ResolvedGroupNode[];
|
|
47
|
+
id: Modules.ContentStructure.ContentStructureSectionKey;
|
|
48
|
+
links: ContentManagerLink[];
|
|
49
|
+
title: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Builds a content structure section for the left menu from the RBAC-provided links and the resolved content structure configuration.
|
|
53
|
+
*/
|
|
54
|
+
export declare function buildContentStructureSection({ compareLinks, groups, links, title, id, }: BuildContentStructureSectionParams): {
|
|
55
|
+
id: Modules.ContentStructure.ContentStructureSectionKey;
|
|
56
|
+
title: string;
|
|
57
|
+
tree: LinkTreeNode[];
|
|
58
|
+
};
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Reconcile a resolved content-structure section (folder groups) with the set of links the user can
|
|
5
|
+
* actually see with respect to their RBAC permissions.
|
|
6
|
+
*/ const deriveVisibleTree = (groups, links, compareUngrouped)=>{
|
|
7
|
+
const linkByUid = new Map(links.map((link)=>[
|
|
8
|
+
link.uid,
|
|
9
|
+
link
|
|
10
|
+
]));
|
|
11
|
+
const grouped = new Set();
|
|
12
|
+
const resolveChildAsNode = (child)=>{
|
|
13
|
+
if (child.type === 'contentType') {
|
|
14
|
+
const link = linkByUid.get(child.uid);
|
|
15
|
+
if (!link) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
grouped.add(child.uid);
|
|
19
|
+
return {
|
|
20
|
+
type: 'link',
|
|
21
|
+
link
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return resolveGroupAsNode(child);
|
|
25
|
+
};
|
|
26
|
+
const isTreeNode = (node)=>{
|
|
27
|
+
return node !== null;
|
|
28
|
+
};
|
|
29
|
+
const resolveGroupAsNode = (group)=>{
|
|
30
|
+
const children = group.children.map(resolveChildAsNode).filter(isTreeNode);
|
|
31
|
+
if (children.length === 0) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
type: 'folder',
|
|
36
|
+
id: group.id,
|
|
37
|
+
name: group.name,
|
|
38
|
+
children
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
const folders = groups.map(resolveGroupAsNode).filter(isTreeNode);
|
|
42
|
+
const ungrouped = links.filter((link)=>!grouped.has(link.uid));
|
|
43
|
+
if (compareUngrouped) {
|
|
44
|
+
ungrouped.sort(compareUngrouped);
|
|
45
|
+
}
|
|
46
|
+
return [
|
|
47
|
+
...folders,
|
|
48
|
+
...ungrouped.map((link)=>({
|
|
49
|
+
type: 'link',
|
|
50
|
+
link
|
|
51
|
+
}))
|
|
52
|
+
];
|
|
53
|
+
};
|
|
54
|
+
function flattenTreeLinks(nodes, parentPath = []) {
|
|
55
|
+
return nodes.flatMap((node)=>{
|
|
56
|
+
if (node.type === 'link') {
|
|
57
|
+
return [
|
|
58
|
+
{
|
|
59
|
+
link: node.link,
|
|
60
|
+
path: parentPath
|
|
61
|
+
}
|
|
62
|
+
];
|
|
63
|
+
}
|
|
64
|
+
return flattenTreeLinks(node.children, [
|
|
65
|
+
...parentPath,
|
|
66
|
+
node.name
|
|
67
|
+
]);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function countTreeLinks(nodes) {
|
|
71
|
+
return flattenTreeLinks(nodes).length;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Search the contentStructure tree, returning the matching links with their folder path.
|
|
75
|
+
*
|
|
76
|
+
* A **link** matches on whatever `matchLink` tests (display name and/or UID) and is returned with its ancestor folder path.
|
|
77
|
+
*
|
|
78
|
+
* A **folder** matches on its name and, when it does, surfaces *all* of its descendant content types (each with
|
|
79
|
+
* its own path).
|
|
80
|
+
*/ function filterTreeLinks({ matchFolderName, matchLink, nodes, parentPath = [] }) {
|
|
81
|
+
return nodes.flatMap((node)=>{
|
|
82
|
+
if (node.type === 'link') {
|
|
83
|
+
return matchLink(node.link) ? [
|
|
84
|
+
{
|
|
85
|
+
link: node.link,
|
|
86
|
+
path: parentPath
|
|
87
|
+
}
|
|
88
|
+
] : [];
|
|
89
|
+
}
|
|
90
|
+
const path = [
|
|
91
|
+
...parentPath,
|
|
92
|
+
node.name
|
|
93
|
+
];
|
|
94
|
+
if (matchFolderName(node.name)) {
|
|
95
|
+
return flattenTreeLinks(node.children, path);
|
|
96
|
+
}
|
|
97
|
+
return filterTreeLinks({
|
|
98
|
+
nodes: node.children,
|
|
99
|
+
matchFolderName,
|
|
100
|
+
matchLink,
|
|
101
|
+
parentPath: path
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Builds a content structure section for the left menu from the RBAC-provided links and the resolved content structure configuration.
|
|
107
|
+
*/ function buildContentStructureSection({ compareLinks, groups, links, title, id }) {
|
|
108
|
+
try {
|
|
109
|
+
return {
|
|
110
|
+
id,
|
|
111
|
+
title,
|
|
112
|
+
tree: deriveVisibleTree(groups, links, compareLinks)
|
|
113
|
+
};
|
|
114
|
+
} catch {
|
|
115
|
+
const tree = [
|
|
116
|
+
...links
|
|
117
|
+
].sort(compareLinks).map((link)=>{
|
|
118
|
+
return {
|
|
119
|
+
type: 'link',
|
|
120
|
+
link
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
id,
|
|
125
|
+
title,
|
|
126
|
+
tree
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
exports.buildContentStructureSection = buildContentStructureSection;
|
|
132
|
+
exports.countTreeLinks = countTreeLinks;
|
|
133
|
+
exports.deriveVisibleTree = deriveVisibleTree;
|
|
134
|
+
exports.filterTreeLinks = filterTreeLinks;
|
|
135
|
+
exports.flattenTreeLinks = flattenTreeLinks;
|
|
136
|
+
//# sourceMappingURL=contentStructure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contentStructure.js","sources":["../../../admin/src/utils/contentStructure.ts"],"sourcesContent":["import type { ContentManagerLink } from '../hooks/useContentManagerInitData';\nimport type { Modules } from '@strapi/types';\n\ntype ResolvedGroupNode = Modules.ContentStructure.ResolvedGroupNode;\ntype ResolvedStructureChild = Modules.ContentStructure.ResolvedStructureChild;\n\ntype VisibleTreeNode<TLink> =\n | { type: 'folder'; id: string; name: string; children: VisibleTreeNode<TLink>[] }\n | { type: 'link'; link: TLink };\n\nexport type LinkTreeNode = VisibleTreeNode<ContentManagerLink>;\n\n/**\n * Reconcile a resolved content-structure section (folder groups) with the set of links the user can\n * actually see with respect to their RBAC permissions.\n */\nexport const deriveVisibleTree = <TLink extends { uid: string }>(\n groups: ResolvedGroupNode[],\n links: TLink[],\n compareUngrouped?: (a: TLink, b: TLink) => number\n): VisibleTreeNode<TLink>[] => {\n const linkByUid = new Map(links.map((link) => [link.uid, link]));\n const grouped = new Set<string>();\n\n const resolveChildAsNode = (child: ResolvedStructureChild): VisibleTreeNode<TLink> | null => {\n if (child.type === 'contentType') {\n const link = linkByUid.get(child.uid);\n\n if (!link) {\n return null;\n }\n\n grouped.add(child.uid);\n\n return { type: 'link', link };\n }\n\n return resolveGroupAsNode(child);\n };\n\n const isTreeNode = (node: VisibleTreeNode<TLink> | null): node is VisibleTreeNode<TLink> => {\n return node !== null;\n };\n\n const resolveGroupAsNode = (group: ResolvedGroupNode): VisibleTreeNode<TLink> | null => {\n const children = group.children.map(resolveChildAsNode).filter(isTreeNode);\n\n if (children.length === 0) {\n return null;\n }\n\n return { type: 'folder', id: group.id, name: group.name, children };\n };\n\n const folders = groups.map(resolveGroupAsNode).filter(isTreeNode);\n\n const ungrouped = links.filter((link) => !grouped.has(link.uid));\n\n if (compareUngrouped) {\n ungrouped.sort(compareUngrouped);\n }\n\n return [...folders, ...ungrouped.map((link): VisibleTreeNode<TLink> => ({ type: 'link', link }))];\n};\n\nexport function flattenTreeLinks<TLink>(\n nodes: VisibleTreeNode<TLink>[],\n parentPath: string[] = []\n): Array<{ link: TLink; path: string[] }> {\n return nodes.flatMap((node) => {\n if (node.type === 'link') {\n return [{ link: node.link, path: parentPath }];\n }\n\n return flattenTreeLinks(node.children, [...parentPath, node.name]);\n });\n}\n\nexport function countTreeLinks<TLink>(nodes: VisibleTreeNode<TLink>[]): number {\n return flattenTreeLinks(nodes).length;\n}\n\ntype FilterTreeLinksParams<TLink> = {\n matchFolderName: (name: string) => boolean;\n matchLink: (link: TLink) => boolean;\n nodes: VisibleTreeNode<TLink>[];\n parentPath?: string[];\n};\n\n/**\n * Search the contentStructure tree, returning the matching links with their folder path.\n *\n * A **link** matches on whatever `matchLink` tests (display name and/or UID) and is returned with its ancestor folder path.\n *\n * A **folder** matches on its name and, when it does, surfaces *all* of its descendant content types (each with\n * its own path).\n */\nexport function filterTreeLinks<TLink>({\n matchFolderName,\n matchLink,\n nodes,\n parentPath = [],\n}: FilterTreeLinksParams<TLink>): Array<{ link: TLink; path: string[] }> {\n return nodes.flatMap((node) => {\n if (node.type === 'link') {\n return matchLink(node.link) ? [{ link: node.link, path: parentPath }] : [];\n }\n\n const path = [...parentPath, node.name];\n\n if (matchFolderName(node.name)) {\n return flattenTreeLinks(node.children, path);\n }\n\n return filterTreeLinks({\n nodes: node.children,\n matchFolderName,\n matchLink,\n parentPath: path,\n });\n });\n}\n\ntype BuildContentStructureSectionParams = {\n compareLinks: (a: ContentManagerLink, b: ContentManagerLink) => number;\n groups: Modules.ContentStructure.ResolvedGroupNode[];\n id: Modules.ContentStructure.ContentStructureSectionKey;\n links: ContentManagerLink[];\n title: string;\n};\n/**\n * Builds a content structure section for the left menu from the RBAC-provided links and the resolved content structure configuration.\n */\nexport function buildContentStructureSection({\n compareLinks,\n groups,\n links,\n title,\n id,\n}: BuildContentStructureSectionParams): {\n id: Modules.ContentStructure.ContentStructureSectionKey;\n title: string;\n tree: LinkTreeNode[];\n} {\n try {\n return { id, title, tree: deriveVisibleTree(groups, links, compareLinks) };\n } catch {\n const tree: LinkTreeNode[] = [...links].sort(compareLinks).map((link) => {\n return { type: 'link', link };\n });\n\n return { id, title, tree };\n }\n}\n"],"names":["deriveVisibleTree","groups","links","compareUngrouped","linkByUid","Map","map","link","uid","grouped","Set","resolveChildAsNode","child","type","get","add","resolveGroupAsNode","isTreeNode","node","group","children","filter","length","id","name","folders","ungrouped","has","sort","flattenTreeLinks","nodes","parentPath","flatMap","path","countTreeLinks","filterTreeLinks","matchFolderName","matchLink","buildContentStructureSection","compareLinks","title","tree"],"mappings":"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"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconcile a resolved content-structure section (folder groups) with the set of links the user can
|
|
3
|
+
* actually see with respect to their RBAC permissions.
|
|
4
|
+
*/ const deriveVisibleTree = (groups, links, compareUngrouped)=>{
|
|
5
|
+
const linkByUid = new Map(links.map((link)=>[
|
|
6
|
+
link.uid,
|
|
7
|
+
link
|
|
8
|
+
]));
|
|
9
|
+
const grouped = new Set();
|
|
10
|
+
const resolveChildAsNode = (child)=>{
|
|
11
|
+
if (child.type === 'contentType') {
|
|
12
|
+
const link = linkByUid.get(child.uid);
|
|
13
|
+
if (!link) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
grouped.add(child.uid);
|
|
17
|
+
return {
|
|
18
|
+
type: 'link',
|
|
19
|
+
link
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return resolveGroupAsNode(child);
|
|
23
|
+
};
|
|
24
|
+
const isTreeNode = (node)=>{
|
|
25
|
+
return node !== null;
|
|
26
|
+
};
|
|
27
|
+
const resolveGroupAsNode = (group)=>{
|
|
28
|
+
const children = group.children.map(resolveChildAsNode).filter(isTreeNode);
|
|
29
|
+
if (children.length === 0) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
type: 'folder',
|
|
34
|
+
id: group.id,
|
|
35
|
+
name: group.name,
|
|
36
|
+
children
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
const folders = groups.map(resolveGroupAsNode).filter(isTreeNode);
|
|
40
|
+
const ungrouped = links.filter((link)=>!grouped.has(link.uid));
|
|
41
|
+
if (compareUngrouped) {
|
|
42
|
+
ungrouped.sort(compareUngrouped);
|
|
43
|
+
}
|
|
44
|
+
return [
|
|
45
|
+
...folders,
|
|
46
|
+
...ungrouped.map((link)=>({
|
|
47
|
+
type: 'link',
|
|
48
|
+
link
|
|
49
|
+
}))
|
|
50
|
+
];
|
|
51
|
+
};
|
|
52
|
+
function flattenTreeLinks(nodes, parentPath = []) {
|
|
53
|
+
return nodes.flatMap((node)=>{
|
|
54
|
+
if (node.type === 'link') {
|
|
55
|
+
return [
|
|
56
|
+
{
|
|
57
|
+
link: node.link,
|
|
58
|
+
path: parentPath
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
return flattenTreeLinks(node.children, [
|
|
63
|
+
...parentPath,
|
|
64
|
+
node.name
|
|
65
|
+
]);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function countTreeLinks(nodes) {
|
|
69
|
+
return flattenTreeLinks(nodes).length;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Search the contentStructure tree, returning the matching links with their folder path.
|
|
73
|
+
*
|
|
74
|
+
* A **link** matches on whatever `matchLink` tests (display name and/or UID) and is returned with its ancestor folder path.
|
|
75
|
+
*
|
|
76
|
+
* A **folder** matches on its name and, when it does, surfaces *all* of its descendant content types (each with
|
|
77
|
+
* its own path).
|
|
78
|
+
*/ function filterTreeLinks({ matchFolderName, matchLink, nodes, parentPath = [] }) {
|
|
79
|
+
return nodes.flatMap((node)=>{
|
|
80
|
+
if (node.type === 'link') {
|
|
81
|
+
return matchLink(node.link) ? [
|
|
82
|
+
{
|
|
83
|
+
link: node.link,
|
|
84
|
+
path: parentPath
|
|
85
|
+
}
|
|
86
|
+
] : [];
|
|
87
|
+
}
|
|
88
|
+
const path = [
|
|
89
|
+
...parentPath,
|
|
90
|
+
node.name
|
|
91
|
+
];
|
|
92
|
+
if (matchFolderName(node.name)) {
|
|
93
|
+
return flattenTreeLinks(node.children, path);
|
|
94
|
+
}
|
|
95
|
+
return filterTreeLinks({
|
|
96
|
+
nodes: node.children,
|
|
97
|
+
matchFolderName,
|
|
98
|
+
matchLink,
|
|
99
|
+
parentPath: path
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Builds a content structure section for the left menu from the RBAC-provided links and the resolved content structure configuration.
|
|
105
|
+
*/ function buildContentStructureSection({ compareLinks, groups, links, title, id }) {
|
|
106
|
+
try {
|
|
107
|
+
return {
|
|
108
|
+
id,
|
|
109
|
+
title,
|
|
110
|
+
tree: deriveVisibleTree(groups, links, compareLinks)
|
|
111
|
+
};
|
|
112
|
+
} catch {
|
|
113
|
+
const tree = [
|
|
114
|
+
...links
|
|
115
|
+
].sort(compareLinks).map((link)=>{
|
|
116
|
+
return {
|
|
117
|
+
type: 'link',
|
|
118
|
+
link
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
return {
|
|
122
|
+
id,
|
|
123
|
+
title,
|
|
124
|
+
tree
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export { buildContentStructureSection, countTreeLinks, deriveVisibleTree, filterTreeLinks, flattenTreeLinks };
|
|
130
|
+
//# sourceMappingURL=contentStructure.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contentStructure.mjs","sources":["../../../admin/src/utils/contentStructure.ts"],"sourcesContent":["import type { ContentManagerLink } from '../hooks/useContentManagerInitData';\nimport type { Modules } from '@strapi/types';\n\ntype ResolvedGroupNode = Modules.ContentStructure.ResolvedGroupNode;\ntype ResolvedStructureChild = Modules.ContentStructure.ResolvedStructureChild;\n\ntype VisibleTreeNode<TLink> =\n | { type: 'folder'; id: string; name: string; children: VisibleTreeNode<TLink>[] }\n | { type: 'link'; link: TLink };\n\nexport type LinkTreeNode = VisibleTreeNode<ContentManagerLink>;\n\n/**\n * Reconcile a resolved content-structure section (folder groups) with the set of links the user can\n * actually see with respect to their RBAC permissions.\n */\nexport const deriveVisibleTree = <TLink extends { uid: string }>(\n groups: ResolvedGroupNode[],\n links: TLink[],\n compareUngrouped?: (a: TLink, b: TLink) => number\n): VisibleTreeNode<TLink>[] => {\n const linkByUid = new Map(links.map((link) => [link.uid, link]));\n const grouped = new Set<string>();\n\n const resolveChildAsNode = (child: ResolvedStructureChild): VisibleTreeNode<TLink> | null => {\n if (child.type === 'contentType') {\n const link = linkByUid.get(child.uid);\n\n if (!link) {\n return null;\n }\n\n grouped.add(child.uid);\n\n return { type: 'link', link };\n }\n\n return resolveGroupAsNode(child);\n };\n\n const isTreeNode = (node: VisibleTreeNode<TLink> | null): node is VisibleTreeNode<TLink> => {\n return node !== null;\n };\n\n const resolveGroupAsNode = (group: ResolvedGroupNode): VisibleTreeNode<TLink> | null => {\n const children = group.children.map(resolveChildAsNode).filter(isTreeNode);\n\n if (children.length === 0) {\n return null;\n }\n\n return { type: 'folder', id: group.id, name: group.name, children };\n };\n\n const folders = groups.map(resolveGroupAsNode).filter(isTreeNode);\n\n const ungrouped = links.filter((link) => !grouped.has(link.uid));\n\n if (compareUngrouped) {\n ungrouped.sort(compareUngrouped);\n }\n\n return [...folders, ...ungrouped.map((link): VisibleTreeNode<TLink> => ({ type: 'link', link }))];\n};\n\nexport function flattenTreeLinks<TLink>(\n nodes: VisibleTreeNode<TLink>[],\n parentPath: string[] = []\n): Array<{ link: TLink; path: string[] }> {\n return nodes.flatMap((node) => {\n if (node.type === 'link') {\n return [{ link: node.link, path: parentPath }];\n }\n\n return flattenTreeLinks(node.children, [...parentPath, node.name]);\n });\n}\n\nexport function countTreeLinks<TLink>(nodes: VisibleTreeNode<TLink>[]): number {\n return flattenTreeLinks(nodes).length;\n}\n\ntype FilterTreeLinksParams<TLink> = {\n matchFolderName: (name: string) => boolean;\n matchLink: (link: TLink) => boolean;\n nodes: VisibleTreeNode<TLink>[];\n parentPath?: string[];\n};\n\n/**\n * Search the contentStructure tree, returning the matching links with their folder path.\n *\n * A **link** matches on whatever `matchLink` tests (display name and/or UID) and is returned with its ancestor folder path.\n *\n * A **folder** matches on its name and, when it does, surfaces *all* of its descendant content types (each with\n * its own path).\n */\nexport function filterTreeLinks<TLink>({\n matchFolderName,\n matchLink,\n nodes,\n parentPath = [],\n}: FilterTreeLinksParams<TLink>): Array<{ link: TLink; path: string[] }> {\n return nodes.flatMap((node) => {\n if (node.type === 'link') {\n return matchLink(node.link) ? [{ link: node.link, path: parentPath }] : [];\n }\n\n const path = [...parentPath, node.name];\n\n if (matchFolderName(node.name)) {\n return flattenTreeLinks(node.children, path);\n }\n\n return filterTreeLinks({\n nodes: node.children,\n matchFolderName,\n matchLink,\n parentPath: path,\n });\n });\n}\n\ntype BuildContentStructureSectionParams = {\n compareLinks: (a: ContentManagerLink, b: ContentManagerLink) => number;\n groups: Modules.ContentStructure.ResolvedGroupNode[];\n id: Modules.ContentStructure.ContentStructureSectionKey;\n links: ContentManagerLink[];\n title: string;\n};\n/**\n * Builds a content structure section for the left menu from the RBAC-provided links and the resolved content structure configuration.\n */\nexport function buildContentStructureSection({\n compareLinks,\n groups,\n links,\n title,\n id,\n}: BuildContentStructureSectionParams): {\n id: Modules.ContentStructure.ContentStructureSectionKey;\n title: string;\n tree: LinkTreeNode[];\n} {\n try {\n return { id, title, tree: deriveVisibleTree(groups, links, compareLinks) };\n } catch {\n const tree: LinkTreeNode[] = [...links].sort(compareLinks).map((link) => {\n return { type: 'link', link };\n });\n\n return { id, title, tree };\n }\n}\n"],"names":["deriveVisibleTree","groups","links","compareUngrouped","linkByUid","Map","map","link","uid","grouped","Set","resolveChildAsNode","child","type","get","add","resolveGroupAsNode","isTreeNode","node","group","children","filter","length","id","name","folders","ungrouped","has","sort","flattenTreeLinks","nodes","parentPath","flatMap","path","countTreeLinks","filterTreeLinks","matchFolderName","matchLink","buildContentStructureSection","compareLinks","title","tree"],"mappings":"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"}
|
|
@@ -3,16 +3,21 @@
|
|
|
3
3
|
var index = require('../utils/index.js');
|
|
4
4
|
|
|
5
5
|
var init = {
|
|
6
|
-
getInitData (ctx) {
|
|
6
|
+
async getInitData (ctx) {
|
|
7
7
|
const { toDto } = index.getService('data-mapper');
|
|
8
8
|
const { findAllComponents } = index.getService('components');
|
|
9
9
|
const { getAllFieldSizes } = index.getService('field-sizes');
|
|
10
10
|
const { findAllContentTypes } = index.getService('content-types');
|
|
11
|
+
const { getContentStructure } = index.getService('content-structure');
|
|
12
|
+
const contentStructure = await getContentStructure();
|
|
11
13
|
ctx.body = {
|
|
12
14
|
data: {
|
|
13
15
|
fieldSizes: getAllFieldSizes(),
|
|
14
16
|
components: findAllComponents().map(toDto),
|
|
15
|
-
contentTypes: findAllContentTypes().map(toDto)
|
|
17
|
+
contentTypes: findAllContentTypes().map(toDto),
|
|
18
|
+
...contentStructure ? {
|
|
19
|
+
contentStructure
|
|
20
|
+
} : {}
|
|
16
21
|
}
|
|
17
22
|
};
|
|
18
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sources":["../../../server/src/controllers/init.ts"],"sourcesContent":["import { getService } from '../utils';\n\nexport default {\n getInitData(ctx: any) {\n const { toDto } = getService('data-mapper');\n const { findAllComponents } = getService('components');\n const { getAllFieldSizes } = getService('field-sizes');\n const { findAllContentTypes } = getService('content-types');\n\n ctx.body = {\n data: {\n fieldSizes: getAllFieldSizes(),\n components: findAllComponents().map(toDto),\n contentTypes: findAllContentTypes().map(toDto),\n },\n };\n },\n};\n"],"names":["getInitData","ctx","toDto","getService","findAllComponents","getAllFieldSizes","findAllContentTypes","body","data","fieldSizes","components","map","contentTypes"],"mappings":";;;;AAEA,WAAe;
|
|
1
|
+
{"version":3,"file":"init.js","sources":["../../../server/src/controllers/init.ts"],"sourcesContent":["import { getService } from '../utils';\n\nexport default {\n async getInitData(ctx: any) {\n const { toDto } = getService('data-mapper');\n const { findAllComponents } = getService('components');\n const { getAllFieldSizes } = getService('field-sizes');\n const { findAllContentTypes } = getService('content-types');\n const { getContentStructure } = getService('content-structure');\n\n const contentStructure = await getContentStructure();\n\n ctx.body = {\n data: {\n fieldSizes: getAllFieldSizes(),\n components: findAllComponents().map(toDto),\n contentTypes: findAllContentTypes().map(toDto),\n ...(contentStructure ? { contentStructure } : {}),\n },\n };\n },\n};\n"],"names":["getInitData","ctx","toDto","getService","findAllComponents","getAllFieldSizes","findAllContentTypes","getContentStructure","contentStructure","body","data","fieldSizes","components","map","contentTypes"],"mappings":";;;;AAEA,WAAe;AACb,IAAA,MAAMA,aAAYC,GAAQ,EAAA;AACxB,QAAA,MAAM,EAAEC,KAAK,EAAE,GAAGC,gBAAAA,CAAW,aAAA,CAAA;AAC7B,QAAA,MAAM,EAAEC,iBAAiB,EAAE,GAAGD,gBAAAA,CAAW,YAAA,CAAA;AACzC,QAAA,MAAM,EAAEE,gBAAgB,EAAE,GAAGF,gBAAAA,CAAW,aAAA,CAAA;AACxC,QAAA,MAAM,EAAEG,mBAAmB,EAAE,GAAGH,gBAAAA,CAAW,eAAA,CAAA;AAC3C,QAAA,MAAM,EAAEI,mBAAmB,EAAE,GAAGJ,gBAAAA,CAAW,mBAAA,CAAA;AAE3C,QAAA,MAAMK,mBAAmB,MAAMD,mBAAAA,EAAAA;AAE/BN,QAAAA,GAAAA,CAAIQ,IAAI,GAAG;YACTC,IAAAA,EAAM;gBACJC,UAAAA,EAAYN,gBAAAA,EAAAA;gBACZO,UAAAA,EAAYR,iBAAAA,EAAAA,CAAoBS,GAAG,CAACX,KAAAA,CAAAA;gBACpCY,YAAAA,EAAcR,mBAAAA,EAAAA,CAAsBO,GAAG,CAACX,KAAAA,CAAAA;AACxC,gBAAA,GAAIM,gBAAAA,GAAmB;AAAEA,oBAAAA;AAAiB,iBAAA,GAAI;AAChD;AACF,SAAA;AACF,IAAA;AACF,CAAA;;;;"}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { getService } from '../utils/index.mjs';
|
|
2
2
|
|
|
3
3
|
var init = {
|
|
4
|
-
getInitData (ctx) {
|
|
4
|
+
async getInitData (ctx) {
|
|
5
5
|
const { toDto } = getService('data-mapper');
|
|
6
6
|
const { findAllComponents } = getService('components');
|
|
7
7
|
const { getAllFieldSizes } = getService('field-sizes');
|
|
8
8
|
const { findAllContentTypes } = getService('content-types');
|
|
9
|
+
const { getContentStructure } = getService('content-structure');
|
|
10
|
+
const contentStructure = await getContentStructure();
|
|
9
11
|
ctx.body = {
|
|
10
12
|
data: {
|
|
11
13
|
fieldSizes: getAllFieldSizes(),
|
|
12
14
|
components: findAllComponents().map(toDto),
|
|
13
|
-
contentTypes: findAllContentTypes().map(toDto)
|
|
15
|
+
contentTypes: findAllContentTypes().map(toDto),
|
|
16
|
+
...contentStructure ? {
|
|
17
|
+
contentStructure
|
|
18
|
+
} : {}
|
|
14
19
|
}
|
|
15
20
|
};
|
|
16
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.mjs","sources":["../../../server/src/controllers/init.ts"],"sourcesContent":["import { getService } from '../utils';\n\nexport default {\n getInitData(ctx: any) {\n const { toDto } = getService('data-mapper');\n const { findAllComponents } = getService('components');\n const { getAllFieldSizes } = getService('field-sizes');\n const { findAllContentTypes } = getService('content-types');\n\n ctx.body = {\n data: {\n fieldSizes: getAllFieldSizes(),\n components: findAllComponents().map(toDto),\n contentTypes: findAllContentTypes().map(toDto),\n },\n };\n },\n};\n"],"names":["getInitData","ctx","toDto","getService","findAllComponents","getAllFieldSizes","findAllContentTypes","body","data","fieldSizes","components","map","contentTypes"],"mappings":";;AAEA,WAAe;
|
|
1
|
+
{"version":3,"file":"init.mjs","sources":["../../../server/src/controllers/init.ts"],"sourcesContent":["import { getService } from '../utils';\n\nexport default {\n async getInitData(ctx: any) {\n const { toDto } = getService('data-mapper');\n const { findAllComponents } = getService('components');\n const { getAllFieldSizes } = getService('field-sizes');\n const { findAllContentTypes } = getService('content-types');\n const { getContentStructure } = getService('content-structure');\n\n const contentStructure = await getContentStructure();\n\n ctx.body = {\n data: {\n fieldSizes: getAllFieldSizes(),\n components: findAllComponents().map(toDto),\n contentTypes: findAllContentTypes().map(toDto),\n ...(contentStructure ? { contentStructure } : {}),\n },\n };\n },\n};\n"],"names":["getInitData","ctx","toDto","getService","findAllComponents","getAllFieldSizes","findAllContentTypes","getContentStructure","contentStructure","body","data","fieldSizes","components","map","contentTypes"],"mappings":";;AAEA,WAAe;AACb,IAAA,MAAMA,aAAYC,GAAQ,EAAA;AACxB,QAAA,MAAM,EAAEC,KAAK,EAAE,GAAGC,UAAAA,CAAW,aAAA,CAAA;AAC7B,QAAA,MAAM,EAAEC,iBAAiB,EAAE,GAAGD,UAAAA,CAAW,YAAA,CAAA;AACzC,QAAA,MAAM,EAAEE,gBAAgB,EAAE,GAAGF,UAAAA,CAAW,aAAA,CAAA;AACxC,QAAA,MAAM,EAAEG,mBAAmB,EAAE,GAAGH,UAAAA,CAAW,eAAA,CAAA;AAC3C,QAAA,MAAM,EAAEI,mBAAmB,EAAE,GAAGJ,UAAAA,CAAW,mBAAA,CAAA;AAE3C,QAAA,MAAMK,mBAAmB,MAAMD,mBAAAA,EAAAA;AAE/BN,QAAAA,GAAAA,CAAIQ,IAAI,GAAG;YACTC,IAAAA,EAAM;gBACJC,UAAAA,EAAYN,gBAAAA,EAAAA;gBACZO,UAAAA,EAAYR,iBAAAA,EAAAA,CAAoBS,GAAG,CAACX,KAAAA,CAAAA;gBACpCY,YAAAA,EAAcR,mBAAAA,EAAAA,CAAsBO,GAAG,CAACX,KAAAA,CAAAA;AACxC,gBAAA,GAAIM,gBAAAA,GAAmB;AAAEA,oBAAAA;AAAiB,iBAAA,GAAI;AAChD;AACF,SAAA;AACF,IAAA;AACF,CAAA;;;;"}
|