@strapi/plugin-users-permissions 5.0.0-beta.0 → 5.0.0-beta.2

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.
Files changed (75) hide show
  1. package/admin/src/pages/AdvancedSettings/index.jsx +4 -4
  2. package/admin/src/pages/EmailTemplates/index.jsx +3 -4
  3. package/admin/src/pages/Providers/index.jsx +3 -4
  4. package/admin/src/pages/Roles/pages/CreatePage.jsx +3 -4
  5. package/admin/src/pages/Roles/pages/EditPage.jsx +3 -4
  6. package/admin/src/pages/Roles/pages/ListPage/index.jsx +3 -4
  7. package/dist/_chunks/{index-YtsLdO8d.js → index-EzbUy3No.js} +10 -10
  8. package/dist/_chunks/{index-YtsLdO8d.js.map → index-EzbUy3No.js.map} +1 -1
  9. package/dist/_chunks/{index-eH8XAk_H.mjs → index-LsKlxP6S.mjs} +14 -30
  10. package/dist/_chunks/index-LsKlxP6S.mjs.map +1 -0
  11. package/dist/_chunks/{index-nKbtq7R-.js → index-NoTh1v48.js} +11 -17
  12. package/dist/_chunks/index-NoTh1v48.js.map +1 -0
  13. package/dist/_chunks/index-PCKQWB49-i9LmKIQp.mjs +10311 -0
  14. package/dist/_chunks/index-PCKQWB49-i9LmKIQp.mjs.map +1 -0
  15. package/dist/_chunks/index-PCKQWB49-mqonSm6K.js +10335 -0
  16. package/dist/_chunks/index-PCKQWB49-mqonSm6K.js.map +1 -0
  17. package/dist/_chunks/{index-AT8MwqgE.js → index-T3jMrI6s.js} +16 -22
  18. package/dist/_chunks/index-T3jMrI6s.js.map +1 -0
  19. package/dist/_chunks/{index-cC7LGLsK.mjs → index-a65O1P4_.mjs} +9 -15
  20. package/dist/_chunks/index-a65O1P4_.mjs.map +1 -0
  21. package/dist/_chunks/{index-Omcy-t4F.js → index-joJkJUWj.js} +21 -37
  22. package/dist/_chunks/index-joJkJUWj.js.map +1 -0
  23. package/dist/_chunks/{index-i1lZHF3N.mjs → index-roTH2zy3.mjs} +10 -16
  24. package/dist/_chunks/index-roTH2zy3.mjs.map +1 -0
  25. package/dist/_chunks/{index-deaP9rgn.js → index-se17lxmu.js} +13 -19
  26. package/dist/_chunks/index-se17lxmu.js.map +1 -0
  27. package/dist/_chunks/{index-OPfJFEYD.mjs → index-wRXHhHPH.mjs} +10 -16
  28. package/dist/_chunks/index-wRXHhHPH.mjs.map +1 -0
  29. package/dist/_chunks/{index-VQ3uu7FR.mjs → index-yRndCUAV.mjs} +10 -10
  30. package/dist/_chunks/{index-VQ3uu7FR.mjs.map → index-yRndCUAV.mjs.map} +1 -1
  31. package/dist/admin/index.js +1 -1
  32. package/dist/admin/index.mjs +1 -1
  33. package/package.json +6 -6
  34. package/server/controllers/auth.js +1 -2
  35. package/server/controllers/user.js +3 -4
  36. package/server/services/user.js +3 -3
  37. package/server/services/users-permissions.js +3 -3
  38. package/server/utils/sanitize/sanitizers.js +5 -1
  39. package/dist/_chunks/EditViewPage-1NY3YGcc-PZo-tzC4.mjs +0 -84382
  40. package/dist/_chunks/EditViewPage-1NY3YGcc-PZo-tzC4.mjs.map +0 -1
  41. package/dist/_chunks/EditViewPage-1NY3YGcc-l5uN1p3e.js +0 -84410
  42. package/dist/_chunks/EditViewPage-1NY3YGcc-l5uN1p3e.js.map +0 -1
  43. package/dist/_chunks/Helmet-En-SEnNC.mjs +0 -1008
  44. package/dist/_chunks/Helmet-En-SEnNC.mjs.map +0 -1
  45. package/dist/_chunks/Helmet-d9JljxUo.js +0 -1010
  46. package/dist/_chunks/Helmet-d9JljxUo.js.map +0 -1
  47. package/dist/_chunks/ListViewPage-rkQXnquk-LJPTb3bJ.mjs +0 -1571
  48. package/dist/_chunks/ListViewPage-rkQXnquk-LJPTb3bJ.mjs.map +0 -1
  49. package/dist/_chunks/ListViewPage-rkQXnquk-rBwGjRm0.js +0 -1595
  50. package/dist/_chunks/ListViewPage-rkQXnquk-rBwGjRm0.js.map +0 -1
  51. package/dist/_chunks/ReviewWorkflowsColumn-m0_IsejA-8zmlk45y.js +0 -33
  52. package/dist/_chunks/ReviewWorkflowsColumn-m0_IsejA-8zmlk45y.js.map +0 -1
  53. package/dist/_chunks/ReviewWorkflowsColumn-m0_IsejA-vbOQ9Ruh.mjs +0 -33
  54. package/dist/_chunks/ReviewWorkflowsColumn-m0_IsejA-vbOQ9Ruh.mjs.map +0 -1
  55. package/dist/_chunks/constants--j5MCV5y-TtrVffUD.js +0 -209
  56. package/dist/_chunks/constants--j5MCV5y-TtrVffUD.js.map +0 -1
  57. package/dist/_chunks/constants--j5MCV5y-h4BGe6Tp.mjs +0 -190
  58. package/dist/_chunks/constants--j5MCV5y-h4BGe6Tp.mjs.map +0 -1
  59. package/dist/_chunks/index-AT8MwqgE.js.map +0 -1
  60. package/dist/_chunks/index-NzLAHRwx-MeSnW6w9.mjs +0 -16566
  61. package/dist/_chunks/index-NzLAHRwx-MeSnW6w9.mjs.map +0 -1
  62. package/dist/_chunks/index-NzLAHRwx-bcHTdv6V.js +0 -16591
  63. package/dist/_chunks/index-NzLAHRwx-bcHTdv6V.js.map +0 -1
  64. package/dist/_chunks/index-OPfJFEYD.mjs.map +0 -1
  65. package/dist/_chunks/index-Omcy-t4F.js.map +0 -1
  66. package/dist/_chunks/index-cC7LGLsK.mjs.map +0 -1
  67. package/dist/_chunks/index-deaP9rgn.js.map +0 -1
  68. package/dist/_chunks/index-eH8XAk_H.mjs.map +0 -1
  69. package/dist/_chunks/index-i1lZHF3N.mjs.map +0 -1
  70. package/dist/_chunks/index-nKbtq7R-.js.map +0 -1
  71. package/dist/_chunks/useSyncRbac-Od0wrAnD-fP3UP9Sk.mjs +0 -45
  72. package/dist/_chunks/useSyncRbac-Od0wrAnD-fP3UP9Sk.mjs.map +0 -1
  73. package/dist/_chunks/useSyncRbac-Od0wrAnD-mYMbQBry.js +0 -63
  74. package/dist/_chunks/useSyncRbac-Od0wrAnD-mYMbQBry.js.map +0 -1
  75. package/dist/style.css +0 -84
@@ -1,1571 +0,0 @@
1
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
- import * as React from "react";
3
- import { useComposedRefs, Button, PopoverPrimitives, Flex, Tag, Typography, HeaderLayout, ActionLayout, ContentLayout, lightTheme, useCollator, Combobox, ComboboxOption, Tooltip, IconButton, Popover, TextButton, BaseCheckbox, Badge, Avatar, AvatarGroup, useNotifyAT, Loader } from "@strapi/design-system";
4
- import { Filter, Plus, Cross, Cog, Layer } from "@strapi/icons";
5
- import isEqual from "lodash/isEqual";
6
- import { J as requiredArgs, K as toInteger, L as millisecondsInHour, M as millisecondsInMinute, c as createContext, N as useControllableState, i as useQueryParams, F as Form, I as InputRenderer, u as useTracking, f as useNotification, h as useAPIErrorHandler, d as useDoc, z as useDocumentLayout, O as usePrev, j as buildValidParams, Q as useGetAllDocumentsQuery, T as lib, o as useDocumentRBAC, U as useEnterprise, l as useStrapiApp, g as getTranslation, P as Page, V as BackButton, W as InjectionZone, X as SearchInput, Y as Table, Z as DocumentStatus, a0 as getDisplayName, a1 as TableActions, a2 as Pagination, G as DocumentRBAC, a3 as useAuth, a4 as useContentTypeSchema, a5 as useAdminUsers, a6 as useGetContentTypeConfigurationQuery, a7 as CREATOR_FIELDS, a8 as getMainField, a as useField, a9 as useTypedSelector, aa as useRBAC, ab as checkIfAttributeIsDisplayable, ac as HOOKS, ad as convertListLayoutToFieldLayouts, p as prefixFileUrlWithBackendUrl, ae as getRelationLabel, af as useGetRelationsQuery } from "./index-NzLAHRwx-MeSnW6w9.mjs";
7
- import { H as HelmetExport } from "./Helmet-En-SEnNC.mjs";
8
- import { useIntl } from "react-intl";
9
- import { useNavigate, Link, NavLink } from "react-router-dom";
10
- import styled from "styled-components";
11
- import { u as useSyncRbac } from "./useSyncRbac-Od0wrAnD-fP3UP9Sk.mjs";
12
- import isEmpty from "lodash/isEmpty";
13
- import toString from "lodash/toString";
14
- import { Menu, LinkButton } from "@strapi/design-system/v2";
15
- function parseISO(argument, options) {
16
- var _options$additionalDi;
17
- requiredArgs(1, arguments);
18
- var additionalDigits = toInteger((_options$additionalDi = options === null || options === void 0 ? void 0 : options.additionalDigits) !== null && _options$additionalDi !== void 0 ? _options$additionalDi : 2);
19
- if (additionalDigits !== 2 && additionalDigits !== 1 && additionalDigits !== 0) {
20
- throw new RangeError("additionalDigits must be 0, 1 or 2");
21
- }
22
- if (!(typeof argument === "string" || Object.prototype.toString.call(argument) === "[object String]")) {
23
- return /* @__PURE__ */ new Date(NaN);
24
- }
25
- var dateStrings = splitDateString(argument);
26
- var date;
27
- if (dateStrings.date) {
28
- var parseYearResult = parseYear(dateStrings.date, additionalDigits);
29
- date = parseDate(parseYearResult.restDateString, parseYearResult.year);
30
- }
31
- if (!date || isNaN(date.getTime())) {
32
- return /* @__PURE__ */ new Date(NaN);
33
- }
34
- var timestamp = date.getTime();
35
- var time = 0;
36
- var offset;
37
- if (dateStrings.time) {
38
- time = parseTime(dateStrings.time);
39
- if (isNaN(time)) {
40
- return /* @__PURE__ */ new Date(NaN);
41
- }
42
- }
43
- if (dateStrings.timezone) {
44
- offset = parseTimezone(dateStrings.timezone);
45
- if (isNaN(offset)) {
46
- return /* @__PURE__ */ new Date(NaN);
47
- }
48
- } else {
49
- var dirtyDate = new Date(timestamp + time);
50
- var result = /* @__PURE__ */ new Date(0);
51
- result.setFullYear(dirtyDate.getUTCFullYear(), dirtyDate.getUTCMonth(), dirtyDate.getUTCDate());
52
- result.setHours(dirtyDate.getUTCHours(), dirtyDate.getUTCMinutes(), dirtyDate.getUTCSeconds(), dirtyDate.getUTCMilliseconds());
53
- return result;
54
- }
55
- return new Date(timestamp + time + offset);
56
- }
57
- var patterns = {
58
- dateTimeDelimiter: /[T ]/,
59
- timeZoneDelimiter: /[Z ]/i,
60
- timezone: /([Z+-].*)$/
61
- };
62
- var dateRegex = /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/;
63
- var timeRegex = /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/;
64
- var timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/;
65
- function splitDateString(dateString) {
66
- var dateStrings = {};
67
- var array = dateString.split(patterns.dateTimeDelimiter);
68
- var timeString;
69
- if (array.length > 2) {
70
- return dateStrings;
71
- }
72
- if (/:/.test(array[0])) {
73
- timeString = array[0];
74
- } else {
75
- dateStrings.date = array[0];
76
- timeString = array[1];
77
- if (patterns.timeZoneDelimiter.test(dateStrings.date)) {
78
- dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0];
79
- timeString = dateString.substr(dateStrings.date.length, dateString.length);
80
- }
81
- }
82
- if (timeString) {
83
- var token = patterns.timezone.exec(timeString);
84
- if (token) {
85
- dateStrings.time = timeString.replace(token[1], "");
86
- dateStrings.timezone = token[1];
87
- } else {
88
- dateStrings.time = timeString;
89
- }
90
- }
91
- return dateStrings;
92
- }
93
- function parseYear(dateString, additionalDigits) {
94
- var regex = new RegExp("^(?:(\\d{4}|[+-]\\d{" + (4 + additionalDigits) + "})|(\\d{2}|[+-]\\d{" + (2 + additionalDigits) + "})$)");
95
- var captures = dateString.match(regex);
96
- if (!captures)
97
- return {
98
- year: NaN,
99
- restDateString: ""
100
- };
101
- var year = captures[1] ? parseInt(captures[1]) : null;
102
- var century = captures[2] ? parseInt(captures[2]) : null;
103
- return {
104
- year: century === null ? year : century * 100,
105
- restDateString: dateString.slice((captures[1] || captures[2]).length)
106
- };
107
- }
108
- function parseDate(dateString, year) {
109
- if (year === null)
110
- return /* @__PURE__ */ new Date(NaN);
111
- var captures = dateString.match(dateRegex);
112
- if (!captures)
113
- return /* @__PURE__ */ new Date(NaN);
114
- var isWeekDate = !!captures[4];
115
- var dayOfYear = parseDateUnit(captures[1]);
116
- var month = parseDateUnit(captures[2]) - 1;
117
- var day = parseDateUnit(captures[3]);
118
- var week = parseDateUnit(captures[4]);
119
- var dayOfWeek = parseDateUnit(captures[5]) - 1;
120
- if (isWeekDate) {
121
- if (!validateWeekDate(year, week, dayOfWeek)) {
122
- return /* @__PURE__ */ new Date(NaN);
123
- }
124
- return dayOfISOWeekYear(year, week, dayOfWeek);
125
- } else {
126
- var date = /* @__PURE__ */ new Date(0);
127
- if (!validateDate(year, month, day) || !validateDayOfYearDate(year, dayOfYear)) {
128
- return /* @__PURE__ */ new Date(NaN);
129
- }
130
- date.setUTCFullYear(year, month, Math.max(dayOfYear, day));
131
- return date;
132
- }
133
- }
134
- function parseDateUnit(value) {
135
- return value ? parseInt(value) : 1;
136
- }
137
- function parseTime(timeString) {
138
- var captures = timeString.match(timeRegex);
139
- if (!captures)
140
- return NaN;
141
- var hours = parseTimeUnit(captures[1]);
142
- var minutes = parseTimeUnit(captures[2]);
143
- var seconds = parseTimeUnit(captures[3]);
144
- if (!validateTime(hours, minutes, seconds)) {
145
- return NaN;
146
- }
147
- return hours * millisecondsInHour + minutes * millisecondsInMinute + seconds * 1e3;
148
- }
149
- function parseTimeUnit(value) {
150
- return value && parseFloat(value.replace(",", ".")) || 0;
151
- }
152
- function parseTimezone(timezoneString) {
153
- if (timezoneString === "Z")
154
- return 0;
155
- var captures = timezoneString.match(timezoneRegex);
156
- if (!captures)
157
- return 0;
158
- var sign = captures[1] === "+" ? -1 : 1;
159
- var hours = parseInt(captures[2]);
160
- var minutes = captures[3] && parseInt(captures[3]) || 0;
161
- if (!validateTimezone(hours, minutes)) {
162
- return NaN;
163
- }
164
- return sign * (hours * millisecondsInHour + minutes * millisecondsInMinute);
165
- }
166
- function dayOfISOWeekYear(isoWeekYear, week, day) {
167
- var date = /* @__PURE__ */ new Date(0);
168
- date.setUTCFullYear(isoWeekYear, 0, 4);
169
- var fourthOfJanuaryDay = date.getUTCDay() || 7;
170
- var diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay;
171
- date.setUTCDate(date.getUTCDate() + diff);
172
- return date;
173
- }
174
- var daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
175
- function isLeapYearIndex(year) {
176
- return year % 400 === 0 || year % 4 === 0 && year % 100 !== 0;
177
- }
178
- function validateDate(year, month, date) {
179
- return month >= 0 && month <= 11 && date >= 1 && date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28));
180
- }
181
- function validateDayOfYearDate(year, dayOfYear) {
182
- return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365);
183
- }
184
- function validateWeekDate(_year, week, day) {
185
- return week >= 1 && week <= 53 && day >= 0 && day <= 6;
186
- }
187
- function validateTime(hours, minutes, seconds) {
188
- if (hours === 24) {
189
- return minutes === 0 && seconds === 0;
190
- }
191
- return seconds >= 0 && seconds < 60 && minutes >= 0 && minutes < 60 && hours >= 0 && hours < 25;
192
- }
193
- function validateTimezone(_hours, minutes) {
194
- return minutes >= 0 && minutes <= 59;
195
- }
196
- const BASE_FILTERS = [
197
- {
198
- label: { id: "components.FilterOptions.FILTER_TYPES.$eq", defaultMessage: "is" },
199
- value: "$eq"
200
- },
201
- {
202
- label: { id: "components.FilterOptions.FILTER_TYPES.$ne", defaultMessage: "is not" },
203
- value: "$ne"
204
- },
205
- {
206
- label: {
207
- id: "components.FilterOptions.FILTER_TYPES.$null",
208
- defaultMessage: "is null"
209
- },
210
- value: "$null"
211
- },
212
- {
213
- label: {
214
- id: "components.FilterOptions.FILTER_TYPES.$notNull",
215
- defaultMessage: "is not null"
216
- },
217
- value: "$notNull"
218
- }
219
- ];
220
- const NUMERIC_FILTERS = [
221
- {
222
- label: {
223
- id: "components.FilterOptions.FILTER_TYPES.$gt",
224
- defaultMessage: "is greater than"
225
- },
226
- value: "$gt"
227
- },
228
- {
229
- label: {
230
- id: "components.FilterOptions.FILTER_TYPES.$gte",
231
- defaultMessage: "is greater than or equal to"
232
- },
233
- value: "$gte"
234
- },
235
- {
236
- label: {
237
- id: "components.FilterOptions.FILTER_TYPES.$lt",
238
- defaultMessage: "is less than"
239
- },
240
- value: "$lt"
241
- },
242
- {
243
- label: {
244
- id: "components.FilterOptions.FILTER_TYPES.$lte",
245
- defaultMessage: "is less than or equal to"
246
- },
247
- value: "$lte"
248
- }
249
- ];
250
- const IS_SENSITIVE_FILTERS = [
251
- {
252
- label: {
253
- id: "components.FilterOptions.FILTER_TYPES.$eqi",
254
- defaultMessage: "is (case insensitive)"
255
- },
256
- value: "$eqi"
257
- },
258
- {
259
- label: {
260
- id: "components.FilterOptions.FILTER_TYPES.$nei",
261
- defaultMessage: "is not (case insensitive)"
262
- },
263
- value: "$nei"
264
- }
265
- ];
266
- const CONTAINS_FILTERS = [
267
- {
268
- label: {
269
- id: "components.FilterOptions.FILTER_TYPES.$contains",
270
- defaultMessage: "contains"
271
- },
272
- value: "$contains"
273
- },
274
- {
275
- label: {
276
- id: "components.FilterOptions.FILTER_TYPES.$containsi",
277
- defaultMessage: "contains (case insensitive)"
278
- },
279
- value: "$containsi"
280
- },
281
- {
282
- label: {
283
- id: "components.FilterOptions.FILTER_TYPES.$notContains",
284
- defaultMessage: "not contains"
285
- },
286
- value: "$notContains"
287
- },
288
- {
289
- label: {
290
- id: "components.FilterOptions.FILTER_TYPES.$notContainsi",
291
- defaultMessage: "not contains (case insensitive)"
292
- },
293
- value: "$notContainsi"
294
- }
295
- ];
296
- const STRING_PARSE_FILTERS = [
297
- {
298
- label: {
299
- id: "components.FilterOptions.FILTER_TYPES.$startsWith",
300
- defaultMessage: "starts with"
301
- },
302
- value: "$startsWith"
303
- },
304
- {
305
- label: {
306
- id: "components.FilterOptions.FILTER_TYPES.$startsWithi",
307
- defaultMessage: "starts with (case insensitive)"
308
- },
309
- value: "$startsWithi"
310
- },
311
- {
312
- label: {
313
- id: "components.FilterOptions.FILTER_TYPES.$endsWith",
314
- defaultMessage: "ends with"
315
- },
316
- value: "$endsWith"
317
- },
318
- {
319
- label: {
320
- id: "components.FilterOptions.FILTER_TYPES.$endsWithi",
321
- defaultMessage: "ends with (case insensitive)"
322
- },
323
- value: "$endsWithi"
324
- }
325
- ];
326
- const [FiltersProvider, useFilters] = createContext("Filters");
327
- const Root = ({
328
- children,
329
- disabled = false,
330
- onChange,
331
- onOpenChange,
332
- open: openProp,
333
- defaultOpen,
334
- options = []
335
- }) => {
336
- const [triggerNode, setTriggerNode] = React.useState(null);
337
- const [open = false, setOpen] = useControllableState({
338
- prop: openProp,
339
- defaultProp: defaultOpen,
340
- onChange: onOpenChange
341
- });
342
- const handleChange = (data) => {
343
- if (onChange) {
344
- onChange(data);
345
- }
346
- };
347
- return /* @__PURE__ */ jsx(
348
- FiltersProvider,
349
- {
350
- disabled,
351
- onChange: handleChange,
352
- open,
353
- options,
354
- setOpen,
355
- setTriggerNode,
356
- triggerNode,
357
- children
358
- }
359
- );
360
- };
361
- const Trigger = React.forwardRef(
362
- ({ label }, forwardedRef) => {
363
- const { formatMessage } = useIntl();
364
- const { setTriggerNode, setOpen } = useFilters("Trigger", ({ setTriggerNode: setTriggerNode2, setOpen: setOpen2 }) => ({
365
- setTriggerNode: setTriggerNode2,
366
- setOpen: setOpen2
367
- }));
368
- const disabled = useFilters("Trigger", ({ disabled: disabled2 }) => disabled2);
369
- const open = useFilters("Trigger", ({ open: open2 }) => open2);
370
- const composedRefs = useComposedRefs(forwardedRef, setTriggerNode);
371
- const handleClick = () => setOpen(!open);
372
- return /* @__PURE__ */ jsx(
373
- Button,
374
- {
375
- variant: "tertiary",
376
- ref: composedRefs,
377
- startIcon: /* @__PURE__ */ jsx(Filter, {}),
378
- onClick: handleClick,
379
- size: "S",
380
- disabled,
381
- children: label || formatMessage({ id: "app.utils.filters", defaultMessage: "Filters" })
382
- }
383
- );
384
- }
385
- );
386
- const PopoverImpl = () => {
387
- const [{ query }, setQuery] = useQueryParams();
388
- const { formatMessage } = useIntl();
389
- const open = useFilters("Popover", ({ open: open2 }) => open2);
390
- const options = useFilters("Popover", ({ options: options2 }) => options2);
391
- const triggerNode = useFilters("Popover", ({ triggerNode: triggerNode2 }) => triggerNode2);
392
- const setOpen = useFilters("Popover", ({ setOpen: setOpen2 }) => setOpen2);
393
- const onChange = useFilters("Popover", ({ onChange: onChange2 }) => onChange2);
394
- if (!open || options.length === 0 || !triggerNode) {
395
- return null;
396
- }
397
- const handleSubmit = (data) => {
398
- if (!data.value) {
399
- return;
400
- }
401
- if (onChange) {
402
- onChange(data);
403
- }
404
- const filterType = options.find((filter) => filter.name === data.name).type;
405
- const operatorValuePairing = {
406
- [data.filter]: data.value
407
- };
408
- const newFilterQuery = {
409
- ...query.filters,
410
- $and: [
411
- ...query.filters?.$and ?? [],
412
- {
413
- [data.name]: filterType === "relation" ? {
414
- id: operatorValuePairing
415
- } : operatorValuePairing
416
- }
417
- ]
418
- };
419
- setQuery({ filters: newFilterQuery, page: 1 });
420
- setOpen(false);
421
- };
422
- return /* @__PURE__ */ jsx(
423
- PopoverPrimitives.Content,
424
- {
425
- source: { current: triggerNode },
426
- onDismiss: () => setOpen(false),
427
- padding: 3,
428
- spacing: 4,
429
- maxHeight: "unset",
430
- children: /* @__PURE__ */ jsx(
431
- Form,
432
- {
433
- method: "POST",
434
- initialValues: {
435
- name: options[0]?.name,
436
- filter: BASE_FILTERS[0].value
437
- },
438
- onSubmit: handleSubmit,
439
- children: ({ values: formValues, modified, isSubmitting }) => {
440
- const filter = options.find((filter2) => filter2.name === formValues.name);
441
- const Input = filter?.input || InputRenderer;
442
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, style: { minWidth: 184 }, children: [
443
- [
444
- {
445
- ["aria-label"]: formatMessage({
446
- id: "app.utils.select-field",
447
- defaultMessage: "Select field"
448
- }),
449
- name: "name",
450
- options: options.map((filter2) => ({
451
- label: filter2.label,
452
- value: filter2.name
453
- })),
454
- placholder: formatMessage({
455
- id: "app.utils.select-field",
456
- defaultMessage: "Select field"
457
- }),
458
- type: "enumeration"
459
- },
460
- {
461
- ["aria-label"]: formatMessage({
462
- id: "app.utils.select-filter",
463
- defaultMessage: "Select filter"
464
- }),
465
- name: "filter",
466
- options: filter?.operators || getFilterList(filter).map((opt) => ({
467
- label: formatMessage(opt.label),
468
- value: opt.value
469
- })),
470
- placeholder: formatMessage({
471
- id: "app.utils.select-filter",
472
- defaultMessage: "Select filter"
473
- }),
474
- type: "enumeration"
475
- }
476
- ].map((field) => /* @__PURE__ */ jsx(InputRenderer, { ...field }, field.name)),
477
- filter && formValues.filter && formValues.filter !== "$null" && formValues.filter !== "$notNull" ? /* @__PURE__ */ jsx(
478
- Input,
479
- {
480
- ...filter,
481
- label: null,
482
- "aria-label": filter.label,
483
- name: "value",
484
- type: filter.mainField?.type ?? filter.type
485
- }
486
- ) : null,
487
- /* @__PURE__ */ jsx(
488
- Button,
489
- {
490
- disabled: !modified || isSubmitting,
491
- size: "L",
492
- variant: "secondary",
493
- startIcon: /* @__PURE__ */ jsx(Plus, {}),
494
- type: "submit",
495
- fullWidth: true,
496
- children: formatMessage({ id: "app.utils.add-filter", defaultMessage: "Add filter" })
497
- }
498
- )
499
- ] });
500
- }
501
- }
502
- )
503
- }
504
- );
505
- };
506
- const getFilterList = (filter) => {
507
- if (!filter) {
508
- return [];
509
- }
510
- const type = filter.mainField?.type ? filter.mainField.type : filter.type;
511
- switch (type) {
512
- case "email":
513
- case "text":
514
- case "enumeration":
515
- case "string": {
516
- return [
517
- ...BASE_FILTERS,
518
- ...IS_SENSITIVE_FILTERS,
519
- ...CONTAINS_FILTERS,
520
- ...STRING_PARSE_FILTERS
521
- ];
522
- }
523
- case "float":
524
- case "integer":
525
- case "biginteger":
526
- case "decimal": {
527
- return [...BASE_FILTERS, ...NUMERIC_FILTERS];
528
- }
529
- case "time":
530
- case "date": {
531
- return [...BASE_FILTERS, ...NUMERIC_FILTERS, ...CONTAINS_FILTERS];
532
- }
533
- case "datetime": {
534
- return [...BASE_FILTERS, ...NUMERIC_FILTERS];
535
- }
536
- default:
537
- return [...BASE_FILTERS, ...IS_SENSITIVE_FILTERS];
538
- }
539
- };
540
- const List = () => {
541
- const [{ query }, setQuery] = useQueryParams();
542
- const options = useFilters("List", ({ options: options2 }) => options2);
543
- const handleClick = (data) => {
544
- const nextFilters = (query?.filters?.$and ?? []).filter((filter) => {
545
- const [attributeName] = Object.keys(filter);
546
- if (attributeName !== data.name) {
547
- return true;
548
- }
549
- const { type, mainField } = options.find(({ name }) => name === attributeName);
550
- if (type === "relation") {
551
- const filterObj = filter[attributeName][mainField?.name ?? "id"];
552
- if (typeof filterObj === "object") {
553
- const [operator] = Object.keys(filterObj);
554
- const value = filterObj[operator];
555
- return !(operator === data.filter && value === data.value);
556
- }
557
- return true;
558
- } else {
559
- const filterObj = filter[attributeName];
560
- const [operator] = Object.keys(filterObj);
561
- const value = filterObj[operator];
562
- return !(operator === data.filter && value === data.value);
563
- }
564
- });
565
- setQuery({ filters: { $and: nextFilters }, page: 1 });
566
- };
567
- if (!query?.filters?.$and?.length) {
568
- return null;
569
- }
570
- return /* @__PURE__ */ jsx(Fragment, { children: query?.filters?.$and?.map((queryFilter) => {
571
- const [attributeName] = Object.keys(queryFilter);
572
- const filter = options.find(({ name }) => name === attributeName);
573
- const filterObj = queryFilter[attributeName];
574
- if (!filter || typeof filterObj !== "object" || filterObj === null) {
575
- return null;
576
- }
577
- if (filter.type === "relation") {
578
- const modelFilter = filterObj[filter.mainField?.name ?? "id"];
579
- if (typeof modelFilter === "object") {
580
- const [operator] = Object.keys(modelFilter);
581
- const value = modelFilter[operator];
582
- return /* @__PURE__ */ jsx(
583
- AttributeTag,
584
- {
585
- ...filter,
586
- onClick: handleClick,
587
- operator,
588
- value
589
- },
590
- `${attributeName}-${operator}-${value}`
591
- );
592
- }
593
- return null;
594
- } else {
595
- const [operator] = Object.keys(filterObj);
596
- const value = filterObj[operator];
597
- if (typeof value === "object") {
598
- return null;
599
- }
600
- return /* @__PURE__ */ jsx(
601
- AttributeTag,
602
- {
603
- ...filter,
604
- onClick: handleClick,
605
- operator,
606
- value
607
- },
608
- `${attributeName}-${operator}-${value}`
609
- );
610
- }
611
- }) });
612
- };
613
- const AttributeTag = ({
614
- input,
615
- label,
616
- mainField,
617
- name,
618
- onClick,
619
- operator,
620
- options,
621
- value,
622
- ...filter
623
- }) => {
624
- const { formatMessage, formatDate, formatTime, formatNumber } = useIntl();
625
- const handleClick = () => {
626
- onClick({ name, value, filter: operator });
627
- };
628
- const type = mainField?.type ? mainField.type : filter.type;
629
- let formattedValue = value;
630
- switch (type) {
631
- case "date":
632
- formattedValue = formatDate(value, { dateStyle: "full" });
633
- break;
634
- case "datetime":
635
- formattedValue = formatDate(value, { dateStyle: "full", timeStyle: "short" });
636
- break;
637
- case "time":
638
- const [hour, minute] = value.split(":");
639
- const date = /* @__PURE__ */ new Date();
640
- date.setHours(Number(hour));
641
- date.setMinutes(Number(minute));
642
- formattedValue = formatTime(date, {
643
- hour: "numeric",
644
- minute: "numeric"
645
- });
646
- break;
647
- case "float":
648
- case "integer":
649
- case "biginteger":
650
- case "decimal":
651
- formattedValue = formatNumber(Number(value));
652
- break;
653
- }
654
- if (input && options) {
655
- const selectedOption = options.find((option) => {
656
- return (typeof option === "string" ? option : option.value) === value;
657
- });
658
- formattedValue = selectedOption ? typeof selectedOption === "string" ? selectedOption : selectedOption.label ?? selectedOption.value : value;
659
- }
660
- const content = `${label} ${formatMessage({
661
- id: `components.FilterOptions.FILTER_TYPES.${operator}`,
662
- defaultMessage: operator
663
- })} ${operator !== "$null" && operator !== "$notNull" ? formattedValue : ""}`;
664
- return /* @__PURE__ */ jsx(Tag, { padding: 1, onClick: handleClick, icon: /* @__PURE__ */ jsx(Cross, {}), children: content });
665
- };
666
- const Filters = {
667
- List,
668
- Popover: PopoverImpl,
669
- Root,
670
- Trigger
671
- };
672
- const REVIEW_WORKFLOW_FILTER_CE = [];
673
- const NOT_ALLOWED_FILTERS = [
674
- "json",
675
- "component",
676
- "media",
677
- "richtext",
678
- "dynamiczone",
679
- "password",
680
- "blocks"
681
- ];
682
- const DEFAULT_ALLOWED_FILTERS = ["createdAt", "updatedAt"];
683
- const USER_FILTER_ATTRIBUTES = [...CREATOR_FIELDS, "strapi_assignee"];
684
- const FiltersImpl = ({ disabled, schema }) => {
685
- const { attributes, uid: model, options } = schema;
686
- const { formatMessage, locale } = useIntl();
687
- const { trackUsage } = useTracking();
688
- const allPermissions = useAuth("FiltersImpl", (state) => state.permissions);
689
- const [{ query }] = useQueryParams();
690
- const { schemas } = useContentTypeSchema();
691
- const canReadAdminUsers = React.useMemo(
692
- () => allPermissions.filter(
693
- (permission) => permission.action === "admin::users.read" && permission.subject === null
694
- ).length > 0,
695
- [allPermissions]
696
- );
697
- const selectedUserIds = (query?.filters?.$and ?? []).reduce((acc, filter) => {
698
- const [key, value] = Object.entries(filter)[0];
699
- if (typeof value.id !== "object") {
700
- return acc;
701
- }
702
- const id = value.id.$eq || value.id.$ne;
703
- if (id && USER_FILTER_ATTRIBUTES.includes(key) && !acc.includes(id)) {
704
- acc.push(id);
705
- }
706
- return acc;
707
- }, []);
708
- const { data: userData, isLoading: isLoadingAdminUsers } = useAdminUsers(
709
- { filters: { id: { $in: selectedUserIds } } },
710
- {
711
- // fetch the list of admin users only if the filter contains users and the
712
- // current user has permissions to display users
713
- skip: selectedUserIds.length === 0 || !canReadAdminUsers
714
- }
715
- );
716
- const { users = [] } = userData ?? {};
717
- const { metadata } = useGetContentTypeConfigurationQuery(model, {
718
- selectFromResult: ({ data }) => ({ metadata: data?.contentType.metadatas ?? {} })
719
- });
720
- const formatter = useCollator(locale, {
721
- sensitivity: "base"
722
- });
723
- const displayedAttributeFilters = React.useMemo(() => {
724
- const [{ properties: { fields = [] } = { fields: [] } }] = allPermissions.filter(
725
- (permission) => permission.action === "plugin::content-manager.explorer.read" && permission.subject === model
726
- );
727
- const allowedFields = fields.filter((field) => {
728
- const attribute = attributes[field] ?? {};
729
- return attribute.type && !NOT_ALLOWED_FILTERS.includes(attribute.type);
730
- });
731
- return [
732
- "id",
733
- ...allowedFields,
734
- ...DEFAULT_ALLOWED_FILTERS,
735
- ...canReadAdminUsers ? CREATOR_FIELDS : []
736
- ].map((name) => {
737
- const attribute = attributes[name];
738
- if (NOT_ALLOWED_FILTERS.includes(attribute.type)) {
739
- return null;
740
- }
741
- const { mainField: mainFieldName = "", label } = metadata[name].list;
742
- let filter = {
743
- name,
744
- label: label ?? "",
745
- mainField: getMainField(attribute, mainFieldName, { schemas, components: {} }),
746
- // @ts-expect-error – TODO: this is filtered out above in the `allowedFields` call but TS complains, is there a better way to solve this?
747
- type: attribute.type
748
- };
749
- if (attribute.type === "relation" && "target" in attribute && attribute.target === "admin::user") {
750
- filter = {
751
- ...filter,
752
- input: AdminUsersFilter,
753
- options: users.map((user) => ({
754
- label: getDisplayName(user, formatMessage),
755
- value: user.id.toString()
756
- })),
757
- operators: [
758
- {
759
- label: formatMessage({
760
- id: "components.FilterOptions.FILTER_TYPES.$eq",
761
- defaultMessage: "is"
762
- }),
763
- value: "$eq"
764
- },
765
- {
766
- label: formatMessage({
767
- id: "components.FilterOptions.FILTER_TYPES.$ne",
768
- defaultMessage: "is not"
769
- }),
770
- value: "$ne"
771
- }
772
- ],
773
- mainField: {
774
- name: "id",
775
- type: "integer"
776
- }
777
- };
778
- }
779
- return filter;
780
- }).filter(Boolean);
781
- }, [
782
- allPermissions,
783
- model,
784
- canReadAdminUsers,
785
- attributes,
786
- metadata,
787
- schemas,
788
- users,
789
- formatMessage
790
- ]);
791
- const reviewWorkflowFilter = useEnterprise(
792
- REVIEW_WORKFLOW_FILTER_CE,
793
- async () => (await import("./constants--j5MCV5y-h4BGe6Tp.mjs")).REVIEW_WORKFLOW_FILTERS,
794
- {
795
- combine(ceFilters, eeFilters) {
796
- return [
797
- ...ceFilters,
798
- ...eeFilters.filter((eeFilter) => {
799
- if (eeFilter.name === "strapi_assignee") {
800
- return canReadAdminUsers;
801
- }
802
- return true;
803
- }).map((eeFilter) => ({
804
- ...eeFilter,
805
- "aria-label": formatMessage(eeFilter.label),
806
- options: (
807
- // TODO: strapi_assignee should not be in here and rather defined
808
- // in the ee directory.
809
- eeFilter.name === "strapi_assignee" ? users.map((user) => ({
810
- label: getDisplayName(user, formatMessage),
811
- value: user.id.toString()
812
- })) : void 0
813
- )
814
- }))
815
- ];
816
- },
817
- defaultValue: [],
818
- // we have to wait for admin users to be fully loaded, because otherwise
819
- // combine is called to early and does not contain the latest state of
820
- // the users array
821
- enabled: !!options?.reviewWorkflows && !isLoadingAdminUsers
822
- }
823
- /**
824
- * this is cast because the data returns MessageDescriptor
825
- * as `metadatas.label` _then_ we turn it to a string.
826
- */
827
- );
828
- const onOpenChange = (isOpen) => {
829
- if (isOpen) {
830
- trackUsage("willFilterEntries");
831
- }
832
- };
833
- const displayedFilters = [...displayedAttributeFilters, ...reviewWorkflowFilter].sort(
834
- (a, b) => formatter.compare(a.label, b.label)
835
- );
836
- const handleFilterChange = (data) => {
837
- const attribute = attributes[data.name];
838
- if (attribute) {
839
- trackUsage("didFilterEntries", {
840
- useRelation: attribute.type === "relation"
841
- });
842
- }
843
- };
844
- return /* @__PURE__ */ jsxs(
845
- Filters.Root,
846
- {
847
- disabled,
848
- options: displayedFilters,
849
- onOpenChange,
850
- onChange: handleFilterChange,
851
- children: [
852
- /* @__PURE__ */ jsx(Filters.Trigger, {}),
853
- /* @__PURE__ */ jsx(Filters.Popover, {}),
854
- /* @__PURE__ */ jsx(Filters.List, {})
855
- ]
856
- }
857
- );
858
- };
859
- const AdminUsersFilter = ({ name }) => {
860
- const [page, setPage] = React.useState(1);
861
- const { formatMessage } = useIntl();
862
- const { data, isLoading } = useAdminUsers({
863
- page
864
- });
865
- const field = useField(name);
866
- const handleOpenChange = (isOpen) => {
867
- if (!isOpen) {
868
- setPage(1);
869
- }
870
- };
871
- const users = data?.users || [];
872
- return /* @__PURE__ */ jsx(
873
- Combobox,
874
- {
875
- value: field.value,
876
- "aria-label": formatMessage({
877
- id: "content-manager.components.Filters.usersSelect.label",
878
- defaultMessage: "Search and select a user to filter"
879
- }),
880
- onOpenChange: handleOpenChange,
881
- onChange: (value) => field.onChange(name, value),
882
- loading: isLoading,
883
- onLoadMore: () => setPage((prev) => prev + 1),
884
- children: users.map((user) => {
885
- return /* @__PURE__ */ jsx(ComboboxOption, { value: user.id.toString(), children: getDisplayName(user, formatMessage) }, user.id);
886
- })
887
- }
888
- );
889
- };
890
- const CellValue = ({ type, value }) => {
891
- const { formatDate, formatTime, formatNumber } = useIntl();
892
- let formattedValue = value;
893
- if (type === "date") {
894
- formattedValue = formatDate(parseISO(value), { dateStyle: "full" });
895
- }
896
- if (type === "datetime") {
897
- formattedValue = formatDate(value, { dateStyle: "full", timeStyle: "short" });
898
- }
899
- if (type === "time") {
900
- const [hour, minute, second] = value.split(":");
901
- const date = /* @__PURE__ */ new Date();
902
- date.setHours(hour);
903
- date.setMinutes(minute);
904
- date.setSeconds(second);
905
- formattedValue = formatTime(date, {
906
- timeStyle: "short"
907
- });
908
- }
909
- if (["float", "decimal"].includes(type)) {
910
- formattedValue = formatNumber(value, {
911
- // Should be kept in sync with the corresponding value
912
- // in the design-system/NumberInput: https://github.com/strapi/design-system/blob/main/packages/strapi-design-system/src/NumberInput/NumberInput.js#L53
913
- maximumFractionDigits: 20
914
- });
915
- }
916
- if (["integer", "biginteger"].includes(type)) {
917
- formattedValue = formatNumber(value, { maximumFractionDigits: 0 });
918
- }
919
- return toString(formattedValue);
920
- };
921
- const SingleComponent = ({ content, mainField }) => {
922
- if (!mainField) {
923
- return null;
924
- }
925
- return /* @__PURE__ */ jsx(Tooltip, { label: content[mainField.name], children: /* @__PURE__ */ jsx(SingleComponentTypography, { textColor: "neutral800", ellipsis: true, children: /* @__PURE__ */ jsx(CellValue, { type: mainField.type, value: content[mainField.name] }) }) });
926
- };
927
- const SingleComponentTypography = styled(Typography)`
928
- max-width: 250px;
929
- `;
930
- const RepeatableComponent = ({ content, mainField }) => {
931
- const { formatMessage } = useIntl();
932
- if (!mainField) {
933
- return null;
934
- }
935
- return /* @__PURE__ */ jsxs(Menu.Root, { children: [
936
- /* @__PURE__ */ jsxs(MenuTrigger$1, { onClick: (e) => e.stopPropagation(), children: [
937
- /* @__PURE__ */ jsx(Badge, { children: content.length }),
938
- " ",
939
- formatMessage(
940
- {
941
- id: "content-manager.containers.list.items",
942
- defaultMessage: "{number, plural, =0 {items} one {item} other {items}}"
943
- },
944
- { number: content.length }
945
- )
946
- ] }),
947
- /* @__PURE__ */ jsx(Menu.Content, { children: content.map((item) => /* @__PURE__ */ jsx(Menu.Item, { disabled: true, children: /* @__PURE__ */ jsx(RepeatableComponentTypography, { ellipsis: true, children: /* @__PURE__ */ jsx(CellValue, { type: mainField.type, value: item[mainField.name] }) }) }, item.id)) })
948
- ] });
949
- };
950
- const RepeatableComponentTypography = styled(Typography)`
951
- max-width: 500px;
952
- `;
953
- const MenuTrigger$1 = styled(Menu.Trigger)`
954
- svg {
955
- width: ${6 / 16}rem;
956
- height: ${4 / 16}rem;
957
- }
958
- `;
959
- const getFileExtension = (ext) => ext && ext[0] === "." ? ext.substring(1) : ext;
960
- const MediaSingle = ({ url, mime, alternativeText, name, ext, formats }) => {
961
- const fileURL = prefixFileUrlWithBackendUrl(url);
962
- if (mime.includes("image")) {
963
- const thumbnail = formats?.thumbnail?.url;
964
- const mediaURL = prefixFileUrlWithBackendUrl(thumbnail) || fileURL;
965
- return /* @__PURE__ */ jsx(Avatar, { src: mediaURL, alt: alternativeText || name, preview: true });
966
- }
967
- const fileExtension = getFileExtension(ext);
968
- const fileName = name.length > 100 ? `${name.substring(0, 100)}...` : name;
969
- return /* @__PURE__ */ jsx(Tooltip, { description: fileName, children: /* @__PURE__ */ jsx(FileWrapper, { children: fileExtension }) });
970
- };
971
- const FileWrapper = ({ children }) => {
972
- return /* @__PURE__ */ jsx(
973
- Flex,
974
- {
975
- as: "span",
976
- position: "relative",
977
- borderRadius: "50%",
978
- width: "26px",
979
- height: "26px",
980
- borderColor: "neutral200",
981
- background: "neutral150",
982
- paddingLeft: "1px",
983
- justifyContent: "center",
984
- alignItems: "center",
985
- children: /* @__PURE__ */ jsx(FileTypography, { variant: "sigma", textColor: "neutral600", children })
986
- }
987
- );
988
- };
989
- const FileTypography = styled(Typography)`
990
- font-size: 0.6rem;
991
- line-height: 0.6rem;
992
- `;
993
- const MediaMultiple = ({ content }) => {
994
- return /* @__PURE__ */ jsx(AvatarGroup, { children: content.map((file, index) => {
995
- const key = `${file.id}${index}`;
996
- if (index === 3) {
997
- const remainingFiles = `+${content.length - 3}`;
998
- return /* @__PURE__ */ jsx(FileWrapper, { children: remainingFiles }, key);
999
- }
1000
- if (index > 3) {
1001
- return null;
1002
- }
1003
- return /* @__PURE__ */ jsx(MediaSingle, { ...file }, key);
1004
- }) });
1005
- };
1006
- const RelationSingle = ({ mainField, content }) => {
1007
- return /* @__PURE__ */ jsx(TypographyMaxWidth$1, { textColor: "neutral800", ellipsis: true, children: getRelationLabel(content, mainField) });
1008
- };
1009
- const TypographyMaxWidth$1 = styled(Typography)`
1010
- max-width: 500px;
1011
- `;
1012
- const RelationMultiple = ({ mainField, content, rowId, name }) => {
1013
- const { model } = useDoc();
1014
- const { formatMessage } = useIntl();
1015
- const { notifyStatus } = useNotifyAT();
1016
- const [isOpen, setIsOpen] = React.useState(false);
1017
- const [targetField] = name.split(".");
1018
- const { data, isLoading } = useGetRelationsQuery(
1019
- {
1020
- model,
1021
- id: rowId,
1022
- targetField
1023
- },
1024
- {
1025
- skip: !isOpen,
1026
- refetchOnMountOrArgChange: true
1027
- }
1028
- );
1029
- React.useEffect(() => {
1030
- if (data) {
1031
- notifyStatus(
1032
- formatMessage({
1033
- id: getTranslation("DynamicTable.relation-loaded"),
1034
- defaultMessage: "Relations have been loaded"
1035
- })
1036
- );
1037
- }
1038
- }, [data, formatMessage, notifyStatus]);
1039
- return /* @__PURE__ */ jsxs(Menu.Root, { onOpenChange: (isOpen2) => setIsOpen(isOpen2), children: [
1040
- /* @__PURE__ */ jsx(MenuTrigger, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxs(Flex, { gap: 1, wrap: "nowrap", children: [
1041
- /* @__PURE__ */ jsx(Badge, { children: content.count }),
1042
- formatMessage(
1043
- {
1044
- id: "content-manager.containers.list.items",
1045
- defaultMessage: "{number, plural, =0 {items} one {item} other {items}}"
1046
- },
1047
- { number: content.count }
1048
- )
1049
- ] }) }),
1050
- /* @__PURE__ */ jsxs(Menu.Content, { children: [
1051
- isLoading && /* @__PURE__ */ jsx(Menu.Item, { disabled: true, children: /* @__PURE__ */ jsx(Loader, { small: true, children: formatMessage({
1052
- id: getTranslation("ListViewTable.relation-loading"),
1053
- defaultMessage: "Relations are loading"
1054
- }) }) }),
1055
- data?.results && /* @__PURE__ */ jsxs(Fragment, { children: [
1056
- data.results.map((entry) => /* @__PURE__ */ jsx(Menu.Item, { disabled: true, children: /* @__PURE__ */ jsx(TypographyMaxWidth$1, { ellipsis: true, children: getRelationLabel(entry, mainField) }) }, entry.documentId)),
1057
- data?.pagination && data?.pagination.total > 10 && /* @__PURE__ */ jsx(
1058
- Menu.Item,
1059
- {
1060
- "aria-disabled": true,
1061
- "aria-label": formatMessage({
1062
- id: getTranslation("ListViewTable.relation-more"),
1063
- defaultMessage: "This relation contains more entities than displayed"
1064
- }),
1065
- children: /* @__PURE__ */ jsx(Typography, { children: "…" })
1066
- }
1067
- )
1068
- ] })
1069
- ] })
1070
- ] });
1071
- };
1072
- const MenuTrigger = styled(Menu.Trigger)`
1073
- svg {
1074
- width: ${6 / 16}rem;
1075
- height: ${4 / 16}rem;
1076
- }
1077
- `;
1078
- const CellContent = ({ content, mainField, attribute, rowId, name }) => {
1079
- if (!hasContent(content, mainField, attribute)) {
1080
- return /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", children: "-" });
1081
- }
1082
- switch (attribute.type) {
1083
- case "media":
1084
- if (!attribute.multiple) {
1085
- return /* @__PURE__ */ jsx(MediaSingle, { ...content });
1086
- }
1087
- return /* @__PURE__ */ jsx(MediaMultiple, { content });
1088
- case "relation": {
1089
- if (isSingleRelation(attribute.relation)) {
1090
- return /* @__PURE__ */ jsx(RelationSingle, { mainField, content });
1091
- }
1092
- return /* @__PURE__ */ jsx(RelationMultiple, { rowId, mainField, content, name });
1093
- }
1094
- case "component":
1095
- if (attribute.repeatable) {
1096
- return /* @__PURE__ */ jsx(RepeatableComponent, { mainField, content });
1097
- }
1098
- return /* @__PURE__ */ jsx(SingleComponent, { mainField, content });
1099
- case "string":
1100
- return /* @__PURE__ */ jsx(Tooltip, { description: content, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { ellipsis: true, textColor: "neutral800", children: /* @__PURE__ */ jsx(CellValue, { type: attribute.type, value: content }) }) });
1101
- default:
1102
- return /* @__PURE__ */ jsx(TypographyMaxWidth, { ellipsis: true, textColor: "neutral800", children: /* @__PURE__ */ jsx(CellValue, { type: attribute.type, value: content }) });
1103
- }
1104
- };
1105
- const TypographyMaxWidth = styled(Typography)`
1106
- max-width: 300px;
1107
- `;
1108
- const hasContent = (content, mainField, attribute) => {
1109
- if (attribute.type === "component") {
1110
- if (attribute.repeatable || !mainField) {
1111
- return content?.length > 0;
1112
- }
1113
- const value = content?.[mainField.name];
1114
- if (mainField.name === "id" && ![void 0, null].includes(value)) {
1115
- return true;
1116
- }
1117
- return !isEmpty(value);
1118
- }
1119
- if (attribute.type === "relation") {
1120
- if (isSingleRelation(attribute.relation)) {
1121
- return !isEmpty(content);
1122
- }
1123
- return content?.count > 0;
1124
- }
1125
- if (["integer", "decimal", "float", "number"].includes(attribute.type)) {
1126
- return typeof content === "number";
1127
- }
1128
- if (attribute.type === "boolean") {
1129
- return content !== null;
1130
- }
1131
- return !isEmpty(content);
1132
- };
1133
- const isSingleRelation = (type) => ["oneToOne", "manyToOne", "oneToOneMorph"].includes(type);
1134
- const ViewSettingsMenu = (props) => {
1135
- const [isVisible, setIsVisible] = React.useState(false);
1136
- const cogButtonRef = React.useRef(null);
1137
- const permissions = useTypedSelector(
1138
- (state) => state.admin_app.permissions.contentManager?.collectionTypesConfigurations ?? []
1139
- );
1140
- const [{ query }] = useQueryParams();
1141
- const { formatMessage } = useIntl();
1142
- const {
1143
- allowedActions: { canViewConfiguration }
1144
- } = useRBAC({
1145
- viewConfiguration: permissions
1146
- });
1147
- const handleToggle = () => {
1148
- setIsVisible((prev) => !prev);
1149
- };
1150
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1151
- /* @__PURE__ */ jsx(
1152
- IconButton,
1153
- {
1154
- icon: /* @__PURE__ */ jsx(Cog, {}),
1155
- label: formatMessage({
1156
- id: "components.ViewSettings.tooltip",
1157
- defaultMessage: "View Settings"
1158
- }),
1159
- ref: cogButtonRef,
1160
- onClick: handleToggle
1161
- }
1162
- ),
1163
- isVisible && /* @__PURE__ */ jsx(
1164
- Popover,
1165
- {
1166
- placement: "bottom-end",
1167
- source: cogButtonRef,
1168
- onDismiss: handleToggle,
1169
- spacing: 4,
1170
- padding: 3,
1171
- children: /* @__PURE__ */ jsxs(Flex, { alignItems: "stretch", direction: "column", gap: 3, children: [
1172
- canViewConfiguration ? /* @__PURE__ */ jsx(
1173
- LinkButton,
1174
- {
1175
- size: "S",
1176
- startIcon: /* @__PURE__ */ jsx(Layer, {}),
1177
- variant: "secondary",
1178
- as: NavLink,
1179
- to: {
1180
- pathname: "configurations/list",
1181
- search: query.plugins ? lib.stringify({ plugins: query.plugins }, { encode: false }) : ""
1182
- },
1183
- children: formatMessage({
1184
- id: "app.links.configure-view",
1185
- defaultMessage: "Configure the view"
1186
- })
1187
- }
1188
- ) : null,
1189
- /* @__PURE__ */ jsx(FieldPicker, { ...props })
1190
- ] })
1191
- }
1192
- )
1193
- ] });
1194
- };
1195
- const FieldPicker = ({ headers = [], resetHeaders, setHeaders }) => {
1196
- const { trackUsage } = useTracking();
1197
- const { formatMessage, locale } = useIntl();
1198
- const { schema, model } = useDoc();
1199
- const { list } = useDocumentLayout(model);
1200
- const formatter = useCollator(locale, {
1201
- sensitivity: "base"
1202
- });
1203
- const attributes = schema?.attributes ?? {};
1204
- const columns = Object.keys(attributes).filter((name) => checkIfAttributeIsDisplayable(attributes[name])).map((name) => ({
1205
- name,
1206
- label: list.metadatas[name]?.label ?? ""
1207
- })).sort((a, b) => formatter.compare(a.label, b.label));
1208
- const handleChange = (name) => {
1209
- trackUsage("didChangeDisplayedFields");
1210
- const newHeaders = headers.includes(name) ? headers.filter((header) => header !== name) : [...headers, name];
1211
- setHeaders(newHeaders);
1212
- };
1213
- const handleReset = () => {
1214
- resetHeaders();
1215
- };
1216
- return /* @__PURE__ */ jsxs(Flex, { as: "fieldset", direction: "column", alignItems: "stretch", gap: 3, children: [
1217
- /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
1218
- /* @__PURE__ */ jsx(Typography, { as: "legend", variant: "pi", fontWeight: "bold", children: formatMessage({
1219
- id: "containers.list.displayedFields",
1220
- defaultMessage: "Displayed fields"
1221
- }) }),
1222
- /* @__PURE__ */ jsx(TextButton, { onClick: handleReset, children: formatMessage({
1223
- id: "app.components.Button.reset",
1224
- defaultMessage: "Reset"
1225
- }) })
1226
- ] }),
1227
- /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", children: columns.map((header) => {
1228
- const isActive = headers.includes(header.name);
1229
- return /* @__PURE__ */ jsxs(
1230
- ChackboxWrapper,
1231
- {
1232
- wrap: "wrap",
1233
- gap: 2,
1234
- as: "label",
1235
- background: isActive ? "primary100" : "transparent",
1236
- hasRadius: true,
1237
- padding: 2,
1238
- children: [
1239
- /* @__PURE__ */ jsx(
1240
- BaseCheckbox,
1241
- {
1242
- onChange: () => handleChange(header.name),
1243
- value: isActive,
1244
- name: header.name
1245
- }
1246
- ),
1247
- /* @__PURE__ */ jsx(Typography, { fontSize: 1, children: header.label })
1248
- ]
1249
- },
1250
- header.name
1251
- );
1252
- }) })
1253
- ] });
1254
- };
1255
- const ChackboxWrapper = styled(Flex)`
1256
- :hover {
1257
- background-color: ${(props) => props.theme.colors.primary100};
1258
- }
1259
- `;
1260
- const { INJECT_COLUMN_IN_TABLE } = HOOKS;
1261
- const REVIEW_WORKFLOW_COLUMNS_CE = null;
1262
- const REVIEW_WORKFLOW_COLUMNS_CELL_CE = {
1263
- ReviewWorkflowsStageEE: () => null,
1264
- ReviewWorkflowsAssigneeEE: () => null
1265
- };
1266
- const ListViewPage = () => {
1267
- const { trackUsage } = useTracking();
1268
- const navigate = useNavigate();
1269
- const { formatMessage } = useIntl();
1270
- const { toggleNotification } = useNotification();
1271
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
1272
- const { collectionType, model, schema } = useDoc();
1273
- const { list } = useDocumentLayout(model);
1274
- const [displayedHeaders, setDisplayedHeaders] = React.useState([]);
1275
- const listLayout = usePrev(list.layout);
1276
- React.useEffect(() => {
1277
- if (!isEqual(listLayout, list.layout)) {
1278
- setDisplayedHeaders(list.layout);
1279
- }
1280
- }, [list.layout, listLayout]);
1281
- const handleSetHeaders = (headers) => {
1282
- setDisplayedHeaders(
1283
- convertListLayoutToFieldLayouts(headers, schema.attributes, list.metadatas)
1284
- );
1285
- };
1286
- const [{ query }] = useQueryParams({
1287
- page: "1",
1288
- pageSize: list.settings.pageSize.toString(),
1289
- sort: list.settings.defaultSortBy ? `${list.settings.defaultSortBy}:${list.settings.defaultSortOrder}` : ""
1290
- });
1291
- const params = React.useMemo(() => buildValidParams(query), [query]);
1292
- const { data, error, isLoading } = useGetAllDocumentsQuery({
1293
- model,
1294
- params
1295
- });
1296
- React.useEffect(() => {
1297
- if (error) {
1298
- toggleNotification({
1299
- type: "danger",
1300
- message: formatAPIError(error)
1301
- });
1302
- }
1303
- }, [error, formatAPIError, toggleNotification]);
1304
- const { results = [], pagination } = data ?? {};
1305
- React.useEffect(() => {
1306
- if (pagination && pagination.pageCount > 0 && pagination.page > pagination.pageCount) {
1307
- navigate(
1308
- {
1309
- search: lib.stringify({
1310
- ...query,
1311
- page: pagination.pageCount
1312
- })
1313
- },
1314
- { replace: true }
1315
- );
1316
- }
1317
- }, [pagination, formatMessage, query, navigate]);
1318
- const { canCreate } = useDocumentRBAC("ListViewPage", ({ canCreate: canCreate2 }) => ({
1319
- canCreate: canCreate2
1320
- }));
1321
- const reviewWorkflowColumns = useEnterprise(
1322
- REVIEW_WORKFLOW_COLUMNS_CE,
1323
- async () => (await import("./constants--j5MCV5y-h4BGe6Tp.mjs")).REVIEW_WORKFLOW_COLUMNS_EE,
1324
- {
1325
- enabled: !!schema?.options?.reviewWorkflows
1326
- }
1327
- );
1328
- const ReviewWorkflowsColumns = useEnterprise(
1329
- REVIEW_WORKFLOW_COLUMNS_CELL_CE,
1330
- async () => {
1331
- const { ReviewWorkflowsStageEE, ReviewWorkflowsAssigneeEE } = await import("./ReviewWorkflowsColumn-m0_IsejA-vbOQ9Ruh.mjs");
1332
- return { ReviewWorkflowsStageEE, ReviewWorkflowsAssigneeEE };
1333
- },
1334
- {
1335
- enabled: !!schema?.options?.reviewWorkflows
1336
- }
1337
- );
1338
- const runHookWaterfall = useStrapiApp("ListViewPage", ({ runHookWaterfall: runHookWaterfall2 }) => runHookWaterfall2);
1339
- const tableHeaders = React.useMemo(() => {
1340
- const headers = runHookWaterfall(INJECT_COLUMN_IN_TABLE, {
1341
- displayedHeaders,
1342
- layout: list
1343
- });
1344
- const formattedHeaders = headers.displayedHeaders.map((header) => {
1345
- return {
1346
- ...header,
1347
- label: typeof header.label === "string" ? header.label : formatMessage(header.label),
1348
- name: `${header.name}${header.mainField ? `.${header.mainField}` : ""}`
1349
- };
1350
- });
1351
- if (schema?.options?.draftAndPublish) {
1352
- formattedHeaders.push({
1353
- attribute: {
1354
- type: "custom"
1355
- },
1356
- name: "status",
1357
- label: formatMessage({
1358
- id: getTranslation(`containers.list.table-headers.status`),
1359
- defaultMessage: "status"
1360
- }),
1361
- searchable: false,
1362
- sortable: false
1363
- });
1364
- }
1365
- if (reviewWorkflowColumns) {
1366
- formattedHeaders.push(
1367
- ...reviewWorkflowColumns.map((column) => ({
1368
- ...column,
1369
- label: formatMessage(column.label)
1370
- }))
1371
- );
1372
- }
1373
- return formattedHeaders;
1374
- }, [
1375
- displayedHeaders,
1376
- formatMessage,
1377
- list,
1378
- reviewWorkflowColumns,
1379
- runHookWaterfall,
1380
- schema?.options?.draftAndPublish
1381
- ]);
1382
- if (isLoading) {
1383
- return /* @__PURE__ */ jsx(Page.Loading, {});
1384
- }
1385
- if (error) {
1386
- return /* @__PURE__ */ jsx(Page.Error, {});
1387
- }
1388
- const contentTypeTitle = schema?.info.displayName ?? "Untitled";
1389
- const handleRowClick = (id) => () => {
1390
- trackUsage("willEditEntryFromList");
1391
- navigate({
1392
- pathname: id.toString(),
1393
- search: lib.stringify({ plugins: query.plugins })
1394
- });
1395
- };
1396
- return /* @__PURE__ */ jsxs(Page.Main, { children: [
1397
- /* @__PURE__ */ jsx(HelmetExport, { title: `${contentTypeTitle} | Strapi` }),
1398
- /* @__PURE__ */ jsx(
1399
- HeaderLayout,
1400
- {
1401
- primaryAction: canCreate ? /* @__PURE__ */ jsx(CreateButton, {}) : null,
1402
- subtitle: formatMessage(
1403
- {
1404
- id: getTranslation("pages.ListView.header-subtitle"),
1405
- defaultMessage: "{number, plural, =0 {# entries} one {# entry} other {# entries}} found"
1406
- },
1407
- { number: pagination?.total }
1408
- ),
1409
- title: contentTypeTitle,
1410
- navigationAction: /* @__PURE__ */ jsx(BackButton, {})
1411
- }
1412
- ),
1413
- /* @__PURE__ */ jsx(
1414
- ActionLayout,
1415
- {
1416
- endActions: /* @__PURE__ */ jsxs(Fragment, { children: [
1417
- /* @__PURE__ */ jsx(InjectionZone, { area: "contentManager.listView.actions" }),
1418
- /* @__PURE__ */ jsx(
1419
- ViewSettingsMenu,
1420
- {
1421
- setHeaders: handleSetHeaders,
1422
- resetHeaders: () => setDisplayedHeaders(list.layout),
1423
- headers: displayedHeaders.map((header) => header.name)
1424
- }
1425
- )
1426
- ] }),
1427
- startActions: /* @__PURE__ */ jsxs(Fragment, { children: [
1428
- list.settings.searchable && /* @__PURE__ */ jsx(
1429
- SearchInput,
1430
- {
1431
- disabled: results.length === 0,
1432
- label: formatMessage(
1433
- { id: "app.component.search.label", defaultMessage: "Search for {target}" },
1434
- { target: contentTypeTitle }
1435
- ),
1436
- placeholder: formatMessage({
1437
- id: "global.search",
1438
- defaultMessage: "Search"
1439
- }),
1440
- trackedEvent: "didSearch"
1441
- }
1442
- ),
1443
- list.settings.filterable && schema ? /* @__PURE__ */ jsx(FiltersImpl, { disabled: results.length === 0, schema }) : null
1444
- ] })
1445
- }
1446
- ),
1447
- /* @__PURE__ */ jsx(ContentLayout, { children: /* @__PURE__ */ jsxs(Flex, { gap: 4, direction: "column", alignItems: "stretch", children: [
1448
- /* @__PURE__ */ jsxs(Table.Root, { rows: results, headers: tableHeaders, isLoading, children: [
1449
- /* @__PURE__ */ jsx(Table.ActionBar, {}),
1450
- /* @__PURE__ */ jsxs(Table.Content, { children: [
1451
- /* @__PURE__ */ jsxs(Table.Head, { children: [
1452
- /* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
1453
- tableHeaders.map((header) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...header }, header.name))
1454
- ] }),
1455
- /* @__PURE__ */ jsx(Table.Loading, {}),
1456
- /* @__PURE__ */ jsx(Table.Empty, { action: canCreate ? /* @__PURE__ */ jsx(CreateButton, { variant: "secondary" }) : null }),
1457
- /* @__PURE__ */ jsx(Table.Body, { children: results.map((row) => {
1458
- return /* @__PURE__ */ jsxs(
1459
- Table.Row,
1460
- {
1461
- cursor: "pointer",
1462
- onClick: handleRowClick(row.documentId),
1463
- children: [
1464
- /* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
1465
- tableHeaders.map(({ cellFormatter, ...header }) => {
1466
- if (header.name === "status") {
1467
- const { status } = row;
1468
- return /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status, maxWidth: "min-content" }) }, header.name);
1469
- }
1470
- if (schema?.options?.reviewWorkflows) {
1471
- if (header.name === "strapi_stage") {
1472
- return /* @__PURE__ */ jsx(Table.Cell, { children: row.strapi_stage ? /* @__PURE__ */ jsx(
1473
- ReviewWorkflowsColumns.ReviewWorkflowsStageEE,
1474
- {
1475
- color: row.strapi_stage.color ?? lightTheme.colors.primary600,
1476
- name: row.strapi_stage.name
1477
- }
1478
- ) : /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", children: "-" }) }, header.name);
1479
- }
1480
- if (header.name === "strapi_assignee") {
1481
- return /* @__PURE__ */ jsx(Table.Cell, { children: row.strapi_assignee ? /* @__PURE__ */ jsx(
1482
- ReviewWorkflowsColumns.ReviewWorkflowsAssigneeEE,
1483
- {
1484
- user: row.strapi_assignee
1485
- }
1486
- ) : /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", children: "-" }) }, header.name);
1487
- }
1488
- }
1489
- if (["createdBy", "updatedBy"].includes(header.name.split(".")[0])) {
1490
- return /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", children: row[header.name.split(".")[0]] ? getDisplayName(row[header.name.split(".")[0]], formatMessage) : "-" }) }, header.name);
1491
- }
1492
- if (typeof cellFormatter === "function") {
1493
- return /* @__PURE__ */ jsx(Table.Cell, { children: cellFormatter(row, header, { collectionType, model }) }, header.name);
1494
- }
1495
- return /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
1496
- CellContent,
1497
- {
1498
- content: row[header.name.split(".")[0]],
1499
- rowId: row.documentId,
1500
- ...header
1501
- }
1502
- ) }, header.name);
1503
- }),
1504
- /* @__PURE__ */ jsx(ActionsCell, { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(TableActions, { document: row }) })
1505
- ]
1506
- },
1507
- row.id
1508
- );
1509
- }) })
1510
- ] })
1511
- ] }),
1512
- /* @__PURE__ */ jsxs(
1513
- Pagination.Root,
1514
- {
1515
- ...pagination,
1516
- onPageSizeChange: () => trackUsage("willChangeNumberOfEntriesPerPage"),
1517
- children: [
1518
- /* @__PURE__ */ jsx(Pagination.PageSize, {}),
1519
- /* @__PURE__ */ jsx(Pagination.Links, {})
1520
- ]
1521
- }
1522
- )
1523
- ] }) })
1524
- ] });
1525
- };
1526
- const ActionsCell = styled(Table.Cell)`
1527
- display: flex;
1528
- justify-content: flex-end;
1529
- `;
1530
- const CreateButton = ({ variant }) => {
1531
- const { formatMessage } = useIntl();
1532
- const { trackUsage } = useTracking();
1533
- const [{ query }] = useQueryParams();
1534
- return /* @__PURE__ */ jsx(
1535
- Button,
1536
- {
1537
- variant,
1538
- forwardedAs: Link,
1539
- onClick: () => {
1540
- trackUsage("willCreateEntry", { status: "draft" });
1541
- },
1542
- startIcon: /* @__PURE__ */ jsx(Plus, {}),
1543
- style: { textDecoration: "none" },
1544
- to: {
1545
- pathname: "create",
1546
- search: lib.stringify({ plugins: query.plugins })
1547
- },
1548
- children: formatMessage({
1549
- id: getTranslation("HeaderLayout.button.label-add-entry"),
1550
- defaultMessage: "Create new entry"
1551
- })
1552
- }
1553
- );
1554
- };
1555
- const ProtectedListViewPage = () => {
1556
- const { model } = useDoc();
1557
- const [{ query }] = useQueryParams();
1558
- const { permissions = [], isLoading, isError } = useSyncRbac(model, query, "editView");
1559
- if (isLoading) {
1560
- return /* @__PURE__ */ jsx(Page.Loading, {});
1561
- }
1562
- if (isError) {
1563
- return /* @__PURE__ */ jsx(Page.Error, {});
1564
- }
1565
- return /* @__PURE__ */ jsx(Page.Protect, { permissions, children: ({ permissions: permissions2 }) => /* @__PURE__ */ jsx(DocumentRBAC, { permissions: permissions2, children: /* @__PURE__ */ jsx(ListViewPage, {}) }) });
1566
- };
1567
- export {
1568
- ListViewPage,
1569
- ProtectedListViewPage
1570
- };
1571
- //# sourceMappingURL=ListViewPage-rkQXnquk-LJPTb3bJ.mjs.map