multi-content-type-relation 2.1.1 → 2.2.1
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/README.md +6 -0
- package/dist/_chunks/en-Bk9okOMP.js +0 -1
- package/dist/_chunks/en-Cj4T04Z2.mjs +0 -1
- package/dist/_chunks/fr-KHPiQOFP.mjs +0 -1
- package/dist/_chunks/fr-ZS3aTnjj.js +0 -1
- package/dist/_chunks/{index-BHcolZ4N.mjs → index-BGSdnZnr.mjs} +37 -13
- package/dist/_chunks/index-Bu99PZdl.js +470 -0
- package/dist/_chunks/{index-BtldAbIW.js → index-CEXSrD4g.js} +40 -16
- package/dist/_chunks/index-DEkcD0zR.mjs +470 -0
- package/dist/admin/index.js +1 -2
- package/dist/admin/index.mjs +1 -2
- package/dist/admin/src/components/Input/InputContentSuggestions.d.ts +1 -2
- package/dist/admin/src/components/Input/TableItem.d.ts +2 -3
- package/dist/admin/src/helpers/content.d.ts +1 -1
- package/dist/server/index.js +129 -61
- package/dist/server/index.mjs +129 -61
- package/dist/server/src/controllers/controller.d.ts +1 -0
- package/dist/server/src/controllers/index.d.ts +1 -0
- package/dist/server/src/index.d.ts +1 -0
- package/dist/server/src/interface.d.ts +2 -0
- package/package.json +2 -1
- package/dist/_chunks/en-Bk9okOMP.js.map +0 -1
- package/dist/_chunks/en-Cj4T04Z2.mjs.map +0 -1
- package/dist/_chunks/fr-KHPiQOFP.mjs.map +0 -1
- package/dist/_chunks/fr-ZS3aTnjj.js.map +0 -1
- package/dist/_chunks/index-BHcolZ4N.mjs.map +0 -1
- package/dist/_chunks/index-BtldAbIW.js.map +0 -1
- package/dist/_chunks/index-CktBIBSM.js +0 -333
- package/dist/_chunks/index-CktBIBSM.js.map +0 -1
- package/dist/_chunks/index-CxWt3llJ.js +0 -3567
- package/dist/_chunks/index-CxWt3llJ.js.map +0 -1
- package/dist/_chunks/index-CyBD50Lc.js +0 -3568
- package/dist/_chunks/index-CyBD50Lc.js.map +0 -1
- package/dist/_chunks/index-D6nv39Fp.mjs +0 -3565
- package/dist/_chunks/index-D6nv39Fp.mjs.map +0 -1
- package/dist/_chunks/index-DGcImy9s.mjs +0 -3566
- package/dist/_chunks/index-DGcImy9s.mjs.map +0 -1
- package/dist/_chunks/index-DdX2rVzB.mjs +0 -334
- package/dist/_chunks/index-DdX2rVzB.mjs.map +0 -1
- package/dist/admin/index.js.map +0 -1
- package/dist/admin/index.mjs.map +0 -1
- package/dist/server/index.js.map +0 -1
- package/dist/server/index.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -74,6 +74,12 @@ If, for some reasons, you want to hydrate the relations of the relations of the
|
|
|
74
74
|
|
|
75
75
|
This setting show debug log of the plugin for better understanding
|
|
76
76
|
|
|
77
|
+
###### Key: `disableRevertRelations`
|
|
78
|
+
|
|
79
|
+
> `required:` no | `type:` Boolean | default false
|
|
80
|
+
|
|
81
|
+
This setting disable relaction MCTR if needed for performances/stability concerns
|
|
82
|
+
|
|
77
83
|
## Submit an issue
|
|
78
84
|
|
|
79
85
|
You can use github issues to raise an issue about this plugin
|
|
@@ -51,15 +51,22 @@ const fetchMatchingContent = async (keyword, contentTypes, locale) => {
|
|
|
51
51
|
total
|
|
52
52
|
};
|
|
53
53
|
};
|
|
54
|
-
const formatToStrapiField = (entries) => {
|
|
54
|
+
const formatToStrapiField = (entries, locale) => {
|
|
55
55
|
if (entries.length === 0) return "";
|
|
56
|
-
|
|
57
|
-
entries.map((entry) =>
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
const storedData = JSON.stringify(
|
|
57
|
+
entries.map((entry) => {
|
|
58
|
+
const obj = {
|
|
59
|
+
uid: entry.uid,
|
|
60
|
+
documentId: entry.item.documentId,
|
|
61
|
+
MRCT: true
|
|
62
|
+
};
|
|
63
|
+
if (locale) {
|
|
64
|
+
obj.locale = locale;
|
|
65
|
+
}
|
|
66
|
+
return obj;
|
|
67
|
+
}).filter(Boolean)
|
|
62
68
|
);
|
|
69
|
+
return storedData;
|
|
63
70
|
};
|
|
64
71
|
const validateCurrentRelations = async (entries) => {
|
|
65
72
|
const { post } = getFetchClient();
|
|
@@ -108,23 +115,41 @@ const SidePanel = () => {
|
|
|
108
115
|
model: uid,
|
|
109
116
|
isSingleType
|
|
110
117
|
} = unstable_useContentManagerContext();
|
|
118
|
+
const currentLocale = new URLSearchParams(location.search).get(
|
|
119
|
+
"plugins[i18n][locale]"
|
|
120
|
+
);
|
|
111
121
|
const [linkedContent, setLinkedContent] = useState([]);
|
|
112
|
-
const [loading, setLoading] = useState(
|
|
122
|
+
const [loading, setLoading] = useState(true);
|
|
123
|
+
const [disabled, setDisabledFeature] = useState(false);
|
|
113
124
|
useEffect(() => {
|
|
114
125
|
const fetchRevertRelations = async () => {
|
|
115
126
|
const { post } = getFetchClient();
|
|
116
127
|
const response = await post(`/${pluginId}/fetch-revert-relations`, {
|
|
117
128
|
documentId,
|
|
118
129
|
uid,
|
|
119
|
-
isSingleType
|
|
130
|
+
isSingleType,
|
|
131
|
+
locale: currentLocale
|
|
120
132
|
});
|
|
121
133
|
setLinkedContent(Array.isArray(response.data) ? response.data.filter(Boolean) : []);
|
|
122
134
|
setLoading(false);
|
|
123
135
|
};
|
|
124
|
-
|
|
136
|
+
const fetchConfiguration = async () => {
|
|
137
|
+
const { get } = getFetchClient();
|
|
138
|
+
const response = await get(`/${pluginId}/get-configuration`);
|
|
139
|
+
if (response.data.disableRevertRelations) {
|
|
140
|
+
setDisabledFeature(true);
|
|
141
|
+
setLoading(false);
|
|
142
|
+
} else {
|
|
143
|
+
fetchRevertRelations();
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
fetchConfiguration();
|
|
125
147
|
}, []);
|
|
126
148
|
if (loading)
|
|
127
149
|
return /* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(Loader, {}) });
|
|
150
|
+
if (disabled) {
|
|
151
|
+
return /* @__PURE__ */ jsx("div", {});
|
|
152
|
+
}
|
|
128
153
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
129
154
|
/* @__PURE__ */ jsx(Divider, {}),
|
|
130
155
|
/* @__PURE__ */ jsxs(Box, { width: "100%", marginTop: 4, children: [
|
|
@@ -164,7 +189,7 @@ const SidePanel = () => {
|
|
|
164
189
|
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
|
|
165
190
|
"a",
|
|
166
191
|
{
|
|
167
|
-
href: content.isSingleType ? `/admin/content-manager/single-types/${content.uid}` : `/admin/content-manager/collection-types/${content.uid}/${content.documentId}`,
|
|
192
|
+
href: content.isSingleType ? `/admin/content-manager/single-types/${content.uid}${currentLocale ? `?plugins[i18n][locale]=${currentLocale}` : ""}` : `/admin/content-manager/collection-types/${content.uid}/${content.documentId}${currentLocale ? `?plugins[i18n][locale]=${currentLocale}` : ""}`,
|
|
168
193
|
target: "_blank",
|
|
169
194
|
style: { textDecoration: "none" },
|
|
170
195
|
children: /* @__PURE__ */ jsx(
|
|
@@ -223,7 +248,7 @@ const index = {
|
|
|
223
248
|
components: {
|
|
224
249
|
Input: () => import(
|
|
225
250
|
/* webpackChunkName: "input-component" */
|
|
226
|
-
"./index-
|
|
251
|
+
"./index-DEkcD0zR.mjs"
|
|
227
252
|
)
|
|
228
253
|
},
|
|
229
254
|
inputSize: {
|
|
@@ -331,4 +356,3 @@ export {
|
|
|
331
356
|
useTranslate as u,
|
|
332
357
|
validateCurrentRelations as v
|
|
333
358
|
};
|
|
334
|
-
//# sourceMappingURL=index-BHcolZ4N.mjs.map
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const react = require("react");
|
|
5
|
+
const reactIntl = require("react-intl");
|
|
6
|
+
const reactRouterDom = require("react-router-dom");
|
|
7
|
+
const designSystem = require("@strapi/design-system");
|
|
8
|
+
const index = require("./index-CEXSrD4g.js");
|
|
9
|
+
const core = require("@dnd-kit/core");
|
|
10
|
+
const sortable = require("@dnd-kit/sortable");
|
|
11
|
+
const icons = require("@strapi/icons");
|
|
12
|
+
function useSearchedEntries(keyword, contentTypes, locale) {
|
|
13
|
+
const [loading, setLoading] = react.useState(false);
|
|
14
|
+
const [results, setResults] = react.useState([]);
|
|
15
|
+
const [total, setTotal] = react.useState(0);
|
|
16
|
+
async function fetchEntries() {
|
|
17
|
+
setResults([]);
|
|
18
|
+
setTotal(0);
|
|
19
|
+
if (loading || !keyword) return;
|
|
20
|
+
try {
|
|
21
|
+
const { data, total: total2 } = await index.fetchMatchingContent(
|
|
22
|
+
keyword,
|
|
23
|
+
contentTypes,
|
|
24
|
+
locale
|
|
25
|
+
);
|
|
26
|
+
setResults(data);
|
|
27
|
+
setTotal(total2);
|
|
28
|
+
} finally {
|
|
29
|
+
setLoading(false);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
react.useEffect(() => {
|
|
33
|
+
const timeout = setTimeout(() => fetchEntries(), 500);
|
|
34
|
+
return () => clearTimeout(timeout);
|
|
35
|
+
}, [keyword]);
|
|
36
|
+
return react.useMemo(
|
|
37
|
+
() => ({
|
|
38
|
+
loading,
|
|
39
|
+
results,
|
|
40
|
+
total
|
|
41
|
+
}),
|
|
42
|
+
[results, total]
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
const PublicationState = ({
|
|
46
|
+
isPublished,
|
|
47
|
+
hasDraftAndPublish
|
|
48
|
+
}) => {
|
|
49
|
+
const { translate } = index.useTranslate();
|
|
50
|
+
const configuration = react.useMemo(() => {
|
|
51
|
+
const conf = {
|
|
52
|
+
variant: "alternative",
|
|
53
|
+
text: translate("publicationState.na")
|
|
54
|
+
};
|
|
55
|
+
if (hasDraftAndPublish) {
|
|
56
|
+
conf.variant = isPublished ? "success" : "secondary";
|
|
57
|
+
conf.text = isPublished ? translate("publicationState.published") : translate("publicationState.draft");
|
|
58
|
+
}
|
|
59
|
+
return conf;
|
|
60
|
+
}, [isPublished, hasDraftAndPublish, translate]);
|
|
61
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
62
|
+
designSystem.Status,
|
|
63
|
+
{
|
|
64
|
+
showbullet: "false",
|
|
65
|
+
variant: configuration.variant,
|
|
66
|
+
size: "S",
|
|
67
|
+
width: "min-content",
|
|
68
|
+
style: { paddingLeft: 12, paddingRight: 12 },
|
|
69
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: `${configuration.variant}700`, children: configuration.text })
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
const CSS = /* @__PURE__ */ Object.freeze({
|
|
74
|
+
Translate: {
|
|
75
|
+
toString(transform) {
|
|
76
|
+
if (!transform) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const {
|
|
80
|
+
x,
|
|
81
|
+
y
|
|
82
|
+
} = transform;
|
|
83
|
+
return "translate3d(" + (x ? Math.round(x) : 0) + "px, " + (y ? Math.round(y) : 0) + "px, 0)";
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
Scale: {
|
|
87
|
+
toString(transform) {
|
|
88
|
+
if (!transform) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const {
|
|
92
|
+
scaleX,
|
|
93
|
+
scaleY
|
|
94
|
+
} = transform;
|
|
95
|
+
return "scaleX(" + scaleX + ") scaleY(" + scaleY + ")";
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
Transform: {
|
|
99
|
+
toString(transform) {
|
|
100
|
+
if (!transform) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
return [CSS.Translate.toString(transform), CSS.Scale.toString(transform)].join(" ");
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
Transition: {
|
|
107
|
+
toString(_ref) {
|
|
108
|
+
let {
|
|
109
|
+
property,
|
|
110
|
+
duration,
|
|
111
|
+
easing
|
|
112
|
+
} = _ref;
|
|
113
|
+
return property + " " + duration + "ms " + easing;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
const TableItem = ({
|
|
118
|
+
entry,
|
|
119
|
+
id,
|
|
120
|
+
type,
|
|
121
|
+
disabled,
|
|
122
|
+
onAdd,
|
|
123
|
+
onDelete
|
|
124
|
+
}) => {
|
|
125
|
+
const { translate } = index.useTranslate();
|
|
126
|
+
const contentType = index.getContentTypeForUid(entry.uid);
|
|
127
|
+
const location = reactRouterDom.useLocation();
|
|
128
|
+
const { setDraggableNodeRef, setDroppableNodeRef, transform, transition, attributes, listeners } = sortable.useSortable({ id });
|
|
129
|
+
const style = {
|
|
130
|
+
transform: CSS.Transform.toString(transform),
|
|
131
|
+
transition
|
|
132
|
+
};
|
|
133
|
+
const [currentLocale, setCurrentLocale] = react.useState("");
|
|
134
|
+
react.useEffect(() => {
|
|
135
|
+
const searchParams = new URLSearchParams(location.search);
|
|
136
|
+
const locale = searchParams.get("plugins[i18n][locale]");
|
|
137
|
+
if (!locale) return;
|
|
138
|
+
setCurrentLocale(locale);
|
|
139
|
+
}, [location]);
|
|
140
|
+
const goToEntry = () => {
|
|
141
|
+
if (!currentLocale) return;
|
|
142
|
+
const contentTypes = window.sessionStorage.getItem("mctr::content_types");
|
|
143
|
+
if (contentTypes) {
|
|
144
|
+
try {
|
|
145
|
+
const parsedContentTypes = JSON.parse(contentTypes);
|
|
146
|
+
if (Array.isArray(parsedContentTypes)) {
|
|
147
|
+
const contentType2 = parsedContentTypes.find(
|
|
148
|
+
(ct) => ct.uid === entry.uid
|
|
149
|
+
);
|
|
150
|
+
if (contentType2) {
|
|
151
|
+
const kind = contentType2.kind;
|
|
152
|
+
let url = "";
|
|
153
|
+
if (kind === "collectionType") {
|
|
154
|
+
url = `/admin/content-manager/collection-types/${entry.uid}/${entry.item.documentId}`;
|
|
155
|
+
} else {
|
|
156
|
+
url = `/admin/content-manager/single-types/${entry.uid}`;
|
|
157
|
+
}
|
|
158
|
+
url += `?plugins[i18n][locale]=${currentLocale}`;
|
|
159
|
+
window.open(url, "_blank");
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} catch (e) {
|
|
164
|
+
console.error("[MCTR] Failed to retrieve content types");
|
|
165
|
+
}
|
|
166
|
+
} else {
|
|
167
|
+
alert(translate("tableItem.error"));
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
171
|
+
"tr",
|
|
172
|
+
{
|
|
173
|
+
style,
|
|
174
|
+
ref: setDroppableNodeRef,
|
|
175
|
+
...attributes,
|
|
176
|
+
children: [
|
|
177
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: type === "selected" ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.IconButton, { ref: setDraggableNodeRef, ...listeners, children: /* @__PURE__ */ jsxRuntime.jsx(icons.Drag, {}) }) : null }),
|
|
178
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { color: "neutral800", children: entry.item[entry.searchableField] }) }),
|
|
179
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { color: "neutral800", children: entry.displayName }) }),
|
|
180
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
181
|
+
PublicationState,
|
|
182
|
+
{
|
|
183
|
+
isPublished: !!entry.item.publishedAt,
|
|
184
|
+
hasDraftAndPublish: contentType?.options?.draftAndPublish
|
|
185
|
+
}
|
|
186
|
+
) }),
|
|
187
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { children: [
|
|
188
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
189
|
+
designSystem.IconButton,
|
|
190
|
+
{
|
|
191
|
+
label: translate("tableItem.goToEntry"),
|
|
192
|
+
onClick: goToEntry,
|
|
193
|
+
style: { "marginRight": "5px" },
|
|
194
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(icons.Eye, {})
|
|
195
|
+
}
|
|
196
|
+
),
|
|
197
|
+
type === "suggestion" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
198
|
+
designSystem.IconButton,
|
|
199
|
+
{
|
|
200
|
+
label: translate("tableItem.add"),
|
|
201
|
+
onClick: () => onAdd(entry),
|
|
202
|
+
disabled,
|
|
203
|
+
marginLeft: 1,
|
|
204
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {})
|
|
205
|
+
}
|
|
206
|
+
) : type === "selected" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
207
|
+
designSystem.IconButton,
|
|
208
|
+
{
|
|
209
|
+
label: translate("tableItem.delete"),
|
|
210
|
+
onClick: () => onDelete(entry),
|
|
211
|
+
marginLeft: 1,
|
|
212
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {})
|
|
213
|
+
}
|
|
214
|
+
) : null
|
|
215
|
+
] }) })
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
};
|
|
220
|
+
function InputContentSuggestions({
|
|
221
|
+
uniqueId,
|
|
222
|
+
suggestions,
|
|
223
|
+
selected,
|
|
224
|
+
onAddEntry,
|
|
225
|
+
onDeleteEntry,
|
|
226
|
+
onEntriesSorted,
|
|
227
|
+
maximum
|
|
228
|
+
}) {
|
|
229
|
+
const { translate } = index.useTranslate();
|
|
230
|
+
const suggestionAsSelectedEntry = react.useMemo(() => {
|
|
231
|
+
return (suggestions || []).flatMap(
|
|
232
|
+
(suggestion) => suggestion.results.map((entrySuggestion) => ({
|
|
233
|
+
displayName: suggestion.displayName,
|
|
234
|
+
item: entrySuggestion,
|
|
235
|
+
searchableField: suggestion.searchableField,
|
|
236
|
+
uid: suggestion.uid
|
|
237
|
+
}))
|
|
238
|
+
).slice(0, 10);
|
|
239
|
+
}, [suggestions]);
|
|
240
|
+
const buildSelectedId = (entry) => {
|
|
241
|
+
return `${uniqueId}-${entry.uid}-${entry.item.documentId}`;
|
|
242
|
+
};
|
|
243
|
+
const availableSuggestions = react.useMemo(() => {
|
|
244
|
+
const selectedIdentifiers = (selected || []).map(buildSelectedId);
|
|
245
|
+
return suggestionAsSelectedEntry.filter(
|
|
246
|
+
(suggestion) => !selectedIdentifiers.includes(buildSelectedId(suggestion))
|
|
247
|
+
);
|
|
248
|
+
}, [suggestions, selected]);
|
|
249
|
+
const onAdd = (entry) => {
|
|
250
|
+
if (typeof onAddEntry === "function") {
|
|
251
|
+
onAddEntry(entry);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
const onDelete = (entry) => {
|
|
255
|
+
if (typeof onDeleteEntry === "function") {
|
|
256
|
+
onDeleteEntry(entry);
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
const onSort = (entries) => {
|
|
260
|
+
if (typeof onEntriesSorted === "function") {
|
|
261
|
+
onEntriesSorted(entries);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
const sensors = core.useSensors(
|
|
265
|
+
core.useSensor(core.PointerSensor)
|
|
266
|
+
);
|
|
267
|
+
const sortableItems = react.useMemo(() => {
|
|
268
|
+
const items = selected?.map((entry) => buildSelectedId(entry)) ?? [];
|
|
269
|
+
return items;
|
|
270
|
+
}, [selected]);
|
|
271
|
+
const handleDragEnd = (event) => {
|
|
272
|
+
const { active, over } = event;
|
|
273
|
+
if (!active || !over) return;
|
|
274
|
+
if (active.id !== over.id) {
|
|
275
|
+
const oldIndex = selected.findIndex(
|
|
276
|
+
(entry) => buildSelectedId(entry) === active.id
|
|
277
|
+
);
|
|
278
|
+
const newIndex = selected.findIndex(
|
|
279
|
+
(entry) => buildSelectedId(entry) === over.id
|
|
280
|
+
);
|
|
281
|
+
onSort(sortable.arrayMove(selected, oldIndex, newIndex));
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
if (!availableSuggestions?.length && !selected?.length) return null;
|
|
285
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: [2, 0, 2, 0], background: "neutral100", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { style: { whiteSpace: "unset", borderCollapse: "separate", borderSpacing: "0 10px" }, children: [
|
|
286
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
|
287
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, {}),
|
|
288
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: translate("contentSuggestions.title") }) }),
|
|
289
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: translate("contentSuggestions.contentType") }) }),
|
|
290
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", children: translate("contentSuggestions.state") }) })
|
|
291
|
+
] }) }),
|
|
292
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tbody, { children: [
|
|
293
|
+
selected?.length ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
294
|
+
core.DndContext,
|
|
295
|
+
{
|
|
296
|
+
sensors,
|
|
297
|
+
collisionDetection: core.closestCenter,
|
|
298
|
+
onDragEnd: handleDragEnd,
|
|
299
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
300
|
+
sortable.SortableContext,
|
|
301
|
+
{
|
|
302
|
+
items: sortableItems,
|
|
303
|
+
strategy: sortable.verticalListSortingStrategy,
|
|
304
|
+
children: selected.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
305
|
+
TableItem,
|
|
306
|
+
{
|
|
307
|
+
id: buildSelectedId(entry),
|
|
308
|
+
entry,
|
|
309
|
+
type: "selected",
|
|
310
|
+
onDelete
|
|
311
|
+
},
|
|
312
|
+
buildSelectedId(entry)
|
|
313
|
+
))
|
|
314
|
+
}
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
) }) : null,
|
|
318
|
+
availableSuggestions.length && selected?.length ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tr, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { colSpan: 5, children: /* @__PURE__ */ jsxRuntime.jsx("hr", { style: { width: "100%" } }) }) }) : null,
|
|
319
|
+
availableSuggestions.map((entry) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
320
|
+
TableItem,
|
|
321
|
+
{
|
|
322
|
+
id: buildSelectedId(entry),
|
|
323
|
+
entry,
|
|
324
|
+
type: "suggestion",
|
|
325
|
+
onAdd,
|
|
326
|
+
disabled: typeof maximum === "number" ? (selected?.length ?? 0) >= maximum : false
|
|
327
|
+
},
|
|
328
|
+
buildSelectedId(entry)
|
|
329
|
+
))
|
|
330
|
+
] })
|
|
331
|
+
] }) });
|
|
332
|
+
}
|
|
333
|
+
const MainInput = ({
|
|
334
|
+
name,
|
|
335
|
+
error,
|
|
336
|
+
description,
|
|
337
|
+
onChange,
|
|
338
|
+
value,
|
|
339
|
+
labelAction,
|
|
340
|
+
label,
|
|
341
|
+
attribute,
|
|
342
|
+
required
|
|
343
|
+
}) => {
|
|
344
|
+
const { formatMessage } = reactIntl.useIntl();
|
|
345
|
+
const { translate } = index.useTranslate();
|
|
346
|
+
const location = reactRouterDom.useLocation();
|
|
347
|
+
const maximumItems = attribute.options.max;
|
|
348
|
+
const minimumItems = attribute.options.min || 0;
|
|
349
|
+
const currentLocale = new URLSearchParams(location.search).get(
|
|
350
|
+
"plugins[i18n][locale]"
|
|
351
|
+
);
|
|
352
|
+
const [keyword, setKeyword] = react.useState("");
|
|
353
|
+
const [selected, setSelected] = react.useState([]);
|
|
354
|
+
const [loading, setLoading] = react.useState(true);
|
|
355
|
+
react.useEffect(() => {
|
|
356
|
+
const value2 = selected.length > maximumItems || selected.length < minimumItems ? [] : selected;
|
|
357
|
+
onChange({ target: { name, value: index.formatToStrapiField(value2, currentLocale) } });
|
|
358
|
+
}, [selected]);
|
|
359
|
+
const hint = react.useMemo(() => {
|
|
360
|
+
const minLabel = minimumItems > 0 ? `${translate("input.hint.min")} ${minimumItems} ${minimumItems > 1 ? translate("input.hint.entries") : translate("input.hint.entry")}` : "";
|
|
361
|
+
const maxLabel = maximumItems > 0 ? `${translate("input.hint.max")} ${maximumItems} ${maximumItems > 1 ? translate("input.hint.entries") : translate("input.hint.entry")}` : "";
|
|
362
|
+
return `
|
|
363
|
+
${minLabel ? `${minLabel}` : ""}
|
|
364
|
+
${minLabel && maxLabel ? ", " : ""}
|
|
365
|
+
${maxLabel}
|
|
366
|
+
${minLabel || maxLabel ? translate("input.hint.separator") : ""}
|
|
367
|
+
${selected.length} ${translate("input.hint.selected")}
|
|
368
|
+
`;
|
|
369
|
+
}, [selected, maximumItems, minimumItems, translate]);
|
|
370
|
+
const inputError = react.useMemo(() => {
|
|
371
|
+
if (!error) return "";
|
|
372
|
+
if (selected.length < minimumItems)
|
|
373
|
+
return `${error} - ${translate("input.error.min")} ${minimumItems} ${translate("input.error.required")}`;
|
|
374
|
+
if (selected.length > maximumItems)
|
|
375
|
+
return `${error} - ${translate("input.error.max")} ${maximumItems} ${translate("input.error.required")}`;
|
|
376
|
+
return error;
|
|
377
|
+
}, [error, maximumItems, minimumItems, selected, translate]);
|
|
378
|
+
const { loading: searchLoading, results } = useSearchedEntries(
|
|
379
|
+
keyword,
|
|
380
|
+
attribute.options.contentTypes,
|
|
381
|
+
currentLocale
|
|
382
|
+
);
|
|
383
|
+
react.useEffect(() => {
|
|
384
|
+
async function validateContent() {
|
|
385
|
+
if (!value) {
|
|
386
|
+
setLoading(false);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const entries = JSON.parse(value);
|
|
390
|
+
const result = await index.validateCurrentRelations(entries);
|
|
391
|
+
setSelected(result);
|
|
392
|
+
setLoading(false);
|
|
393
|
+
}
|
|
394
|
+
validateContent();
|
|
395
|
+
}, []);
|
|
396
|
+
const onAddEntry = (entry) => {
|
|
397
|
+
const alreadyDefined = selected.some(
|
|
398
|
+
(selectedEntry) => selectedEntry.uid === entry.uid && selectedEntry.item.id === entry.item.id
|
|
399
|
+
);
|
|
400
|
+
if (alreadyDefined) return;
|
|
401
|
+
setSelected([...selected, entry]);
|
|
402
|
+
};
|
|
403
|
+
const onDeleteEntry = (entry) => {
|
|
404
|
+
const newSelected = selected.filter(
|
|
405
|
+
(selectedEntry) => !(selectedEntry.uid === entry.uid && selectedEntry.item.id === entry.item.id)
|
|
406
|
+
);
|
|
407
|
+
setSelected(newSelected);
|
|
408
|
+
};
|
|
409
|
+
const onEntriesSorted = (entries) => {
|
|
410
|
+
setSelected(entries);
|
|
411
|
+
};
|
|
412
|
+
if (loading) return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, {});
|
|
413
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
414
|
+
designSystem.Field.Root,
|
|
415
|
+
{
|
|
416
|
+
name,
|
|
417
|
+
id: name,
|
|
418
|
+
error,
|
|
419
|
+
hint: description,
|
|
420
|
+
required,
|
|
421
|
+
children: [
|
|
422
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { action: labelAction, children: label }),
|
|
423
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
424
|
+
designSystem.TextInput,
|
|
425
|
+
{
|
|
426
|
+
placeholder: translate("input.placeholder"),
|
|
427
|
+
required,
|
|
428
|
+
hint,
|
|
429
|
+
error: inputError,
|
|
430
|
+
value: keyword,
|
|
431
|
+
onChange: (e) => setKeyword(e.target.value)
|
|
432
|
+
}
|
|
433
|
+
),
|
|
434
|
+
searchLoading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, {}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
435
|
+
InputContentSuggestions,
|
|
436
|
+
{
|
|
437
|
+
uniqueId: Date.now(),
|
|
438
|
+
suggestions: results,
|
|
439
|
+
selected,
|
|
440
|
+
onAddEntry,
|
|
441
|
+
onDeleteEntry,
|
|
442
|
+
onEntriesSorted,
|
|
443
|
+
maximum: maximumItems
|
|
444
|
+
}
|
|
445
|
+
)
|
|
446
|
+
]
|
|
447
|
+
}
|
|
448
|
+
);
|
|
449
|
+
};
|
|
450
|
+
const Index = (props) => {
|
|
451
|
+
const { locale } = reactIntl.useIntl();
|
|
452
|
+
const theme = react.useMemo(() => ({}), []);
|
|
453
|
+
const attribute = react.useMemo(() => {
|
|
454
|
+
if (!props.attribute) return props.attribute;
|
|
455
|
+
if (!props.attribute.options) return props.attribute;
|
|
456
|
+
if (!props.attribute.options.contentTypes) return props.attribute;
|
|
457
|
+
const contentTypes = Object.keys(
|
|
458
|
+
props.attribute.options.contentTypes
|
|
459
|
+
).filter((key) => props.attribute.options.contentTypes[key]);
|
|
460
|
+
return {
|
|
461
|
+
...props.attribute,
|
|
462
|
+
options: {
|
|
463
|
+
...props.attribute.options,
|
|
464
|
+
contentTypes: contentTypes.join(",")
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
}, [props.attribute]);
|
|
468
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.DesignSystemProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsx(MainInput, { ...props, attribute }) });
|
|
469
|
+
};
|
|
470
|
+
exports.default = Index;
|