@strapi/content-manager 0.0.0-experimental.a4161dd0ce4a6742074cbfc43734281e14a29baa → 0.0.0-experimental.a4cee39f4705cbd534afa66170f94f2f68e65b75
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/chunks/{ComponentConfigurationPage-CDKJ1saA.js → ComponentConfigurationPage-BWB_urBW.js} +3 -3
- package/dist/admin/chunks/{ComponentConfigurationPage-CDKJ1saA.js.map → ComponentConfigurationPage-BWB_urBW.js.map} +1 -1
- package/dist/admin/chunks/{ComponentConfigurationPage-BdKTyTdt.mjs → ComponentConfigurationPage-Bw3SD5w3.mjs} +3 -3
- package/dist/admin/chunks/{ComponentConfigurationPage-BdKTyTdt.mjs.map → ComponentConfigurationPage-Bw3SD5w3.mjs.map} +1 -1
- package/dist/admin/chunks/{EditConfigurationPage-BW5fpvkO.js → EditConfigurationPage-BazMqkY5.js} +3 -3
- package/dist/admin/chunks/{EditConfigurationPage-BW5fpvkO.js.map → EditConfigurationPage-BazMqkY5.js.map} +1 -1
- package/dist/admin/chunks/{EditConfigurationPage-CaJ_CmJz.mjs → EditConfigurationPage-bP8cL5u8.mjs} +3 -3
- package/dist/admin/chunks/{EditConfigurationPage-CaJ_CmJz.mjs.map → EditConfigurationPage-bP8cL5u8.mjs.map} +1 -1
- package/dist/admin/chunks/{EditViewPage-BDekCXSy.mjs → EditViewPage-D3F0FbHV.mjs} +10 -7
- package/dist/admin/chunks/EditViewPage-D3F0FbHV.mjs.map +1 -0
- package/dist/admin/chunks/{EditViewPage-CNacGhk_.js → EditViewPage-DjB2aEuN.js} +11 -8
- package/dist/admin/chunks/EditViewPage-DjB2aEuN.js.map +1 -0
- package/dist/admin/chunks/{Form-2LZDIqUE.mjs → Form-CO-twQva.mjs} +2 -2
- package/dist/admin/chunks/{Form-2LZDIqUE.mjs.map → Form-CO-twQva.mjs.map} +1 -1
- package/dist/admin/chunks/{Form-CouVf26p.js → Form-Dyr8enar.js} +2 -2
- package/dist/admin/chunks/{Form-CouVf26p.js.map → Form-Dyr8enar.js.map} +1 -1
- package/dist/admin/chunks/{History-Cv3uNjvV.js → History-BsZCxc7e.js} +6 -6
- package/dist/admin/chunks/{History-Cv3uNjvV.js.map → History-BsZCxc7e.js.map} +1 -1
- package/dist/admin/chunks/{History-B7zZvnQF.mjs → History-DJ_pI0gL.mjs} +5 -5
- package/dist/admin/chunks/{History-B7zZvnQF.mjs.map → History-DJ_pI0gL.mjs.map} +1 -1
- package/dist/admin/chunks/{Input-DPH5j7Yl.js → Input-D-yPzkxz.js} +634 -848
- package/dist/admin/chunks/Input-D-yPzkxz.js.map +1 -0
- package/dist/admin/chunks/{Input-BPTHgeyh.mjs → Input-DWQWd5MK.mjs} +634 -847
- package/dist/admin/chunks/Input-DWQWd5MK.mjs.map +1 -0
- package/dist/admin/chunks/{ListConfigurationPage-FS8YuoKF.mjs → ListConfigurationPage-DlvGrjR_.mjs} +2 -2
- package/dist/admin/chunks/{ListConfigurationPage-FS8YuoKF.mjs.map → ListConfigurationPage-DlvGrjR_.mjs.map} +1 -1
- package/dist/admin/chunks/{ListConfigurationPage-Cj1tt01r.js → ListConfigurationPage-dHbA6tve.js} +2 -2
- package/dist/admin/chunks/{ListConfigurationPage-Cj1tt01r.js.map → ListConfigurationPage-dHbA6tve.js.map} +1 -1
- package/dist/admin/chunks/{ListViewPage-Xv5mmaJq.mjs → ListViewPage-DaxIL_8o.mjs} +3 -3
- package/dist/admin/chunks/{ListViewPage-Xv5mmaJq.mjs.map → ListViewPage-DaxIL_8o.mjs.map} +1 -1
- package/dist/admin/chunks/{ListViewPage-BCmGmK7N.js → ListViewPage-gsJS3ulI.js} +3 -3
- package/dist/admin/chunks/{ListViewPage-BCmGmK7N.js.map → ListViewPage-gsJS3ulI.js.map} +1 -1
- package/dist/admin/chunks/{NoContentTypePage-DpvfQfhU.js → NoContentTypePage-BD-VEn6M.js} +2 -2
- package/dist/admin/chunks/{NoContentTypePage-DpvfQfhU.js.map → NoContentTypePage-BD-VEn6M.js.map} +1 -1
- package/dist/admin/chunks/{NoContentTypePage-Bbqw5ZV9.mjs → NoContentTypePage-xzAGzlVY.mjs} +2 -2
- package/dist/admin/chunks/{NoContentTypePage-Bbqw5ZV9.mjs.map → NoContentTypePage-xzAGzlVY.mjs.map} +1 -1
- package/dist/admin/chunks/{NoPermissionsPage-igrvpcW0.mjs → NoPermissionsPage-BAKqxUK7.mjs} +2 -2
- package/dist/admin/chunks/{NoPermissionsPage-igrvpcW0.mjs.map → NoPermissionsPage-BAKqxUK7.mjs.map} +1 -1
- package/dist/admin/chunks/{NoPermissionsPage-BYEkhBnk.js → NoPermissionsPage-BmE5T_Mq.js} +2 -2
- package/dist/admin/chunks/{NoPermissionsPage-BYEkhBnk.js.map → NoPermissionsPage-BmE5T_Mq.js.map} +1 -1
- package/dist/admin/chunks/{Preview-DR-9uYxZ.mjs → Preview-Bz2ir5R5.mjs} +102 -182
- package/dist/admin/chunks/Preview-Bz2ir5R5.mjs.map +1 -0
- package/dist/admin/chunks/{Preview-DlRltQbE.js → Preview-CP4m2RBm.js} +101 -181
- package/dist/admin/chunks/Preview-CP4m2RBm.js.map +1 -0
- package/dist/admin/chunks/{en-DBP0Gaid.mjs → en-C2zEwS3-.mjs} +3 -1
- package/dist/admin/chunks/{en-DBP0Gaid.mjs.map → en-C2zEwS3-.mjs.map} +1 -1
- package/dist/admin/chunks/{en-CH__IC8g.js → en-G976DLsg.js} +3 -1
- package/dist/admin/chunks/{en-CH__IC8g.js.map → en-G976DLsg.js.map} +1 -1
- package/dist/admin/chunks/{index-CISU19oJ.js → index-CFa6xmgK.js} +197 -127
- package/dist/admin/chunks/index-CFa6xmgK.js.map +1 -0
- package/dist/admin/chunks/{index-C_e5v8f7.mjs → index-ZyDJIuQ1.mjs} +196 -129
- package/dist/admin/chunks/index-ZyDJIuQ1.mjs.map +1 -0
- package/dist/admin/chunks/{layout-CrqscUTi.mjs → layout-D2tOWWAq.mjs} +4 -4
- package/dist/admin/chunks/{layout-CrqscUTi.mjs.map → layout-D2tOWWAq.mjs.map} +1 -1
- package/dist/admin/chunks/{layout-CajJum-G.js → layout-XA97mHoN.js} +4 -4
- package/dist/admin/chunks/{layout-CajJum-G.js.map → layout-XA97mHoN.js.map} +1 -1
- package/dist/admin/chunks/uk-BtM6WnaE.mjs +313 -0
- package/dist/admin/chunks/uk-BtM6WnaE.mjs.map +1 -0
- package/dist/admin/chunks/uk-DB6OgySY.js +318 -0
- package/dist/admin/chunks/uk-DB6OgySY.js.map +1 -0
- package/dist/admin/chunks/{usePrev-CHotxABl.js → usePrev-BEkg-rKP.js} +2 -2
- package/dist/admin/chunks/{usePrev-CHotxABl.js.map → usePrev-BEkg-rKP.js.map} +1 -1
- package/dist/admin/chunks/{usePrev-DF3ZO0z4.mjs → usePrev-DAPoUN3D.mjs} +2 -2
- package/dist/admin/chunks/{usePrev-DF3ZO0z4.mjs.map → usePrev-DAPoUN3D.mjs.map} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/content-manager.d.ts +1 -0
- package/dist/admin/src/features/DocumentContext.d.ts +13 -2
- package/dist/admin/src/hooks/useDocument.d.ts +2 -0
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations/RelationModal.d.ts +5 -7
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations/Relations.d.ts +1 -2
- package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +3 -1
- package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +5 -2
- package/dist/admin/src/preview/components/PreviewHeader.d.ts +1 -2
- package/package.json +8 -8
- package/dist/admin/chunks/EditViewPage-BDekCXSy.mjs.map +0 -1
- package/dist/admin/chunks/EditViewPage-CNacGhk_.js.map +0 -1
- package/dist/admin/chunks/Input-BPTHgeyh.mjs.map +0 -1
- package/dist/admin/chunks/Input-DPH5j7Yl.js.map +0 -1
- package/dist/admin/chunks/Preview-DR-9uYxZ.mjs.map +0 -1
- package/dist/admin/chunks/Preview-DlRltQbE.js.map +0 -1
- package/dist/admin/chunks/index-CISU19oJ.js.map +0 -1
- package/dist/admin/chunks/index-C_e5v8f7.mjs.map +0 -1
- package/dist/admin/chunks/uk-B24MoTVg.js +0 -145
- package/dist/admin/chunks/uk-B24MoTVg.js.map +0 -1
- package/dist/admin/chunks/uk-Cpgmm7gE.mjs +0 -140
- package/dist/admin/chunks/uk-Cpgmm7gE.mjs.map +0 -1
- package/dist/admin/src/preview/components/PreviewContent.d.ts +0 -3
@@ -1,11 +1,11 @@
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
2
2
|
import * as React from 'react';
|
3
3
|
import { useState, useEffect, useCallback } from 'react';
|
4
|
-
import {
|
5
|
-
import { Box, SingleSelect, SingleSelectOption, Typography, Flex, Button, Popover, Field, Menu, IconButton, Tooltip, useComposedRefs, Portal, FocusTrap, Divider, VisuallyHidden, Accordion, MenuItem, Grid as Grid$1, TextInput, Modal, Loader, EmptyStateLayout,
|
6
|
-
import { CodeBlock as CodeBlock$1, HeadingOne, HeadingTwo, HeadingThree, HeadingFour, HeadingFive, HeadingSix, Image as Image$1, NumberList, BulletList, Paragraph, Quotes, More, Link as Link$1, Drag, Collapse, Bold, Italic, Underline, StrikeThrough, Code, Expand, PlusCircle, Trash, EyeStriked, ArrowLeft, WarningCircle, ArrowClockwise, Cross, CheckCircle, Loader as Loader$1, Plus } from '@strapi/icons';
|
4
|
+
import { useStrapiApp, useElementOnScreen, createContext, useField, useForm, useNotification, Form, ConfirmDialog, useRBAC, DescriptionComponentRenderer, useQueryParams, useFocusInputField, useAPIErrorHandler, InputRenderer as InputRenderer$1 } from '@strapi/admin/strapi-admin';
|
5
|
+
import { Box, SingleSelect, SingleSelectOption, Typography, Flex, Button, Popover, Field, Menu, IconButton, Tooltip, useComposedRefs, Portal, FocusTrap, Divider, VisuallyHidden, Accordion, MenuItem, Grid as Grid$1, TextInput, Modal, TextButton, Dialog, Loader, EmptyStateLayout, Link as Link$2, Combobox, ComboboxOption, IconButtonGroup } from '@strapi/design-system';
|
6
|
+
import { CodeBlock as CodeBlock$1, HeadingOne, HeadingTwo, HeadingThree, HeadingFour, HeadingFive, HeadingSix, Image as Image$1, NumberList, BulletList, Paragraph, Quotes, More, Link as Link$1, Drag, Collapse, Bold, Italic, Underline, StrikeThrough, Code, Expand, PlusCircle, Trash, EyeStriked, ArrowLeft, ArrowsOut, WarningCircle, ArrowClockwise, Cross, CheckCircle, Loader as Loader$1, Plus } from '@strapi/icons';
|
7
7
|
import { useIntl } from 'react-intl';
|
8
|
-
import {
|
8
|
+
import { g as getTranslation, c as useDocumentContext, d as useDocumentLayout, e as createDefaultForm, t as transformDocument, f as useLazyGetDocumentQuery, h as createYupSchema, P as PERMISSIONS, i as DocumentRBAC, j as DocumentActionButton, D as DocumentStatus, C as COLLECTION_TYPES, S as SINGLE_TYPES, k as buildValidParams, l as contentManagerApi, m as useDoc, n as CLONE_PATH, o as useDocumentRBAC } from './index-ZyDJIuQ1.mjs';
|
9
9
|
import { styled, css, keyframes } from 'styled-components';
|
10
10
|
import { Editor as Editor$1, Transforms, Node, Element, Range, Path, Point, createEditor } from 'slate';
|
11
11
|
import { withHistory } from 'slate-history';
|
@@ -61,11 +61,11 @@ import 'prismjs/components/prism-typescript';
|
|
61
61
|
import 'prismjs/components/prism-tsx';
|
62
62
|
import 'prismjs/components/prism-vbnet';
|
63
63
|
import 'prismjs/components/prism-yaml';
|
64
|
-
import { p as prefixFileUrlWithBackendUrl, u as useGetRelationsQuery, g as getRelationLabel, a as useDebounce, b as useLazySearchRelationsQuery, c as usePrev } from './usePrev-
|
64
|
+
import { p as prefixFileUrlWithBackendUrl, u as useGetRelationsQuery, g as getRelationLabel, a as useDebounce, b as useLazySearchRelationsQuery, c as usePrev } from './usePrev-DAPoUN3D.mjs';
|
65
65
|
import { D as DIRECTIONS, u as useDragAndDrop, I as ItemTypes, g as getIn, a as DROP_SENSITIVITY } from './objects-D2z-IJgu.mjs';
|
66
66
|
import * as Toolbar from '@radix-ui/react-toolbar';
|
67
67
|
import { getEmptyImage } from 'react-dnd-html5-backend';
|
68
|
-
import {
|
68
|
+
import { useNavigate, useLocation, useMatch } from 'react-router-dom';
|
69
69
|
import pipe$1 from 'lodash/fp/pipe';
|
70
70
|
import { C as ComponentIcon, a as COMPONENT_ICONS } from './ComponentIcon-BZcTc4rj.mjs';
|
71
71
|
import { generateNKeysBetween } from 'fractional-indexing';
|
@@ -86,31 +86,6 @@ import sup from 'markdown-it-sup';
|
|
86
86
|
import 'highlight.js/styles/solarized-dark.css';
|
87
87
|
import 'codemirror5/addon/display/placeholder';
|
88
88
|
|
89
|
-
const [DocumentProvider, useDocumentContext] = createContext('DocumentContext');
|
90
|
-
/**
|
91
|
-
* TODO: Document in contributor docs, Add unit test
|
92
|
-
*
|
93
|
-
* This context provider and its associated hook are used to access a document at its root level
|
94
|
-
* and expose a function to change the current document being viewed to one of the root level docuemnt's relations.
|
95
|
-
*
|
96
|
-
* The useDocumentContext hook exposes:
|
97
|
-
* - meta: information about the currentDocument,
|
98
|
-
* - document: the actual document,
|
99
|
-
* - changeDocument: a function to change the current document to one of its relations.
|
100
|
-
*/ const DocumentContextProvider = ({ children, initialDocument })=>{
|
101
|
-
/**
|
102
|
-
* Initialize with the "root" document and expose a setter method to change to
|
103
|
-
* one of the root level document's relations.
|
104
|
-
*/ const [currentDocumentMeta, changeDocument] = React.useState(initialDocument);
|
105
|
-
const document = useDocument(currentDocumentMeta);
|
106
|
-
return /*#__PURE__*/ jsx(DocumentProvider, {
|
107
|
-
changeDocument: changeDocument,
|
108
|
-
document: document,
|
109
|
-
meta: currentDocumentMeta,
|
110
|
-
children: children
|
111
|
-
});
|
112
|
-
};
|
113
|
-
|
114
89
|
const componentStore = new Map();
|
115
90
|
/**
|
116
91
|
* @description A hook to lazy load custom field components
|
@@ -3606,15 +3581,24 @@ const ComponentCategory = ({ category, components = [], variant = 'primary', onA
|
|
3606
3581
|
const ResponsiveAccordionContent = styled(Accordion.Content)`
|
3607
3582
|
container-type: inline-size;
|
3608
3583
|
`;
|
3609
|
-
|
3610
|
-
|
3611
|
-
|
3612
|
-
|
3613
|
-
|
3614
|
-
|
3615
|
-
|
3616
|
-
|
3617
|
-
|
3584
|
+
/**
|
3585
|
+
* TODO:
|
3586
|
+
* JSDOM cannot handle container queries.
|
3587
|
+
* This is a temporary workaround so that tests do not fail in the CI when jestdom throws an error
|
3588
|
+
* for failing to parse the stylesheet.
|
3589
|
+
*/ const Grid = process.env.NODE_ENV !== 'test' ? styled(Box)`
|
3590
|
+
display: grid;
|
3591
|
+
grid-template-columns: repeat(auto-fill, 100%);
|
3592
|
+
grid-gap: 4px;
|
3593
|
+
|
3594
|
+
@container (min-width: ${()=>RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
|
3595
|
+
grid-template-columns: repeat(auto-fill, 14rem);
|
3596
|
+
}
|
3597
|
+
` : styled(Box)`
|
3598
|
+
display: grid;
|
3599
|
+
grid-template-columns: repeat(auto-fill, 100%);
|
3600
|
+
grid-gap: 4px;
|
3601
|
+
`;
|
3618
3602
|
const ComponentBox = styled(Flex)`
|
3619
3603
|
color: ${({ theme })=>theme.colors.neutral600};
|
3620
3604
|
cursor: pointer;
|
@@ -3680,7 +3664,18 @@ const DynamicComponent = ({ componentUid, disabled, index, name, onRemoveCompone
|
|
3680
3664
|
const { formatMessage } = useIntl();
|
3681
3665
|
const formValues = useForm('DynamicComponent', (state)=>state.values);
|
3682
3666
|
const documentMeta = useDocumentContext('DynamicComponent', (state)=>state.meta);
|
3683
|
-
const
|
3667
|
+
const rootDocumentMeta = useDocumentContext('DynamicComponent', (state)=>state.rootDocumentMeta);
|
3668
|
+
const { edit: { components: rootComponents } } = useDocumentLayout(rootDocumentMeta.model);
|
3669
|
+
const { edit: { components: relatedComponents } } = useDocumentLayout(documentMeta.model);
|
3670
|
+
// Merge the root level components and dynamic zone components
|
3671
|
+
const components = React.useMemo(()=>({
|
3672
|
+
...rootComponents,
|
3673
|
+
...relatedComponents
|
3674
|
+
}), [
|
3675
|
+
rootComponents,
|
3676
|
+
relatedComponents
|
3677
|
+
]);
|
3678
|
+
const document = useDocumentContext('DynamicComponent', (state)=>state.document);
|
3684
3679
|
const title = React.useMemo(()=>{
|
3685
3680
|
const { mainField } = components[componentUid]?.settings ?? {
|
3686
3681
|
mainField: 'id'
|
@@ -3912,9 +3907,11 @@ const DynamicComponent = ({ componentUid, disabled, index, name, onRemoveCompone
|
|
3912
3907
|
alignItems: "stretch",
|
3913
3908
|
children: children ? children({
|
3914
3909
|
...fieldWithTranslatedLabel,
|
3910
|
+
document,
|
3915
3911
|
name: fieldName
|
3916
3912
|
}) : /*#__PURE__*/ jsx(MemoizedInputRenderer, {
|
3917
3913
|
...fieldWithTranslatedLabel,
|
3914
|
+
document: document,
|
3918
3915
|
name: fieldName
|
3919
3916
|
})
|
3920
3917
|
}, fieldName);
|
@@ -4277,68 +4274,278 @@ const CustomModalContent = styled(Modal.Content)`
|
|
4277
4274
|
height: 90%;
|
4278
4275
|
max-height: 100%;
|
4279
4276
|
`;
|
4280
|
-
const
|
4277
|
+
const [RelationModalProvider, useRelationModal] = createContext('RelationModal', {
|
4278
|
+
parentModified: false,
|
4279
|
+
depth: 0
|
4280
|
+
});
|
4281
|
+
const RelationModalForm = ({ relation, triggerButtonLabel })=>{
|
4282
|
+
const navigate = useNavigate();
|
4283
|
+
const { pathname, search } = useLocation();
|
4281
4284
|
const { formatMessage } = useIntl();
|
4282
|
-
|
4283
|
-
|
4284
|
-
|
4285
|
-
|
4286
|
-
|
4287
|
-
|
4288
|
-
|
4285
|
+
const [triggerRefetchDocument] = useLazyGetDocumentQuery();
|
4286
|
+
const currentDocument = useDocumentContext('RelationModalForm', (state)=>state.document);
|
4287
|
+
const rootDocumentMeta = useDocumentContext('RelationModalForm', (state)=>state.rootDocumentMeta);
|
4288
|
+
const currentDocumentMeta = useDocumentContext('RelationModalForm', (state)=>state.meta);
|
4289
|
+
const changeDocument = useDocumentContext('RelationModalForm', (state)=>state.changeDocument);
|
4290
|
+
const documentHistory = useDocumentContext('RelationModalForm', (state)=>state.documentHistory);
|
4291
|
+
const setDocumentHistory = useDocumentContext('RelationModalForm', (state)=>state.setDocumentHistory);
|
4292
|
+
const [isConfirmationOpen, setIsConfirmationOpen] = React.useState(false);
|
4293
|
+
const [actionPosition, setActionPosition] = React.useState('cancel');
|
4294
|
+
const [isModalOpen, setIsModalOpen] = React.useState(false);
|
4295
|
+
// NOTE: Not sure about this relation modal context, maybe we should move this to DocumentContext?
|
4296
|
+
// Get parent modal context if it exists
|
4297
|
+
const parentContext = useRelationModal('RelationModalForm', (state)=>state);
|
4298
|
+
// Get depth of nested modals
|
4299
|
+
const depth = parentContext ? parentContext.depth + 1 : 0;
|
4300
|
+
// Check if this is a nested modal
|
4301
|
+
const isNested = depth > 0;
|
4302
|
+
const addDocumentToHistory = (document)=>setDocumentHistory((prev)=>[
|
4303
|
+
...prev,
|
4304
|
+
document
|
4305
|
+
]);
|
4306
|
+
const getPreviousDocument = ()=>{
|
4307
|
+
if (documentHistory.length === 0) return undefined;
|
4308
|
+
const lastDocument = documentHistory[documentHistory.length - 1];
|
4309
|
+
return lastDocument;
|
4310
|
+
};
|
4311
|
+
const removeLastDocumentFromHistory = ()=>{
|
4312
|
+
setDocumentHistory((prev)=>[
|
4313
|
+
...prev
|
4314
|
+
].slice(0, prev.length - 1));
|
4315
|
+
};
|
4316
|
+
const handleToggleModal = ()=>{
|
4317
|
+
if (isModalOpen) {
|
4318
|
+
setIsModalOpen(false);
|
4319
|
+
const document = {
|
4320
|
+
collectionType: rootDocumentMeta.collectionType,
|
4321
|
+
model: rootDocumentMeta.model,
|
4322
|
+
documentId: rootDocumentMeta.documentId
|
4323
|
+
};
|
4324
|
+
// Change back to the root document
|
4325
|
+
changeDocument(document);
|
4326
|
+
// Reset the document history
|
4327
|
+
setDocumentHistory([]);
|
4328
|
+
// Reset action position
|
4329
|
+
setActionPosition('cancel');
|
4330
|
+
// Read from cache or refetch root document
|
4331
|
+
triggerRefetchDocument(document, // Favor the cache
|
4332
|
+
true);
|
4333
|
+
} else {
|
4334
|
+
changeDocument(relation);
|
4335
|
+
setIsModalOpen(true);
|
4336
|
+
}
|
4337
|
+
};
|
4338
|
+
const getFullPageLink = ()=>{
|
4339
|
+
const isSingleType = currentDocumentMeta.collectionType === SINGLE_TYPES;
|
4340
|
+
const queryParams = currentDocumentMeta.params?.locale ? `?plugins[i18n][locale]=${currentDocumentMeta.params.locale}` : '';
|
4341
|
+
return `/content-manager/${currentDocumentMeta.collectionType}/${currentDocumentMeta.model}${isSingleType ? '' : '/' + currentDocumentMeta.documentId}${queryParams}`;
|
4342
|
+
};
|
4343
|
+
const handleRedirection = ()=>{
|
4344
|
+
const editViewUrl = `${pathname}${search}`;
|
4345
|
+
const isRootDocumentUrl = editViewUrl.includes(getFullPageLink());
|
4346
|
+
if (isRootDocumentUrl) {
|
4347
|
+
handleToggleModal();
|
4348
|
+
} else {
|
4349
|
+
navigate(getFullPageLink());
|
4350
|
+
}
|
4351
|
+
};
|
4352
|
+
const handleConfirm = ()=>{
|
4353
|
+
if (actionPosition === 'navigate') {
|
4354
|
+
handleRedirection();
|
4355
|
+
} else if (actionPosition === 'back') {
|
4356
|
+
const previousRelation = getPreviousDocument();
|
4357
|
+
if (previousRelation) {
|
4358
|
+
removeLastDocumentFromHistory();
|
4359
|
+
changeDocument(previousRelation);
|
4360
|
+
}
|
4361
|
+
} else {
|
4362
|
+
handleToggleModal();
|
4363
|
+
}
|
4364
|
+
};
|
4365
|
+
return /*#__PURE__*/ jsx(Form, {
|
4366
|
+
method: "PUT",
|
4367
|
+
initialValues: currentDocument.getInitialFormValues(),
|
4368
|
+
validate: (values, options)=>{
|
4369
|
+
const yupSchema = createYupSchema(currentDocument.schema?.attributes, currentDocument.components, {
|
4370
|
+
status: currentDocument.document?.status,
|
4371
|
+
...options
|
4372
|
+
});
|
4373
|
+
return yupSchema.validate(values, {
|
4374
|
+
abortEarly: false
|
4375
|
+
});
|
4376
|
+
},
|
4377
|
+
children: ({ modified, isSubmitting, resetForm })=>{
|
4378
|
+
// We don't count the root document, so history starts after 1
|
4379
|
+
const hasHistory = documentHistory.length > 1;
|
4380
|
+
return /*#__PURE__*/ jsxs(RelationModalProvider, {
|
4381
|
+
parentModified: modified,
|
4382
|
+
depth: depth,
|
4383
|
+
children: [
|
4384
|
+
/*#__PURE__*/ jsxs(Modal.Root, {
|
4385
|
+
open: isModalOpen,
|
4386
|
+
onOpenChange: ()=>{
|
4387
|
+
if (isModalOpen) {
|
4388
|
+
if (modified && !isSubmitting) {
|
4389
|
+
setIsConfirmationOpen(true);
|
4390
|
+
} else {
|
4391
|
+
handleToggleModal();
|
4392
|
+
}
|
4393
|
+
}
|
4394
|
+
},
|
4289
4395
|
children: [
|
4290
|
-
/*#__PURE__*/ jsx(
|
4291
|
-
|
4292
|
-
|
4293
|
-
|
4294
|
-
|
4295
|
-
|
4296
|
-
|
4297
|
-
|
4298
|
-
|
4299
|
-
|
4300
|
-
|
4301
|
-
|
4302
|
-
|
4303
|
-
|
4304
|
-
|
4396
|
+
/*#__PURE__*/ jsx(Modal.Trigger, {
|
4397
|
+
children: /*#__PURE__*/ jsx(Tooltip, {
|
4398
|
+
description: triggerButtonLabel,
|
4399
|
+
children: /*#__PURE__*/ jsx(CustomTextButton, {
|
4400
|
+
onClick: ()=>{
|
4401
|
+
// Check if parent modal has unsaved changes
|
4402
|
+
if (isNested && parentContext.parentModified) {
|
4403
|
+
setIsConfirmationOpen(true);
|
4404
|
+
// Return early to avoid opening the modal
|
4405
|
+
return;
|
4406
|
+
} else {
|
4407
|
+
if (modified && !isSubmitting) {
|
4408
|
+
setIsConfirmationOpen(true);
|
4409
|
+
} else {
|
4410
|
+
// Add current relation to history before opening a new one
|
4411
|
+
if (currentDocumentMeta && Object.keys(currentDocumentMeta).length > 0) {
|
4412
|
+
addDocumentToHistory(currentDocumentMeta);
|
4413
|
+
}
|
4414
|
+
handleToggleModal();
|
4415
|
+
}
|
4416
|
+
if (!isModalOpen) {
|
4417
|
+
setIsModalOpen(true);
|
4418
|
+
}
|
4419
|
+
}
|
4420
|
+
},
|
4421
|
+
children: triggerButtonLabel
|
4422
|
+
})
|
4305
4423
|
})
|
4424
|
+
}),
|
4425
|
+
/*#__PURE__*/ jsxs(CustomModalContent, {
|
4426
|
+
children: [
|
4427
|
+
/*#__PURE__*/ jsx(Modal.Header, {
|
4428
|
+
gap: 2,
|
4429
|
+
children: /*#__PURE__*/ jsx(Flex, {
|
4430
|
+
justifyContent: "space-between",
|
4431
|
+
alignItems: "center",
|
4432
|
+
width: "100%",
|
4433
|
+
children: /*#__PURE__*/ jsxs(Flex, {
|
4434
|
+
gap: 2,
|
4435
|
+
children: [
|
4436
|
+
/*#__PURE__*/ jsx(IconButton, {
|
4437
|
+
withTooltip: false,
|
4438
|
+
label: "Back",
|
4439
|
+
variant: "ghost",
|
4440
|
+
disabled: !hasHistory,
|
4441
|
+
onClick: ()=>{
|
4442
|
+
setActionPosition('back');
|
4443
|
+
if (modified && !isSubmitting) {
|
4444
|
+
setIsConfirmationOpen(true);
|
4445
|
+
} else {
|
4446
|
+
const previousRelation = getPreviousDocument();
|
4447
|
+
if (previousRelation) {
|
4448
|
+
removeLastDocumentFromHistory();
|
4449
|
+
changeDocument(previousRelation);
|
4450
|
+
}
|
4451
|
+
}
|
4452
|
+
},
|
4453
|
+
marginRight: 1,
|
4454
|
+
children: /*#__PURE__*/ jsx(ArrowLeft, {})
|
4455
|
+
}),
|
4456
|
+
/*#__PURE__*/ jsx(Typography, {
|
4457
|
+
tag: "span",
|
4458
|
+
fontWeight: 600,
|
4459
|
+
children: formatMessage({
|
4460
|
+
id: 'content-manager.components.RelationInputModal.modal-title',
|
4461
|
+
defaultMessage: 'Edit a relation'
|
4462
|
+
})
|
4463
|
+
})
|
4464
|
+
]
|
4465
|
+
})
|
4466
|
+
})
|
4467
|
+
}),
|
4468
|
+
/*#__PURE__*/ jsx(RelationModalBody, {
|
4469
|
+
children: /*#__PURE__*/ jsx(IconButton, {
|
4470
|
+
onClick: ()=>{
|
4471
|
+
setActionPosition('navigate');
|
4472
|
+
if (modified && !isSubmitting) {
|
4473
|
+
setIsConfirmationOpen(true);
|
4474
|
+
} else {
|
4475
|
+
navigate(getFullPageLink());
|
4476
|
+
}
|
4477
|
+
},
|
4478
|
+
variant: "tertiary",
|
4479
|
+
label: formatMessage({
|
4480
|
+
id: 'content-manager.components.RelationInputModal.button-fullpage',
|
4481
|
+
defaultMessage: 'Go to entry'
|
4482
|
+
}),
|
4483
|
+
children: /*#__PURE__*/ jsx(ArrowsOut, {})
|
4484
|
+
})
|
4485
|
+
}),
|
4486
|
+
/*#__PURE__*/ jsx(Modal.Footer, {
|
4487
|
+
children: /*#__PURE__*/ jsx(Button, {
|
4488
|
+
onClick: ()=>{
|
4489
|
+
if (modified && !isSubmitting) {
|
4490
|
+
setIsConfirmationOpen(true);
|
4491
|
+
} else {
|
4492
|
+
handleToggleModal();
|
4493
|
+
}
|
4494
|
+
},
|
4495
|
+
variant: "tertiary",
|
4496
|
+
children: formatMessage({
|
4497
|
+
id: 'app.components.Button.cancel',
|
4498
|
+
defaultMessage: 'Cancel'
|
4499
|
+
})
|
4500
|
+
})
|
4501
|
+
})
|
4502
|
+
]
|
4306
4503
|
})
|
4307
4504
|
]
|
4308
|
-
})
|
4309
|
-
|
4310
|
-
|
4311
|
-
|
4312
|
-
|
4313
|
-
|
4314
|
-
|
4315
|
-
|
4316
|
-
|
4317
|
-
|
4318
|
-
|
4319
|
-
|
4320
|
-
|
4321
|
-
|
4322
|
-
|
4323
|
-
|
4505
|
+
}),
|
4506
|
+
/*#__PURE__*/ jsx(Dialog.Root, {
|
4507
|
+
open: isConfirmationOpen,
|
4508
|
+
onOpenChange: setIsConfirmationOpen,
|
4509
|
+
children: /*#__PURE__*/ jsx(ConfirmDialog, {
|
4510
|
+
onConfirm: ()=>{
|
4511
|
+
handleConfirm();
|
4512
|
+
setIsConfirmationOpen(false);
|
4513
|
+
resetForm();
|
4514
|
+
},
|
4515
|
+
onCancel: ()=>{
|
4516
|
+
setIsConfirmationOpen(false);
|
4517
|
+
},
|
4518
|
+
variant: "danger",
|
4519
|
+
children: formatMessage({
|
4520
|
+
id: 'content-manager.components.RelationInputModal.confirmation-message',
|
4521
|
+
defaultMessage: 'Some changes were not saved. Are you sure you want to close this relation? All changes that were not saved will be lost.'
|
4522
|
+
})
|
4324
4523
|
})
|
4325
4524
|
})
|
4326
|
-
|
4327
|
-
|
4328
|
-
}
|
4525
|
+
]
|
4526
|
+
});
|
4527
|
+
}
|
4329
4528
|
});
|
4330
4529
|
};
|
4331
|
-
const
|
4530
|
+
const CustomTextButton = styled(TextButton)`
|
4531
|
+
& > span {
|
4532
|
+
font-size: ${({ theme })=>theme.fontSizes[2]};
|
4533
|
+
}
|
4534
|
+
`;
|
4535
|
+
const RelationModalBody = ({ children })=>{
|
4332
4536
|
const { formatMessage } = useIntl();
|
4333
4537
|
const documentMeta = useDocumentContext('RelationModalBody', (state)=>state.meta);
|
4334
4538
|
const documentResponse = useDocumentContext('RelationModalBody', (state)=>state.document);
|
4539
|
+
const onPreview = useDocumentContext('RelationModalBody', (state)=>state.onPreview);
|
4335
4540
|
const documentLayoutResponse = useDocumentLayout(documentMeta.model);
|
4541
|
+
const plugins = useStrapiApp('RelationModalBody', (state)=>state.plugins);
|
4336
4542
|
const initialValues = documentResponse.getInitialFormValues();
|
4337
|
-
const { permissions = [], isLoading, error } = useRBAC(PERMISSIONS.map((action)=>({
|
4543
|
+
const { permissions = [], isLoading: isLoadingPermissions, error } = useRBAC(PERMISSIONS.map((action)=>({
|
4338
4544
|
action,
|
4339
4545
|
subject: documentMeta.model
|
4340
4546
|
})));
|
4341
|
-
|
4547
|
+
const isLoading = isLoadingPermissions || documentLayoutResponse.isLoading || documentResponse.isLoading;
|
4548
|
+
if (isLoading && !documentResponse.document?.documentId) {
|
4342
4549
|
return /*#__PURE__*/ jsx(Loader, {
|
4343
4550
|
small: true,
|
4344
4551
|
children: formatMessage({
|
@@ -4365,44 +4572,95 @@ const RelationModalBody = ({ id })=>{
|
|
4365
4572
|
}
|
4366
4573
|
const documentTitle = documentResponse.getTitle(documentLayoutResponse.edit.settings.mainField);
|
4367
4574
|
const hasDraftAndPublished = documentResponse.schema?.options?.draftAndPublish ?? false;
|
4575
|
+
const props = {
|
4576
|
+
activeTab: 'draft',
|
4577
|
+
collectionType: documentMeta.collectionType,
|
4578
|
+
model: documentMeta.model,
|
4579
|
+
documentId: documentMeta.documentId,
|
4580
|
+
document: documentResponse.document,
|
4581
|
+
meta: documentResponse.meta,
|
4582
|
+
onPreview
|
4583
|
+
};
|
4368
4584
|
return /*#__PURE__*/ jsx(Modal.Body, {
|
4369
4585
|
children: /*#__PURE__*/ jsxs(DocumentRBAC, {
|
4370
4586
|
permissions: permissions,
|
4371
4587
|
model: documentMeta.model,
|
4372
4588
|
children: [
|
4373
4589
|
/*#__PURE__*/ jsxs(Flex, {
|
4374
|
-
direction: "column",
|
4375
4590
|
alignItems: "flex-start",
|
4591
|
+
direction: "column",
|
4376
4592
|
gap: 2,
|
4377
4593
|
children: [
|
4378
|
-
/*#__PURE__*/
|
4379
|
-
|
4380
|
-
|
4381
|
-
|
4594
|
+
/*#__PURE__*/ jsxs(Flex, {
|
4595
|
+
width: "100%",
|
4596
|
+
justifyContent: "space-between",
|
4597
|
+
gap: 2,
|
4598
|
+
children: [
|
4599
|
+
/*#__PURE__*/ jsx(Typography, {
|
4600
|
+
tag: "h2",
|
4601
|
+
variant: "alpha",
|
4602
|
+
children: documentTitle
|
4603
|
+
}),
|
4604
|
+
/*#__PURE__*/ jsxs(Flex, {
|
4605
|
+
gap: 2,
|
4606
|
+
children: [
|
4607
|
+
children,
|
4608
|
+
/*#__PURE__*/ jsx(DescriptionComponentRenderer, {
|
4609
|
+
props: props,
|
4610
|
+
descriptions: plugins['content-manager'].apis.getDocumentActions('relation-modal'),
|
4611
|
+
children: (actions)=>{
|
4612
|
+
const filteredActions = actions.filter((action)=>{
|
4613
|
+
return [
|
4614
|
+
action.position
|
4615
|
+
].flat().includes('relation-modal');
|
4616
|
+
});
|
4617
|
+
const [primaryAction, secondaryAction] = filteredActions;
|
4618
|
+
if (!primaryAction && !secondaryAction) return null;
|
4619
|
+
// Both actions are available when draft and publish enabled
|
4620
|
+
if (primaryAction && secondaryAction) {
|
4621
|
+
return /*#__PURE__*/ jsxs(Fragment, {
|
4622
|
+
children: [
|
4623
|
+
/*#__PURE__*/ jsx(DocumentActionButton, {
|
4624
|
+
...secondaryAction,
|
4625
|
+
variant: secondaryAction.variant || 'secondary'
|
4626
|
+
}),
|
4627
|
+
/*#__PURE__*/ jsx(DocumentActionButton, {
|
4628
|
+
...primaryAction,
|
4629
|
+
variant: primaryAction.variant || 'default'
|
4630
|
+
})
|
4631
|
+
]
|
4632
|
+
});
|
4633
|
+
}
|
4634
|
+
// Otherwise we just have the save action
|
4635
|
+
return /*#__PURE__*/ jsx(DocumentActionButton, {
|
4636
|
+
...primaryAction,
|
4637
|
+
variant: primaryAction.variant || 'secondary'
|
4638
|
+
});
|
4639
|
+
}
|
4640
|
+
})
|
4641
|
+
]
|
4642
|
+
})
|
4643
|
+
]
|
4382
4644
|
}),
|
4383
4645
|
hasDraftAndPublished ? /*#__PURE__*/ jsx(Box, {
|
4384
|
-
marginTop: 1,
|
4385
4646
|
children: /*#__PURE__*/ jsx(DocumentStatus, {
|
4386
4647
|
status: documentResponse.document?.status
|
4387
4648
|
})
|
4388
4649
|
}) : null
|
4389
4650
|
]
|
4390
4651
|
}),
|
4391
|
-
/*#__PURE__*/ jsx(
|
4392
|
-
|
4393
|
-
|
4394
|
-
|
4395
|
-
|
4652
|
+
/*#__PURE__*/ jsx(Flex, {
|
4653
|
+
flex: 1,
|
4654
|
+
overflow: "auto",
|
4655
|
+
alignItems: "stretch",
|
4656
|
+
paddingTop: 7,
|
4657
|
+
children: /*#__PURE__*/ jsx(Box, {
|
4396
4658
|
overflow: "auto",
|
4397
|
-
|
4398
|
-
|
4399
|
-
|
4400
|
-
|
4401
|
-
|
4402
|
-
children: /*#__PURE__*/ jsx(FormLayout, {
|
4403
|
-
layout: documentLayoutResponse.edit.layout,
|
4404
|
-
hasBackground: false
|
4405
|
-
})
|
4659
|
+
flex: 1,
|
4660
|
+
children: /*#__PURE__*/ jsx(FormLayout, {
|
4661
|
+
layout: documentLayoutResponse.edit.layout,
|
4662
|
+
document: documentResponse,
|
4663
|
+
hasBackground: false
|
4406
4664
|
})
|
4407
4665
|
})
|
4408
4666
|
})
|
@@ -4463,15 +4721,18 @@ const ONE_WAY_RELATIONS = [
|
|
4463
4721
|
* @description The relations field holds a lot of domain logic for handling relations which is rather complicated
|
4464
4722
|
* At present we do not expose this to plugin developers, however, they are able to overwrite it themselves should
|
4465
4723
|
* they wish to do so.
|
4466
|
-
*/ const
|
4467
|
-
const
|
4468
|
-
const
|
4469
|
-
const
|
4724
|
+
*/ const RelationsField = /*#__PURE__*/ React.forwardRef(({ disabled, label, ...props }, ref)=>{
|
4725
|
+
const currentDocumentMeta = useDocumentContext('RelationsField', (state)=>state.meta);
|
4726
|
+
const currentDocument = useDocumentContext('RelationsField', (state)=>state.document);
|
4727
|
+
const rootDocumentMeta = useDocumentContext('RelationsField', (state)=>state.rootDocumentMeta);
|
4470
4728
|
const [currentPage, setCurrentPage] = React.useState(1);
|
4471
|
-
const
|
4729
|
+
const isRootDocument = rootDocumentMeta.documentId === currentDocumentMeta.documentId;
|
4730
|
+
const documentMeta = isRootDocument ? rootDocumentMeta : currentDocumentMeta;
|
4731
|
+
// Use the documentId from the actual document, not the params (meta)
|
4732
|
+
const documentId = currentDocument.document?.documentId;
|
4472
4733
|
const { formatMessage } = useIntl();
|
4473
4734
|
const [{ query }] = useQueryParams();
|
4474
|
-
const params = buildValidParams(query);
|
4735
|
+
const params = documentMeta.params ?? buildValidParams(query);
|
4475
4736
|
const isMorph = props.attribute.relation.toLowerCase().includes('morph');
|
4476
4737
|
const isDisabled = isMorph || disabled;
|
4477
4738
|
const { componentId, componentUID } = useComponent('RelationsField', ({ uid, id })=>({
|
@@ -4484,17 +4745,24 @@ const ONE_WAY_RELATIONS = [
|
|
4484
4745
|
}, [
|
4485
4746
|
isSubmitting
|
4486
4747
|
]);
|
4748
|
+
const component = componentUID && currentDocument.components[componentUID];
|
4487
4749
|
/**
|
4488
4750
|
* We'll always have a documentId in a created entry, so we look for a componentId first.
|
4489
4751
|
* Same with `uid` and `documentModel`.
|
4490
|
-
*/ const
|
4491
|
-
const
|
4752
|
+
*/ const model = component ? component.uid : documentMeta.model;
|
4753
|
+
const id = component && componentId ? componentId.toString() : documentId;
|
4492
4754
|
/**
|
4493
4755
|
* The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
|
4494
4756
|
* Where the above example would a nested field within two components, however
|
4495
4757
|
* we only require the field on the component not the complete path since we query
|
4496
4758
|
* individual components. Therefore we split the string and take the last item.
|
4497
4759
|
*/ const [targetField] = props.name.split('.').slice(-1);
|
4760
|
+
const schemaAttributes = component ? component.attributes ?? {} : currentDocument.schema?.attributes ?? {};
|
4761
|
+
/**
|
4762
|
+
* Confirm the target field is related to the current document.
|
4763
|
+
* Since relations can exist in a modal on top of the root document,
|
4764
|
+
* we need to ensure we are fetching relations for the correct document (root document vs related document),
|
4765
|
+
*/ const isRelatedToCurrentDocument = Object.values(schemaAttributes).filter((attribute)=>attribute.type === 'relation' && 'target' in attribute && 'target' in props.attribute && attribute.target === props.attribute.target).length > 0;
|
4498
4766
|
const { data, isLoading, isFetching } = useGetRelationsQuery({
|
4499
4767
|
model,
|
4500
4768
|
targetField,
|
@@ -4507,7 +4775,7 @@ const ONE_WAY_RELATIONS = [
|
|
4507
4775
|
}
|
4508
4776
|
}, {
|
4509
4777
|
refetchOnMountOrArgChange: true,
|
4510
|
-
skip: !id,
|
4778
|
+
skip: !id || !isRelatedToCurrentDocument,
|
4511
4779
|
selectFromResult: (result)=>{
|
4512
4780
|
return {
|
4513
4781
|
...result,
|
@@ -4616,10 +4884,11 @@ const ONE_WAY_RELATIONS = [
|
|
4616
4884
|
/*#__PURE__*/ jsx(RelationsInput, {
|
4617
4885
|
disabled: isDisabled,
|
4618
4886
|
// NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
|
4619
|
-
id: componentUID ? componentId ? `${componentId}` : '' : documentId,
|
4887
|
+
id: componentUID && component ? componentId ? `${componentId}` : '' : documentId,
|
4620
4888
|
label: `${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`,
|
4621
4889
|
model: model,
|
4622
4890
|
onChange: handleConnect,
|
4891
|
+
isRelatedToCurrentDocument: isRelatedToCurrentDocument,
|
4623
4892
|
...props
|
4624
4893
|
}),
|
4625
4894
|
'pagination' in data && data.pagination && data.pagination.pageCount > data.pagination.page ? /*#__PURE__*/ jsx(TextButton, {
|
@@ -4636,7 +4905,7 @@ const ONE_WAY_RELATIONS = [
|
|
4636
4905
|
}) : null
|
4637
4906
|
]
|
4638
4907
|
}),
|
4639
|
-
/*#__PURE__*/ jsx(
|
4908
|
+
/*#__PURE__*/ jsx(RelationsList, {
|
4640
4909
|
data: relations,
|
4641
4910
|
serverData: data.results,
|
4642
4911
|
disabled: isDisabled,
|
@@ -4644,575 +4913,226 @@ const ONE_WAY_RELATIONS = [
|
|
4644
4913
|
isLoading: isFetchingMoreRelations,
|
4645
4914
|
relationType: props.attribute.relation,
|
4646
4915
|
// @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
|
4647
|
-
targetModel: props.attribute.targetModel
|
4648
|
-
setCurrentDocument: changeDocument
|
4916
|
+
targetModel: props.attribute.targetModel
|
4649
4917
|
})
|
4650
4918
|
]
|
4651
4919
|
});
|
4652
4920
|
});
|
4653
|
-
|
4654
|
-
|
4655
|
-
|
4656
|
-
|
4657
|
-
|
4921
|
+
/**
|
4922
|
+
* TODO: this can be removed once we stop shipping Inputs with
|
4923
|
+
* labels wrapped round in DS@2.
|
4924
|
+
*/ const StyledFlex = styled(Flex)`
|
4925
|
+
& > div {
|
4926
|
+
width: 100%;
|
4927
|
+
}
|
4928
|
+
`;
|
4929
|
+
/**
|
4930
|
+
* If it's in the connected array, it can get out of our data array,
|
4931
|
+
* we'll be putting it back in later and sorting it anyway.
|
4932
|
+
*/ const removeConnected = ({ field })=>(relations)=>{
|
4933
|
+
return relations.filter((relation)=>{
|
4934
|
+
const connectedRelations = field?.connect ?? [];
|
4935
|
+
return connectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
|
4936
|
+
});
|
4937
|
+
};
|
4938
|
+
/**
|
4939
|
+
* @description Removes relations that are in the `disconnect` array of the field
|
4940
|
+
*/ const removeDisconnected = ({ field })=>(relations)=>relations.filter((relation)=>{
|
4941
|
+
const disconnectedRelations = field?.disconnect ?? [];
|
4942
|
+
return disconnectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
|
4943
|
+
});
|
4944
|
+
/**
|
4945
|
+
* @description Adds a label and href to the relation object we use this to render
|
4946
|
+
* a better UI where we can link to the relation and display a human-readable label.
|
4947
|
+
*/ const addLabelAndHref = ({ mainField, href })=>(relations)=>relations.map((relation)=>{
|
4948
|
+
return {
|
4949
|
+
...relation,
|
4950
|
+
// Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
|
4951
|
+
[mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
|
4952
|
+
label: getRelationLabel(relation, mainField),
|
4953
|
+
href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
|
4954
|
+
};
|
4955
|
+
});
|
4956
|
+
/**
|
4957
|
+
* @description Contains all the logic for the combobox that can search
|
4958
|
+
* for relations and then add them to the field's connect array.
|
4959
|
+
*/ const RelationsInput = ({ hint, id, model, label, labelAction, name, mainField, placeholder, required, unique: _unique, 'aria-label': _ariaLabel, onChange, isRelatedToCurrentDocument, ...props })=>{
|
4960
|
+
const [textValue, setTextValue] = React.useState('');
|
4961
|
+
const [searchParams, setSearchParams] = React.useState({
|
4962
|
+
_q: '',
|
4963
|
+
page: 1
|
4964
|
+
});
|
4965
|
+
const { toggleNotification } = useNotification();
|
4658
4966
|
const [{ query }] = useQueryParams();
|
4659
|
-
const
|
4660
|
-
const
|
4661
|
-
const
|
4662
|
-
const
|
4663
|
-
|
4664
|
-
|
4665
|
-
|
4666
|
-
const
|
4667
|
-
|
4668
|
-
setCurrentPage(1);
|
4669
|
-
}, [
|
4670
|
-
isSubmitting
|
4671
|
-
]);
|
4672
|
-
/**
|
4673
|
-
* We'll always have a documentId in a created entry, so we look for a componentId first.
|
4674
|
-
* Same with `uid` and `documentModel`.
|
4675
|
-
*/ const id = componentId ? componentId.toString() : documentId;
|
4676
|
-
const model = componentUID ?? documentModel;
|
4967
|
+
const currentDocumentMeta = useDocumentContext('RelationsInput', (state)=>state.meta);
|
4968
|
+
const rootDocumentMeta = useDocumentContext('RelationsInput', (state)=>state.rootDocumentMeta);
|
4969
|
+
const isRootDocument = rootDocumentMeta.documentId === currentDocumentMeta.documentId;
|
4970
|
+
const documentMeta = isRootDocument ? rootDocumentMeta : currentDocumentMeta;
|
4971
|
+
const { formatMessage } = useIntl();
|
4972
|
+
const fieldRef = useFocusInputField(name);
|
4973
|
+
const field = useField(name);
|
4974
|
+
const searchParamsDebounced = useDebounce(searchParams, 300);
|
4975
|
+
const [searchForTrigger, { data, isLoading }] = useLazySearchRelationsQuery();
|
4677
4976
|
/**
|
4977
|
+
* Because we're using a lazy query, we need to trigger the search
|
4978
|
+
* when the component mounts and when the search params change.
|
4979
|
+
* We also need to trigger the search when the field value changes
|
4980
|
+
* so that we can filter out the relations that are already connected.
|
4981
|
+
*/ React.useEffect(()=>{
|
4982
|
+
/**
|
4678
4983
|
* The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
|
4679
4984
|
* Where the above example would a nested field within two components, however
|
4680
4985
|
* we only require the field on the component not the complete path since we query
|
4681
4986
|
* individual components. Therefore we split the string and take the last item.
|
4682
|
-
*/ const [targetField] =
|
4683
|
-
|
4987
|
+
*/ const [targetField] = name.split('.').slice(-1);
|
4988
|
+
// Return early if there is no relation to the document
|
4989
|
+
if (!isRelatedToCurrentDocument) return;
|
4990
|
+
const params = documentMeta.params ?? buildValidParams(query);
|
4991
|
+
searchForTrigger({
|
4992
|
+
model,
|
4993
|
+
targetField,
|
4994
|
+
params: {
|
4995
|
+
...params,
|
4996
|
+
id: id ?? '',
|
4997
|
+
pageSize: 10,
|
4998
|
+
idsToInclude: field.value?.disconnect?.map((rel)=>rel.id.toString()) ?? [],
|
4999
|
+
idsToOmit: field.value?.connect?.map((rel)=>rel.id.toString()) ?? [],
|
5000
|
+
...searchParamsDebounced
|
5001
|
+
}
|
5002
|
+
});
|
5003
|
+
}, [
|
5004
|
+
field.value?.connect,
|
5005
|
+
field.value?.disconnect,
|
5006
|
+
id,
|
4684
5007
|
model,
|
4685
|
-
|
4686
|
-
|
4687
|
-
|
4688
|
-
|
4689
|
-
|
4690
|
-
|
4691
|
-
|
5008
|
+
name,
|
5009
|
+
query,
|
5010
|
+
searchForTrigger,
|
5011
|
+
searchParamsDebounced,
|
5012
|
+
isRelatedToCurrentDocument,
|
5013
|
+
documentMeta
|
5014
|
+
]);
|
5015
|
+
const handleSearch = async (search)=>{
|
5016
|
+
setSearchParams((s)=>({
|
5017
|
+
...s,
|
5018
|
+
_q: search,
|
5019
|
+
page: 1
|
5020
|
+
}));
|
5021
|
+
};
|
5022
|
+
const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
|
5023
|
+
const options = data?.results ?? [];
|
5024
|
+
const handleChange = (relationId)=>{
|
5025
|
+
if (!relationId) {
|
5026
|
+
return;
|
4692
5027
|
}
|
4693
|
-
|
4694
|
-
|
4695
|
-
|
4696
|
-
|
4697
|
-
|
4698
|
-
|
4699
|
-
|
4700
|
-
|
4701
|
-
|
4702
|
-
|
4703
|
-
};
|
5028
|
+
const relation = options.find((opt)=>opt.id.toString() === relationId);
|
5029
|
+
if (!relation) {
|
5030
|
+
// This is very unlikely to happen, but it ensures we don't have any data for.
|
5031
|
+
console.error("You've tried to add a relation with an id that does not exist in the options you can see, this is likely a bug with Strapi. Please open an issue.");
|
5032
|
+
toggleNotification({
|
5033
|
+
message: formatMessage({
|
5034
|
+
id: getTranslation('relation.error-adding-relation'),
|
5035
|
+
defaultMessage: 'An error occurred while trying to add the relation.'
|
5036
|
+
}),
|
5037
|
+
type: 'danger'
|
5038
|
+
});
|
5039
|
+
return;
|
4704
5040
|
}
|
4705
|
-
|
4706
|
-
|
4707
|
-
|
4708
|
-
|
4709
|
-
|
4710
|
-
|
4711
|
-
|
4712
|
-
/**
|
4713
|
-
* Items that are already connected, but reordered would be in
|
4714
|
-
* this list, so to get an accurate figure, we remove them.
|
4715
|
-
*/ const relationsConnected = (field.value?.connect ?? []).filter((rel)=>data.results.findIndex((relation)=>relation.id === rel.id) === -1).length ?? 0;
|
4716
|
-
const relationsDisconnected = field.value?.disconnect?.length ?? 0;
|
4717
|
-
const relationsCount = realServerRelationsCount + relationsConnected - relationsDisconnected;
|
4718
|
-
/**
|
4719
|
-
* This is it, the source of truth for reordering in conjunction with partial loading & updating
|
4720
|
-
* of relations. Relations on load are given __temp_key__ when fetched, because we don't want to
|
4721
|
-
* create brand new keys everytime the data updates, just keep adding them onto the newly loaded ones.
|
4722
|
-
*/ const relations = React.useMemo(()=>{
|
4723
|
-
const ctx = {
|
4724
|
-
field: field.value,
|
4725
|
-
// @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
|
4726
|
-
href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}`,
|
4727
|
-
mainField: props.mainField
|
4728
|
-
};
|
4729
|
-
/**
|
4730
|
-
* Tidy up our data.
|
4731
|
-
*/ const transformations = pipe$1(removeConnected(ctx), removeDisconnected(ctx), addLabelAndHref(ctx));
|
4732
|
-
const transformedRels = transformations([
|
4733
|
-
...data.results
|
4734
|
-
]);
|
4735
|
-
/**
|
4736
|
-
* THIS IS CRUCIAL. If you don't sort by the __temp_key__ which comes from fractional indexing
|
4737
|
-
* then the list will be in the wrong order.
|
4738
|
-
*/ return [
|
4739
|
-
...transformedRels,
|
4740
|
-
...field.value?.connect ?? []
|
4741
|
-
].sort((a, b)=>{
|
4742
|
-
if (a.__temp_key__ < b.__temp_key__) return -1;
|
4743
|
-
if (a.__temp_key__ > b.__temp_key__) return 1;
|
4744
|
-
return 0;
|
4745
|
-
});
|
4746
|
-
}, [
|
4747
|
-
data.results,
|
4748
|
-
field.value,
|
4749
|
-
// @ts-expect-error – targetModel does exist on the attribute. But it's not typed.
|
4750
|
-
props.attribute.targetModel,
|
4751
|
-
props.mainField
|
4752
|
-
]);
|
4753
|
-
const handleDisconnect = useHandleDisconnect(props.name, 'RelationsField');
|
4754
|
-
const handleConnect = (relation)=>{
|
4755
|
-
const [lastItemInList] = relations.slice(-1);
|
4756
|
-
const item = {
|
4757
|
-
id: relation.id,
|
4758
|
-
apiData: {
|
4759
|
-
id: relation.id,
|
4760
|
-
documentId: relation.documentId,
|
4761
|
-
locale: relation.locale
|
4762
|
-
},
|
4763
|
-
status: relation.status,
|
4764
|
-
/**
|
4765
|
-
* If there's a last item, that's the first key we use to generate out next one.
|
4766
|
-
*/ __temp_key__: generateNKeysBetween(lastItemInList?.__temp_key__ ?? null, null, 1)[0],
|
4767
|
-
// Fallback to `id` if there is no `mainField` value, which will overwrite the above `id` property with the exact same data.
|
4768
|
-
[props.mainField?.name ?? 'documentId']: relation[props.mainField?.name ?? 'documentId'],
|
4769
|
-
label: getRelationLabel(relation, props.mainField),
|
4770
|
-
// @ts-expect-error – targetModel does exist on the attribute, but it's not typed.
|
4771
|
-
href: `../${COLLECTION_TYPES}/${props.attribute.targetModel}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
|
4772
|
-
};
|
4773
|
-
if (ONE_WAY_RELATIONS.includes(props.attribute.relation)) {
|
4774
|
-
// Remove any existing relation so they can be replaced with the new one
|
4775
|
-
field.value?.connect?.forEach(handleDisconnect);
|
4776
|
-
relations.forEach(handleDisconnect);
|
4777
|
-
field.onChange(`${props.name}.connect`, [
|
4778
|
-
item
|
4779
|
-
]);
|
4780
|
-
} else {
|
4781
|
-
field.onChange(`${props.name}.connect`, [
|
4782
|
-
...field.value?.connect ?? [],
|
4783
|
-
item
|
4784
|
-
]);
|
4785
|
-
}
|
4786
|
-
};
|
4787
|
-
return /*#__PURE__*/ jsxs(Flex, {
|
4788
|
-
ref: ref,
|
4789
|
-
direction: "column",
|
4790
|
-
gap: 3,
|
4791
|
-
justifyContent: "space-between",
|
4792
|
-
alignItems: "stretch",
|
4793
|
-
wrap: "wrap",
|
4794
|
-
children: [
|
4795
|
-
/*#__PURE__*/ jsxs(StyledFlex, {
|
4796
|
-
direction: "column",
|
4797
|
-
alignItems: "start",
|
4798
|
-
gap: 2,
|
4799
|
-
width: "100%",
|
4800
|
-
children: [
|
4801
|
-
/*#__PURE__*/ jsx(RelationsInput, {
|
4802
|
-
disabled: isDisabled,
|
4803
|
-
// NOTE: we should not default to using the documentId if the component is being created (componentUID is undefined)
|
4804
|
-
id: componentUID ? componentId ? `${componentId}` : '' : documentId,
|
4805
|
-
label: `${label} ${relationsCount > 0 ? `(${relationsCount})` : ''}`,
|
4806
|
-
model: model,
|
4807
|
-
onChange: handleConnect,
|
4808
|
-
...props
|
4809
|
-
}),
|
4810
|
-
'pagination' in data && data.pagination && data.pagination.pageCount > data.pagination.page ? /*#__PURE__*/ jsx(TextButton, {
|
4811
|
-
disabled: isFetchingMoreRelations,
|
4812
|
-
onClick: handleLoadMore,
|
4813
|
-
loading: isFetchingMoreRelations,
|
4814
|
-
startIcon: /*#__PURE__*/ jsx(ArrowClockwise, {}),
|
4815
|
-
// prevent the label from line-wrapping
|
4816
|
-
shrink: 0,
|
4817
|
-
children: formatMessage({
|
4818
|
-
id: getTranslation('relation.loadMore'),
|
4819
|
-
defaultMessage: 'Load More'
|
4820
|
-
})
|
4821
|
-
}) : null
|
4822
|
-
]
|
4823
|
-
}),
|
4824
|
-
/*#__PURE__*/ jsx(RelationsList, {
|
4825
|
-
data: relations,
|
4826
|
-
serverData: data.results,
|
4827
|
-
disabled: isDisabled,
|
4828
|
-
name: props.name,
|
4829
|
-
isLoading: isFetchingMoreRelations,
|
4830
|
-
relationType: props.attribute.relation
|
4831
|
-
})
|
4832
|
-
]
|
4833
|
-
});
|
4834
|
-
});
|
4835
|
-
/**
|
4836
|
-
* TODO: this can be removed once we stop shipping Inputs with
|
4837
|
-
* labels wrapped round in DS@2.
|
4838
|
-
*/ const StyledFlex = styled(Flex)`
|
4839
|
-
& > div {
|
4840
|
-
width: 100%;
|
4841
|
-
}
|
4842
|
-
`;
|
4843
|
-
/**
|
4844
|
-
* If it's in the connected array, it can get out of our data array,
|
4845
|
-
* we'll be putting it back in later and sorting it anyway.
|
4846
|
-
*/ const removeConnected = ({ field })=>(relations)=>{
|
4847
|
-
return relations.filter((relation)=>{
|
4848
|
-
const connectedRelations = field?.connect ?? [];
|
4849
|
-
return connectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
|
4850
|
-
});
|
4851
|
-
};
|
4852
|
-
/**
|
4853
|
-
* @description Removes relations that are in the `disconnect` array of the field
|
4854
|
-
*/ const removeDisconnected = ({ field })=>(relations)=>relations.filter((relation)=>{
|
4855
|
-
const disconnectedRelations = field?.disconnect ?? [];
|
4856
|
-
return disconnectedRelations.findIndex((rel)=>rel.id === relation.id) === -1;
|
4857
|
-
});
|
4858
|
-
/**
|
4859
|
-
* @description Adds a label and href to the relation object we use this to render
|
4860
|
-
* a better UI where we can link to the relation and display a human-readable label.
|
4861
|
-
*/ const addLabelAndHref = ({ mainField, href })=>(relations)=>relations.map((relation)=>{
|
4862
|
-
return {
|
4863
|
-
...relation,
|
4864
|
-
// Fallback to `id` if there is no `mainField` value, which will overwrite the above `documentId` property with the exact same data.
|
4865
|
-
[mainField?.name ?? 'documentId']: relation[mainField?.name ?? 'documentId'],
|
4866
|
-
label: getRelationLabel(relation, mainField),
|
4867
|
-
href: `${href}/${relation.documentId}?${relation.locale ? `plugins[i18n][locale]=${relation.locale}` : ''}`
|
4868
|
-
};
|
4869
|
-
});
|
4870
|
-
/**
|
4871
|
-
* @description Contains all the logic for the combobox that can search
|
4872
|
-
* for relations and then add them to the field's connect array.
|
4873
|
-
*/ const RelationsInput = ({ hint, id, model, label, labelAction, name, mainField, placeholder, required, unique: _unique, 'aria-label': _ariaLabel, onChange, ...props })=>{
|
4874
|
-
const [textValue, setTextValue] = React.useState('');
|
4875
|
-
const [searchParams, setSearchParams] = React.useState({
|
4876
|
-
_q: '',
|
4877
|
-
page: 1
|
4878
|
-
});
|
4879
|
-
const { toggleNotification } = useNotification();
|
4880
|
-
const [{ query }] = useQueryParams();
|
4881
|
-
const { formatMessage } = useIntl();
|
4882
|
-
const fieldRef = useFocusInputField(name);
|
4883
|
-
const field = useField(name);
|
4884
|
-
const searchParamsDebounced = useDebounce(searchParams, 300);
|
4885
|
-
const [searchForTrigger, { data, isLoading }] = useLazySearchRelationsQuery();
|
4886
|
-
/**
|
4887
|
-
* Because we're using a lazy query, we need to trigger the search
|
4888
|
-
* when the component mounts and when the search params change.
|
4889
|
-
* We also need to trigger the search when the field value changes
|
4890
|
-
* so that we can filter out the relations that are already connected.
|
4891
|
-
*/ React.useEffect(()=>{
|
4892
|
-
/**
|
4893
|
-
* The `name` prop is a complete path to the field, e.g. `field1.field2.field3`.
|
4894
|
-
* Where the above example would a nested field within two components, however
|
4895
|
-
* we only require the field on the component not the complete path since we query
|
4896
|
-
* individual components. Therefore we split the string and take the last item.
|
4897
|
-
*/ const [targetField] = name.split('.').slice(-1);
|
4898
|
-
searchForTrigger({
|
4899
|
-
model,
|
4900
|
-
targetField,
|
4901
|
-
params: {
|
4902
|
-
...buildValidParams(query),
|
4903
|
-
id: id ?? '',
|
4904
|
-
pageSize: 10,
|
4905
|
-
idsToInclude: field.value?.disconnect?.map((rel)=>rel.id.toString()) ?? [],
|
4906
|
-
idsToOmit: field.value?.connect?.map((rel)=>rel.id.toString()) ?? [],
|
4907
|
-
...searchParamsDebounced
|
4908
|
-
}
|
4909
|
-
});
|
4910
|
-
}, [
|
4911
|
-
field.value?.connect,
|
4912
|
-
field.value?.disconnect,
|
4913
|
-
id,
|
4914
|
-
model,
|
4915
|
-
name,
|
4916
|
-
query,
|
4917
|
-
searchForTrigger,
|
4918
|
-
searchParamsDebounced
|
4919
|
-
]);
|
4920
|
-
const handleSearch = async (search)=>{
|
4921
|
-
setSearchParams((s)=>({
|
4922
|
-
...s,
|
4923
|
-
_q: search,
|
4924
|
-
page: 1
|
4925
|
-
}));
|
4926
|
-
};
|
4927
|
-
const hasNextPage = data?.pagination ? data.pagination.page < data.pagination.pageCount : false;
|
4928
|
-
const options = data?.results ?? [];
|
4929
|
-
const handleChange = (relationId)=>{
|
4930
|
-
if (!relationId) {
|
4931
|
-
return;
|
4932
|
-
}
|
4933
|
-
const relation = options.find((opt)=>opt.id.toString() === relationId);
|
4934
|
-
if (!relation) {
|
4935
|
-
// This is very unlikely to happen, but it ensures we don't have any data for.
|
4936
|
-
console.error("You've tried to add a relation with an id that does not exist in the options you can see, this is likely a bug with Strapi. Please open an issue.");
|
4937
|
-
toggleNotification({
|
4938
|
-
message: formatMessage({
|
4939
|
-
id: getTranslation('relation.error-adding-relation'),
|
4940
|
-
defaultMessage: 'An error occurred while trying to add the relation.'
|
4941
|
-
}),
|
4942
|
-
type: 'danger'
|
4943
|
-
});
|
4944
|
-
return;
|
4945
|
-
}
|
4946
|
-
/**
|
4947
|
-
* You need to give this relation a correct _temp_key_ but
|
4948
|
-
* this component doesn't know about those ones, you can't rely
|
4949
|
-
* on the connect array because that doesn't hold items that haven't
|
4950
|
-
* moved. So use a callback to fill in the gaps when connecting.
|
4951
|
-
*
|
4952
|
-
*/ onChange(relation);
|
4953
|
-
};
|
4954
|
-
const handleLoadMore = ()=>{
|
4955
|
-
if (!data || !data.pagination) {
|
4956
|
-
return;
|
4957
|
-
} else if (data.pagination.page < data.pagination.pageCount) {
|
4958
|
-
setSearchParams((s)=>({
|
4959
|
-
...s,
|
4960
|
-
page: s.page + 1
|
4961
|
-
}));
|
4962
|
-
}
|
4963
|
-
};
|
4964
|
-
React.useLayoutEffect(()=>{
|
4965
|
-
setTextValue('');
|
4966
|
-
}, [
|
4967
|
-
field.value
|
4968
|
-
]);
|
4969
|
-
return /*#__PURE__*/ jsxs(Field.Root, {
|
4970
|
-
error: field.error,
|
4971
|
-
hint: hint,
|
4972
|
-
name: name,
|
4973
|
-
required: required,
|
4974
|
-
children: [
|
4975
|
-
/*#__PURE__*/ jsx(Field.Label, {
|
4976
|
-
action: labelAction,
|
4977
|
-
children: label
|
4978
|
-
}),
|
4979
|
-
/*#__PURE__*/ jsx(Combobox, {
|
4980
|
-
ref: fieldRef,
|
4981
|
-
name: name,
|
4982
|
-
autocomplete: "list",
|
4983
|
-
placeholder: placeholder || formatMessage({
|
4984
|
-
id: getTranslation('relation.add'),
|
4985
|
-
defaultMessage: 'Add relation'
|
4986
|
-
}),
|
4987
|
-
hasMoreItems: hasNextPage,
|
4988
|
-
loading: isLoading,
|
4989
|
-
onOpenChange: ()=>{
|
4990
|
-
handleSearch(textValue ?? '');
|
4991
|
-
},
|
4992
|
-
noOptionsMessage: ()=>formatMessage({
|
4993
|
-
id: getTranslation('relation.notAvailable'),
|
4994
|
-
defaultMessage: 'No relations available'
|
4995
|
-
}),
|
4996
|
-
loadingMessage: formatMessage({
|
4997
|
-
id: getTranslation('relation.isLoading'),
|
4998
|
-
defaultMessage: 'Relations are loading'
|
4999
|
-
}),
|
5000
|
-
onLoadMore: handleLoadMore,
|
5001
|
-
textValue: textValue,
|
5002
|
-
onChange: handleChange,
|
5003
|
-
onTextValueChange: (text)=>{
|
5004
|
-
setTextValue(text);
|
5005
|
-
},
|
5006
|
-
onInputChange: (event)=>{
|
5007
|
-
handleSearch(event.currentTarget.value);
|
5008
|
-
},
|
5009
|
-
...props,
|
5010
|
-
children: options.map((opt)=>{
|
5011
|
-
const textValue = getRelationLabel(opt, mainField);
|
5012
|
-
return /*#__PURE__*/ jsx(ComboboxOption, {
|
5013
|
-
value: opt.id.toString(),
|
5014
|
-
textValue: textValue,
|
5015
|
-
children: /*#__PURE__*/ jsxs(Flex, {
|
5016
|
-
gap: 2,
|
5017
|
-
justifyContent: "space-between",
|
5018
|
-
children: [
|
5019
|
-
/*#__PURE__*/ jsx(Typography, {
|
5020
|
-
ellipsis: true,
|
5021
|
-
children: textValue
|
5022
|
-
}),
|
5023
|
-
opt.status ? /*#__PURE__*/ jsx(DocumentStatus, {
|
5024
|
-
status: opt.status
|
5025
|
-
}) : null
|
5026
|
-
]
|
5027
|
-
})
|
5028
|
-
}, opt.id);
|
5029
|
-
})
|
5030
|
-
}),
|
5031
|
-
/*#__PURE__*/ jsx(Field.Error, {}),
|
5032
|
-
/*#__PURE__*/ jsx(Field.Hint, {})
|
5033
|
-
]
|
5034
|
-
});
|
5035
|
-
};
|
5036
|
-
/* -------------------------------------------------------------------------------------------------
|
5037
|
-
* RelationsList
|
5038
|
-
* -----------------------------------------------------------------------------------------------*/ const RELATION_ITEM_HEIGHT = 50;
|
5039
|
-
const RELATION_GUTTER = 4;
|
5040
|
-
const UnstableRelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel, setCurrentDocument })=>{
|
5041
|
-
const ariaDescriptionId = React.useId();
|
5042
|
-
const { formatMessage } = useIntl();
|
5043
|
-
const listRef = React.useRef(null);
|
5044
|
-
const outerListRef = React.useRef(null);
|
5045
|
-
const [overflow, setOverflow] = React.useState();
|
5046
|
-
const [liveText, setLiveText] = React.useState('');
|
5047
|
-
const field = useField(name);
|
5048
|
-
React.useEffect(()=>{
|
5049
|
-
if (data.length <= RELATIONS_TO_DISPLAY) {
|
5050
|
-
return setOverflow(undefined);
|
5051
|
-
}
|
5052
|
-
const handleNativeScroll = (e)=>{
|
5053
|
-
const el = e.target;
|
5054
|
-
const parentScrollContainerHeight = el.parentNode.scrollHeight;
|
5055
|
-
const maxScrollBottom = el.scrollHeight - el.scrollTop;
|
5056
|
-
if (el.scrollTop === 0) {
|
5057
|
-
return setOverflow('bottom');
|
5058
|
-
}
|
5059
|
-
if (maxScrollBottom === parentScrollContainerHeight) {
|
5060
|
-
return setOverflow('top');
|
5061
|
-
}
|
5062
|
-
return setOverflow('top-bottom');
|
5063
|
-
};
|
5064
|
-
const outerListRefCurrent = outerListRef?.current;
|
5065
|
-
if (!isLoading && data.length > 0 && outerListRefCurrent) {
|
5066
|
-
outerListRef.current.addEventListener('scroll', handleNativeScroll);
|
5067
|
-
}
|
5068
|
-
return ()=>{
|
5069
|
-
if (outerListRefCurrent) {
|
5070
|
-
outerListRefCurrent.removeEventListener('scroll', handleNativeScroll);
|
5071
|
-
}
|
5072
|
-
};
|
5073
|
-
}, [
|
5074
|
-
isLoading,
|
5075
|
-
data.length
|
5076
|
-
]);
|
5077
|
-
const getItemPos = (index)=>`${index + 1} of ${data.length}`;
|
5078
|
-
const handleMoveItem = (newIndex, oldIndex)=>{
|
5079
|
-
const item = data[oldIndex];
|
5080
|
-
setLiveText(formatMessage({
|
5081
|
-
id: getTranslation('dnd.reorder'),
|
5082
|
-
defaultMessage: '{item}, moved. New position in list: {position}.'
|
5083
|
-
}, {
|
5084
|
-
item: item.label ?? item.documentId,
|
5085
|
-
position: getItemPos(newIndex)
|
5086
|
-
}));
|
5087
|
-
/**
|
5088
|
-
* Splicing mutates the array, so we need to create a new array
|
5089
|
-
*/ const newData = [
|
5090
|
-
...data
|
5091
|
-
];
|
5092
|
-
const currentRow = data[oldIndex];
|
5093
|
-
const startKey = oldIndex > newIndex ? newData[newIndex - 1]?.__temp_key__ : newData[newIndex]?.__temp_key__;
|
5094
|
-
const endKey = oldIndex > newIndex ? newData[newIndex]?.__temp_key__ : newData[newIndex + 1]?.__temp_key__;
|
5095
|
-
/**
|
5096
|
-
* We're moving the relation between two other relations, so
|
5097
|
-
* we need to generate a new key that keeps the order
|
5098
|
-
*/ const [newKey] = generateNKeysBetween(startKey, endKey, 1);
|
5099
|
-
newData.splice(oldIndex, 1);
|
5100
|
-
newData.splice(newIndex, 0, {
|
5101
|
-
...currentRow,
|
5102
|
-
__temp_key__: newKey
|
5103
|
-
});
|
5104
|
-
/**
|
5105
|
-
* Now we diff against the server to understand what's different so we
|
5106
|
-
* can keep the connect array nice and tidy. It also needs reversing because
|
5107
|
-
* we reverse the relations from the server in the first place.
|
5108
|
-
*/ const connectedRelations = newData.reduce((acc, relation, currentIndex, array)=>{
|
5109
|
-
const relationOnServer = serverData.find((oldRelation)=>oldRelation.id === relation.id);
|
5110
|
-
const relationInFront = array[currentIndex + 1];
|
5111
|
-
if (!relationOnServer || relationOnServer.__temp_key__ !== relation.__temp_key__) {
|
5112
|
-
const position = relationInFront ? {
|
5113
|
-
before: relationInFront.documentId,
|
5114
|
-
locale: relationInFront.locale,
|
5115
|
-
status: 'publishedAt' in relationInFront && relationInFront.publishedAt ? 'published' : 'draft'
|
5116
|
-
} : {
|
5117
|
-
end: true
|
5118
|
-
};
|
5119
|
-
const relationWithPosition = {
|
5120
|
-
...relation,
|
5121
|
-
...{
|
5122
|
-
apiData: {
|
5123
|
-
id: relation.id,
|
5124
|
-
documentId: relation.documentId,
|
5125
|
-
locale: relation.locale,
|
5126
|
-
position
|
5127
|
-
}
|
5128
|
-
}
|
5129
|
-
};
|
5130
|
-
return [
|
5131
|
-
...acc,
|
5132
|
-
relationWithPosition
|
5133
|
-
];
|
5134
|
-
}
|
5135
|
-
return acc;
|
5136
|
-
}, []).toReversed();
|
5137
|
-
field.onChange(`${name}.connect`, connectedRelations);
|
5138
|
-
};
|
5139
|
-
const handleGrabItem = (index)=>{
|
5140
|
-
const item = data[index];
|
5141
|
-
setLiveText(formatMessage({
|
5142
|
-
id: getTranslation('dnd.grab-item'),
|
5143
|
-
defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
|
5144
|
-
}, {
|
5145
|
-
item: item.label ?? item.documentId,
|
5146
|
-
position: getItemPos(index)
|
5147
|
-
}));
|
5148
|
-
};
|
5149
|
-
const handleDropItem = (index)=>{
|
5150
|
-
const { href: _href, label, ...item } = data[index];
|
5151
|
-
setLiveText(formatMessage({
|
5152
|
-
id: getTranslation('dnd.drop-item'),
|
5153
|
-
defaultMessage: `{item}, dropped. Final position in list: {position}.`
|
5154
|
-
}, {
|
5155
|
-
item: label ?? item.documentId,
|
5156
|
-
position: getItemPos(index)
|
5157
|
-
}));
|
5041
|
+
/**
|
5042
|
+
* You need to give this relation a correct _temp_key_ but
|
5043
|
+
* this component doesn't know about those ones, you can't rely
|
5044
|
+
* on the connect array because that doesn't hold items that haven't
|
5045
|
+
* moved. So use a callback to fill in the gaps when connecting.
|
5046
|
+
*
|
5047
|
+
*/ onChange(relation);
|
5158
5048
|
};
|
5159
|
-
const
|
5160
|
-
|
5161
|
-
|
5162
|
-
|
5163
|
-
|
5164
|
-
|
5165
|
-
|
5166
|
-
|
5049
|
+
const handleLoadMore = ()=>{
|
5050
|
+
if (!data || !data.pagination) {
|
5051
|
+
return;
|
5052
|
+
} else if (data.pagination.page < data.pagination.pageCount) {
|
5053
|
+
setSearchParams((s)=>({
|
5054
|
+
...s,
|
5055
|
+
page: s.page + 1
|
5056
|
+
}));
|
5057
|
+
}
|
5167
5058
|
};
|
5168
|
-
|
5169
|
-
|
5170
|
-
|
5171
|
-
|
5172
|
-
|
5173
|
-
|
5174
|
-
|
5175
|
-
|
5059
|
+
React.useLayoutEffect(()=>{
|
5060
|
+
setTextValue('');
|
5061
|
+
}, [
|
5062
|
+
field.value
|
5063
|
+
]);
|
5064
|
+
return /*#__PURE__*/ jsxs(Field.Root, {
|
5065
|
+
error: field.error,
|
5066
|
+
hint: hint,
|
5067
|
+
name: name,
|
5068
|
+
required: required,
|
5176
5069
|
children: [
|
5177
|
-
/*#__PURE__*/ jsx(
|
5178
|
-
|
5179
|
-
children:
|
5180
|
-
id: getTranslation('dnd.instructions'),
|
5181
|
-
defaultMessage: `Press spacebar to grab and re-order`
|
5182
|
-
})
|
5183
|
-
}),
|
5184
|
-
/*#__PURE__*/ jsx(VisuallyHidden, {
|
5185
|
-
"aria-live": "assertive",
|
5186
|
-
children: liveText
|
5070
|
+
/*#__PURE__*/ jsx(Field.Label, {
|
5071
|
+
action: labelAction,
|
5072
|
+
children: label
|
5187
5073
|
}),
|
5188
|
-
/*#__PURE__*/ jsx(
|
5189
|
-
|
5190
|
-
|
5191
|
-
|
5192
|
-
|
5193
|
-
|
5194
|
-
|
5195
|
-
|
5196
|
-
|
5197
|
-
|
5198
|
-
|
5199
|
-
|
5200
|
-
handleGrabItem,
|
5201
|
-
handleMoveItem,
|
5202
|
-
name,
|
5203
|
-
handleDisconnect,
|
5204
|
-
relations: data,
|
5205
|
-
targetModel,
|
5206
|
-
setCurrentDocument
|
5074
|
+
/*#__PURE__*/ jsx(Combobox, {
|
5075
|
+
ref: fieldRef,
|
5076
|
+
name: name,
|
5077
|
+
autocomplete: "list",
|
5078
|
+
placeholder: placeholder || formatMessage({
|
5079
|
+
id: getTranslation('relation.add'),
|
5080
|
+
defaultMessage: 'Add relation'
|
5081
|
+
}),
|
5082
|
+
hasMoreItems: hasNextPage,
|
5083
|
+
loading: isLoading,
|
5084
|
+
onOpenChange: ()=>{
|
5085
|
+
handleSearch(textValue ?? '');
|
5207
5086
|
},
|
5208
|
-
|
5209
|
-
|
5210
|
-
|
5211
|
-
|
5087
|
+
noOptionsMessage: ()=>formatMessage({
|
5088
|
+
id: getTranslation('relation.notAvailable'),
|
5089
|
+
defaultMessage: 'No relations available'
|
5090
|
+
}),
|
5091
|
+
loadingMessage: formatMessage({
|
5092
|
+
id: getTranslation('relation.isLoading'),
|
5093
|
+
defaultMessage: 'Relations are loading'
|
5094
|
+
}),
|
5095
|
+
onLoadMore: handleLoadMore,
|
5096
|
+
textValue: textValue,
|
5097
|
+
onChange: handleChange,
|
5098
|
+
onTextValueChange: (text)=>{
|
5099
|
+
setTextValue(text);
|
5100
|
+
},
|
5101
|
+
onInputChange: (event)=>{
|
5102
|
+
handleSearch(event.currentTarget.value);
|
5103
|
+
},
|
5104
|
+
...props,
|
5105
|
+
children: options.map((opt)=>{
|
5106
|
+
const textValue = getRelationLabel(opt, mainField);
|
5107
|
+
return /*#__PURE__*/ jsx(ComboboxOption, {
|
5108
|
+
value: opt.id.toString(),
|
5109
|
+
textValue: textValue,
|
5110
|
+
children: /*#__PURE__*/ jsxs(Flex, {
|
5111
|
+
gap: 2,
|
5112
|
+
justifyContent: "space-between",
|
5113
|
+
children: [
|
5114
|
+
/*#__PURE__*/ jsx(Typography, {
|
5115
|
+
ellipsis: true,
|
5116
|
+
children: textValue
|
5117
|
+
}),
|
5118
|
+
opt.status ? /*#__PURE__*/ jsx(DocumentStatus, {
|
5119
|
+
status: opt.status
|
5120
|
+
}) : null
|
5121
|
+
]
|
5122
|
+
})
|
5123
|
+
}, opt.id);
|
5124
|
+
})
|
5125
|
+
}),
|
5126
|
+
/*#__PURE__*/ jsx(Field.Error, {}),
|
5127
|
+
/*#__PURE__*/ jsx(Field.Hint, {})
|
5212
5128
|
]
|
5213
5129
|
});
|
5214
5130
|
};
|
5215
|
-
|
5131
|
+
/* -------------------------------------------------------------------------------------------------
|
5132
|
+
* RelationsList
|
5133
|
+
* -----------------------------------------------------------------------------------------------*/ const RELATION_ITEM_HEIGHT = 50;
|
5134
|
+
const RELATION_GUTTER = 4;
|
5135
|
+
const RelationsList = ({ data, serverData, disabled, name, isLoading, relationType, targetModel })=>{
|
5216
5136
|
const ariaDescriptionId = React.useId();
|
5217
5137
|
const { formatMessage } = useIntl();
|
5218
5138
|
const listRef = React.useRef(null);
|
@@ -5376,7 +5296,8 @@ const RelationsList = ({ data, serverData, disabled, name, isLoading, relationTy
|
|
5376
5296
|
handleMoveItem,
|
5377
5297
|
name,
|
5378
5298
|
handleDisconnect,
|
5379
|
-
relations: data
|
5299
|
+
relations: data,
|
5300
|
+
targetModel
|
5380
5301
|
},
|
5381
5302
|
itemKey: (index)=>data[index].id,
|
5382
5303
|
innerElementType: "ol",
|
@@ -5416,144 +5337,10 @@ const ShadowBox = styled(Box)`
|
|
5416
5337
|
transition: opacity 0.2s ease-in-out;
|
5417
5338
|
}
|
5418
5339
|
`;
|
5419
|
-
const CustomTextButton = styled(TextButton)`
|
5420
|
-
& > span {
|
5421
|
-
font-size: ${({ theme })=>theme.fontSizes[2]};
|
5422
|
-
}
|
5423
|
-
`;
|
5424
|
-
const UnstableListItem = ({ data, index, style })=>{
|
5425
|
-
const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel, setCurrentDocument } = data;
|
5426
|
-
const { formatMessage } = useIntl();
|
5427
|
-
const [isModalOpen, setIsModalOpen] = React.useState(false);
|
5428
|
-
const { id, label, status, documentId, href, apiData } = relations[index];
|
5429
|
-
const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(canDrag && !disabled, {
|
5430
|
-
type: `${ItemTypes.RELATION}_${name}`,
|
5431
|
-
index,
|
5432
|
-
item: {
|
5433
|
-
displayedValue: label,
|
5434
|
-
status,
|
5435
|
-
id: id,
|
5436
|
-
index
|
5437
|
-
},
|
5438
|
-
onMoveItem: handleMoveItem,
|
5439
|
-
onDropItem: handleDropItem,
|
5440
|
-
onGrabItem: handleGrabItem,
|
5441
|
-
onCancel: handleCancel,
|
5442
|
-
dropSensitivity: DROP_SENSITIVITY.REGULAR
|
5443
|
-
});
|
5444
|
-
const composedRefs = useComposedRefs(relationRef, dragRef);
|
5445
|
-
const handleChangeModalContent = ()=>{
|
5446
|
-
if (setCurrentDocument) {
|
5447
|
-
const newRelation = {
|
5448
|
-
documentId: documentId ? documentId : apiData?.documentId || '',
|
5449
|
-
model: targetModel,
|
5450
|
-
collectionType: getCollectionType(href)
|
5451
|
-
};
|
5452
|
-
setCurrentDocument(newRelation);
|
5453
|
-
}
|
5454
|
-
};
|
5455
|
-
React.useEffect(()=>{
|
5456
|
-
dragPreviewRef(getEmptyImage());
|
5457
|
-
}, [
|
5458
|
-
dragPreviewRef
|
5459
|
-
]);
|
5460
|
-
return /*#__PURE__*/ jsx(Box, {
|
5461
|
-
style: style,
|
5462
|
-
tag: "li",
|
5463
|
-
ref: dropRef,
|
5464
|
-
"aria-describedby": ariaDescribedBy,
|
5465
|
-
cursor: canDrag ? 'all-scroll' : 'default',
|
5466
|
-
children: isDragging ? /*#__PURE__*/ jsx(RelationItemPlaceholder, {}) : /*#__PURE__*/ jsxs(Flex, {
|
5467
|
-
paddingTop: 2,
|
5468
|
-
paddingBottom: 2,
|
5469
|
-
paddingLeft: canDrag ? 2 : 4,
|
5470
|
-
paddingRight: 4,
|
5471
|
-
hasRadius: true,
|
5472
|
-
borderColor: "neutral200",
|
5473
|
-
background: disabled ? 'neutral150' : 'neutral0',
|
5474
|
-
justifyContent: "space-between",
|
5475
|
-
ref: composedRefs,
|
5476
|
-
"data-handler-id": handlerId,
|
5477
|
-
children: [
|
5478
|
-
/*#__PURE__*/ jsxs(FlexWrapper, {
|
5479
|
-
gap: 1,
|
5480
|
-
children: [
|
5481
|
-
canDrag ? /*#__PURE__*/ jsx(IconButton, {
|
5482
|
-
tag: "div",
|
5483
|
-
role: "button",
|
5484
|
-
tabIndex: 0,
|
5485
|
-
withTooltip: false,
|
5486
|
-
label: formatMessage({
|
5487
|
-
id: getTranslation('components.RelationInput.icon-button-aria-label'),
|
5488
|
-
defaultMessage: 'Drag'
|
5489
|
-
}),
|
5490
|
-
variant: "ghost",
|
5491
|
-
onKeyDown: handleKeyDown,
|
5492
|
-
disabled: disabled,
|
5493
|
-
children: /*#__PURE__*/ jsx(Drag, {})
|
5494
|
-
}) : null,
|
5495
|
-
/*#__PURE__*/ jsxs(Flex, {
|
5496
|
-
width: "100%",
|
5497
|
-
minWidth: 0,
|
5498
|
-
justifyContent: "space-between",
|
5499
|
-
children: [
|
5500
|
-
/*#__PURE__*/ jsx(Box, {
|
5501
|
-
minWidth: 0,
|
5502
|
-
paddingTop: 1,
|
5503
|
-
paddingBottom: 1,
|
5504
|
-
paddingRight: 4,
|
5505
|
-
children: /*#__PURE__*/ jsx(Tooltip, {
|
5506
|
-
description: label,
|
5507
|
-
children: isModalOpen ? /*#__PURE__*/ jsx(CustomTextButton, {
|
5508
|
-
onClick: handleChangeModalContent,
|
5509
|
-
children: label
|
5510
|
-
}) : /*#__PURE__*/ jsx(CustomTextButton, {
|
5511
|
-
onClick: ()=>{
|
5512
|
-
setIsModalOpen(true);
|
5513
|
-
handleChangeModalContent();
|
5514
|
-
},
|
5515
|
-
children: label
|
5516
|
-
})
|
5517
|
-
})
|
5518
|
-
}),
|
5519
|
-
status ? /*#__PURE__*/ jsx(DocumentStatus, {
|
5520
|
-
status: status
|
5521
|
-
}) : null,
|
5522
|
-
isModalOpen && /*#__PURE__*/ jsx(RelationModal, {
|
5523
|
-
open: isModalOpen,
|
5524
|
-
onToggle: ()=>{
|
5525
|
-
setIsModalOpen(!isModalOpen);
|
5526
|
-
},
|
5527
|
-
model: targetModel,
|
5528
|
-
id: documentId ? documentId : apiData?.documentId,
|
5529
|
-
relationUrl: href
|
5530
|
-
})
|
5531
|
-
]
|
5532
|
-
})
|
5533
|
-
]
|
5534
|
-
}),
|
5535
|
-
/*#__PURE__*/ jsx(Box, {
|
5536
|
-
paddingLeft: 4,
|
5537
|
-
children: /*#__PURE__*/ jsx(IconButton, {
|
5538
|
-
onClick: ()=>handleDisconnect(relations[index]),
|
5539
|
-
disabled: disabled,
|
5540
|
-
label: formatMessage({
|
5541
|
-
id: getTranslation('relation.disconnect'),
|
5542
|
-
defaultMessage: 'Remove'
|
5543
|
-
}),
|
5544
|
-
variant: "ghost",
|
5545
|
-
size: "S",
|
5546
|
-
children: /*#__PURE__*/ jsx(Cross, {})
|
5547
|
-
})
|
5548
|
-
})
|
5549
|
-
]
|
5550
|
-
})
|
5551
|
-
});
|
5552
|
-
};
|
5553
5340
|
const ListItem = ({ data, index, style })=>{
|
5554
|
-
const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations } = data;
|
5341
|
+
const { ariaDescribedBy, canDrag = false, disabled = false, handleCancel, handleDisconnect, handleDropItem, handleGrabItem, handleMoveItem, name, relations, targetModel } = data;
|
5555
5342
|
const { formatMessage } = useIntl();
|
5556
|
-
const { href, id, label, status } = relations[index];
|
5343
|
+
const { href, id, label, status, documentId, apiData, locale } = relations[index];
|
5557
5344
|
const [{ handlerId, isDragging, handleKeyDown }, relationRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(canDrag && !disabled, {
|
5558
5345
|
type: `${ItemTypes.RELATION}_${name}`,
|
5559
5346
|
index,
|
@@ -5620,18 +5407,16 @@ const ListItem = ({ data, index, style })=>{
|
|
5620
5407
|
paddingTop: 1,
|
5621
5408
|
paddingBottom: 1,
|
5622
5409
|
paddingRight: 4,
|
5623
|
-
children: /*#__PURE__*/ jsx(
|
5624
|
-
|
5625
|
-
|
5626
|
-
|
5627
|
-
|
5628
|
-
|
5629
|
-
|
5630
|
-
|
5631
|
-
|
5632
|
-
|
5633
|
-
children: label
|
5634
|
-
})
|
5410
|
+
children: /*#__PURE__*/ jsx(RelationModalForm, {
|
5411
|
+
triggerButtonLabel: label,
|
5412
|
+
relation: {
|
5413
|
+
documentId: documentId ?? apiData?.documentId,
|
5414
|
+
model: targetModel,
|
5415
|
+
collectionType: getCollectionType(href),
|
5416
|
+
params: {
|
5417
|
+
locale: locale || apiData?.locale || null
|
5418
|
+
}
|
5419
|
+
}
|
5635
5420
|
})
|
5636
5421
|
}),
|
5637
5422
|
status ? /*#__PURE__*/ jsx(DocumentStatus, {
|
@@ -5701,7 +5486,6 @@ const RelationItemPlaceholder = ()=>/*#__PURE__*/ jsx(Box, {
|
|
5701
5486
|
height: `calc(100% - ${RELATION_GUTTER}px)`
|
5702
5487
|
});
|
5703
5488
|
const MemoizedRelationsField = /*#__PURE__*/ React.memo(RelationsField);
|
5704
|
-
const MemoizedUnstableRelationsField = /*#__PURE__*/ React.memo(UnstableRelationsField);
|
5705
5489
|
|
5706
5490
|
const uidApi = contentManagerApi.injectEndpoints({
|
5707
5491
|
endpoints: (builder)=>({
|
@@ -7871,22 +7655,27 @@ const Wysiwyg = /*#__PURE__*/ React.forwardRef(({ hint, disabled, label, name, p
|
|
7871
7655
|
});
|
7872
7656
|
const MemoizedWysiwyg = /*#__PURE__*/ React.memo(Wysiwyg);
|
7873
7657
|
|
7874
|
-
|
7875
|
-
|
7876
|
-
|
7877
|
-
|
7878
|
-
|
7879
|
-
|
7880
|
-
|
7658
|
+
/**
|
7659
|
+
* @internal
|
7660
|
+
*
|
7661
|
+
* @description An abstraction around the regular form input renderer designed
|
7662
|
+
* specifically to be used in the EditView of the content-manager this understands
|
7663
|
+
* the complete EditFieldLayout and will handle RBAC conditions and rendering CM specific
|
7664
|
+
* components such as Blocks / Relations.
|
7665
|
+
*/ const InputRenderer = ({ visible, hint: providedHint, document, ...props })=>{
|
7666
|
+
const { model: rootModel } = useDoc();
|
7667
|
+
const documentLayout = useDocumentLayout(document.schema?.uid ?? rootModel);
|
7668
|
+
const components = documentLayout.edit.components;
|
7669
|
+
const collectionType = document.schema?.kind === 'collectionType' ? 'collection-types' : 'single-types';
|
7881
7670
|
const isInDynamicZone = useDynamicZone('isInDynamicZone', (state)=>state.isInDynamicZone);
|
7882
7671
|
const isFormDisabled = useForm('InputRenderer', (state)=>state.disabled);
|
7883
7672
|
const canCreateFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canCreateFields);
|
7884
7673
|
const canReadFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canReadFields);
|
7885
7674
|
const canUpdateFields = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUpdateFields);
|
7886
7675
|
const canUserAction = useDocumentRBAC('InputRenderer', (rbac)=>rbac.canUserAction);
|
7887
|
-
let idToCheck =
|
7676
|
+
let idToCheck = document.document?.documentId;
|
7888
7677
|
if (collectionType === SINGLE_TYPES) {
|
7889
|
-
idToCheck = document?.documentId;
|
7678
|
+
idToCheck = document?.document?.documentId;
|
7890
7679
|
}
|
7891
7680
|
const editableFields = idToCheck ? canUpdateFields : canCreateFields;
|
7892
7681
|
const readableFields = idToCheck ? canReadFields : canCreateFields;
|
@@ -7900,8 +7689,6 @@ const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
|
|
7900
7689
|
props.attribute.customField
|
7901
7690
|
] : undefined);
|
7902
7691
|
const hint = useFieldHint(providedHint, props.attribute);
|
7903
|
-
const { edit: { components: rootDocumentComponents } } = useDocLayout();
|
7904
|
-
const components = Object.keys(rootDocumentComponents).length !== 0 ? rootDocumentComponents : documentLayout.edit.components;
|
7905
7692
|
// We pass field in case of Custom Fields to keep backward compatibility
|
7906
7693
|
const field = useField(props.name);
|
7907
7694
|
if (!visible) {
|
@@ -7978,13 +7765,6 @@ const InputRenderer = ({ visible, hint: providedHint, ...props })=>{
|
|
7978
7765
|
disabled: fieldIsDisabled
|
7979
7766
|
});
|
7980
7767
|
case 'relation':
|
7981
|
-
if (window.strapi.future.isEnabled('unstableRelationsOnTheFly')) {
|
7982
|
-
return /*#__PURE__*/ jsx(MemoizedUnstableRelationsField, {
|
7983
|
-
...props,
|
7984
|
-
hint: hint,
|
7985
|
-
disabled: fieldIsDisabled
|
7986
|
-
});
|
7987
|
-
}
|
7988
7768
|
return /*#__PURE__*/ jsx(MemoizedRelationsField, {
|
7989
7769
|
...props,
|
7990
7770
|
hint: hint,
|
@@ -8090,10 +7870,12 @@ const RESPONSIVE_CONTAINER_BREAKPOINTS = {
|
|
8090
7870
|
const ResponsiveGridRoot = styled(Grid$1.Root)`
|
8091
7871
|
container-type: inline-size;
|
8092
7872
|
`;
|
8093
|
-
|
8094
|
-
|
8095
|
-
|
8096
|
-
|
7873
|
+
const ResponsiveGridItem = /**
|
7874
|
+
* TODO:
|
7875
|
+
* JSDOM cannot handle container queries.
|
7876
|
+
* This is a temporary workaround so that tests do not fail in the CI when jestdom throws an error
|
7877
|
+
* for failing to parse the stylesheet.
|
7878
|
+
*/ process.env.NODE_ENV !== 'test' ? styled(Grid$1.Item)`
|
8097
7879
|
grid-column: span 12;
|
8098
7880
|
@container (min-width: ${RESPONSIVE_CONTAINER_BREAKPOINTS.sm}) {
|
8099
7881
|
${({ col })=>col && `grid-column: span ${col};`}
|
@@ -8101,10 +7883,9 @@ process.env.NODE_ENV !== 'test' ? styled(Grid$1.Item)`
|
|
8101
7883
|
` : styled(Grid$1.Item)`
|
8102
7884
|
grid-column: span 12;
|
8103
7885
|
`;
|
8104
|
-
const FormLayout = ({ layout, hasBackground = true })=>{
|
7886
|
+
const FormLayout = ({ layout, document, hasBackground = true })=>{
|
8105
7887
|
const { formatMessage } = useIntl();
|
8106
|
-
const
|
8107
|
-
const model = documentMeta.model;
|
7888
|
+
const model = document.schema?.modelName;
|
8108
7889
|
return /*#__PURE__*/ jsx(Flex, {
|
8109
7890
|
direction: "column",
|
8110
7891
|
alignItems: "stretch",
|
@@ -8129,7 +7910,8 @@ const FormLayout = ({ layout, hasBackground = true })=>{
|
|
8129
7910
|
direction: "column",
|
8130
7911
|
alignItems: "stretch",
|
8131
7912
|
children: /*#__PURE__*/ jsx(MemoizedInputRenderer, {
|
8132
|
-
...fieldWithTranslatedLabel
|
7913
|
+
...fieldWithTranslatedLabel,
|
7914
|
+
document: document
|
8133
7915
|
})
|
8134
7916
|
})
|
8135
7917
|
}, field.name);
|
@@ -8163,7 +7945,8 @@ const FormLayout = ({ layout, hasBackground = true })=>{
|
|
8163
7945
|
direction: "column",
|
8164
7946
|
alignItems: "stretch",
|
8165
7947
|
children: /*#__PURE__*/ jsx(MemoizedInputRenderer, {
|
8166
|
-
...fieldWithTranslatedLabel
|
7948
|
+
...fieldWithTranslatedLabel,
|
7949
|
+
document: document
|
8167
7950
|
})
|
8168
7951
|
}, field.name);
|
8169
7952
|
})
|
@@ -8179,6 +7962,7 @@ const NonRepeatableComponent = ({ attribute, name, children, layout })=>{
|
|
8179
7962
|
const { value } = useField(name);
|
8180
7963
|
const level = useComponent('NonRepeatableComponent', (state)=>state.level);
|
8181
7964
|
const isNested = level > 0;
|
7965
|
+
const currentDocument = useDocumentContext('NonRepeatableComponent', (state)=>state.document);
|
8182
7966
|
return /*#__PURE__*/ jsx(ComponentProvider, {
|
8183
7967
|
id: value?.id,
|
8184
7968
|
uid: attribute.component,
|
@@ -8219,7 +8003,8 @@ const NonRepeatableComponent = ({ attribute, name, children, layout })=>{
|
|
8219
8003
|
children: children({
|
8220
8004
|
...field,
|
8221
8005
|
label: translatedLabel,
|
8222
|
-
name: completeFieldName
|
8006
|
+
name: completeFieldName,
|
8007
|
+
document: currentDocument
|
8223
8008
|
})
|
8224
8009
|
}, completeFieldName);
|
8225
8010
|
})
|
@@ -8237,7 +8022,8 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
|
|
8237
8022
|
const search = React.useMemo(()=>new URLSearchParams(searchString), [
|
8238
8023
|
searchString
|
8239
8024
|
]);
|
8240
|
-
const
|
8025
|
+
const currentDocument = useDocumentContext('RepeatableComponent', (state)=>state.document);
|
8026
|
+
const components = currentDocument.components;
|
8241
8027
|
const { value = [], error, rawError } = useField(name);
|
8242
8028
|
const addFieldRow = useForm('RepeatableComponent', (state)=>state.addFieldRow);
|
8243
8029
|
const moveFieldRow = useForm('RepeatableComponent', (state)=>state.moveFieldRow);
|
@@ -8440,7 +8226,8 @@ const RepeatableComponent = ({ attribute, disabled, name, mainField, children, l
|
|
8440
8226
|
children: children({
|
8441
8227
|
...field,
|
8442
8228
|
label: translatedLabel,
|
8443
|
-
name: completeFieldName
|
8229
|
+
name: completeFieldName,
|
8230
|
+
document: currentDocument
|
8444
8231
|
})
|
8445
8232
|
}, completeFieldName);
|
8446
8233
|
})
|
@@ -8667,5 +8454,5 @@ const ComponentInput = ({ label, required, name, attribute, disabled, labelActio
|
|
8667
8454
|
};
|
8668
8455
|
const MemoizedComponentInput = /*#__PURE__*/ React.memo(ComponentInput);
|
8669
8456
|
|
8670
|
-
export { DisconnectButton as D, FlexWrapper as F, LinkEllipsis as L, MemoizedUIDInput as M, NotAllowedInput as N,
|
8671
|
-
//# sourceMappingURL=Input-
|
8457
|
+
export { DisconnectButton as D, FlexWrapper as F, LinkEllipsis as L, MemoizedUIDInput as M, NotAllowedInput as N, FormLayout as a, useDynamicZone as b, useFieldHint as c, MemoizedWysiwyg as d, DynamicZone as e, MemoizedComponentInput as f, MemoizedBlocksInput as g, useLazyComponents as u };
|
8458
|
+
//# sourceMappingURL=Input-DWQWd5MK.mjs.map
|