@strapi/content-type-builder 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/AIChat/hooks/useAIFetch.js +6 -2
- package/dist/admin/components/AIChat/hooks/useAIFetch.js.map +1 -1
- package/dist/admin/components/AIChat/hooks/useAIFetch.mjs +7 -3
- package/dist/admin/components/AIChat/hooks/useAIFetch.mjs.map +1 -1
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.js +20 -0
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.js.map +1 -0
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.mjs +18 -0
- package/dist/admin/components/AIChat/hooks/usePrefetchAIToken.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.js +83 -59
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.js.map +1 -1
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.mjs +86 -62
- package/dist/admin/components/ContentTypeBuilderNav/ContentTypeBuilderNav.mjs.map +1 -1
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.js +112 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.mjs +110 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.js +159 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.mjs +157 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.js +311 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.mjs +309 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.js +379 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.mjs +376 -0
- package/dist/admin/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.js +172 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.mjs +166 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.js +62 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.mjs +60 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useFolderActions.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.js +145 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.mjs +143 -0
- package/dist/admin/components/ContentTypeBuilderNav/hooks/useSortableTree.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.js +176 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.mjs +169 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/buildFolderTree.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.js +277 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.mjs +273 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/dropProjection.mjs.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.js +62 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.js.map +1 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.mjs +58 -0
- package/dist/admin/components/ContentTypeBuilderNav/lib/flatModel.mjs.map +1 -0
- package/dist/admin/components/DataManager/DataManagerContext.js.map +1 -1
- package/dist/admin/components/DataManager/DataManagerContext.mjs.map +1 -1
- package/dist/admin/components/DataManager/DataManagerProvider.js +70 -8
- package/dist/admin/components/DataManager/DataManagerProvider.js.map +1 -1
- package/dist/admin/components/DataManager/DataManagerProvider.mjs +70 -8
- package/dist/admin/components/DataManager/DataManagerProvider.mjs.map +1 -1
- package/dist/admin/components/DataManager/reducer.js +411 -33
- package/dist/admin/components/DataManager/reducer.js.map +1 -1
- package/dist/admin/components/DataManager/reducer.mjs +411 -33
- package/dist/admin/components/DataManager/reducer.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.js +11 -2
- package/dist/admin/components/DataManager/utils/cleanData.js.map +1 -1
- package/dist/admin/components/DataManager/utils/cleanData.mjs +11 -2
- package/dist/admin/components/DataManager/utils/cleanData.mjs.map +1 -1
- package/dist/admin/components/DataManager/utils/contentStructure.js +150 -0
- package/dist/admin/components/DataManager/utils/contentStructure.js.map +1 -0
- package/dist/admin/components/DataManager/utils/contentStructure.mjs +133 -0
- package/dist/admin/components/DataManager/utils/contentStructure.mjs.map +1 -0
- package/dist/admin/components/FolderSelect.js +200 -0
- package/dist/admin/components/FolderSelect.js.map +1 -0
- package/dist/admin/components/FolderSelect.mjs +198 -0
- package/dist/admin/components/FolderSelect.mjs.map +1 -0
- package/dist/admin/components/FormModal/FormModal.js +23 -2
- package/dist/admin/components/FormModal/FormModal.js.map +1 -1
- package/dist/admin/components/FormModal/FormModal.mjs +23 -2
- package/dist/admin/components/FormModal/FormModal.mjs.map +1 -1
- package/dist/admin/components/FormModal/contentType/contentTypeForm.js +15 -18
- package/dist/admin/components/FormModal/contentType/contentTypeForm.js.map +1 -1
- package/dist/admin/components/FormModal/contentType/contentTypeForm.mjs +15 -18
- package/dist/admin/components/FormModal/contentType/contentTypeForm.mjs.map +1 -1
- package/dist/admin/components/FormModal/reducer.js +6 -0
- package/dist/admin/components/FormModal/reducer.js.map +1 -1
- package/dist/admin/components/FormModal/reducer.mjs +6 -0
- package/dist/admin/components/FormModal/reducer.mjs.map +1 -1
- package/dist/admin/pages/App/index.js +2 -5
- package/dist/admin/pages/App/index.js.map +1 -1
- package/dist/admin/pages/App/index.mjs +2 -5
- package/dist/admin/pages/App/index.mjs.map +1 -1
- package/dist/admin/src/components/AIChat/hooks/usePrefetchAIToken.d.ts +1 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/DeleteFolderDialog.d.ts +16 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/FolderNameField.d.ts +12 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/FolderNavSection.d.ts +14 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/components/FolderNav/SortableTreeRow.d.ts +38 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/{useContentTypeBuilderMenu.d.ts → hooks/useContentTypeBuilderMenu.d.ts} +17 -7
- package/dist/admin/src/components/ContentTypeBuilderNav/hooks/useFolderActions.d.ts +42 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/hooks/useSortableTree.d.ts +53 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/lib/buildFolderTree.d.ts +42 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/lib/dropProjection.d.ts +58 -0
- package/dist/admin/src/components/ContentTypeBuilderNav/lib/flatModel.d.ts +18 -0
- package/dist/admin/src/components/DataManager/DataManagerContext.d.ts +41 -0
- package/dist/admin/src/components/DataManager/reducer.d.ts +105 -1
- package/dist/admin/src/components/DataManager/utils/cleanData.d.ts +5 -1
- package/dist/admin/src/components/DataManager/utils/contentStructure.d.ts +68 -0
- package/dist/admin/src/components/FolderSelect.d.ts +18 -0
- package/dist/admin/src/components/FormModal/contentType/contentTypeForm.d.ts +0 -21
- package/dist/admin/src/components/FormModal/forms/forms.d.ts +0 -10
- package/dist/admin/src/components/FormModal/reducer.d.ts +7 -0
- package/dist/admin/src/utils/folderTelemetry.d.ts +5 -0
- package/dist/admin/translations/en.json.js +23 -0
- package/dist/admin/translations/en.json.js.map +1 -1
- package/dist/admin/translations/en.json.mjs +23 -0
- package/dist/admin/translations/en.json.mjs.map +1 -1
- package/dist/admin/utils/folderTelemetry.js +19 -0
- package/dist/admin/utils/folderTelemetry.js.map +1 -0
- package/dist/admin/utils/folderTelemetry.mjs +16 -0
- package/dist/admin/utils/folderTelemetry.mjs.map +1 -0
- package/dist/server/controllers/schema.js +1 -1
- package/dist/server/controllers/schema.js.map +1 -1
- package/dist/server/controllers/schema.mjs +1 -1
- package/dist/server/controllers/schema.mjs.map +1 -1
- package/dist/server/controllers/validation/common.js +3 -0
- package/dist/server/controllers/validation/common.js.map +1 -1
- package/dist/server/controllers/validation/common.mjs +3 -1
- package/dist/server/controllers/validation/common.mjs.map +1 -1
- package/dist/server/controllers/validation/content-structure.js +177 -0
- package/dist/server/controllers/validation/content-structure.js.map +1 -0
- package/dist/server/controllers/validation/content-structure.mjs +173 -0
- package/dist/server/controllers/validation/content-structure.mjs.map +1 -0
- package/dist/server/controllers/validation/schema.js +3 -1
- package/dist/server/controllers/validation/schema.js.map +1 -1
- package/dist/server/controllers/validation/schema.mjs +3 -1
- package/dist/server/controllers/validation/schema.mjs.map +1 -1
- package/dist/server/register.js +1 -1
- package/dist/server/register.js.map +1 -1
- package/dist/server/register.mjs +1 -1
- package/dist/server/register.mjs.map +1 -1
- package/dist/server/routes/content-api.js +4 -4
- package/dist/server/routes/content-api.js.map +1 -1
- package/dist/server/routes/content-api.mjs +4 -4
- package/dist/server/routes/content-api.mjs.map +1 -1
- package/dist/server/services/api-handler.js +37 -4
- package/dist/server/services/api-handler.js.map +1 -1
- package/dist/server/services/api-handler.mjs +36 -5
- package/dist/server/services/api-handler.mjs.map +1 -1
- package/dist/server/services/content-structure.js +174 -0
- package/dist/server/services/content-structure.js.map +1 -0
- package/dist/server/services/content-structure.mjs +172 -0
- package/dist/server/services/content-structure.mjs.map +1 -0
- package/dist/server/services/content-types.js +196 -44
- package/dist/server/services/content-types.js.map +1 -1
- package/dist/server/services/content-types.mjs +195 -45
- package/dist/server/services/content-types.mjs.map +1 -1
- package/dist/server/services/index.js +3 -1
- package/dist/server/services/index.js.map +1 -1
- package/dist/server/services/index.mjs +3 -1
- package/dist/server/services/index.mjs.map +1 -1
- package/dist/server/services/schema-builder/index.js +4 -2
- package/dist/server/services/schema-builder/index.js.map +1 -1
- package/dist/server/services/schema-builder/index.mjs +4 -2
- package/dist/server/services/schema-builder/index.mjs.map +1 -1
- package/dist/server/services/schema-builder/schema-handler.js +19 -17
- package/dist/server/services/schema-builder/schema-handler.js.map +1 -1
- package/dist/server/services/schema-builder/schema-handler.mjs +19 -17
- package/dist/server/services/schema-builder/schema-handler.mjs.map +1 -1
- package/dist/server/services/schema-mutation.js +46 -0
- package/dist/server/services/schema-mutation.js.map +1 -0
- package/dist/server/services/schema-mutation.mjs +43 -0
- package/dist/server/services/schema-mutation.mjs.map +1 -0
- package/dist/server/services/schema.js +134 -79
- package/dist/server/services/schema.js.map +1 -1
- package/dist/server/services/schema.mjs +135 -80
- package/dist/server/services/schema.mjs.map +1 -1
- package/dist/server/src/controllers/schema.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/common.d.ts +1 -0
- package/dist/server/src/controllers/validation/common.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/content-structure.d.ts +56 -0
- package/dist/server/src/controllers/validation/content-structure.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/schema.d.ts +35 -0
- package/dist/server/src/controllers/validation/schema.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +3 -0
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/routes/content-api.d.ts.map +1 -1
- package/dist/server/src/services/api-handler.d.ts +13 -1
- package/dist/server/src/services/api-handler.d.ts.map +1 -1
- package/dist/server/src/services/content-structure.d.ts +37 -0
- package/dist/server/src/services/content-structure.d.ts.map +1 -0
- package/dist/server/src/services/content-types.d.ts +4 -0
- package/dist/server/src/services/content-types.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +4 -0
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/schema-builder/index.d.ts +3 -1
- package/dist/server/src/services/schema-builder/index.d.ts.map +1 -1
- package/dist/server/src/services/schema-builder/schema-handler.d.ts.map +1 -1
- package/dist/server/src/services/schema-mutation.d.ts +26 -0
- package/dist/server/src/services/schema-mutation.d.ts.map +1 -0
- package/dist/server/src/services/schema.d.ts +1 -0
- package/dist/server/src/services/schema.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/package.json +8 -8
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.js +0 -157
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.js.map +0 -1
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.mjs +0 -151
- package/dist/admin/components/ContentTypeBuilderNav/useContentTypeBuilderMenu.mjs.map +0 -1
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { useFilter, useCollator } from '@strapi/design-system';
|
|
3
|
+
import upperFirst from 'lodash/upperFirst';
|
|
4
|
+
import { useIntl } from 'react-intl';
|
|
5
|
+
import { pluginId } from '../../../pluginId.mjs';
|
|
6
|
+
import { getTrad } from '../../../utils/getTrad.mjs';
|
|
7
|
+
import 'react/jsx-runtime';
|
|
8
|
+
import '../../CTBSession/sessionContext.mjs';
|
|
9
|
+
import { useCTBTracking } from '../../CTBSession/useCTBTracking.mjs';
|
|
10
|
+
import { useDataManager } from '../../DataManager/useDataManager.mjs';
|
|
11
|
+
import { useFormModalNavigation } from '../../FormModalNavigation/useFormModalNavigation.mjs';
|
|
12
|
+
|
|
13
|
+
function useContentTypeBuilderMenu() {
|
|
14
|
+
const { componentsGroupedByCategory, isInDevelopmentMode, sortedContentTypesList } = useDataManager();
|
|
15
|
+
const { onOpenModalCreateSchema } = useFormModalNavigation();
|
|
16
|
+
const { locale, formatMessage } = useIntl();
|
|
17
|
+
const { trackUsage } = useCTBTracking();
|
|
18
|
+
const [searchValue, setSearchValue] = useState('');
|
|
19
|
+
const { contains } = useFilter(locale, {
|
|
20
|
+
sensitivity: 'base'
|
|
21
|
+
});
|
|
22
|
+
const formatter = useCollator(locale, {
|
|
23
|
+
sensitivity: 'base'
|
|
24
|
+
});
|
|
25
|
+
const handleClickOpenModalCreateCollectionType = ()=>{
|
|
26
|
+
trackUsage(`willCreateContentType`);
|
|
27
|
+
onOpenModalCreateSchema({
|
|
28
|
+
forTarget: 'contentType',
|
|
29
|
+
modalType: 'contentType',
|
|
30
|
+
kind: 'collectionType',
|
|
31
|
+
actionType: 'create'
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
const handleClickOpenModalCreateSingleType = ()=>{
|
|
35
|
+
trackUsage(`willCreateSingleType`);
|
|
36
|
+
onOpenModalCreateSchema({
|
|
37
|
+
forTarget: 'contentType',
|
|
38
|
+
modalType: 'contentType',
|
|
39
|
+
actionType: 'create',
|
|
40
|
+
kind: 'singleType'
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
const handleClickOpenModalCreateComponent = ()=>{
|
|
44
|
+
trackUsage('willCreateComponent');
|
|
45
|
+
onOpenModalCreateSchema({
|
|
46
|
+
modalType: 'component',
|
|
47
|
+
kind: 'collectionType',
|
|
48
|
+
forTarget: 'component',
|
|
49
|
+
actionType: 'create'
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
const sortByTitle = (a, b)=>{
|
|
53
|
+
return formatter.compare(a.title, b.title);
|
|
54
|
+
};
|
|
55
|
+
const componentsData = Object.entries(componentsGroupedByCategory).map(([category, components])=>{
|
|
56
|
+
const categoryLinks = components.map((component)=>({
|
|
57
|
+
to: `/plugins/${pluginId}/component-categories/${category}/${component.uid}`,
|
|
58
|
+
title: component.info.displayName,
|
|
59
|
+
status: component.status,
|
|
60
|
+
name: component.uid
|
|
61
|
+
})).sort(sortByTitle);
|
|
62
|
+
return {
|
|
63
|
+
title: upperFirst(category),
|
|
64
|
+
links: categoryLinks,
|
|
65
|
+
name: category
|
|
66
|
+
};
|
|
67
|
+
}).sort(sortByTitle);
|
|
68
|
+
const displayedContentTypes = sortedContentTypesList.filter((obj)=>obj.visible).map((info)=>({
|
|
69
|
+
status: info.status,
|
|
70
|
+
title: info.title,
|
|
71
|
+
kind: info.kind,
|
|
72
|
+
name: info.name,
|
|
73
|
+
to: info.to
|
|
74
|
+
}));
|
|
75
|
+
const toContentTypeLink = (contentType)=>({
|
|
76
|
+
status: contentType.status,
|
|
77
|
+
title: contentType.title,
|
|
78
|
+
uid: contentType.name,
|
|
79
|
+
to: contentType.to
|
|
80
|
+
});
|
|
81
|
+
const folderSections = [
|
|
82
|
+
{
|
|
83
|
+
section: 'collectionTypes',
|
|
84
|
+
sectionId: 'models',
|
|
85
|
+
title: formatMessage({
|
|
86
|
+
id: getTrad('menu.section.models.name'),
|
|
87
|
+
defaultMessage: 'Collection Types'
|
|
88
|
+
}),
|
|
89
|
+
links: displayedContentTypes.filter((contentType)=>contentType.kind === 'collectionType').map(toContentTypeLink),
|
|
90
|
+
createTypeLabel: formatMessage({
|
|
91
|
+
id: getTrad('nav.action.new-collection-type'),
|
|
92
|
+
defaultMessage: 'New Collection-Type'
|
|
93
|
+
}),
|
|
94
|
+
onCreateContentType: handleClickOpenModalCreateCollectionType
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
section: 'singleTypes',
|
|
98
|
+
sectionId: 'singleTypes',
|
|
99
|
+
title: formatMessage({
|
|
100
|
+
id: getTrad('menu.section.single-types.name'),
|
|
101
|
+
defaultMessage: 'Single Types'
|
|
102
|
+
}),
|
|
103
|
+
links: displayedContentTypes.filter((contentType)=>contentType.kind === 'singleType').map(toContentTypeLink),
|
|
104
|
+
createTypeLabel: formatMessage({
|
|
105
|
+
id: getTrad('nav.action.new-single-type'),
|
|
106
|
+
defaultMessage: 'New Single-Type'
|
|
107
|
+
}),
|
|
108
|
+
onCreateContentType: handleClickOpenModalCreateSingleType
|
|
109
|
+
}
|
|
110
|
+
];
|
|
111
|
+
const flatSections = [
|
|
112
|
+
{
|
|
113
|
+
name: 'components',
|
|
114
|
+
title: {
|
|
115
|
+
id: `${getTrad('menu.section.components.name')}`,
|
|
116
|
+
defaultMessage: 'Components'
|
|
117
|
+
},
|
|
118
|
+
customLink: isInDevelopmentMode ? {
|
|
119
|
+
id: `${getTrad('button.component.create')}`,
|
|
120
|
+
defaultMessage: 'Create a new component',
|
|
121
|
+
onClick: handleClickOpenModalCreateComponent
|
|
122
|
+
} : undefined,
|
|
123
|
+
links: componentsData
|
|
124
|
+
}
|
|
125
|
+
].map((section)=>{
|
|
126
|
+
const hasChild = section.links.some((l)=>'links' in l && Array.isArray(l.links));
|
|
127
|
+
if (hasChild) {
|
|
128
|
+
let filteredLinksCount = 0;
|
|
129
|
+
const links = section.links.reduce((acc, link)=>{
|
|
130
|
+
const filteredLinks = 'links' in link ? link.links.filter((link)=>contains(link.title, searchValue)) : [];
|
|
131
|
+
if (filteredLinks.length === 0) {
|
|
132
|
+
return acc;
|
|
133
|
+
}
|
|
134
|
+
filteredLinksCount += filteredLinks.length;
|
|
135
|
+
acc.push({
|
|
136
|
+
...link,
|
|
137
|
+
links: filteredLinks.sort(sortByTitle)
|
|
138
|
+
});
|
|
139
|
+
return acc;
|
|
140
|
+
}, []);
|
|
141
|
+
return {
|
|
142
|
+
...section,
|
|
143
|
+
linksCount: filteredLinksCount,
|
|
144
|
+
links: links
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
const filteredLinks = section.links.filter((link)=>contains(link.title, searchValue)).sort(sortByTitle);
|
|
148
|
+
return {
|
|
149
|
+
...section,
|
|
150
|
+
linksCount: filteredLinks.length,
|
|
151
|
+
links: filteredLinks
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
return {
|
|
155
|
+
folderSections,
|
|
156
|
+
flatSections,
|
|
157
|
+
search: {
|
|
158
|
+
clear: ()=>setSearchValue(''),
|
|
159
|
+
onChange: setSearchValue,
|
|
160
|
+
value: searchValue
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export { useContentTypeBuilderMenu };
|
|
166
|
+
//# sourceMappingURL=useContentTypeBuilderMenu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useContentTypeBuilderMenu.mjs","sources":["../../../../../admin/src/components/ContentTypeBuilderNav/hooks/useContentTypeBuilderMenu.ts"],"sourcesContent":["import { useState } from 'react';\n\nimport { useCollator, useFilter } from '@strapi/design-system';\nimport upperFirst from 'lodash/upperFirst';\nimport { useIntl } from 'react-intl';\n\nimport { pluginId } from '../../../pluginId';\nimport { getTrad } from '../../../utils/getTrad';\nimport { useCTBTracking } from '../../CTBSession/ctbSession';\nimport { useDataManager } from '../../DataManager/useDataManager';\nimport { useFormModalNavigation } from '../../FormModalNavigation/useFormModalNavigation';\n\nimport type { Status } from '../../../types';\nimport type { SectionKey } from '../../DataManager/utils/contentStructure';\nimport type { ContentTypeLink } from '../lib/buildFolderTree';\n\nexport type FolderMenuSection = {\n onCreateContentType: () => void;\n links: ContentTypeLink[];\n createTypeLabel: string;\n section: SectionKey;\n sectionId: string;\n title: string;\n};\n\ntype Link = {\n name: string;\n to: string;\n status: Status;\n title: string;\n};\n\ntype SubSection = {\n name: string;\n title: string;\n links: Link[];\n};\n\nexport type FlatMenuSection = {\n name: string;\n title: {\n id: string;\n defaultMessage: string;\n };\n customLink?: {\n id: string;\n defaultMessage: string;\n onClick: () => void;\n };\n links: Array<SubSection | Link>;\n linksCount?: number;\n};\n\nexport function useContentTypeBuilderMenu() {\n const { componentsGroupedByCategory, isInDevelopmentMode, sortedContentTypesList } =\n useDataManager();\n const { onOpenModalCreateSchema } = useFormModalNavigation();\n const { locale, formatMessage } = useIntl();\n const { trackUsage } = useCTBTracking();\n\n const [searchValue, setSearchValue] = useState('');\n\n const { contains } = useFilter(locale, {\n sensitivity: 'base',\n });\n\n const formatter = useCollator(locale, {\n sensitivity: 'base',\n });\n\n const handleClickOpenModalCreateCollectionType = () => {\n trackUsage(`willCreateContentType`);\n\n onOpenModalCreateSchema({\n forTarget: 'contentType',\n modalType: 'contentType',\n kind: 'collectionType',\n actionType: 'create',\n });\n };\n\n const handleClickOpenModalCreateSingleType = () => {\n trackUsage(`willCreateSingleType`);\n\n onOpenModalCreateSchema({\n forTarget: 'contentType',\n modalType: 'contentType',\n actionType: 'create',\n kind: 'singleType',\n });\n };\n\n const handleClickOpenModalCreateComponent = () => {\n trackUsage('willCreateComponent');\n\n onOpenModalCreateSchema({\n modalType: 'component',\n kind: 'collectionType',\n forTarget: 'component',\n actionType: 'create',\n });\n };\n\n const sortByTitle = (a: { title: string }, b: { title: string }) => {\n return formatter.compare(a.title, b.title);\n };\n\n const componentsData = Object.entries(componentsGroupedByCategory)\n .map(([category, components]) => {\n const categoryLinks = components\n .map((component) => ({\n to: `/plugins/${pluginId}/component-categories/${category}/${component.uid}`,\n title: component.info.displayName,\n status: component.status,\n name: component.uid,\n }))\n .sort(sortByTitle);\n\n return {\n title: upperFirst(category),\n links: categoryLinks,\n name: category,\n };\n })\n .sort(sortByTitle);\n\n const displayedContentTypes = sortedContentTypesList\n .filter((obj) => obj.visible)\n .map((info) => ({\n status: info.status,\n title: info.title,\n kind: info.kind,\n name: info.name,\n to: info.to,\n }));\n\n const toContentTypeLink = (\n contentType: (typeof displayedContentTypes)[number]\n ): ContentTypeLink => ({\n status: contentType.status,\n title: contentType.title,\n uid: contentType.name,\n to: contentType.to,\n });\n\n const folderSections: FolderMenuSection[] = [\n {\n section: 'collectionTypes',\n sectionId: 'models',\n title: formatMessage({\n id: getTrad('menu.section.models.name'),\n defaultMessage: 'Collection Types',\n }),\n links: displayedContentTypes\n .filter((contentType) => contentType.kind === 'collectionType')\n .map(toContentTypeLink),\n createTypeLabel: formatMessage({\n id: getTrad('nav.action.new-collection-type'),\n defaultMessage: 'New Collection-Type',\n }),\n onCreateContentType: handleClickOpenModalCreateCollectionType,\n },\n {\n section: 'singleTypes',\n sectionId: 'singleTypes',\n title: formatMessage({\n id: getTrad('menu.section.single-types.name'),\n defaultMessage: 'Single Types',\n }),\n links: displayedContentTypes\n .filter((contentType) => contentType.kind === 'singleType')\n .map(toContentTypeLink),\n createTypeLabel: formatMessage({\n id: getTrad('nav.action.new-single-type'),\n defaultMessage: 'New Single-Type',\n }),\n onCreateContentType: handleClickOpenModalCreateSingleType,\n },\n ];\n\n const flatSections: FlatMenuSection[] = [\n {\n name: 'components',\n title: {\n id: `${getTrad('menu.section.components.name')}`,\n defaultMessage: 'Components',\n },\n customLink: isInDevelopmentMode\n ? {\n id: `${getTrad('button.component.create')}`,\n defaultMessage: 'Create a new component',\n onClick: handleClickOpenModalCreateComponent,\n }\n : undefined,\n links: componentsData,\n },\n ].map((section) => {\n const hasChild = section.links.some((l) => 'links' in l && Array.isArray(l.links));\n\n if (hasChild) {\n let filteredLinksCount = 0;\n\n const links = section.links.reduce((acc, link) => {\n const filteredLinks =\n 'links' in link ? link.links.filter((link) => contains(link.title, searchValue)) : [];\n\n if (filteredLinks.length === 0) {\n return acc;\n }\n\n filteredLinksCount += filteredLinks.length;\n\n acc.push({\n ...link,\n links: filteredLinks.sort(sortByTitle),\n });\n\n return acc;\n }, [] as SubSection[]);\n\n return {\n ...section,\n linksCount: filteredLinksCount,\n links: links,\n };\n }\n\n const filteredLinks = section.links\n .filter((link) => contains(link.title, searchValue))\n .sort(sortByTitle);\n\n return {\n ...section,\n linksCount: filteredLinks.length,\n links: filteredLinks,\n };\n });\n\n return {\n folderSections,\n flatSections,\n search: {\n clear: () => setSearchValue(''),\n onChange: setSearchValue,\n value: searchValue,\n },\n };\n}\n"],"names":["useContentTypeBuilderMenu","componentsGroupedByCategory","isInDevelopmentMode","sortedContentTypesList","useDataManager","onOpenModalCreateSchema","useFormModalNavigation","locale","formatMessage","useIntl","trackUsage","useCTBTracking","searchValue","setSearchValue","useState","contains","useFilter","sensitivity","formatter","useCollator","handleClickOpenModalCreateCollectionType","forTarget","modalType","kind","actionType","handleClickOpenModalCreateSingleType","handleClickOpenModalCreateComponent","sortByTitle","a","b","compare","title","componentsData","Object","entries","map","category","components","categoryLinks","component","to","pluginId","uid","info","displayName","status","name","sort","upperFirst","links","displayedContentTypes","filter","obj","visible","toContentTypeLink","contentType","folderSections","section","sectionId","id","getTrad","defaultMessage","createTypeLabel","onCreateContentType","flatSections","customLink","onClick","undefined","hasChild","some","l","Array","isArray","filteredLinksCount","reduce","acc","link","filteredLinks","length","push","linksCount","search","clear","onChange","value"],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var folderTelemetry = require('../../../utils/folderTelemetry.js');
|
|
5
|
+
require('react/jsx-runtime');
|
|
6
|
+
require('../../CTBSession/sessionContext.js');
|
|
7
|
+
var useCTBTracking = require('../../CTBSession/useCTBTracking.js');
|
|
8
|
+
var useDataManager = require('../../DataManager/useDataManager.js');
|
|
9
|
+
|
|
10
|
+
const useFolderActions = ()=>{
|
|
11
|
+
const { trackUsage } = useCTBTracking.useCTBTracking();
|
|
12
|
+
const { assignContentTypeToFolder, deleteFolderAndContent, reorderFolderChildren, deleteFolderOnly, createFolder, renameFolder, moveFolder } = useDataManager.useDataManager();
|
|
13
|
+
return React.useMemo(()=>{
|
|
14
|
+
const track = (action)=>{
|
|
15
|
+
return trackUsage(folderTelemetry.DID_ACT_ON_FOLDERS, {
|
|
16
|
+
operation: folderTelemetry.folderTelemetryOperation(action)
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
return {
|
|
20
|
+
createFolder: (payload)=>{
|
|
21
|
+
createFolder(payload);
|
|
22
|
+
track('create');
|
|
23
|
+
},
|
|
24
|
+
renameFolder: (payload)=>{
|
|
25
|
+
renameFolder(payload);
|
|
26
|
+
track('rename');
|
|
27
|
+
},
|
|
28
|
+
moveFolder: (payload)=>{
|
|
29
|
+
moveFolder(payload);
|
|
30
|
+
track('move');
|
|
31
|
+
},
|
|
32
|
+
deleteFolderOnly: (payload)=>{
|
|
33
|
+
deleteFolderOnly(payload);
|
|
34
|
+
track('deleteOnly');
|
|
35
|
+
},
|
|
36
|
+
deleteFolderAndContent: (payload)=>{
|
|
37
|
+
deleteFolderAndContent(payload);
|
|
38
|
+
track('deleteSubtree');
|
|
39
|
+
},
|
|
40
|
+
assignContentTypeToFolder: (payload)=>{
|
|
41
|
+
assignContentTypeToFolder(payload);
|
|
42
|
+
track('assign');
|
|
43
|
+
},
|
|
44
|
+
reorderFolderChildren: (payload)=>{
|
|
45
|
+
reorderFolderChildren(payload);
|
|
46
|
+
track('reorder');
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}, [
|
|
50
|
+
assignContentTypeToFolder,
|
|
51
|
+
deleteFolderAndContent,
|
|
52
|
+
reorderFolderChildren,
|
|
53
|
+
deleteFolderOnly,
|
|
54
|
+
createFolder,
|
|
55
|
+
renameFolder,
|
|
56
|
+
moveFolder,
|
|
57
|
+
trackUsage
|
|
58
|
+
]);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
exports.useFolderActions = useFolderActions;
|
|
62
|
+
//# sourceMappingURL=useFolderActions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFolderActions.js","sources":["../../../../../admin/src/components/ContentTypeBuilderNav/hooks/useFolderActions.ts"],"sourcesContent":["import { useMemo } from 'react';\n\nimport { DID_ACT_ON_FOLDERS, folderTelemetryOperation } from '../../../utils/folderTelemetry';\nimport { useCTBTracking } from '../../CTBSession/ctbSession';\nimport { useDataManager } from '../../DataManager/useDataManager';\n\nimport type { FolderAction } from '../../../utils/folderTelemetry';\nimport type { SectionKey } from '../../DataManager/utils/contentStructure';\nimport type { UID } from '@strapi/types';\n\nexport const useFolderActions = () => {\n const { trackUsage } = useCTBTracking();\n const {\n assignContentTypeToFolder,\n deleteFolderAndContent,\n reorderFolderChildren,\n deleteFolderOnly,\n createFolder,\n renameFolder,\n moveFolder,\n } = useDataManager();\n\n return useMemo(() => {\n const track = (action: FolderAction) => {\n return trackUsage(DID_ACT_ON_FOLDERS, { operation: folderTelemetryOperation(action) });\n };\n\n return {\n createFolder: (payload: { section: SectionKey; name: string; parentId: string | null }) => {\n createFolder(payload);\n track('create');\n },\n renameFolder: (payload: { section: SectionKey; id: string; name: string }) => {\n renameFolder(payload);\n track('rename');\n },\n moveFolder: (payload: {\n section: SectionKey;\n id: string;\n newParentId: string | null;\n index?: number;\n }) => {\n moveFolder(payload);\n track('move');\n },\n deleteFolderOnly: (payload: { section: SectionKey; id: string }) => {\n deleteFolderOnly(payload);\n track('deleteOnly');\n },\n deleteFolderAndContent: (payload: {\n section: SectionKey;\n id: string;\n contentTypeUids: UID.ContentType[];\n }) => {\n deleteFolderAndContent(payload);\n track('deleteSubtree');\n },\n assignContentTypeToFolder: (payload: {\n section: SectionKey;\n uid: UID.ContentType;\n targetGroupId: string | null;\n index?: number;\n }) => {\n assignContentTypeToFolder(payload);\n track('assign');\n },\n reorderFolderChildren: (payload: {\n section: SectionKey;\n groupId: string;\n from: number;\n to: number;\n }) => {\n reorderFolderChildren(payload);\n track('reorder');\n },\n };\n }, [\n assignContentTypeToFolder,\n deleteFolderAndContent,\n reorderFolderChildren,\n deleteFolderOnly,\n createFolder,\n renameFolder,\n moveFolder,\n trackUsage,\n ]);\n};\n\nexport type FolderActions = ReturnType<typeof useFolderActions>;\n"],"names":["useFolderActions","trackUsage","useCTBTracking","assignContentTypeToFolder","deleteFolderAndContent","reorderFolderChildren","deleteFolderOnly","createFolder","renameFolder","moveFolder","useDataManager","useMemo","track","action","DID_ACT_ON_FOLDERS","operation","folderTelemetryOperation","payload"],"mappings":";;;;;;;;;MAUaA,gBAAAA,GAAmB,IAAA;IAC9B,MAAM,EAAEC,UAAU,EAAE,GAAGC,6BAAAA,EAAAA;AACvB,IAAA,MAAM,EACJC,yBAAyB,EACzBC,sBAAsB,EACtBC,qBAAqB,EACrBC,gBAAgB,EAChBC,YAAY,EACZC,YAAY,EACZC,UAAU,EACX,GAAGC,6BAAAA,EAAAA;AAEJ,IAAA,OAAOC,aAAAA,CAAQ,IAAA;AACb,QAAA,MAAMC,QAAQ,CAACC,MAAAA,GAAAA;AACb,YAAA,OAAOZ,WAAWa,kCAAAA,EAAoB;AAAEC,gBAAAA,SAAAA,EAAWC,wCAAAA,CAAyBH,MAAAA;AAAQ,aAAA,CAAA;AACtF,QAAA,CAAA;QAEA,OAAO;AACLN,YAAAA,YAAAA,EAAc,CAACU,OAAAA,GAAAA;gBACbV,YAAAA,CAAaU,OAAAA,CAAAA;gBACbL,KAAAA,CAAM,QAAA,CAAA;AACR,YAAA,CAAA;AACAJ,YAAAA,YAAAA,EAAc,CAACS,OAAAA,GAAAA;gBACbT,YAAAA,CAAaS,OAAAA,CAAAA;gBACbL,KAAAA,CAAM,QAAA,CAAA;AACR,YAAA,CAAA;AACAH,YAAAA,UAAAA,EAAY,CAACQ,OAAAA,GAAAA;gBAMXR,UAAAA,CAAWQ,OAAAA,CAAAA;gBACXL,KAAAA,CAAM,MAAA,CAAA;AACR,YAAA,CAAA;AACAN,YAAAA,gBAAAA,EAAkB,CAACW,OAAAA,GAAAA;gBACjBX,gBAAAA,CAAiBW,OAAAA,CAAAA;gBACjBL,KAAAA,CAAM,YAAA,CAAA;AACR,YAAA,CAAA;AACAR,YAAAA,sBAAAA,EAAwB,CAACa,OAAAA,GAAAA;gBAKvBb,sBAAAA,CAAuBa,OAAAA,CAAAA;gBACvBL,KAAAA,CAAM,eAAA,CAAA;AACR,YAAA,CAAA;AACAT,YAAAA,yBAAAA,EAA2B,CAACc,OAAAA,GAAAA;gBAM1Bd,yBAAAA,CAA0Bc,OAAAA,CAAAA;gBAC1BL,KAAAA,CAAM,QAAA,CAAA;AACR,YAAA,CAAA;AACAP,YAAAA,qBAAAA,EAAuB,CAACY,OAAAA,GAAAA;gBAMtBZ,qBAAAA,CAAsBY,OAAAA,CAAAA;gBACtBL,KAAAA,CAAM,SAAA,CAAA;AACR,YAAA;AACF,SAAA;IACF,CAAA,EAAG;AACDT,QAAAA,yBAAAA;AACAC,QAAAA,sBAAAA;AACAC,QAAAA,qBAAAA;AACAC,QAAAA,gBAAAA;AACAC,QAAAA,YAAAA;AACAC,QAAAA,YAAAA;AACAC,QAAAA,UAAAA;AACAR,QAAAA;AACD,KAAA,CAAA;AACH;;;;"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { DID_ACT_ON_FOLDERS, folderTelemetryOperation } from '../../../utils/folderTelemetry.mjs';
|
|
3
|
+
import 'react/jsx-runtime';
|
|
4
|
+
import '../../CTBSession/sessionContext.mjs';
|
|
5
|
+
import { useCTBTracking } from '../../CTBSession/useCTBTracking.mjs';
|
|
6
|
+
import { useDataManager } from '../../DataManager/useDataManager.mjs';
|
|
7
|
+
|
|
8
|
+
const useFolderActions = ()=>{
|
|
9
|
+
const { trackUsage } = useCTBTracking();
|
|
10
|
+
const { assignContentTypeToFolder, deleteFolderAndContent, reorderFolderChildren, deleteFolderOnly, createFolder, renameFolder, moveFolder } = useDataManager();
|
|
11
|
+
return useMemo(()=>{
|
|
12
|
+
const track = (action)=>{
|
|
13
|
+
return trackUsage(DID_ACT_ON_FOLDERS, {
|
|
14
|
+
operation: folderTelemetryOperation(action)
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
return {
|
|
18
|
+
createFolder: (payload)=>{
|
|
19
|
+
createFolder(payload);
|
|
20
|
+
track('create');
|
|
21
|
+
},
|
|
22
|
+
renameFolder: (payload)=>{
|
|
23
|
+
renameFolder(payload);
|
|
24
|
+
track('rename');
|
|
25
|
+
},
|
|
26
|
+
moveFolder: (payload)=>{
|
|
27
|
+
moveFolder(payload);
|
|
28
|
+
track('move');
|
|
29
|
+
},
|
|
30
|
+
deleteFolderOnly: (payload)=>{
|
|
31
|
+
deleteFolderOnly(payload);
|
|
32
|
+
track('deleteOnly');
|
|
33
|
+
},
|
|
34
|
+
deleteFolderAndContent: (payload)=>{
|
|
35
|
+
deleteFolderAndContent(payload);
|
|
36
|
+
track('deleteSubtree');
|
|
37
|
+
},
|
|
38
|
+
assignContentTypeToFolder: (payload)=>{
|
|
39
|
+
assignContentTypeToFolder(payload);
|
|
40
|
+
track('assign');
|
|
41
|
+
},
|
|
42
|
+
reorderFolderChildren: (payload)=>{
|
|
43
|
+
reorderFolderChildren(payload);
|
|
44
|
+
track('reorder');
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}, [
|
|
48
|
+
assignContentTypeToFolder,
|
|
49
|
+
deleteFolderAndContent,
|
|
50
|
+
reorderFolderChildren,
|
|
51
|
+
deleteFolderOnly,
|
|
52
|
+
createFolder,
|
|
53
|
+
renameFolder,
|
|
54
|
+
moveFolder,
|
|
55
|
+
trackUsage
|
|
56
|
+
]);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export { useFolderActions };
|
|
60
|
+
//# sourceMappingURL=useFolderActions.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFolderActions.mjs","sources":["../../../../../admin/src/components/ContentTypeBuilderNav/hooks/useFolderActions.ts"],"sourcesContent":["import { useMemo } from 'react';\n\nimport { DID_ACT_ON_FOLDERS, folderTelemetryOperation } from '../../../utils/folderTelemetry';\nimport { useCTBTracking } from '../../CTBSession/ctbSession';\nimport { useDataManager } from '../../DataManager/useDataManager';\n\nimport type { FolderAction } from '../../../utils/folderTelemetry';\nimport type { SectionKey } from '../../DataManager/utils/contentStructure';\nimport type { UID } from '@strapi/types';\n\nexport const useFolderActions = () => {\n const { trackUsage } = useCTBTracking();\n const {\n assignContentTypeToFolder,\n deleteFolderAndContent,\n reorderFolderChildren,\n deleteFolderOnly,\n createFolder,\n renameFolder,\n moveFolder,\n } = useDataManager();\n\n return useMemo(() => {\n const track = (action: FolderAction) => {\n return trackUsage(DID_ACT_ON_FOLDERS, { operation: folderTelemetryOperation(action) });\n };\n\n return {\n createFolder: (payload: { section: SectionKey; name: string; parentId: string | null }) => {\n createFolder(payload);\n track('create');\n },\n renameFolder: (payload: { section: SectionKey; id: string; name: string }) => {\n renameFolder(payload);\n track('rename');\n },\n moveFolder: (payload: {\n section: SectionKey;\n id: string;\n newParentId: string | null;\n index?: number;\n }) => {\n moveFolder(payload);\n track('move');\n },\n deleteFolderOnly: (payload: { section: SectionKey; id: string }) => {\n deleteFolderOnly(payload);\n track('deleteOnly');\n },\n deleteFolderAndContent: (payload: {\n section: SectionKey;\n id: string;\n contentTypeUids: UID.ContentType[];\n }) => {\n deleteFolderAndContent(payload);\n track('deleteSubtree');\n },\n assignContentTypeToFolder: (payload: {\n section: SectionKey;\n uid: UID.ContentType;\n targetGroupId: string | null;\n index?: number;\n }) => {\n assignContentTypeToFolder(payload);\n track('assign');\n },\n reorderFolderChildren: (payload: {\n section: SectionKey;\n groupId: string;\n from: number;\n to: number;\n }) => {\n reorderFolderChildren(payload);\n track('reorder');\n },\n };\n }, [\n assignContentTypeToFolder,\n deleteFolderAndContent,\n reorderFolderChildren,\n deleteFolderOnly,\n createFolder,\n renameFolder,\n moveFolder,\n trackUsage,\n ]);\n};\n\nexport type FolderActions = ReturnType<typeof useFolderActions>;\n"],"names":["useFolderActions","trackUsage","useCTBTracking","assignContentTypeToFolder","deleteFolderAndContent","reorderFolderChildren","deleteFolderOnly","createFolder","renameFolder","moveFolder","useDataManager","useMemo","track","action","DID_ACT_ON_FOLDERS","operation","folderTelemetryOperation","payload"],"mappings":";;;;;;;MAUaA,gBAAAA,GAAmB,IAAA;IAC9B,MAAM,EAAEC,UAAU,EAAE,GAAGC,cAAAA,EAAAA;AACvB,IAAA,MAAM,EACJC,yBAAyB,EACzBC,sBAAsB,EACtBC,qBAAqB,EACrBC,gBAAgB,EAChBC,YAAY,EACZC,YAAY,EACZC,UAAU,EACX,GAAGC,cAAAA,EAAAA;AAEJ,IAAA,OAAOC,OAAAA,CAAQ,IAAA;AACb,QAAA,MAAMC,QAAQ,CAACC,MAAAA,GAAAA;AACb,YAAA,OAAOZ,WAAWa,kBAAAA,EAAoB;AAAEC,gBAAAA,SAAAA,EAAWC,wBAAAA,CAAyBH,MAAAA;AAAQ,aAAA,CAAA;AACtF,QAAA,CAAA;QAEA,OAAO;AACLN,YAAAA,YAAAA,EAAc,CAACU,OAAAA,GAAAA;gBACbV,YAAAA,CAAaU,OAAAA,CAAAA;gBACbL,KAAAA,CAAM,QAAA,CAAA;AACR,YAAA,CAAA;AACAJ,YAAAA,YAAAA,EAAc,CAACS,OAAAA,GAAAA;gBACbT,YAAAA,CAAaS,OAAAA,CAAAA;gBACbL,KAAAA,CAAM,QAAA,CAAA;AACR,YAAA,CAAA;AACAH,YAAAA,UAAAA,EAAY,CAACQ,OAAAA,GAAAA;gBAMXR,UAAAA,CAAWQ,OAAAA,CAAAA;gBACXL,KAAAA,CAAM,MAAA,CAAA;AACR,YAAA,CAAA;AACAN,YAAAA,gBAAAA,EAAkB,CAACW,OAAAA,GAAAA;gBACjBX,gBAAAA,CAAiBW,OAAAA,CAAAA;gBACjBL,KAAAA,CAAM,YAAA,CAAA;AACR,YAAA,CAAA;AACAR,YAAAA,sBAAAA,EAAwB,CAACa,OAAAA,GAAAA;gBAKvBb,sBAAAA,CAAuBa,OAAAA,CAAAA;gBACvBL,KAAAA,CAAM,eAAA,CAAA;AACR,YAAA,CAAA;AACAT,YAAAA,yBAAAA,EAA2B,CAACc,OAAAA,GAAAA;gBAM1Bd,yBAAAA,CAA0Bc,OAAAA,CAAAA;gBAC1BL,KAAAA,CAAM,QAAA,CAAA;AACR,YAAA,CAAA;AACAP,YAAAA,qBAAAA,EAAuB,CAACY,OAAAA,GAAAA;gBAMtBZ,qBAAAA,CAAsBY,OAAAA,CAAAA;gBACtBL,KAAAA,CAAM,SAAA,CAAA;AACR,YAAA;AACF,SAAA;IACF,CAAA,EAAG;AACDT,QAAAA,yBAAAA;AACAC,QAAAA,sBAAAA;AACAC,QAAAA,qBAAAA;AACAC,QAAAA,gBAAAA;AACAC,QAAAA,YAAAA;AACAC,QAAAA,YAAAA;AACAC,QAAAA,UAAAA;AACAR,QAAAA;AACD,KAAA,CAAA;AACH;;;;"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var core = require('@dnd-kit/core');
|
|
5
|
+
var dropProjection = require('../lib/dropProjection.js');
|
|
6
|
+
var flatModel = require('../lib/flatModel.js');
|
|
7
|
+
|
|
8
|
+
// How long the pointer must dwell over a closed folder's nest zone before it
|
|
9
|
+
// springs open, letting you drop deeper.
|
|
10
|
+
const SPRING_OPEN_MS = 700;
|
|
11
|
+
const useHoverFolderOpen = (onExpandFolder)=>{
|
|
12
|
+
const springRef = React.useRef({
|
|
13
|
+
folderId: null
|
|
14
|
+
});
|
|
15
|
+
const cancelFolderOpen = ()=>{
|
|
16
|
+
clearTimeout(springRef.current.timer);
|
|
17
|
+
springRef.current = {
|
|
18
|
+
folderId: null
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
// Arm (once per folder) a timer that springs the closed folder open after a
|
|
22
|
+
// dwell, so the user can drop into a deeper level.
|
|
23
|
+
const scheduleFolderOpen = (folderId)=>{
|
|
24
|
+
if (springRef.current.folderId === folderId) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
cancelFolderOpen();
|
|
28
|
+
springRef.current.folderId = folderId;
|
|
29
|
+
springRef.current.timer = setTimeout(()=>{
|
|
30
|
+
onExpandFolder(folderId);
|
|
31
|
+
springRef.current.folderId = null;
|
|
32
|
+
}, SPRING_OPEN_MS);
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
scheduleFolderOpen,
|
|
36
|
+
cancelFolderOpen
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* The drag-and-drop engine for a flattened folder tree: it owns the drag state
|
|
41
|
+
* machine, pointer-vs-row geometry, spring-open timers and drop projection, and
|
|
42
|
+
* returns the props a `DndContext` + `SortableContext` need plus the resolved
|
|
43
|
+
* drop indicator. It carries no domain logic — nesting rules, the move itself,
|
|
44
|
+
* and expansion are supplied by the caller through {@link UseSortableTreeOptions}.
|
|
45
|
+
*/ const useSortableTree = ({ onExpandFolder, collapsed, disabled, onDrop, canDrop = ()=>true, items })=>{
|
|
46
|
+
const [projected, setProjected] = React.useState(null);
|
|
47
|
+
const [activeId, setActiveId] = React.useState(null);
|
|
48
|
+
const pointerRef = React.useRef(null);
|
|
49
|
+
const { scheduleFolderOpen, cancelFolderOpen } = useHoverFolderOpen(onExpandFolder);
|
|
50
|
+
const collisionDetection = React.useCallback((args)=>{
|
|
51
|
+
// Captured here (onDragMove has no pointer position) to decide whether the
|
|
52
|
+
// pointer sits over a folder's nest zone (its middle third).
|
|
53
|
+
pointerRef.current = args.pointerCoordinates;
|
|
54
|
+
// Resolve `over` from the pointer, NOT the drag overlay's centre. dnd-kit
|
|
55
|
+
// keeps the grab point under the cursor, so the overlay centre sits up to
|
|
56
|
+
// half a row from the pointer depending on where the row was picked up; with
|
|
57
|
+
// closest-centre, `over` and the pointer-based nest-zone check then disagree
|
|
58
|
+
// and nesting into a folder misfires. Fall back to closest-centre only when
|
|
59
|
+
// the pointer is outside every row (the list's padding / edges). A static
|
|
60
|
+
// list keeps both results stable, so no hysteresis is needed.
|
|
61
|
+
const withinPointer = core.pointerWithin(args);
|
|
62
|
+
return withinPointer.length > 0 ? withinPointer : core.closestCenter(args);
|
|
63
|
+
}, []);
|
|
64
|
+
// While dragging a folder, its descendents are hidden so it cannot nest in itself.
|
|
65
|
+
const renderedItems = activeId ? flatModel.removeSubtree(items, activeId) : items;
|
|
66
|
+
const activeItem = items.find((item)=>item.id === activeId) ?? null;
|
|
67
|
+
const sensors = core.useSensors(core.useSensor(core.PointerSensor, {
|
|
68
|
+
activationConstraint: {
|
|
69
|
+
distance: 8
|
|
70
|
+
}
|
|
71
|
+
}));
|
|
72
|
+
const onDragStart = (event)=>{
|
|
73
|
+
if (disabled) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
cancelFolderOpen();
|
|
77
|
+
setActiveId(String(event.active.id));
|
|
78
|
+
setProjected(null);
|
|
79
|
+
};
|
|
80
|
+
const onDragCancel = ()=>{
|
|
81
|
+
resetDrag();
|
|
82
|
+
};
|
|
83
|
+
const onDragMove = (event)=>{
|
|
84
|
+
if (!activeId || !event.over) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const target = dropProjection.resolveDropTarget(renderedItems, {
|
|
88
|
+
pointer: pointerRef.current ?? undefined,
|
|
89
|
+
overId: String(event.over.id),
|
|
90
|
+
overRect: event.over.rect,
|
|
91
|
+
offsetX: event.delta.x,
|
|
92
|
+
activeId
|
|
93
|
+
});
|
|
94
|
+
if (target && activeItem && !canDrop(activeItem.node, target)) {
|
|
95
|
+
setProjected(null);
|
|
96
|
+
cancelFolderOpen();
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
setProjected(target);
|
|
100
|
+
if (target?.kind === 'nest' && collapsed.has(target.folderId)) {
|
|
101
|
+
scheduleFolderOpen(target.folderId);
|
|
102
|
+
} else {
|
|
103
|
+
cancelFolderOpen();
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const resetDrag = ()=>{
|
|
107
|
+
cancelFolderOpen();
|
|
108
|
+
setActiveId(null);
|
|
109
|
+
setProjected(null);
|
|
110
|
+
};
|
|
111
|
+
const onDragEnd = ()=>{
|
|
112
|
+
if (disabled) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const item = activeItem;
|
|
116
|
+
const target = projected;
|
|
117
|
+
resetDrag();
|
|
118
|
+
if (!item || !target) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
onDrop(item.node, target);
|
|
122
|
+
};
|
|
123
|
+
const dropLine = projected?.kind === 'insert' && projected.line ? {
|
|
124
|
+
...projected.line,
|
|
125
|
+
depth: projected.depth
|
|
126
|
+
} : null;
|
|
127
|
+
const dropTargetId = projected?.kind === 'nest' ? `folder:${projected.folderId}` : null;
|
|
128
|
+
const sortingStrategy = ()=>null;
|
|
129
|
+
return {
|
|
130
|
+
collisionDetection,
|
|
131
|
+
sortingStrategy,
|
|
132
|
+
renderedItems,
|
|
133
|
+
dropTargetId,
|
|
134
|
+
activeItem,
|
|
135
|
+
dropLine,
|
|
136
|
+
sensors,
|
|
137
|
+
onDragCancel,
|
|
138
|
+
onDragStart,
|
|
139
|
+
onDragMove,
|
|
140
|
+
onDragEnd
|
|
141
|
+
};
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
exports.useSortableTree = useSortableTree;
|
|
145
|
+
//# sourceMappingURL=useSortableTree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSortableTree.js","sources":["../../../../../admin/src/components/ContentTypeBuilderNav/hooks/useSortableTree.ts"],"sourcesContent":["import { useCallback, useRef, useState } from 'react';\n\nimport { closestCenter, PointerSensor, pointerWithin, useSensor, useSensors } from '@dnd-kit/core';\n\nimport { resolveDropTarget } from '../lib/dropProjection';\nimport { removeSubtree } from '../lib/flatModel';\n\nimport type { FolderTreeNode } from '../lib/buildFolderTree';\nimport type { DropTarget } from '../lib/dropProjection';\nimport type { FlatItem } from '../lib/flatModel';\nimport type {\n CollisionDetection,\n DragMoveEvent,\n DragStartEvent,\n SensorDescriptor,\n} from '@dnd-kit/core';\nimport type { SortingStrategy } from '@dnd-kit/sortable';\n\n// How long the pointer must dwell over a closed folder's nest zone before it\n// springs open, letting you drop deeper.\nconst SPRING_OPEN_MS = 700;\n\n/** The insertion line to paint, plus the depth its left edge indents to. */\nexport type DropLine = { anchorId: string; edge: 'top' | 'bottom'; depth: number };\n\ninterface UseSortableTreeOptions {\n /** Commit a drop. Called only for a real move, with the node and its resolved target. */\n onDrop: (activeNode: FolderTreeNode, target: DropTarget) => void;\n /**\n * Function which determines whether the dragged node may land on the resolved target.\n */\n canDrop?: (activeNode: FolderTreeNode, target: DropTarget) => boolean;\n /** Spring-open a closed folder held under the pointer, so the user can drop deeper. */\n onExpandFolder: (folderId: string) => void;\n /** Ids of collapsed folders — used to tell a closed folder (springs open) from an empty one. */\n collapsed: Set<string>;\n /** When true the contentStructure tree is read-only. */\n disabled: boolean;\n /** The full flattened, visible tree (descendants of collapsed folders omitted). */\n items: FlatItem[];\n}\n\nexport interface UseSortableTreeResult {\n collisionDetection: CollisionDetection;\n sensors: SensorDescriptor<object>[];\n sortingStrategy: SortingStrategy;\n /** The items to render (the dragged folder's descendants are hidden mid-drag). */\n renderedItems: FlatItem[];\n /** The row being dragged, or null. */\n activeItem: FlatItem | null;\n /** Folder row (by dnd id) to highlight as the nest target — no line is drawn for it. */\n dropTargetId: string | null;\n /** The insertion line to paint, or null when nesting into a highlighted folder. */\n dropLine: DropLine | null;\n onDragStart: (event: DragStartEvent) => void;\n onDragMove: (event: DragMoveEvent) => void;\n onDragCancel: () => void;\n onDragEnd: () => void;\n}\n\ntype SpringRef = { folderId: string | null; timer?: ReturnType<typeof setTimeout> };\n\nconst useHoverFolderOpen = (onExpandFolder: (folderId: string) => void) => {\n const springRef = useRef<SpringRef>({ folderId: null });\n\n const cancelFolderOpen = () => {\n clearTimeout(springRef.current.timer);\n springRef.current = { folderId: null };\n };\n\n // Arm (once per folder) a timer that springs the closed folder open after a\n // dwell, so the user can drop into a deeper level.\n const scheduleFolderOpen = (folderId: string) => {\n if (springRef.current.folderId === folderId) {\n return;\n }\n\n cancelFolderOpen();\n springRef.current.folderId = folderId;\n\n springRef.current.timer = setTimeout(() => {\n onExpandFolder(folderId);\n springRef.current.folderId = null;\n }, SPRING_OPEN_MS);\n };\n\n return { scheduleFolderOpen, cancelFolderOpen };\n};\n\n/**\n * The drag-and-drop engine for a flattened folder tree: it owns the drag state\n * machine, pointer-vs-row geometry, spring-open timers and drop projection, and\n * returns the props a `DndContext` + `SortableContext` need plus the resolved\n * drop indicator. It carries no domain logic — nesting rules, the move itself,\n * and expansion are supplied by the caller through {@link UseSortableTreeOptions}.\n */\nexport const useSortableTree = ({\n onExpandFolder,\n collapsed,\n disabled,\n onDrop,\n canDrop = () => true,\n items,\n}: UseSortableTreeOptions): UseSortableTreeResult => {\n const [projected, setProjected] = useState<DropTarget | null>(null);\n const [activeId, setActiveId] = useState<string | null>(null);\n\n const pointerRef = useRef<{ x: number; y: number } | null>(null);\n const { scheduleFolderOpen, cancelFolderOpen } = useHoverFolderOpen(onExpandFolder);\n\n const collisionDetection = useCallback<CollisionDetection>((args) => {\n // Captured here (onDragMove has no pointer position) to decide whether the\n // pointer sits over a folder's nest zone (its middle third).\n pointerRef.current = args.pointerCoordinates;\n\n // Resolve `over` from the pointer, NOT the drag overlay's centre. dnd-kit\n // keeps the grab point under the cursor, so the overlay centre sits up to\n // half a row from the pointer depending on where the row was picked up; with\n // closest-centre, `over` and the pointer-based nest-zone check then disagree\n // and nesting into a folder misfires. Fall back to closest-centre only when\n // the pointer is outside every row (the list's padding / edges). A static\n // list keeps both results stable, so no hysteresis is needed.\n const withinPointer = pointerWithin(args);\n return withinPointer.length > 0 ? withinPointer : closestCenter(args);\n }, []);\n\n // While dragging a folder, its descendents are hidden so it cannot nest in itself.\n const renderedItems = activeId ? removeSubtree(items, activeId) : items;\n const activeItem = items.find((item) => item.id === activeId) ?? null;\n\n const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 8 } }));\n\n const onDragStart = (event: DragStartEvent) => {\n if (disabled) {\n return;\n }\n\n cancelFolderOpen();\n setActiveId(String(event.active.id));\n setProjected(null);\n };\n\n const onDragCancel = () => {\n resetDrag();\n };\n\n const onDragMove = (event: DragMoveEvent) => {\n if (!activeId || !event.over) {\n return;\n }\n\n const target = resolveDropTarget(renderedItems, {\n pointer: pointerRef.current ?? undefined,\n overId: String(event.over.id),\n overRect: event.over.rect,\n offsetX: event.delta.x,\n activeId,\n });\n\n if (target && activeItem && !canDrop(activeItem.node, target)) {\n setProjected(null);\n cancelFolderOpen();\n return;\n }\n\n setProjected(target);\n\n if (target?.kind === 'nest' && collapsed.has(target.folderId)) {\n scheduleFolderOpen(target.folderId);\n } else {\n cancelFolderOpen();\n }\n };\n\n const resetDrag = () => {\n cancelFolderOpen();\n setActiveId(null);\n setProjected(null);\n };\n\n const onDragEnd = () => {\n if (disabled) {\n return;\n }\n\n const item = activeItem;\n const target = projected;\n\n resetDrag();\n\n if (!item || !target) {\n return;\n }\n\n onDrop(item.node, target);\n };\n\n const dropLine =\n projected?.kind === 'insert' && projected.line\n ? { ...projected.line, depth: projected.depth }\n : null;\n\n const dropTargetId = projected?.kind === 'nest' ? `folder:${projected.folderId}` : null;\n\n const sortingStrategy: SortingStrategy = () => null;\n\n return {\n collisionDetection,\n sortingStrategy,\n renderedItems,\n dropTargetId,\n activeItem,\n dropLine,\n sensors,\n onDragCancel,\n onDragStart,\n onDragMove,\n onDragEnd,\n };\n};\n"],"names":["SPRING_OPEN_MS","useHoverFolderOpen","onExpandFolder","springRef","useRef","folderId","cancelFolderOpen","clearTimeout","current","timer","scheduleFolderOpen","setTimeout","useSortableTree","collapsed","disabled","onDrop","canDrop","items","projected","setProjected","useState","activeId","setActiveId","pointerRef","collisionDetection","useCallback","args","pointerCoordinates","withinPointer","pointerWithin","length","closestCenter","renderedItems","removeSubtree","activeItem","find","item","id","sensors","useSensors","useSensor","PointerSensor","activationConstraint","distance","onDragStart","event","String","active","onDragCancel","resetDrag","onDragMove","over","target","resolveDropTarget","pointer","undefined","overId","overRect","rect","offsetX","delta","x","node","kind","has","onDragEnd","dropLine","line","depth","dropTargetId","sortingStrategy"],"mappings":";;;;;;;AAkBA;AACA;AACA,MAAMA,cAAAA,GAAiB,GAAA;AA0CvB,MAAMC,qBAAqB,CAACC,cAAAA,GAAAA;AAC1B,IAAA,MAAMC,YAAYC,YAAAA,CAAkB;QAAEC,QAAAA,EAAU;AAAK,KAAA,CAAA;AAErD,IAAA,MAAMC,gBAAAA,GAAmB,IAAA;QACvBC,YAAAA,CAAaJ,SAAAA,CAAUK,OAAO,CAACC,KAAK,CAAA;AACpCN,QAAAA,SAAAA,CAAUK,OAAO,GAAG;YAAEH,QAAAA,EAAU;AAAK,SAAA;AACvC,IAAA,CAAA;;;AAIA,IAAA,MAAMK,qBAAqB,CAACL,QAAAA,GAAAA;AAC1B,QAAA,IAAIF,SAAAA,CAAUK,OAAO,CAACH,QAAQ,KAAKA,QAAAA,EAAU;AAC3C,YAAA;AACF,QAAA;AAEAC,QAAAA,gBAAAA,EAAAA;QACAH,SAAAA,CAAUK,OAAO,CAACH,QAAQ,GAAGA,QAAAA;AAE7BF,QAAAA,SAAAA,CAAUK,OAAO,CAACC,KAAK,GAAGE,UAAAA,CAAW,IAAA;YACnCT,cAAAA,CAAeG,QAAAA,CAAAA;YACfF,SAAAA,CAAUK,OAAO,CAACH,QAAQ,GAAG,IAAA;QAC/B,CAAA,EAAGL,cAAAA,CAAAA;AACL,IAAA,CAAA;IAEA,OAAO;AAAEU,QAAAA,kBAAAA;AAAoBJ,QAAAA;AAAiB,KAAA;AAChD,CAAA;AAEA;;;;;;AAMC,IACM,MAAMM,eAAAA,GAAkB,CAAC,EAC9BV,cAAc,EACdW,SAAS,EACTC,QAAQ,EACRC,MAAM,EACNC,OAAAA,GAAU,IAAM,IAAI,EACpBC,KAAK,EACkB,GAAA;AACvB,IAAA,MAAM,CAACC,SAAAA,EAAWC,YAAAA,CAAa,GAAGC,cAAAA,CAA4B,IAAA,CAAA;AAC9D,IAAA,MAAM,CAACC,QAAAA,EAAUC,WAAAA,CAAY,GAAGF,cAAAA,CAAwB,IAAA,CAAA;AAExD,IAAA,MAAMG,aAAanB,YAAAA,CAAwC,IAAA,CAAA;AAC3D,IAAA,MAAM,EAAEM,kBAAkB,EAAEJ,gBAAgB,EAAE,GAAGL,kBAAAA,CAAmBC,cAAAA,CAAAA;IAEpE,MAAMsB,kBAAAA,GAAqBC,kBAAgC,CAACC,IAAAA,GAAAA;;;QAG1DH,UAAAA,CAAWf,OAAO,GAAGkB,IAAAA,CAAKC,kBAAkB;;;;;;;;AAS5C,QAAA,MAAMC,gBAAgBC,kBAAAA,CAAcH,IAAAA,CAAAA;AACpC,QAAA,OAAOE,aAAAA,CAAcE,MAAM,GAAG,CAAA,GAAIF,gBAAgBG,kBAAAA,CAAcL,IAAAA,CAAAA;AAClE,IAAA,CAAA,EAAG,EAAE,CAAA;;AAGL,IAAA,MAAMM,aAAAA,GAAgBX,QAAAA,GAAWY,uBAAAA,CAAchB,KAAAA,EAAOI,QAAAA,CAAAA,GAAYJ,KAAAA;IAClE,MAAMiB,UAAAA,GAAajB,MAAMkB,IAAI,CAAC,CAACC,IAAAA,GAASA,IAAAA,CAAKC,EAAE,KAAKhB,QAAAA,CAAAA,IAAa,IAAA;IAEjE,MAAMiB,OAAAA,GAAUC,eAAAA,CAAWC,cAAAA,CAAUC,kBAAAA,EAAe;QAAEC,oBAAAA,EAAsB;YAAEC,QAAAA,EAAU;AAAE;AAAE,KAAA,CAAA,CAAA;AAE5F,IAAA,MAAMC,cAAc,CAACC,KAAAA,GAAAA;AACnB,QAAA,IAAI/B,QAAAA,EAAU;AACZ,YAAA;AACF,QAAA;AAEAR,QAAAA,gBAAAA,EAAAA;AACAgB,QAAAA,WAAAA,CAAYwB,MAAAA,CAAOD,KAAAA,CAAME,MAAM,CAACV,EAAE,CAAA,CAAA;QAClClB,YAAAA,CAAa,IAAA,CAAA;AACf,IAAA,CAAA;AAEA,IAAA,MAAM6B,YAAAA,GAAe,IAAA;AACnBC,QAAAA,SAAAA,EAAAA;AACF,IAAA,CAAA;AAEA,IAAA,MAAMC,aAAa,CAACL,KAAAA,GAAAA;AAClB,QAAA,IAAI,CAACxB,QAAAA,IAAY,CAACwB,KAAAA,CAAMM,IAAI,EAAE;AAC5B,YAAA;AACF,QAAA;QAEA,MAAMC,MAAAA,GAASC,iCAAkBrB,aAAAA,EAAe;YAC9CsB,OAAAA,EAAS/B,UAAAA,CAAWf,OAAO,IAAI+C,SAAAA;AAC/BC,YAAAA,MAAAA,EAAQV,MAAAA,CAAOD,KAAAA,CAAMM,IAAI,CAACd,EAAE,CAAA;YAC5BoB,QAAAA,EAAUZ,KAAAA,CAAMM,IAAI,CAACO,IAAI;YACzBC,OAAAA,EAASd,KAAAA,CAAMe,KAAK,CAACC,CAAC;AACtBxC,YAAAA;AACF,SAAA,CAAA;AAEA,QAAA,IAAI+B,UAAUlB,UAAAA,IAAc,CAAClB,QAAQkB,UAAAA,CAAW4B,IAAI,EAAEV,MAAAA,CAAAA,EAAS;YAC7DjC,YAAAA,CAAa,IAAA,CAAA;AACbb,YAAAA,gBAAAA,EAAAA;AACA,YAAA;AACF,QAAA;QAEAa,YAAAA,CAAaiC,MAAAA,CAAAA;QAEb,IAAIA,MAAAA,EAAQW,SAAS,MAAA,IAAUlD,SAAAA,CAAUmD,GAAG,CAACZ,MAAAA,CAAO/C,QAAQ,CAAA,EAAG;AAC7DK,YAAAA,kBAAAA,CAAmB0C,OAAO/C,QAAQ,CAAA;QACpC,CAAA,MAAO;AACLC,YAAAA,gBAAAA,EAAAA;AACF,QAAA;AACF,IAAA,CAAA;AAEA,IAAA,MAAM2C,SAAAA,GAAY,IAAA;AAChB3C,QAAAA,gBAAAA,EAAAA;QACAgB,WAAAA,CAAY,IAAA,CAAA;QACZH,YAAAA,CAAa,IAAA,CAAA;AACf,IAAA,CAAA;AAEA,IAAA,MAAM8C,SAAAA,GAAY,IAAA;AAChB,QAAA,IAAInD,QAAAA,EAAU;AACZ,YAAA;AACF,QAAA;AAEA,QAAA,MAAMsB,IAAAA,GAAOF,UAAAA;AACb,QAAA,MAAMkB,MAAAA,GAASlC,SAAAA;AAEf+B,QAAAA,SAAAA,EAAAA;QAEA,IAAI,CAACb,IAAAA,IAAQ,CAACgB,MAAAA,EAAQ;AACpB,YAAA;AACF,QAAA;QAEArC,MAAAA,CAAOqB,IAAAA,CAAK0B,IAAI,EAAEV,MAAAA,CAAAA;AACpB,IAAA,CAAA;AAEA,IAAA,MAAMc,WACJhD,SAAAA,EAAW6C,IAAAA,KAAS,QAAA,IAAY7C,SAAAA,CAAUiD,IAAI,GAC1C;AAAE,QAAA,GAAGjD,UAAUiD,IAAI;AAAEC,QAAAA,KAAAA,EAAOlD,UAAUkD;KAAM,GAC5C,IAAA;IAEN,MAAMC,YAAAA,GAAenD,SAAAA,EAAW6C,IAAAA,KAAS,MAAA,GAAS,CAAC,OAAO,EAAE7C,SAAAA,CAAUb,QAAQ,CAAA,CAAE,GAAG,IAAA;AAEnF,IAAA,MAAMiE,kBAAmC,IAAM,IAAA;IAE/C,OAAO;AACL9C,QAAAA,kBAAAA;AACA8C,QAAAA,eAAAA;AACAtC,QAAAA,aAAAA;AACAqC,QAAAA,YAAAA;AACAnC,QAAAA,UAAAA;AACAgC,QAAAA,QAAAA;AACA5B,QAAAA,OAAAA;AACAU,QAAAA,YAAAA;AACAJ,QAAAA,WAAAA;AACAM,QAAAA,UAAAA;AACAe,QAAAA;AACF,KAAA;AACF;;;;"}
|