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