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