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