@appcorp/fusion-storybook 0.5.1 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/base-modules/workspace/cache.d.ts +10 -1
- package/base-modules/workspace/cache.js +37 -2
- package/base-modules/workspace/context.d.ts +36 -2
- package/base-modules/workspace/context.js +62 -17
- package/base-modules/workspace/form.js +14 -11
- package/base-modules/workspace/page.d.ts +5 -0
- package/base-modules/workspace/page.js +1 -1
- package/base-modules/workspace/view.js +11 -11
- package/base-modules/workspace-user/context.d.ts +11 -5
- package/base-modules/workspace-user/context.js +99 -32
- package/base-modules/workspace-user/form.js +59 -1
- package/base-modules/workspace-user/more-actions.js +3 -4
- package/base-modules/workspace-user/page.js +2 -2
- package/package.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/types/user-management.d.ts +2 -1
- package/utils/resolve-rbac-permissions.js +84 -1
|
@@ -32,7 +32,7 @@ import { workspaceUserFormValidation } from "./validate";
|
|
|
32
32
|
import { generateThemeToast, TOAST_VARIANT, } from "@appcorp/shadcn/lib/toast-utils";
|
|
33
33
|
import { useTranslations } from "next-intl";
|
|
34
34
|
import { getCachedWorkspaceSync } from "../workspace/cache";
|
|
35
|
-
import { Eye, Filter, Plus } from "lucide-react";
|
|
35
|
+
import { Eye, Filter, Pencil, Plus, Trash2 } from "lucide-react";
|
|
36
36
|
// ============================================================================
|
|
37
37
|
// 1.1 DRAWER TYPES
|
|
38
38
|
// ============================================================================
|
|
@@ -69,6 +69,7 @@ const workspaceUserConfig = {
|
|
|
69
69
|
workspaceId: "",
|
|
70
70
|
// Relations (populated from byId fetch)
|
|
71
71
|
role: undefined,
|
|
72
|
+
user: undefined,
|
|
72
73
|
workspace: undefined,
|
|
73
74
|
},
|
|
74
75
|
drawerTypes: DRAWER_TYPES,
|
|
@@ -108,8 +109,16 @@ export const useWorkspaceUserModule = () => {
|
|
|
108
109
|
id: state.id,
|
|
109
110
|
roleId: state.roleId,
|
|
110
111
|
userId: state.userId,
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
// The form field is read-only; the cached workspace is the source of truth.
|
|
113
|
+
workspaceId: state.workspaceId || (workspace === null || workspace === void 0 ? void 0 : workspace.id),
|
|
114
|
+
}), [
|
|
115
|
+
state.enabled,
|
|
116
|
+
state.id,
|
|
117
|
+
state.roleId,
|
|
118
|
+
state.userId,
|
|
119
|
+
state.workspaceId,
|
|
120
|
+
workspace === null || workspace === void 0 ? void 0 : workspace.id,
|
|
121
|
+
]);
|
|
113
122
|
const byIdParams = useMemo(() => ({ id: state.id }), [state.id]);
|
|
114
123
|
const deleteParams = useMemo(() => ({ id: state.id }), [state.id]);
|
|
115
124
|
// ============================================================================
|
|
@@ -150,17 +159,17 @@ export const useWorkspaceUserModule = () => {
|
|
|
150
159
|
payload: {
|
|
151
160
|
form: {
|
|
152
161
|
enabled: true,
|
|
153
|
-
filterEnabled: undefined,
|
|
154
162
|
id: "",
|
|
155
163
|
roleId: null,
|
|
156
164
|
userId: "",
|
|
157
|
-
workspaceId: "",
|
|
165
|
+
workspaceId: (workspace === null || workspace === void 0 ? void 0 : workspace.id) || "",
|
|
158
166
|
role: undefined,
|
|
167
|
+
user: undefined,
|
|
159
168
|
workspace: undefined,
|
|
160
169
|
},
|
|
161
170
|
},
|
|
162
171
|
});
|
|
163
|
-
}, [dispatch]);
|
|
172
|
+
}, [dispatch, workspace === null || workspace === void 0 ? void 0 : workspace.id]);
|
|
164
173
|
// ============================================================================
|
|
165
174
|
// 1.4.4 API CALLBACKS
|
|
166
175
|
// ============================================================================
|
|
@@ -181,7 +190,6 @@ export const useWorkspaceUserModule = () => {
|
|
|
181
190
|
}
|
|
182
191
|
}, [dispatch, showToast, t]);
|
|
183
192
|
const updateCallback = useCallback(({ data, error }) => {
|
|
184
|
-
var _a;
|
|
185
193
|
const isCreated = isCreatedOrUpdated(data);
|
|
186
194
|
if (error) {
|
|
187
195
|
showToast(isCreated
|
|
@@ -191,7 +199,6 @@ export const useWorkspaceUserModule = () => {
|
|
|
191
199
|
}
|
|
192
200
|
if (data) {
|
|
193
201
|
showToast(t("messagesWorkspaceUserSaved"), TOAST_VARIANT.SUCCESS);
|
|
194
|
-
(_a = listFetchNowRef.current) === null || _a === void 0 ? void 0 : _a.call(listFetchNowRef);
|
|
195
202
|
resetFormAndCloseDrawer();
|
|
196
203
|
}
|
|
197
204
|
}, [resetFormAndCloseDrawer, showToast, t]);
|
|
@@ -203,25 +210,25 @@ export const useWorkspaceUserModule = () => {
|
|
|
203
210
|
if (data) {
|
|
204
211
|
dispatch({
|
|
205
212
|
type: WORKSPACE_USER_ACTION_TYPES.SET_FORM_DATA,
|
|
206
|
-
payload: { form:
|
|
213
|
+
payload: { form: data },
|
|
207
214
|
});
|
|
208
215
|
}
|
|
209
216
|
}, [dispatch, showToast, t]);
|
|
210
217
|
const deleteCallback = useCallback(({ data, error }) => {
|
|
211
|
-
var _a;
|
|
212
218
|
if (error) {
|
|
213
219
|
showToast(t("messagesWorkspaceUserDeleteFailed"), TOAST_VARIANT.ERROR);
|
|
214
220
|
return;
|
|
215
221
|
}
|
|
216
222
|
if (data) {
|
|
217
223
|
showToast(t("messagesWorkspaceUserDeleted"), TOAST_VARIANT.SUCCESS);
|
|
218
|
-
(
|
|
224
|
+
resetRecordFormState();
|
|
225
|
+
resetFormAndCloseDrawer();
|
|
219
226
|
}
|
|
220
|
-
}, [showToast, t]);
|
|
227
|
+
}, [resetFormAndCloseDrawer, resetRecordFormState, showToast, t]);
|
|
221
228
|
// ============================================================================
|
|
222
229
|
// 1.4.5 API HOOKS
|
|
223
230
|
// ============================================================================
|
|
224
|
-
const { listFetchNow, listLoading, updateFetchNow, updateLoading, deleteFetchNow, deleteLoading, byIdLoading, } = useModuleEntityV2({
|
|
231
|
+
const { listFetchNow, listLoading, updateFetchNow, updateLoading, deleteFetchNow, deleteLoading, byIdFetchNow, byIdLoading, } = useModuleEntityV2({
|
|
225
232
|
byIdCallback,
|
|
226
233
|
byIdParams,
|
|
227
234
|
deleteCallback,
|
|
@@ -248,9 +255,18 @@ export const useWorkspaceUserModule = () => {
|
|
|
248
255
|
const handleChange = useCallback((field, value) => {
|
|
249
256
|
dispatch({
|
|
250
257
|
type: WORKSPACE_USER_ACTION_TYPES.SET_INPUT_FIELD,
|
|
251
|
-
payload: { field, value },
|
|
258
|
+
payload: { key: field, value },
|
|
252
259
|
});
|
|
253
|
-
|
|
260
|
+
// A retried field must not keep blocking the Save button.
|
|
261
|
+
if (state.errors[field]) {
|
|
262
|
+
const nextErrors = Object.assign({}, state.errors);
|
|
263
|
+
delete nextErrors[field];
|
|
264
|
+
dispatch({
|
|
265
|
+
type: WORKSPACE_USER_ACTION_TYPES.SET_ERRORS,
|
|
266
|
+
payload: { errors: nextErrors },
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}, [dispatch, state.errors]);
|
|
254
270
|
const handleFilters = useCallback(() => {
|
|
255
271
|
dispatch({
|
|
256
272
|
type: WORKSPACE_USER_ACTION_TYPES.SET_DRAWER,
|
|
@@ -260,15 +276,16 @@ export const useWorkspaceUserModule = () => {
|
|
|
260
276
|
const handleMoreActions = useCallback(() => {
|
|
261
277
|
dispatch({
|
|
262
278
|
type: WORKSPACE_USER_ACTION_TYPES.SET_DRAWER,
|
|
263
|
-
payload: { drawer: WORKSPACE_USER_DRAWER.
|
|
279
|
+
payload: { drawer: WORKSPACE_USER_DRAWER.MORE_ACTIONS_DRAWER },
|
|
264
280
|
});
|
|
265
281
|
}, [dispatch]);
|
|
266
|
-
const handleView = useCallback(() => {
|
|
282
|
+
const handleView = useCallback((row) => {
|
|
283
|
+
byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row === null || row === void 0 ? void 0 : row.id } });
|
|
267
284
|
dispatch({
|
|
268
285
|
type: WORKSPACE_USER_ACTION_TYPES.SET_DRAWER,
|
|
269
286
|
payload: { drawer: WORKSPACE_USER_DRAWER.VIEW_DRAWER },
|
|
270
287
|
});
|
|
271
|
-
}, [dispatch]);
|
|
288
|
+
}, [byIdFetchNow, dispatch]);
|
|
272
289
|
const handleSearch = useCallback((query) => {
|
|
273
290
|
dispatch({
|
|
274
291
|
type: WORKSPACE_USER_ACTION_TYPES.SET_SEARCH_QUERY,
|
|
@@ -299,14 +316,49 @@ export const useWorkspaceUserModule = () => {
|
|
|
299
316
|
});
|
|
300
317
|
}, [dispatch]);
|
|
301
318
|
const handleDelete = useCallback((row) => {
|
|
302
|
-
if (row === null || row === void 0 ? void 0 : row.id)
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
319
|
+
if (!(row === null || row === void 0 ? void 0 : row.id))
|
|
320
|
+
return;
|
|
321
|
+
if (!confirm(t("messagesDeleteConfirmation")))
|
|
322
|
+
return;
|
|
323
|
+
deleteFetchNow === null || deleteFetchNow === void 0 ? void 0 : deleteFetchNow(undefined, {
|
|
324
|
+
body: JSON.stringify({ id: row.id }),
|
|
325
|
+
});
|
|
326
|
+
}, [deleteFetchNow, t]);
|
|
327
|
+
const handleCreate = useCallback(() => {
|
|
328
|
+
resetRecordFormState();
|
|
329
|
+
dispatch({
|
|
330
|
+
type: WORKSPACE_USER_ACTION_TYPES.SET_DRAWER,
|
|
331
|
+
payload: { drawer: WORKSPACE_USER_DRAWER.FORM_DRAWER },
|
|
332
|
+
});
|
|
333
|
+
}, [dispatch, resetRecordFormState]);
|
|
334
|
+
const handleEdit = useCallback((row) => {
|
|
335
|
+
var _a, _b, _c, _d, _e;
|
|
336
|
+
if (!(row === null || row === void 0 ? void 0 : row.id))
|
|
337
|
+
return;
|
|
338
|
+
// Seed the form from the row so Save is never sent against a stale id,
|
|
339
|
+
// then refresh the full record (relations) from the API.
|
|
340
|
+
dispatch({
|
|
341
|
+
type: WORKSPACE_USER_ACTION_TYPES.SET_FORM_DATA,
|
|
342
|
+
payload: {
|
|
343
|
+
form: {
|
|
344
|
+
enabled: (_a = row.enabled) !== null && _a !== void 0 ? _a : true,
|
|
345
|
+
id: row.id,
|
|
346
|
+
roleId: (_b = row.roleId) !== null && _b !== void 0 ? _b : null,
|
|
347
|
+
userId: (_c = row.userId) !== null && _c !== void 0 ? _c : "",
|
|
348
|
+
workspaceId: (_e = (_d = row.workspaceId) !== null && _d !== void 0 ? _d : workspace === null || workspace === void 0 ? void 0 : workspace.id) !== null && _e !== void 0 ? _e : "",
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
});
|
|
352
|
+
dispatch({
|
|
353
|
+
type: WORKSPACE_USER_ACTION_TYPES.SET_ERRORS,
|
|
354
|
+
payload: { errors: {} },
|
|
355
|
+
});
|
|
356
|
+
byIdFetchNow === null || byIdFetchNow === void 0 ? void 0 : byIdFetchNow(undefined, { params: { id: row.id } });
|
|
357
|
+
dispatch({
|
|
358
|
+
type: WORKSPACE_USER_ACTION_TYPES.SET_DRAWER,
|
|
359
|
+
payload: { drawer: WORKSPACE_USER_DRAWER.FORM_DRAWER },
|
|
360
|
+
});
|
|
361
|
+
}, [byIdFetchNow, dispatch, workspace === null || workspace === void 0 ? void 0 : workspace.id]);
|
|
310
362
|
const handlePageChange = useCallback((page) => {
|
|
311
363
|
const nextPage = typeof page === "number" ? page : state.currentPage + 1;
|
|
312
364
|
dispatch({
|
|
@@ -358,20 +410,20 @@ export const useWorkspaceUserModule = () => {
|
|
|
358
410
|
// ============================================================================
|
|
359
411
|
const headerActions = useMemo(() => [
|
|
360
412
|
{
|
|
361
|
-
enabled:
|
|
413
|
+
enabled: true,
|
|
362
414
|
handleOnClick: handleFilters,
|
|
363
415
|
label: t("actionsButtonFilters"),
|
|
364
416
|
order: 1,
|
|
365
417
|
icon: Filter,
|
|
366
418
|
},
|
|
367
419
|
{
|
|
368
|
-
enabled:
|
|
369
|
-
handleOnClick:
|
|
370
|
-
label: t("
|
|
420
|
+
enabled: true,
|
|
421
|
+
handleOnClick: handleCreate,
|
|
422
|
+
label: t("actionsButtonAdd"),
|
|
371
423
|
order: 2,
|
|
372
424
|
icon: Plus,
|
|
373
425
|
},
|
|
374
|
-
], [
|
|
426
|
+
], [handleCreate, handleFilters, t]);
|
|
375
427
|
const rowActions = useMemo(() => [
|
|
376
428
|
{
|
|
377
429
|
enabled: true,
|
|
@@ -380,7 +432,22 @@ export const useWorkspaceUserModule = () => {
|
|
|
380
432
|
order: 1,
|
|
381
433
|
icon: Eye,
|
|
382
434
|
},
|
|
383
|
-
|
|
435
|
+
{
|
|
436
|
+
enabled: true,
|
|
437
|
+
handleOnClick: handleEdit,
|
|
438
|
+
label: t("actionsButtonEdit"),
|
|
439
|
+
order: 2,
|
|
440
|
+
icon: Pencil,
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
enabled: true,
|
|
444
|
+
handleOnClick: handleDelete,
|
|
445
|
+
label: t("actionsButtonDelete"),
|
|
446
|
+
order: 3,
|
|
447
|
+
icon: Trash2,
|
|
448
|
+
variant: "destructive",
|
|
449
|
+
},
|
|
450
|
+
], [handleDelete, handleEdit, handleView, t]);
|
|
384
451
|
// ============================================================================
|
|
385
452
|
// 1.4.9 EFFECTS
|
|
386
453
|
// ============================================================================
|
|
@@ -2,12 +2,70 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
|
|
4
4
|
import { EnhancedCheckbox } from "@appcorp/shadcn/components/enhanced-checkbox";
|
|
5
|
+
import { useEnhancedCombobox } from "@appcorp/shadcn/hooks/use-enhanced-combobox";
|
|
5
6
|
import { useWorkspaceUserModule } from "./context";
|
|
6
7
|
import { useTranslations } from "next-intl";
|
|
7
8
|
import { getTranslatedError } from "../../utils/get-translated-error";
|
|
9
|
+
import { getCachedWorkspaceSync } from "../workspace/cache";
|
|
10
|
+
import { RBAC_API_ROUTES, USER_API_ROUTES } from "../../constants";
|
|
8
11
|
export const WorkspaceUserForm = () => {
|
|
12
|
+
var _a;
|
|
9
13
|
const { state, handleChange } = useWorkspaceUserModule();
|
|
10
14
|
const { enabled, errors, roleId, userId, workspaceId } = state;
|
|
11
15
|
const t = useTranslations("workspaceUser");
|
|
12
|
-
|
|
16
|
+
const workspace = getCachedWorkspaceSync();
|
|
17
|
+
const resolvedWorkspaceId = workspaceId || (workspace === null || workspace === void 0 ? void 0 : workspace.id) || "";
|
|
18
|
+
const workspaceLabel = ((_a = state.workspace) === null || _a === void 0 ? void 0 : _a.name) || (workspace === null || workspace === void 0 ? void 0 : workspace.name) || "";
|
|
19
|
+
const { enhancedComboboxElement: userIdCombo } = useEnhancedCombobox({
|
|
20
|
+
id: "userId",
|
|
21
|
+
error: getTranslatedError({ errors, key: "userId", t }),
|
|
22
|
+
info: t("formUserIdInfo"),
|
|
23
|
+
label: t("formUserIdLabel"),
|
|
24
|
+
onValueChange: (value) => handleChange("userId", value),
|
|
25
|
+
options: state.user
|
|
26
|
+
? [
|
|
27
|
+
{
|
|
28
|
+
label: state.user.name || state.user.email || state.user.id,
|
|
29
|
+
value: state.user.id,
|
|
30
|
+
},
|
|
31
|
+
]
|
|
32
|
+
: [],
|
|
33
|
+
placeholder: t("formUserIdPlaceholder"),
|
|
34
|
+
required: true,
|
|
35
|
+
searchEndpoint: USER_API_ROUTES.UNIT,
|
|
36
|
+
searchPlaceholder: t("formUserIdPlaceholder"),
|
|
37
|
+
emptyText: t("formNoUserFound"),
|
|
38
|
+
formatSearchResult: (item) => {
|
|
39
|
+
var _a;
|
|
40
|
+
return ({
|
|
41
|
+
label: String(item.name || item.email || item.id || ""),
|
|
42
|
+
value: String((_a = item.id) !== null && _a !== void 0 ? _a : ""),
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
value: userId,
|
|
46
|
+
});
|
|
47
|
+
const { enhancedComboboxElement: roleIdCombo } = useEnhancedCombobox({
|
|
48
|
+
id: "roleId",
|
|
49
|
+
error: getTranslatedError({ errors, key: "roleId", t }),
|
|
50
|
+
info: t("formRoleIdInfo"),
|
|
51
|
+
label: t("formRoleIdLabel"),
|
|
52
|
+
onValueChange: (value) => handleChange("roleId", value || ""),
|
|
53
|
+
options: state.role
|
|
54
|
+
? [{ label: state.role.name || state.role.id, value: state.role.id }]
|
|
55
|
+
: [],
|
|
56
|
+
placeholder: t("formRoleIdPlaceholder"),
|
|
57
|
+
searchEndpoint: RBAC_API_ROUTES.UNIT,
|
|
58
|
+
searchParams: Object.assign(Object.assign({}, (resolvedWorkspaceId ? { workspaceId: resolvedWorkspaceId } : {})), { includeSystem: "true" }),
|
|
59
|
+
searchPlaceholder: t("formRoleIdPlaceholder"),
|
|
60
|
+
emptyText: t("formNoRoleFound"),
|
|
61
|
+
formatSearchResult: (item) => {
|
|
62
|
+
var _a;
|
|
63
|
+
return ({
|
|
64
|
+
label: String(item.name || item.userRole || item.id || ""),
|
|
65
|
+
value: String((_a = item.id) !== null && _a !== void 0 ? _a : ""),
|
|
66
|
+
});
|
|
67
|
+
},
|
|
68
|
+
value: roleId || "",
|
|
69
|
+
});
|
|
70
|
+
return (_jsx("div", { className: "space-y-4", children: _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: t("formSectionWorkspaceUserInformation") }), _jsxs("div", { className: "grid grid-cols-1 gap-4", children: [_jsx(EnhancedInput, { id: "workspaceId", error: getTranslatedError({ errors, key: "workspaceId", t }), info: t("formWorkspaceIdInfo"), label: t("formWorkspaceIdLabel"), onChange: (e) => handleChange("workspaceId", e.target.value), placeholder: t("formWorkspaceIdPlaceholder"), required: true, readOnly: true, value: workspaceLabel || resolvedWorkspaceId }), userIdCombo, roleIdCombo] }), _jsx(EnhancedCheckbox, { checked: enabled, label: t("badgeActive"), onCheckedChange: (checked) => handleChange("enabled", checked) })] }) }));
|
|
13
71
|
};
|
|
@@ -9,8 +9,8 @@ import { useTranslations } from "next-intl";
|
|
|
9
9
|
export const WorkspaceUserMoreActions = () => {
|
|
10
10
|
const t = useTranslations("workspaceUser");
|
|
11
11
|
const workspace = getCachedWorkspaceSync();
|
|
12
|
-
const handleGetAllRecords = async (
|
|
13
|
-
const response = await fetch(`/api/workspace-user?pageLimit=1000¤tPage=1&
|
|
12
|
+
const handleGetAllRecords = async (workspaceId) => {
|
|
13
|
+
const response = await fetch(`/api/v1/workspace-user?pageLimit=1000¤tPage=1&workspaceId=${workspaceId}`, { method: API_METHODS.GET });
|
|
14
14
|
const result = await response.json();
|
|
15
15
|
const csv = await converter.json2csv(result.items || [], {});
|
|
16
16
|
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
|
@@ -35,8 +35,7 @@ export const WorkspaceUserMoreActions = () => {
|
|
|
35
35
|
id: "1",
|
|
36
36
|
title: t("downloadPopulatedCsvTemplate"),
|
|
37
37
|
handleOnClick: async () => {
|
|
38
|
-
|
|
39
|
-
await handleGetAllRecords(((_a = workspace === null || workspace === void 0 ? void 0 : workspace.school) === null || _a === void 0 ? void 0 : _a.id) || "");
|
|
38
|
+
await handleGetAllRecords((workspace === null || workspace === void 0 ? void 0 : workspace.id) || "");
|
|
40
39
|
},
|
|
41
40
|
},
|
|
42
41
|
{ id: "2", title: t("updateYourDataInTheCsv") },
|
|
@@ -127,10 +127,10 @@ const WorkspaceUserPageInner = (props) => {
|
|
|
127
127
|
]);
|
|
128
128
|
const hasPermission = resolveRbacPermissions({
|
|
129
129
|
userRole: props.userRole,
|
|
130
|
-
moduleName: "
|
|
130
|
+
moduleName: "Workspace User",
|
|
131
131
|
});
|
|
132
132
|
if (!hasPermission) {
|
|
133
|
-
return _jsx(RbacNoAccess, { moduleName: "
|
|
133
|
+
return _jsx(RbacNoAccess, { moduleName: "Workspace User" });
|
|
134
134
|
}
|
|
135
135
|
return (_jsx("div", { className: "p-4", children: _jsx(GenericWorkspaceUserPage, { overrideConfig: workspaceUserConfig, context: context, tableBodyCols: tableBodyCols }) }));
|
|
136
136
|
};
|