@strapi/plugin-users-permissions 4.15.0 → 4.15.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 (131) hide show
  1. package/.eslintignore +1 -2
  2. package/.eslintrc +14 -0
  3. package/admin/src/index.js +5 -15
  4. package/dist/_chunks/ar-20af7bfe.js +44 -0
  5. package/dist/_chunks/ar-20af7bfe.js.map +1 -0
  6. package/dist/_chunks/ar-56e57465.mjs +44 -0
  7. package/dist/_chunks/ar-56e57465.mjs.map +1 -0
  8. package/dist/_chunks/cs-0521a3c8.mjs +50 -0
  9. package/dist/_chunks/cs-0521a3c8.mjs.map +1 -0
  10. package/dist/_chunks/cs-6d7de06a.js +50 -0
  11. package/dist/_chunks/cs-6d7de06a.js.map +1 -0
  12. package/dist/_chunks/de-4af0884b.js +62 -0
  13. package/dist/_chunks/de-4af0884b.js.map +1 -0
  14. package/dist/_chunks/de-84fed33d.mjs +62 -0
  15. package/dist/_chunks/de-84fed33d.mjs.map +1 -0
  16. package/dist/_chunks/dk-21e25c4b.js +86 -0
  17. package/dist/_chunks/dk-21e25c4b.js.map +1 -0
  18. package/dist/_chunks/dk-d8302360.mjs +86 -0
  19. package/dist/_chunks/dk-d8302360.mjs.map +1 -0
  20. package/dist/_chunks/en-746a275e.js +86 -0
  21. package/dist/_chunks/en-746a275e.js.map +1 -0
  22. package/dist/_chunks/en-a610d7d0.mjs +86 -0
  23. package/dist/_chunks/en-a610d7d0.mjs.map +1 -0
  24. package/dist/_chunks/es-9d9ad31c.mjs +86 -0
  25. package/dist/_chunks/es-9d9ad31c.mjs.map +1 -0
  26. package/dist/_chunks/es-b6ae0f5e.js +86 -0
  27. package/dist/_chunks/es-b6ae0f5e.js.map +1 -0
  28. package/dist/_chunks/fr-0722d6cd.mjs +50 -0
  29. package/dist/_chunks/fr-0722d6cd.mjs.map +1 -0
  30. package/dist/_chunks/fr-dd77fc67.js +50 -0
  31. package/dist/_chunks/fr-dd77fc67.js.map +1 -0
  32. package/dist/_chunks/id-03eb1a4c.mjs +62 -0
  33. package/dist/_chunks/id-03eb1a4c.mjs.map +1 -0
  34. package/dist/_chunks/id-c19698f1.js +62 -0
  35. package/dist/_chunks/id-c19698f1.js.map +1 -0
  36. package/dist/_chunks/index-25a30587.mjs +253 -0
  37. package/dist/_chunks/index-25a30587.mjs.map +1 -0
  38. package/dist/_chunks/index-3b689442.js +252 -0
  39. package/dist/_chunks/index-3b689442.js.map +1 -0
  40. package/dist/_chunks/index-44d267a6.mjs +385 -0
  41. package/dist/_chunks/index-44d267a6.mjs.map +1 -0
  42. package/dist/_chunks/index-4f41c158.js +319 -0
  43. package/dist/_chunks/index-4f41c158.js.map +1 -0
  44. package/dist/_chunks/index-6d4afe40.mjs +615 -0
  45. package/dist/_chunks/index-6d4afe40.mjs.map +1 -0
  46. package/dist/_chunks/index-8d1dab8c.js +638 -0
  47. package/dist/_chunks/index-8d1dab8c.js.map +1 -0
  48. package/dist/_chunks/index-9aae7d58.js +1191 -0
  49. package/dist/_chunks/index-9aae7d58.js.map +1 -0
  50. package/dist/_chunks/index-d2ccdeea.mjs +300 -0
  51. package/dist/_chunks/index-d2ccdeea.mjs.map +1 -0
  52. package/dist/_chunks/index-d52af4b4.js +407 -0
  53. package/dist/_chunks/index-d52af4b4.js.map +1 -0
  54. package/dist/_chunks/index-f50d43b2.mjs +1159 -0
  55. package/dist/_chunks/index-f50d43b2.mjs.map +1 -0
  56. package/dist/_chunks/it-06b8d8a3.js +62 -0
  57. package/dist/_chunks/it-06b8d8a3.js.map +1 -0
  58. package/dist/_chunks/it-95fb8dcc.mjs +62 -0
  59. package/dist/_chunks/it-95fb8dcc.mjs.map +1 -0
  60. package/dist/_chunks/ja-557e03ee.mjs +48 -0
  61. package/dist/_chunks/ja-557e03ee.mjs.map +1 -0
  62. package/dist/_chunks/ja-e92e9903.js +48 -0
  63. package/dist/_chunks/ja-e92e9903.js.map +1 -0
  64. package/dist/_chunks/ko-5148326d.js +86 -0
  65. package/dist/_chunks/ko-5148326d.js.map +1 -0
  66. package/dist/_chunks/ko-d3b19f18.mjs +86 -0
  67. package/dist/_chunks/ko-d3b19f18.mjs.map +1 -0
  68. package/dist/_chunks/ms-1e62b726.js +49 -0
  69. package/dist/_chunks/ms-1e62b726.js.map +1 -0
  70. package/dist/_chunks/ms-b8a16476.mjs +49 -0
  71. package/dist/_chunks/ms-b8a16476.mjs.map +1 -0
  72. package/dist/_chunks/nl-66ef33aa.js +48 -0
  73. package/dist/_chunks/nl-66ef33aa.js.map +1 -0
  74. package/dist/_chunks/nl-fb114313.mjs +48 -0
  75. package/dist/_chunks/nl-fb114313.mjs.map +1 -0
  76. package/dist/_chunks/pl-5d70d4e8.mjs +86 -0
  77. package/dist/_chunks/pl-5d70d4e8.mjs.map +1 -0
  78. package/dist/_chunks/pl-7aa4933a.js +86 -0
  79. package/dist/_chunks/pl-7aa4933a.js.map +1 -0
  80. package/dist/_chunks/pt-95c2c76f.mjs +48 -0
  81. package/dist/_chunks/pt-95c2c76f.mjs.map +1 -0
  82. package/dist/_chunks/pt-BR-075f271a.mjs +44 -0
  83. package/dist/_chunks/pt-BR-075f271a.mjs.map +1 -0
  84. package/dist/_chunks/pt-BR-820fcd20.js +44 -0
  85. package/dist/_chunks/pt-BR-820fcd20.js.map +1 -0
  86. package/dist/_chunks/pt-a470d4e6.js +48 -0
  87. package/dist/_chunks/pt-a470d4e6.js.map +1 -0
  88. package/dist/_chunks/ru-625a0fe5.mjs +86 -0
  89. package/dist/_chunks/ru-625a0fe5.mjs.map +1 -0
  90. package/dist/_chunks/ru-cd0d1ac9.js +86 -0
  91. package/dist/_chunks/ru-cd0d1ac9.js.map +1 -0
  92. package/dist/_chunks/sk-495ecbe4.mjs +50 -0
  93. package/dist/_chunks/sk-495ecbe4.mjs.map +1 -0
  94. package/dist/_chunks/sk-8334fbf7.js +50 -0
  95. package/dist/_chunks/sk-8334fbf7.js.map +1 -0
  96. package/dist/_chunks/sv-137a2f79.js +86 -0
  97. package/dist/_chunks/sv-137a2f79.js.map +1 -0
  98. package/dist/_chunks/sv-60a1fabf.mjs +86 -0
  99. package/dist/_chunks/sv-60a1fabf.mjs.map +1 -0
  100. package/dist/_chunks/th-7fe328ef.js +60 -0
  101. package/dist/_chunks/th-7fe328ef.js.map +1 -0
  102. package/dist/_chunks/th-f633d0ed.mjs +60 -0
  103. package/dist/_chunks/th-f633d0ed.mjs.map +1 -0
  104. package/dist/_chunks/tr-16211986.mjs +85 -0
  105. package/dist/_chunks/tr-16211986.mjs.map +1 -0
  106. package/dist/_chunks/tr-eae92999.js +85 -0
  107. package/dist/_chunks/tr-eae92999.js.map +1 -0
  108. package/dist/_chunks/uk-0c33935a.js +49 -0
  109. package/dist/_chunks/uk-0c33935a.js.map +1 -0
  110. package/dist/_chunks/uk-f1fae414.mjs +49 -0
  111. package/dist/_chunks/uk-f1fae414.mjs.map +1 -0
  112. package/dist/_chunks/vi-b5d581a1.js +50 -0
  113. package/dist/_chunks/vi-b5d581a1.js.map +1 -0
  114. package/dist/_chunks/vi-e8fd97e4.mjs +50 -0
  115. package/dist/_chunks/vi-e8fd97e4.mjs.map +1 -0
  116. package/dist/_chunks/zh-284557f3.mjs +86 -0
  117. package/dist/_chunks/zh-284557f3.mjs.map +1 -0
  118. package/dist/_chunks/zh-9babf307.js +86 -0
  119. package/dist/_chunks/zh-9babf307.js.map +1 -0
  120. package/dist/_chunks/zh-Hans-68e4b43a.mjs +86 -0
  121. package/dist/_chunks/zh-Hans-68e4b43a.mjs.map +1 -0
  122. package/dist/_chunks/zh-Hans-baae8c78.js +86 -0
  123. package/dist/_chunks/zh-Hans-baae8c78.js.map +1 -0
  124. package/dist/admin/index.js +5 -0
  125. package/dist/admin/index.js.map +1 -0
  126. package/dist/admin/index.mjs +6 -0
  127. package/dist/admin/index.mjs.map +1 -0
  128. package/package.json +28 -7
  129. package/packup.config.ts +42 -0
  130. package/.eslintrc.js +0 -14
  131. package/strapi-admin.js +0 -3
@@ -0,0 +1,1191 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const jsxRuntime = require("react/jsx-runtime");
4
+ const helperPlugin = require("@strapi/helper-plugin");
5
+ const reactRouterDom = require("react-router-dom");
6
+ const index = require("./index-3b689442.js");
7
+ const React = require("react");
8
+ const designSystem = require("@strapi/design-system");
9
+ const icons = require("@strapi/icons");
10
+ const formik = require("formik");
11
+ const reactIntl = require("react-intl");
12
+ const reactQuery = require("react-query");
13
+ const PropTypes = require("prop-types");
14
+ const upperFirst = require("lodash/upperFirst");
15
+ const sortBy = require("lodash/sortBy");
16
+ const get = require("lodash/get");
17
+ const styled = require("styled-components");
18
+ const produce = require("immer");
19
+ const isEmpty = require("lodash/isEmpty");
20
+ const without = require("lodash/without");
21
+ const map = require("lodash/map");
22
+ const tail = require("lodash/tail");
23
+ const set = require("lodash/set");
24
+ const take = require("lodash/take");
25
+ const yup = require("yup");
26
+ const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
27
+ function _interopNamespace(e) {
28
+ if (e && e.__esModule)
29
+ return e;
30
+ const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
31
+ if (e) {
32
+ for (const k in e) {
33
+ if (k !== "default") {
34
+ const d = Object.getOwnPropertyDescriptor(e, k);
35
+ Object.defineProperty(n, k, d.get ? d : {
36
+ enumerable: true,
37
+ get: () => e[k]
38
+ });
39
+ }
40
+ }
41
+ }
42
+ n.default = e;
43
+ return Object.freeze(n);
44
+ }
45
+ const React__namespace = /* @__PURE__ */ _interopNamespace(React);
46
+ const PropTypes__default = /* @__PURE__ */ _interopDefault(PropTypes);
47
+ const upperFirst__default = /* @__PURE__ */ _interopDefault(upperFirst);
48
+ const sortBy__default = /* @__PURE__ */ _interopDefault(sortBy);
49
+ const get__default = /* @__PURE__ */ _interopDefault(get);
50
+ const styled__default = /* @__PURE__ */ _interopDefault(styled);
51
+ const produce__default = /* @__PURE__ */ _interopDefault(produce);
52
+ const isEmpty__default = /* @__PURE__ */ _interopDefault(isEmpty);
53
+ const without__default = /* @__PURE__ */ _interopDefault(without);
54
+ const map__default = /* @__PURE__ */ _interopDefault(map);
55
+ const tail__default = /* @__PURE__ */ _interopDefault(tail);
56
+ const set__default = /* @__PURE__ */ _interopDefault(set);
57
+ const take__default = /* @__PURE__ */ _interopDefault(take);
58
+ const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
59
+ const UsersPermissions$2 = React.createContext({});
60
+ const UsersPermissionsProvider = ({ children, value }) => {
61
+ return /* @__PURE__ */ jsxRuntime.jsx(UsersPermissions$2.Provider, { value, children });
62
+ };
63
+ const useUsersPermissions = () => React.useContext(UsersPermissions$2);
64
+ UsersPermissionsProvider.propTypes = {
65
+ children: PropTypes__default.default.node.isRequired,
66
+ value: PropTypes__default.default.object.isRequired
67
+ };
68
+ function formatPluginName(pluginSlug) {
69
+ switch (pluginSlug) {
70
+ case "application":
71
+ return "Application";
72
+ case "plugin::content-manager":
73
+ return "Content manager";
74
+ case "plugin::content-type-builder":
75
+ return "Content types builder";
76
+ case "plugin::documentation":
77
+ return "Documentation";
78
+ case "plugin::email":
79
+ return "Email";
80
+ case "plugin::i18n":
81
+ return "i18n";
82
+ case "plugin::upload":
83
+ return "Upload";
84
+ case "plugin::users-permissions":
85
+ return "Users-permissions";
86
+ default:
87
+ return upperFirst__default.default(pluginSlug.replace("api::", "").replace("plugin::", ""));
88
+ }
89
+ }
90
+ const init$1 = (initialState2, permissions) => {
91
+ const collapses = Object.keys(permissions).sort().map((name) => ({ name, isOpen: false }));
92
+ return { ...initialState2, collapses };
93
+ };
94
+ const activeCheckboxWrapperStyles = styled.css`
95
+ background: ${(props) => props.theme.colors.primary100};
96
+ svg {
97
+ opacity: 1;
98
+ }
99
+ `;
100
+ const CheckboxWrapper = styled__default.default(designSystem.Box)`
101
+ display: flex;
102
+ justify-content: space-between;
103
+ align-items: center;
104
+
105
+ svg {
106
+ opacity: 0;
107
+ path {
108
+ fill: ${(props) => props.theme.colors.primary600};
109
+ }
110
+ }
111
+
112
+ /* Show active style both on hover and when the action is selected */
113
+ ${(props) => props.isActive && activeCheckboxWrapperStyles}
114
+ &:hover {
115
+ ${activeCheckboxWrapperStyles}
116
+ }
117
+ `;
118
+ const Border = styled__default.default.div`
119
+ flex: 1;
120
+ align-self: center;
121
+ border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
122
+ `;
123
+ const SubCategory = ({ subCategory }) => {
124
+ const { formatMessage } = reactIntl.useIntl();
125
+ const { onChange, onChangeSelectAll, onSelectedAction, selectedAction, modifiedData } = useUsersPermissions();
126
+ const currentScopedModifiedData = React.useMemo(() => {
127
+ return get__default.default(modifiedData, subCategory.name, {});
128
+ }, [modifiedData, subCategory]);
129
+ const hasAllActionsSelected = React.useMemo(() => {
130
+ return Object.values(currentScopedModifiedData).every((action) => action.enabled === true);
131
+ }, [currentScopedModifiedData]);
132
+ const hasSomeActionsSelected = React.useMemo(() => {
133
+ return Object.values(currentScopedModifiedData).some((action) => action.enabled === true) && !hasAllActionsSelected;
134
+ }, [currentScopedModifiedData, hasAllActionsSelected]);
135
+ const handleChangeSelectAll = React.useCallback(
136
+ ({ target: { name } }) => {
137
+ onChangeSelectAll({ target: { name, value: !hasAllActionsSelected } });
138
+ },
139
+ [hasAllActionsSelected, onChangeSelectAll]
140
+ );
141
+ const isActionSelected = React.useCallback(
142
+ (actionName) => {
143
+ return selectedAction === actionName;
144
+ },
145
+ [selectedAction]
146
+ );
147
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { children: [
148
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", alignItems: "center", children: [
149
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingRight: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: subCategory.label }) }),
150
+ /* @__PURE__ */ jsxRuntime.jsx(Border, {}),
151
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingLeft: 4, children: /* @__PURE__ */ jsxRuntime.jsx(
152
+ designSystem.Checkbox,
153
+ {
154
+ name: subCategory.name,
155
+ value: hasAllActionsSelected,
156
+ onValueChange: (value) => handleChangeSelectAll({ target: { name: subCategory.name, value } }),
157
+ indeterminate: hasSomeActionsSelected,
158
+ children: formatMessage({ id: "app.utils.select-all", defaultMessage: "Select all" })
159
+ }
160
+ ) })
161
+ ] }),
162
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { paddingTop: 6, paddingBottom: 6, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid, { gap: 2, style: { flex: 1 }, children: subCategory.actions.map((action) => {
163
+ const name = `${action.name}.enabled`;
164
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.GridItem, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(CheckboxWrapper, { isActive: isActionSelected(action.name), padding: 2, hasRadius: true, children: [
165
+ /* @__PURE__ */ jsxRuntime.jsx(
166
+ designSystem.Checkbox,
167
+ {
168
+ value: get__default.default(modifiedData, name, false),
169
+ name,
170
+ onValueChange: (value) => onChange({ target: { name, value } }),
171
+ children: action.label
172
+ }
173
+ ),
174
+ /* @__PURE__ */ jsxRuntime.jsxs(
175
+ "button",
176
+ {
177
+ type: "button",
178
+ onClick: () => onSelectedAction(action.name),
179
+ style: { display: "inline-flex", alignItems: "center" },
180
+ children: [
181
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { as: "span", children: formatMessage(
182
+ {
183
+ id: "app.utils.show-bound-route",
184
+ defaultMessage: "Show bound route for {route}"
185
+ },
186
+ {
187
+ route: action.name
188
+ }
189
+ ) }),
190
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Cog, {})
191
+ ]
192
+ }
193
+ )
194
+ ] }) }, action.name);
195
+ }) }) })
196
+ ] });
197
+ };
198
+ SubCategory.propTypes = {
199
+ subCategory: PropTypes__default.default.object.isRequired
200
+ };
201
+ const PermissionRow = ({ name, permissions }) => {
202
+ const subCategories = React.useMemo(() => {
203
+ return sortBy__default.default(
204
+ Object.values(permissions.controllers).reduce((acc, curr, index2) => {
205
+ const currentName = `${name}.controllers.${Object.keys(permissions.controllers)[index2]}`;
206
+ const actions = sortBy__default.default(
207
+ Object.keys(curr).reduce((acc2, current) => {
208
+ return [
209
+ ...acc2,
210
+ {
211
+ ...curr[current],
212
+ label: current,
213
+ name: `${currentName}.${current}`
214
+ }
215
+ ];
216
+ }, []),
217
+ "label"
218
+ );
219
+ return [
220
+ ...acc,
221
+ {
222
+ actions,
223
+ label: Object.keys(permissions.controllers)[index2],
224
+ name: currentName
225
+ }
226
+ ];
227
+ }, []),
228
+ "label"
229
+ );
230
+ }, [name, permissions]);
231
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 6, children: subCategories.map((subCategory) => /* @__PURE__ */ jsxRuntime.jsx(SubCategory, { subCategory }, subCategory.name)) });
232
+ };
233
+ PermissionRow.propTypes = {
234
+ name: PropTypes__default.default.string.isRequired,
235
+ permissions: PropTypes__default.default.object.isRequired
236
+ };
237
+ const initialState$1 = {
238
+ collapses: []
239
+ };
240
+ const reducer$1 = (state, action) => (
241
+ // eslint-disable-next-line consistent-return
242
+ produce__default.default(state, (draftState) => {
243
+ switch (action.type) {
244
+ case "TOGGLE_COLLAPSE": {
245
+ draftState.collapses = state.collapses.map((collapse, index2) => {
246
+ if (index2 === action.index) {
247
+ return { ...collapse, isOpen: !collapse.isOpen };
248
+ }
249
+ return { ...collapse, isOpen: false };
250
+ });
251
+ break;
252
+ }
253
+ default:
254
+ return draftState;
255
+ }
256
+ })
257
+ );
258
+ const Permissions = () => {
259
+ const { modifiedData } = useUsersPermissions();
260
+ const { formatMessage } = reactIntl.useIntl();
261
+ const [{ collapses }, dispatch] = React.useReducer(
262
+ reducer$1,
263
+ initialState$1,
264
+ (state) => init$1(state, modifiedData)
265
+ );
266
+ const handleToggle = (index2) => dispatch({
267
+ type: "TOGGLE_COLLAPSE",
268
+ index: index2
269
+ });
270
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 1, children: collapses.map((collapse, index2) => /* @__PURE__ */ jsxRuntime.jsxs(
271
+ designSystem.Accordion,
272
+ {
273
+ expanded: collapse.isOpen,
274
+ onToggle: () => handleToggle(index2),
275
+ variant: index2 % 2 === 0 ? "secondary" : void 0,
276
+ children: [
277
+ /* @__PURE__ */ jsxRuntime.jsx(
278
+ designSystem.AccordionToggle,
279
+ {
280
+ title: formatPluginName(collapse.name),
281
+ description: formatMessage(
282
+ {
283
+ id: "users-permissions.Plugin.permissions.plugins.description",
284
+ defaultMessage: "Define all allowed actions for the {name} plugin."
285
+ },
286
+ { name: collapse.name }
287
+ ),
288
+ variant: index2 % 2 ? "primary" : "secondary"
289
+ }
290
+ ),
291
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.AccordionContent, { children: /* @__PURE__ */ jsxRuntime.jsx(PermissionRow, { permissions: modifiedData[collapse.name], name: collapse.name }) })
292
+ ]
293
+ },
294
+ collapse.name
295
+ )) });
296
+ };
297
+ const getMethodColor = (verb) => {
298
+ switch (verb) {
299
+ case "POST": {
300
+ return {
301
+ text: "success600",
302
+ border: "success200",
303
+ background: "success100"
304
+ };
305
+ }
306
+ case "GET": {
307
+ return {
308
+ text: "secondary600",
309
+ border: "secondary200",
310
+ background: "secondary100"
311
+ };
312
+ }
313
+ case "PUT": {
314
+ return {
315
+ text: "warning600",
316
+ border: "warning200",
317
+ background: "warning100"
318
+ };
319
+ }
320
+ case "DELETE": {
321
+ return {
322
+ text: "danger600",
323
+ border: "danger200",
324
+ background: "danger100"
325
+ };
326
+ }
327
+ default: {
328
+ return {
329
+ text: "neutral600",
330
+ border: "neutral200",
331
+ background: "neutral100"
332
+ };
333
+ }
334
+ }
335
+ };
336
+ const MethodBox = styled__default.default(designSystem.Box)`
337
+ margin: -1px;
338
+ border-radius: ${({ theme }) => theme.spaces[1]} 0 0 ${({ theme }) => theme.spaces[1]};
339
+ `;
340
+ function BoundRoute({ route }) {
341
+ const { formatMessage } = reactIntl.useIntl();
342
+ const { method, handler: title, path } = route;
343
+ const formattedRoute = path ? tail__default.default(path.split("/")) : [];
344
+ const [controller = "", action = ""] = title ? title.split(".") : [];
345
+ const colors = getMethodColor(route.method);
346
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
347
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "delta", as: "h3", children: [
348
+ formatMessage({
349
+ id: "users-permissions.BoundRoute.title",
350
+ defaultMessage: "Bound route to"
351
+ }),
352
+ " ",
353
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: controller }),
354
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "delta", textColor: "primary600", children: [
355
+ ".",
356
+ action
357
+ ] })
358
+ ] }),
359
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { hasRadius: true, background: "neutral0", borderColor: "neutral200", gap: 0, children: [
360
+ /* @__PURE__ */ jsxRuntime.jsx(MethodBox, { background: colors.background, borderColor: colors.border, padding: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: colors.text, children: method }) }),
361
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingLeft: 2, paddingRight: 2, children: map__default.default(formattedRoute, (value) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { textColor: value.includes(":") ? "neutral600" : "neutral900", children: [
362
+ "/",
363
+ value
364
+ ] }, value)) })
365
+ ] })
366
+ ] });
367
+ }
368
+ BoundRoute.defaultProps = {
369
+ route: {
370
+ handler: "Nocontroller.error",
371
+ method: "GET",
372
+ path: "/there-is-no-path"
373
+ }
374
+ };
375
+ BoundRoute.propTypes = {
376
+ route: PropTypes__default.default.shape({
377
+ handler: PropTypes__default.default.string,
378
+ method: PropTypes__default.default.string,
379
+ path: PropTypes__default.default.string
380
+ })
381
+ };
382
+ const Policies = () => {
383
+ const { formatMessage } = reactIntl.useIntl();
384
+ const { selectedAction, routes } = useUsersPermissions();
385
+ const path = without__default.default(selectedAction.split("."), "controllers");
386
+ const controllerRoutes = get__default.default(routes, path[0]);
387
+ const pathResolved = path.slice(1).join(".");
388
+ const displayedRoutes = isEmpty__default.default(controllerRoutes) ? [] : controllerRoutes.filter((o) => o.handler.endsWith(pathResolved));
389
+ return /* @__PURE__ */ jsxRuntime.jsx(
390
+ designSystem.GridItem,
391
+ {
392
+ col: 5,
393
+ background: "neutral150",
394
+ paddingTop: 6,
395
+ paddingBottom: 6,
396
+ paddingLeft: 7,
397
+ paddingRight: 7,
398
+ style: { minHeight: "100%" },
399
+ children: selectedAction ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: displayedRoutes.map((route, key) => (
400
+ // eslint-disable-next-line react/no-array-index-key
401
+ /* @__PURE__ */ jsxRuntime.jsx(BoundRoute, { route }, key)
402
+ )) }) : /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
403
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", as: "h3", children: formatMessage({
404
+ id: "users-permissions.Policies.header.title",
405
+ defaultMessage: "Advanced settings"
406
+ }) }),
407
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", textColor: "neutral600", children: formatMessage({
408
+ id: "users-permissions.Policies.header.hint",
409
+ defaultMessage: "Select the application's actions or the plugin's actions and click on the cog icon to display the bound route"
410
+ }) })
411
+ ] })
412
+ }
413
+ );
414
+ };
415
+ const init = (state, permissions, routes) => {
416
+ return {
417
+ ...state,
418
+ initialData: permissions,
419
+ modifiedData: permissions,
420
+ routes
421
+ };
422
+ };
423
+ const initialState = {
424
+ initialData: {},
425
+ modifiedData: {},
426
+ routes: {},
427
+ selectedAction: "",
428
+ policies: []
429
+ };
430
+ const reducer = (state, action) => produce__default.default(state, (draftState) => {
431
+ switch (action.type) {
432
+ case "ON_CHANGE": {
433
+ const keysLength = action.keys.length;
434
+ const isChangingCheckbox = action.keys[keysLength - 1] === "enabled";
435
+ if (action.value && isChangingCheckbox) {
436
+ const selectedAction = take__default.default(action.keys, keysLength - 1).join(".");
437
+ draftState.selectedAction = selectedAction;
438
+ }
439
+ set__default.default(draftState, ["modifiedData", ...action.keys], action.value);
440
+ break;
441
+ }
442
+ case "ON_CHANGE_SELECT_ALL": {
443
+ const pathToValue = ["modifiedData", ...action.keys];
444
+ const oldValues = get__default.default(state, pathToValue, {});
445
+ const updatedValues = Object.keys(oldValues).reduce((acc, current) => {
446
+ acc[current] = { ...oldValues[current], enabled: action.value };
447
+ return acc;
448
+ }, {});
449
+ set__default.default(draftState, pathToValue, updatedValues);
450
+ break;
451
+ }
452
+ case "ON_RESET": {
453
+ draftState.modifiedData = state.initialData;
454
+ break;
455
+ }
456
+ case "ON_SUBMIT_SUCCEEDED": {
457
+ draftState.initialData = state.modifiedData;
458
+ break;
459
+ }
460
+ case "SELECT_ACTION": {
461
+ const { actionToSelect } = action;
462
+ draftState.selectedAction = actionToSelect === state.selectedAction ? "" : actionToSelect;
463
+ break;
464
+ }
465
+ default:
466
+ return draftState;
467
+ }
468
+ });
469
+ const UsersPermissions = React.forwardRef(({ permissions, routes }, ref) => {
470
+ const { formatMessage } = reactIntl.useIntl();
471
+ const [state, dispatch] = React.useReducer(
472
+ reducer,
473
+ initialState,
474
+ (state2) => init(state2, permissions, routes)
475
+ );
476
+ React.useImperativeHandle(ref, () => ({
477
+ getPermissions() {
478
+ return {
479
+ permissions: state.modifiedData
480
+ };
481
+ },
482
+ resetForm() {
483
+ dispatch({ type: "ON_RESET" });
484
+ },
485
+ setFormAfterSubmit() {
486
+ dispatch({ type: "ON_SUBMIT_SUCCEEDED" });
487
+ }
488
+ }));
489
+ const handleChange = ({ target: { name, value } }) => dispatch({
490
+ type: "ON_CHANGE",
491
+ keys: name.split("."),
492
+ value: value === "empty__string_value" ? "" : value
493
+ });
494
+ const handleChangeSelectAll = ({ target: { name, value } }) => dispatch({
495
+ type: "ON_CHANGE_SELECT_ALL",
496
+ keys: name.split("."),
497
+ value
498
+ });
499
+ const handleSelectedAction = (actionToSelect) => dispatch({
500
+ type: "SELECT_ACTION",
501
+ actionToSelect
502
+ });
503
+ const providerValue = {
504
+ ...state,
505
+ onChange: handleChange,
506
+ onChangeSelectAll: handleChangeSelectAll,
507
+ onSelectedAction: handleSelectedAction
508
+ };
509
+ return /* @__PURE__ */ jsxRuntime.jsx(UsersPermissionsProvider, { value: providerValue, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid, { gap: 0, shadow: "filterShadow", hasRadius: true, background: "neutral0", children: [
510
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.GridItem, { col: 7, paddingTop: 6, paddingBottom: 6, paddingLeft: 7, paddingRight: 7, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
511
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
512
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", as: "h2", children: formatMessage({
513
+ id: index.getTrad("Plugins.header.title"),
514
+ defaultMessage: "Permissions"
515
+ }) }),
516
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", textColor: "neutral600", children: formatMessage({
517
+ id: index.getTrad("Plugins.header.description"),
518
+ defaultMessage: "Only actions bound by a route are listed below."
519
+ }) })
520
+ ] }),
521
+ /* @__PURE__ */ jsxRuntime.jsx(Permissions, {})
522
+ ] }) }),
523
+ /* @__PURE__ */ jsxRuntime.jsx(Policies, {})
524
+ ] }) });
525
+ });
526
+ UsersPermissions.propTypes = {
527
+ permissions: PropTypes__default.default.object.isRequired,
528
+ routes: PropTypes__default.default.object.isRequired
529
+ };
530
+ const UsersPermissions$1 = React.memo(UsersPermissions);
531
+ const createRoleSchema = yup__namespace.object().shape({
532
+ name: yup__namespace.string().required(helperPlugin.translatedErrors.required),
533
+ description: yup__namespace.string().required(helperPlugin.translatedErrors.required)
534
+ });
535
+ const cleanPermissions = (permissions) => Object.keys(permissions).reduce((acc, current) => {
536
+ const currentPermission = permissions[current].controllers;
537
+ const cleanedControllers = Object.keys(currentPermission).reduce((acc2, curr) => {
538
+ if (isEmpty__default.default(currentPermission[curr])) {
539
+ return acc2;
540
+ }
541
+ acc2[curr] = currentPermission[curr];
542
+ return acc2;
543
+ }, {});
544
+ if (isEmpty__default.default(cleanedControllers)) {
545
+ return acc;
546
+ }
547
+ acc[current] = { controllers: cleanedControllers };
548
+ return acc;
549
+ }, {});
550
+ const usePlugins = () => {
551
+ const toggleNotification = helperPlugin.useNotification();
552
+ const { get: get2 } = helperPlugin.useFetchClient();
553
+ const { formatAPIError } = helperPlugin.useAPIErrorHandler(index.getTrad);
554
+ const [
555
+ {
556
+ data: permissions,
557
+ isLoading: isLoadingPermissions,
558
+ error: permissionsError,
559
+ refetch: refetchPermissions
560
+ },
561
+ { data: routes, isLoading: isLoadingRoutes, error: routesError, refetch: refetchRoutes }
562
+ ] = reactQuery.useQueries([
563
+ {
564
+ queryKey: ["users-permissions", "permissions"],
565
+ async queryFn() {
566
+ const {
567
+ data: { permissions: permissions2 }
568
+ } = await get2(`/users-permissions/permissions`);
569
+ return permissions2;
570
+ }
571
+ },
572
+ {
573
+ queryKey: ["users-permissions", "routes"],
574
+ async queryFn() {
575
+ const {
576
+ data: { routes: routes2 }
577
+ } = await get2(`/users-permissions/routes`);
578
+ return routes2;
579
+ }
580
+ }
581
+ ]);
582
+ const refetchQueries = async () => {
583
+ await Promise.all([refetchPermissions(), refetchRoutes()]);
584
+ };
585
+ React.useEffect(() => {
586
+ if (permissionsError) {
587
+ toggleNotification({
588
+ type: "warning",
589
+ message: formatAPIError(permissionsError)
590
+ });
591
+ }
592
+ }, [toggleNotification, permissionsError, formatAPIError]);
593
+ React.useEffect(() => {
594
+ if (routesError) {
595
+ toggleNotification({
596
+ type: "warning",
597
+ message: formatAPIError(routesError)
598
+ });
599
+ }
600
+ }, [toggleNotification, routesError, formatAPIError]);
601
+ const isLoading = isLoadingPermissions || isLoadingRoutes;
602
+ return {
603
+ // TODO: these return values need to be memoized, otherwise
604
+ // they will create infinite rendering loops when used as
605
+ // effect dependencies
606
+ permissions: permissions ? cleanPermissions(permissions) : {},
607
+ routes: routes ?? {},
608
+ getData: refetchQueries,
609
+ isLoading
610
+ };
611
+ };
612
+ const CreatePage = () => {
613
+ const { formatMessage } = reactIntl.useIntl();
614
+ const toggleNotification = helperPlugin.useNotification();
615
+ const { goBack } = reactRouterDom.useHistory();
616
+ const { lockApp, unlockApp } = helperPlugin.useOverlayBlocker();
617
+ const { isLoading: isLoadingPlugins, permissions, routes } = usePlugins();
618
+ const { trackUsage } = helperPlugin.useTracking();
619
+ const permissionsRef = React__namespace.useRef();
620
+ const { post } = helperPlugin.useFetchClient();
621
+ const mutation = reactQuery.useMutation((body) => post(`/users-permissions/roles`, body), {
622
+ onError() {
623
+ toggleNotification({
624
+ type: "warning",
625
+ message: {
626
+ id: "notification.error",
627
+ defaultMessage: "An error occurred"
628
+ }
629
+ });
630
+ },
631
+ onSuccess() {
632
+ trackUsage("didCreateRole");
633
+ toggleNotification({
634
+ type: "success",
635
+ message: {
636
+ id: index.getTrad("Settings.roles.created"),
637
+ defaultMessage: "Role created"
638
+ }
639
+ });
640
+ goBack();
641
+ }
642
+ });
643
+ const handleCreateRoleSubmit = async (data) => {
644
+ lockApp();
645
+ const permissions2 = permissionsRef.current.getPermissions();
646
+ await mutation.mutate({ ...data, ...permissions2, users: [] });
647
+ unlockApp();
648
+ };
649
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { children: [
650
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.SettingsPageTitle, { name: "Roles" }),
651
+ /* @__PURE__ */ jsxRuntime.jsx(
652
+ formik.Formik,
653
+ {
654
+ enableReinitialize: true,
655
+ initialValues: { name: "", description: "" },
656
+ onSubmit: handleCreateRoleSubmit,
657
+ validationSchema: createRoleSchema,
658
+ children: ({ handleSubmit, values, handleChange, errors }) => /* @__PURE__ */ jsxRuntime.jsxs(helperPlugin.Form, { noValidate: true, onSubmit: handleSubmit, children: [
659
+ /* @__PURE__ */ jsxRuntime.jsx(
660
+ designSystem.HeaderLayout,
661
+ {
662
+ primaryAction: !isLoadingPlugins && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { type: "submit", loading: mutation.isLoading, startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}), children: formatMessage({
663
+ id: "global.save",
664
+ defaultMessage: "Save"
665
+ }) }),
666
+ title: formatMessage({
667
+ id: "Settings.roles.create.title",
668
+ defaultMessage: "Create a role"
669
+ }),
670
+ subtitle: formatMessage({
671
+ id: "Settings.roles.create.description",
672
+ defaultMessage: "Define the rights given to the role"
673
+ })
674
+ }
675
+ ),
676
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(
677
+ designSystem.Flex,
678
+ {
679
+ background: "neutral0",
680
+ direction: "column",
681
+ alignItems: "stretch",
682
+ gap: 7,
683
+ hasRadius: true,
684
+ paddingTop: 6,
685
+ paddingBottom: 6,
686
+ paddingLeft: 7,
687
+ paddingRight: 7,
688
+ shadow: "filterShadow",
689
+ children: [
690
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", children: [
691
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", as: "h2", children: formatMessage({
692
+ id: index.getTrad("EditPage.form.roles"),
693
+ defaultMessage: "Role details"
694
+ }) }),
695
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid, { gap: 4, children: [
696
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.GridItem, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsx(
697
+ designSystem.TextInput,
698
+ {
699
+ name: "name",
700
+ value: values.name || "",
701
+ onChange: handleChange,
702
+ label: formatMessage({
703
+ id: "global.name",
704
+ defaultMessage: "Name"
705
+ }),
706
+ error: errors?.name ? formatMessage({ id: errors.name, defaultMessage: "Name is required" }) : false,
707
+ required: true
708
+ }
709
+ ) }),
710
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.GridItem, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsx(
711
+ designSystem.Textarea,
712
+ {
713
+ id: "description",
714
+ value: values.description || "",
715
+ onChange: handleChange,
716
+ label: formatMessage({
717
+ id: "global.description",
718
+ defaultMessage: "Description"
719
+ }),
720
+ error: errors?.description ? formatMessage({
721
+ id: errors.description,
722
+ defaultMessage: "Description is required"
723
+ }) : false,
724
+ required: true
725
+ }
726
+ ) })
727
+ ] })
728
+ ] }),
729
+ !isLoadingPlugins && /* @__PURE__ */ jsxRuntime.jsx(
730
+ UsersPermissions$1,
731
+ {
732
+ ref: permissionsRef,
733
+ permissions,
734
+ routes
735
+ }
736
+ )
737
+ ]
738
+ }
739
+ ) })
740
+ ] })
741
+ }
742
+ )
743
+ ] });
744
+ };
745
+ const ProtectedRolesCreatePage = () => /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.createRole, children: /* @__PURE__ */ jsxRuntime.jsx(CreatePage, {}) });
746
+ const EditPage = () => {
747
+ const { formatMessage } = reactIntl.useIntl();
748
+ const toggleNotification = helperPlugin.useNotification();
749
+ const { lockApp, unlockApp } = helperPlugin.useOverlayBlocker();
750
+ const {
751
+ params: { id }
752
+ } = reactRouterDom.useRouteMatch(`/settings/users-permissions/roles/:id`);
753
+ const { get: get2 } = helperPlugin.useFetchClient();
754
+ const { isLoading: isLoadingPlugins, routes } = usePlugins();
755
+ const {
756
+ data: role,
757
+ isLoading: isLoadingRole,
758
+ refetch: refetchRole
759
+ } = reactQuery.useQuery(["users-permissions", "role", id], async () => {
760
+ const {
761
+ data: { role: role2 }
762
+ } = await get2(`/users-permissions/roles/${id}`);
763
+ return role2;
764
+ });
765
+ const permissionsRef = React__namespace.useRef();
766
+ const { put } = helperPlugin.useFetchClient();
767
+ const { formatAPIError } = helperPlugin.useAPIErrorHandler();
768
+ const mutation = reactQuery.useMutation((body) => put(`/users-permissions/roles/${id}`, body), {
769
+ onError(error) {
770
+ toggleNotification({
771
+ type: "warning",
772
+ message: formatAPIError(error)
773
+ });
774
+ },
775
+ async onSuccess() {
776
+ toggleNotification({
777
+ type: "success",
778
+ message: {
779
+ id: index.getTrad("Settings.roles.created"),
780
+ defaultMessage: "Role edited"
781
+ }
782
+ });
783
+ await refetchRole();
784
+ }
785
+ });
786
+ const handleEditRoleSubmit = async (data) => {
787
+ lockApp();
788
+ const permissions = permissionsRef.current.getPermissions();
789
+ await mutation.mutate({ ...data, ...permissions, users: [] });
790
+ unlockApp();
791
+ };
792
+ if (isLoadingRole) {
793
+ return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {});
794
+ }
795
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { children: [
796
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.SettingsPageTitle, { name: "Roles" }),
797
+ /* @__PURE__ */ jsxRuntime.jsx(
798
+ formik.Formik,
799
+ {
800
+ enableReinitialize: true,
801
+ initialValues: { name: role.name, description: role.description },
802
+ onSubmit: handleEditRoleSubmit,
803
+ validationSchema: createRoleSchema,
804
+ children: ({ handleSubmit, values, handleChange, errors }) => /* @__PURE__ */ jsxRuntime.jsxs(helperPlugin.Form, { noValidate: true, onSubmit: handleSubmit, children: [
805
+ /* @__PURE__ */ jsxRuntime.jsx(
806
+ designSystem.HeaderLayout,
807
+ {
808
+ primaryAction: !isLoadingPlugins && /* @__PURE__ */ jsxRuntime.jsx(
809
+ designSystem.Button,
810
+ {
811
+ disabled: role.code === "strapi-super-admin",
812
+ type: "submit",
813
+ loading: mutation.isLoading,
814
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}),
815
+ children: formatMessage({
816
+ id: "global.save",
817
+ defaultMessage: "Save"
818
+ })
819
+ }
820
+ ),
821
+ title: role.name,
822
+ subtitle: role.description,
823
+ navigationAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.Link, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLeft, {}), to: "/settings/users-permissions/roles", children: formatMessage({
824
+ id: "global.back",
825
+ defaultMessage: "Back"
826
+ }) })
827
+ }
828
+ ),
829
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.ContentLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(
830
+ designSystem.Flex,
831
+ {
832
+ background: "neutral0",
833
+ direction: "column",
834
+ alignItems: "stretch",
835
+ gap: 7,
836
+ hasRadius: true,
837
+ paddingTop: 6,
838
+ paddingBottom: 6,
839
+ paddingLeft: 7,
840
+ paddingRight: 7,
841
+ shadow: "filterShadow",
842
+ children: [
843
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 4, children: [
844
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", as: "h2", children: formatMessage({
845
+ id: index.getTrad("EditPage.form.roles"),
846
+ defaultMessage: "Role details"
847
+ }) }),
848
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid, { gap: 4, children: [
849
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.GridItem, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsx(
850
+ designSystem.TextInput,
851
+ {
852
+ name: "name",
853
+ value: values.name || "",
854
+ onChange: handleChange,
855
+ label: formatMessage({
856
+ id: "global.name",
857
+ defaultMessage: "Name"
858
+ }),
859
+ error: errors?.name ? formatMessage({ id: errors.name, defaultMessage: "Name is required" }) : false,
860
+ required: true
861
+ }
862
+ ) }),
863
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.GridItem, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsx(
864
+ designSystem.Textarea,
865
+ {
866
+ id: "description",
867
+ value: values.description || "",
868
+ onChange: handleChange,
869
+ label: formatMessage({
870
+ id: "global.description",
871
+ defaultMessage: "Description"
872
+ }),
873
+ error: errors?.description ? formatMessage({
874
+ id: errors.description,
875
+ defaultMessage: "Description is required"
876
+ }) : false,
877
+ required: true
878
+ }
879
+ ) })
880
+ ] })
881
+ ] }),
882
+ !isLoadingPlugins && /* @__PURE__ */ jsxRuntime.jsx(
883
+ UsersPermissions$1,
884
+ {
885
+ ref: permissionsRef,
886
+ permissions: role.permissions,
887
+ routes
888
+ }
889
+ )
890
+ ]
891
+ }
892
+ ) })
893
+ ] })
894
+ }
895
+ )
896
+ ] });
897
+ };
898
+ const ProtectedRolesEditPage = () => /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.updateRole, children: /* @__PURE__ */ jsxRuntime.jsx(EditPage, {}) });
899
+ const EditLink = styled__default.default(designSystem.Link)`
900
+ align-items: center;
901
+ height: ${helperPlugin.pxToRem(32)};
902
+ display: flex;
903
+ justify-content: center;
904
+ padding: ${({ theme }) => `${theme.spaces[2]}}`};
905
+ width: ${helperPlugin.pxToRem(32)};
906
+
907
+ svg {
908
+ height: ${helperPlugin.pxToRem(12)};
909
+ width: ${helperPlugin.pxToRem(12)};
910
+
911
+ path {
912
+ fill: ${({ theme }) => theme.colors.neutral500};
913
+ }
914
+ }
915
+
916
+ &:hover,
917
+ &:focus {
918
+ svg {
919
+ path {
920
+ fill: ${({ theme }) => theme.colors.neutral800};
921
+ }
922
+ }
923
+ }
924
+ `;
925
+ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDelete }) => {
926
+ const { formatMessage } = reactIntl.useIntl();
927
+ const { push } = reactRouterDom.useHistory();
928
+ const [showConfirmDelete, setShowConfirmDelete] = onDelete;
929
+ const checkCanDeleteRole = (role) => canDelete && !["public", "authenticated"].includes(role.type);
930
+ const handleClickDelete = (id) => {
931
+ setRoleToDelete(id);
932
+ setShowConfirmDelete(!showConfirmDelete);
933
+ };
934
+ const handleClickEdit = (id) => {
935
+ push(`/settings/users-permissions/roles/${id}`);
936
+ };
937
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tbody, { children: sortedRoles?.map((role) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { ...helperPlugin.onRowClick({ fn: () => handleClickEdit(role.id) }), children: [
938
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "20%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: role.name }) }),
939
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "50%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: role.description }) }),
940
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { width: "30%", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage(
941
+ {
942
+ id: "Roles.RoleRow.user-count",
943
+ defaultMessage: "{number, plural, =0 {# user} one {# user} other {# users}}"
944
+ },
945
+ { number: role.nb_users }
946
+ ) }) }),
947
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "end", ...helperPlugin.stopPropagation, children: [
948
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: permissions.updateRole, children: /* @__PURE__ */ jsxRuntime.jsx(
949
+ EditLink,
950
+ {
951
+ to: `/settings/users-permissions/roles/${role.id}`,
952
+ "aria-label": formatMessage(
953
+ { id: "app.component.table.edit", defaultMessage: "Edit {target}" },
954
+ { target: `${role.name}` }
955
+ ),
956
+ children: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {})
957
+ }
958
+ ) }),
959
+ checkCanDeleteRole(role) && /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: permissions.deleteRole, children: /* @__PURE__ */ jsxRuntime.jsx(
960
+ designSystem.IconButton,
961
+ {
962
+ onClick: () => handleClickDelete(role.id),
963
+ noBorder: true,
964
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}),
965
+ label: formatMessage(
966
+ { id: "global.delete-target", defaultMessage: "Delete {target}" },
967
+ { target: `${role.name}` }
968
+ )
969
+ }
970
+ ) })
971
+ ] }) })
972
+ ] }, role.name)) });
973
+ };
974
+ TableBody.defaultProps = {
975
+ canDelete: false
976
+ };
977
+ TableBody.propTypes = {
978
+ onDelete: PropTypes__default.default.array.isRequired,
979
+ permissions: PropTypes__default.default.object.isRequired,
980
+ setRoleToDelete: PropTypes__default.default.func.isRequired,
981
+ sortedRoles: PropTypes__default.default.array.isRequired,
982
+ canDelete: PropTypes__default.default.bool
983
+ };
984
+ const fetchData = async (toggleNotification, notifyStatus) => {
985
+ try {
986
+ const { get: get2 } = helperPlugin.getFetchClient();
987
+ const { data } = await get2("/users-permissions/roles");
988
+ notifyStatus("The roles have loaded successfully");
989
+ return data;
990
+ } catch (err) {
991
+ toggleNotification({
992
+ type: "warning",
993
+ message: { id: "notification.error" }
994
+ });
995
+ throw new Error(err);
996
+ }
997
+ };
998
+ const deleteData = async (id, toggleNotification) => {
999
+ try {
1000
+ const { del } = helperPlugin.getFetchClient();
1001
+ await del(`/users-permissions/roles/${id}`);
1002
+ } catch (error) {
1003
+ toggleNotification({
1004
+ type: "warning",
1005
+ message: { id: "notification.error", defaultMessage: "An error occured" }
1006
+ });
1007
+ }
1008
+ };
1009
+ const RolesListPage = () => {
1010
+ const { trackUsage } = helperPlugin.useTracking();
1011
+ const { formatMessage, locale } = reactIntl.useIntl();
1012
+ const toggleNotification = helperPlugin.useNotification();
1013
+ const { notifyStatus } = designSystem.useNotifyAT();
1014
+ const [{ query }] = helperPlugin.useQueryParams();
1015
+ const _q = query?._q || "";
1016
+ const [showConfirmDelete, setShowConfirmDelete] = React.useState(false);
1017
+ const [isConfirmButtonLoading, setIsConfirmButtonLoading] = React.useState(false);
1018
+ const [roleToDelete, setRoleToDelete] = React.useState();
1019
+ helperPlugin.useFocusWhenNavigate();
1020
+ const {
1021
+ isLoading: isLoadingForPermissions,
1022
+ allowedActions: { canRead, canDelete }
1023
+ } = helperPlugin.useRBAC({
1024
+ create: index.PERMISSIONS.createRole,
1025
+ read: index.PERMISSIONS.readRoles,
1026
+ update: index.PERMISSIONS.updateRole,
1027
+ delete: index.PERMISSIONS.deleteRole
1028
+ });
1029
+ const {
1030
+ isLoading: isLoadingForData,
1031
+ data: { roles },
1032
+ isFetching,
1033
+ refetch
1034
+ } = reactQuery.useQuery("get-roles", () => fetchData(toggleNotification, notifyStatus), {
1035
+ initialData: {},
1036
+ enabled: canRead
1037
+ });
1038
+ const { includes } = helperPlugin.useFilter(locale, {
1039
+ sensitivity: "base"
1040
+ });
1041
+ const formatter = helperPlugin.useCollator(locale, {
1042
+ sensitivity: "base"
1043
+ });
1044
+ const isLoading = isLoadingForData || isFetching;
1045
+ const handleShowConfirmDelete = () => {
1046
+ setShowConfirmDelete(!showConfirmDelete);
1047
+ };
1048
+ const emptyLayout = {
1049
+ roles: {
1050
+ id: index.getTrad("Roles.empty"),
1051
+ defaultMessage: "You don't have any roles yet."
1052
+ },
1053
+ search: {
1054
+ id: index.getTrad("Roles.empty.search"),
1055
+ defaultMessage: "No roles match the search."
1056
+ }
1057
+ };
1058
+ const pageTitle = formatMessage({
1059
+ id: "global.roles",
1060
+ defaultMessage: "Roles"
1061
+ });
1062
+ const deleteMutation = reactQuery.useMutation((id) => deleteData(id, toggleNotification), {
1063
+ async onSuccess() {
1064
+ await refetch();
1065
+ }
1066
+ });
1067
+ const handleConfirmDelete = async () => {
1068
+ setIsConfirmButtonLoading(true);
1069
+ await deleteMutation.mutateAsync(roleToDelete);
1070
+ setShowConfirmDelete(!showConfirmDelete);
1071
+ setIsConfirmButtonLoading(false);
1072
+ };
1073
+ const sortedRoles = (roles || []).filter((role) => includes(role.name, _q) || includes(role.description, _q)).sort(
1074
+ (a, b) => formatter.compare(a.name, b.name) || formatter.compare(a.description, b.description)
1075
+ );
1076
+ const emptyContent = _q && !sortedRoles.length ? "search" : "roles";
1077
+ const colCount = 4;
1078
+ const rowCount = (roles?.length || 0) + 1;
1079
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Layout, { children: [
1080
+ /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.SettingsPageTitle, { name: pageTitle }),
1081
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Main, { "aria-busy": isLoading, children: [
1082
+ /* @__PURE__ */ jsxRuntime.jsx(
1083
+ designSystem.HeaderLayout,
1084
+ {
1085
+ title: formatMessage({
1086
+ id: "global.roles",
1087
+ defaultMessage: "Roles"
1088
+ }),
1089
+ subtitle: formatMessage({
1090
+ id: "Settings.roles.list.description",
1091
+ defaultMessage: "List of roles"
1092
+ }),
1093
+ primaryAction: /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPermissions, { permissions: index.PERMISSIONS.createRole, children: /* @__PURE__ */ jsxRuntime.jsx(
1094
+ helperPlugin.LinkButton,
1095
+ {
1096
+ to: "/settings/users-permissions/roles/new",
1097
+ onClick: () => trackUsage("willCreateRole"),
1098
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
1099
+ size: "S",
1100
+ children: formatMessage({
1101
+ id: index.getTrad("List.button.roles"),
1102
+ defaultMessage: "Add new role"
1103
+ })
1104
+ }
1105
+ ) })
1106
+ }
1107
+ ),
1108
+ /* @__PURE__ */ jsxRuntime.jsx(
1109
+ designSystem.ActionLayout,
1110
+ {
1111
+ startActions: /* @__PURE__ */ jsxRuntime.jsx(
1112
+ helperPlugin.SearchURLQuery,
1113
+ {
1114
+ label: formatMessage({
1115
+ id: "app.component.search.label",
1116
+ defaultMessage: "Search"
1117
+ })
1118
+ }
1119
+ )
1120
+ }
1121
+ ),
1122
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ContentLayout, { children: [
1123
+ !canRead && /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.NoPermissions, {}),
1124
+ (isLoading || isLoadingForPermissions) && /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.LoadingIndicatorPage, {}),
1125
+ canRead && sortedRoles && sortedRoles?.length ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Table, { colCount, rowCount, children: [
1126
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Thead, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
1127
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: formatMessage({ id: "global.name", defaultMessage: "Name" }) }) }),
1128
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: formatMessage({
1129
+ id: "global.description",
1130
+ defaultMessage: "Description"
1131
+ }) }) }),
1132
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", textColor: "neutral600", children: formatMessage({
1133
+ id: "global.users",
1134
+ defaultMessage: "Users"
1135
+ }) }) }),
1136
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Th, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { children: formatMessage({
1137
+ id: "global.actions",
1138
+ defaultMessage: "Actions"
1139
+ }) }) })
1140
+ ] }) }),
1141
+ /* @__PURE__ */ jsxRuntime.jsx(
1142
+ TableBody,
1143
+ {
1144
+ sortedRoles,
1145
+ canDelete,
1146
+ permissions: index.PERMISSIONS,
1147
+ setRoleToDelete,
1148
+ onDelete: [showConfirmDelete, setShowConfirmDelete]
1149
+ }
1150
+ )
1151
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.EmptyStateLayout, { content: emptyLayout[emptyContent] })
1152
+ ] }),
1153
+ /* @__PURE__ */ jsxRuntime.jsx(
1154
+ helperPlugin.ConfirmDialog,
1155
+ {
1156
+ isConfirmButtonLoading,
1157
+ onConfirm: handleConfirmDelete,
1158
+ onToggleDialog: handleShowConfirmDelete,
1159
+ isOpen: showConfirmDelete
1160
+ }
1161
+ )
1162
+ ] })
1163
+ ] });
1164
+ };
1165
+ const ProtectedRolesListPage = () => {
1166
+ return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.accessRoles, children: /* @__PURE__ */ jsxRuntime.jsx(RolesListPage, {}) });
1167
+ };
1168
+ const Roles = () => {
1169
+ return /* @__PURE__ */ jsxRuntime.jsx(helperPlugin.CheckPagePermissions, { permissions: index.PERMISSIONS.accessRoles, children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Switch, { children: [
1170
+ /* @__PURE__ */ jsxRuntime.jsx(
1171
+ reactRouterDom.Route,
1172
+ {
1173
+ path: "/settings/users-permissions/roles/new",
1174
+ component: ProtectedRolesCreatePage,
1175
+ exact: true
1176
+ }
1177
+ ),
1178
+ /* @__PURE__ */ jsxRuntime.jsx(
1179
+ reactRouterDom.Route,
1180
+ {
1181
+ path: "/settings/users-permissions/roles/:id",
1182
+ component: ProtectedRolesEditPage,
1183
+ exact: true
1184
+ }
1185
+ ),
1186
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "/settings/users-permissions/roles", component: ProtectedRolesListPage, exact: true }),
1187
+ /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Route, { path: "", component: helperPlugin.AnErrorOccurred })
1188
+ ] }) });
1189
+ };
1190
+ exports.default = Roles;
1191
+ //# sourceMappingURL=index-9aae7d58.js.map