@asteby/metacore-runtime-react 30.0.0 → 30.0.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.
- package/CHANGELOG.md +12 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/permissions-manager.d.ts +31 -3
- package/dist/permissions-manager.d.ts.map +1 -1
- package/dist/permissions-manager.js +64 -9
- package/package.json +1 -1
- package/src/__tests__/permissions-manager.test.tsx +38 -0
- package/src/index.ts +1 -0
- package/src/permissions-manager.tsx +180 -19
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 30.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- a5ca1a8: Permisos: agrupar acciones en secciones desplegables (action.group)
|
|
8
|
+
|
|
9
|
+
## 30.0.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 0016511: PermissionActionDef.capability: atajos cross-módulo en el grid de permisos
|
|
14
|
+
|
|
3
15
|
## 30.0.0
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export * from './slot';
|
|
|
23
23
|
export * from './capability-gate';
|
|
24
24
|
export { PermissionsProvider, useCan, usePermissionsActive, makeCan, capabilityForActionKey, modelCapability, gateTableMetadata, resolveRowActions, type CanFn, type PermissionsProviderProps, } from './permissions-context';
|
|
25
25
|
export { useDynamicRowActions, type UseDynamicRowActionsParams, type DynamicRowActions, } from './dynamic-row-actions';
|
|
26
|
-
export { PermissionsManager, moduleActionCapability, moduleCapabilities, grantedCountForModule, capabilitySetsEqual, defaultActionIcon, normalizeCatalogGroups, flattenGroups, filterModuleGroups, type PermissionsManagerProps, type PermissionsCatalog, type GroupedPermissionsCatalog, type FlatPermissionsCatalog, type ModuleGroup, type PermissionModuleDef, type PermissionActionDef, type GeneralPermissionDef, type RoleDef, type RoleInput, } from './permissions-manager';
|
|
26
|
+
export { PermissionsManager, moduleActionCapability, moduleCapabilities, grantedCountForModule, capabilitySetsEqual, defaultActionIcon, normalizeCatalogGroups, flattenGroups, filterModuleGroups, groupModuleActions, type PermissionsManagerProps, type PermissionsCatalog, type GroupedPermissionsCatalog, type FlatPermissionsCatalog, type ModuleGroup, type PermissionModuleDef, type PermissionActionDef, type GeneralPermissionDef, type RoleDef, type RoleInput, } from './permissions-manager';
|
|
27
27
|
export * from './org-runtime-context';
|
|
28
28
|
export * from './org-runtime-provider';
|
|
29
29
|
export * from './navigation-builder';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ export * from './slot';
|
|
|
28
28
|
export * from './capability-gate';
|
|
29
29
|
export { PermissionsProvider, useCan, usePermissionsActive, makeCan, capabilityForActionKey, modelCapability, gateTableMetadata, resolveRowActions, } from './permissions-context';
|
|
30
30
|
export { useDynamicRowActions, } from './dynamic-row-actions';
|
|
31
|
-
export { PermissionsManager, moduleActionCapability, moduleCapabilities, grantedCountForModule, capabilitySetsEqual, defaultActionIcon, normalizeCatalogGroups, flattenGroups, filterModuleGroups, } from './permissions-manager';
|
|
31
|
+
export { PermissionsManager, moduleActionCapability, moduleCapabilities, grantedCountForModule, capabilitySetsEqual, defaultActionIcon, normalizeCatalogGroups, flattenGroups, filterModuleGroups, groupModuleActions, } from './permissions-manager';
|
|
32
32
|
export * from './org-runtime-context';
|
|
33
33
|
export * from './org-runtime-provider';
|
|
34
34
|
export * from './navigation-builder';
|
|
@@ -9,8 +9,23 @@ export interface PermissionActionDef {
|
|
|
9
9
|
/**
|
|
10
10
|
* `crud` for the derived CRUD set, `custom` for manifest actions,
|
|
11
11
|
* `screen` for the single `access` action of a non-model screen.
|
|
12
|
+
* `dependency` for a shortcut to another module's capability (see
|
|
13
|
+
* {@link capability}).
|
|
12
14
|
*/
|
|
13
|
-
kind?: 'crud' | 'custom' | 'screen' | string;
|
|
15
|
+
kind?: 'crud' | 'custom' | 'screen' | 'dependency' | string;
|
|
16
|
+
/**
|
|
17
|
+
* Full capability string override. When set, the grant uses this exact key
|
|
18
|
+
* instead of `${moduleKey}.${key}` — hosts use it so a screen (Terminal)
|
|
19
|
+
* can show checkboxes for other modules' caps (`product.index`, …) as
|
|
20
|
+
* shortcuts without inventing `screen….product.index`.
|
|
21
|
+
*/
|
|
22
|
+
capability?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Optional section title for the action grid (e.g. "Catálogo", "Ventas").
|
|
25
|
+
* When any action on a module sets `group`, the right-hand panel renders
|
|
26
|
+
* collapsible sections instead of one flat checkbox grid.
|
|
27
|
+
*/
|
|
28
|
+
group?: string;
|
|
14
29
|
}
|
|
15
30
|
export interface PermissionModuleDef {
|
|
16
31
|
/**
|
|
@@ -94,10 +109,23 @@ export interface PermissionsManagerProps {
|
|
|
94
109
|
title?: string;
|
|
95
110
|
className?: string;
|
|
96
111
|
}
|
|
97
|
-
/** Capability for a catalog module action: `lowercase(moduleKey).actionKey
|
|
98
|
-
|
|
112
|
+
/** Capability for a catalog module action: `lowercase(moduleKey).actionKey`,
|
|
113
|
+
* or {@link PermissionActionDef.capability} when the action is a cross-module
|
|
114
|
+
* shortcut. */
|
|
115
|
+
export declare function moduleActionCapability(moduleKey: string, actionKey: string, capability?: string): string;
|
|
99
116
|
/** All capabilities of one module. */
|
|
100
117
|
export declare function moduleCapabilities(module: PermissionModuleDef): string[];
|
|
118
|
+
export interface ActionGroupSection {
|
|
119
|
+
/** Empty string = ungrouped actions rendered above the collapsibles. */
|
|
120
|
+
title: string;
|
|
121
|
+
actions: PermissionActionDef[];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Split a module's actions into an optional ungrouped prefix + named sections
|
|
125
|
+
* (first-seen order of `action.group`). Modules without any `group` yield a
|
|
126
|
+
* single untitled section (flat grid, backward compatible).
|
|
127
|
+
*/
|
|
128
|
+
export declare function groupModuleActions(actions: PermissionActionDef[]): ActionGroupSection[];
|
|
101
129
|
/** How many of the module's capabilities are in the granted set. */
|
|
102
130
|
export declare function grantedCountForModule(granted: ReadonlySet<string>, module: PermissionModuleDef): number;
|
|
103
131
|
export declare function capabilitySetsEqual(a: ReadonlySet<string>, b: ReadonlySet<string>): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions-manager.d.ts","sourceRoot":"","sources":["../src/permissions-manager.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"permissions-manager.d.ts","sourceRoot":"","sources":["../src/permissions-manager.tsx"],"names":[],"mappings":"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"}
|
|
@@ -25,21 +25,56 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
25
25
|
// state is tracked against the loaded baseline and surfaced next to the
|
|
26
26
|
// save button.
|
|
27
27
|
import * as React from 'react';
|
|
28
|
-
import { Check, ChevronsUpDown, CheckCheck, Eraser, Pencil, Plus, Save, Shield, Trash2, } from 'lucide-react';
|
|
28
|
+
import { Check, ChevronsUpDown, CheckCheck, ChevronDown, Eraser, Pencil, Plus, Save, Shield, Trash2, } from 'lucide-react';
|
|
29
29
|
import { toast } from 'sonner';
|
|
30
30
|
import { cn } from '@asteby/metacore-ui/lib';
|
|
31
|
-
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Checkbox, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Popover, PopoverContent, PopoverTrigger, Separator, Skeleton, } from '@asteby/metacore-ui/primitives';
|
|
31
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, Badge, Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Checkbox, Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Popover, PopoverContent, PopoverTrigger, Separator, Skeleton, Collapsible, CollapsibleContent, CollapsibleTrigger, } from '@asteby/metacore-ui/primitives';
|
|
32
32
|
import { DynamicIcon } from './dynamic-icon';
|
|
33
33
|
// ---------------------------------------------------------------------------
|
|
34
34
|
// Pure helpers (exported for hosts/tests)
|
|
35
35
|
// ---------------------------------------------------------------------------
|
|
36
|
-
/** Capability for a catalog module action: `lowercase(moduleKey).actionKey
|
|
37
|
-
|
|
36
|
+
/** Capability for a catalog module action: `lowercase(moduleKey).actionKey`,
|
|
37
|
+
* or {@link PermissionActionDef.capability} when the action is a cross-module
|
|
38
|
+
* shortcut. */
|
|
39
|
+
export function moduleActionCapability(moduleKey, actionKey, capability) {
|
|
40
|
+
if (capability)
|
|
41
|
+
return capability;
|
|
38
42
|
return `${moduleKey.toLowerCase()}.${actionKey}`;
|
|
39
43
|
}
|
|
40
44
|
/** All capabilities of one module. */
|
|
41
45
|
export function moduleCapabilities(module) {
|
|
42
|
-
return module.actions.map((a) => moduleActionCapability(module.key, a.key));
|
|
46
|
+
return module.actions.map((a) => moduleActionCapability(module.key, a.key, a.capability));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Split a module's actions into an optional ungrouped prefix + named sections
|
|
50
|
+
* (first-seen order of `action.group`). Modules without any `group` yield a
|
|
51
|
+
* single untitled section (flat grid, backward compatible).
|
|
52
|
+
*/
|
|
53
|
+
export function groupModuleActions(actions) {
|
|
54
|
+
const ungrouped = [];
|
|
55
|
+
const byTitle = new Map();
|
|
56
|
+
const order = [];
|
|
57
|
+
for (const action of actions) {
|
|
58
|
+
const title = (action.group ?? '').trim();
|
|
59
|
+
if (!title) {
|
|
60
|
+
ungrouped.push(action);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
let list = byTitle.get(title);
|
|
64
|
+
if (!list) {
|
|
65
|
+
list = [];
|
|
66
|
+
byTitle.set(title, list);
|
|
67
|
+
order.push(title);
|
|
68
|
+
}
|
|
69
|
+
list.push(action);
|
|
70
|
+
}
|
|
71
|
+
const out = [];
|
|
72
|
+
if (ungrouped.length > 0)
|
|
73
|
+
out.push({ title: '', actions: ungrouped });
|
|
74
|
+
for (const title of order) {
|
|
75
|
+
out.push({ title, actions: byTitle.get(title) });
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
43
78
|
}
|
|
44
79
|
/** How many of the module's capabilities are in the granted set. */
|
|
45
80
|
export function grantedCountForModule(granted, module) {
|
|
@@ -75,6 +110,8 @@ export function defaultActionIcon(actionKey, kind) {
|
|
|
75
110
|
return 'List';
|
|
76
111
|
if (kind === 'screen')
|
|
77
112
|
return 'Eye';
|
|
113
|
+
if (kind === 'dependency')
|
|
114
|
+
return 'Link2';
|
|
78
115
|
return 'Zap';
|
|
79
116
|
}
|
|
80
117
|
}
|
|
@@ -444,10 +481,7 @@ export function PermissionsManager({ loadModules, loadRoles, loadRolePermissions
|
|
|
444
481
|
0 && (_jsxs(Badge, { variant: "secondary", className: "ml-auto shrink-0 tabular-nums", children: [grantedCountForModule(draft, mod), "/", mod.actions.length] })), mod.key === activeModuleKey && (_jsx(Check, { className: "ml-2 h-4 w-4 shrink-0" }))] }, mod.key))) }, group.title || `__untitled_${gi}`)))] })] }) })] }) })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { className: "flex flex-wrap items-start justify-between gap-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [activeModule && (_jsx(DynamicIcon, { name: activeModule.icon ||
|
|
445
482
|
(activeModule.kind === 'screen' ? 'Eye' : 'Square'), className: "h-4 w-4 shrink-0 text-primary" })), _jsx("span", { className: "truncate", children: activeModule ? activeModule.label : 'Acciones permitidas' })] }), _jsx(CardDescription, { children: activeModule
|
|
446
483
|
? `${activeModuleGroupTitle || 'Sistema'} · configura las acciones permitidas`
|
|
447
|
-
: 'Configura los permisos del módulo seleccionado.' })] }), activeRole && activeModule && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Badge, { variant: "secondary", className: "tabular-nums", children: [moduleGranted, "/", moduleTotal] }), _jsxs(Button, { variant: "outline", size: "sm", className: "h-8", disabled: checksDisabled || moduleGranted === moduleTotal, onClick: () => setModuleAll(true), children: [_jsx(CheckCheck, { className: "mr-1.5 h-3.5 w-3.5" }), " Marcar todo"] }), _jsxs(Button, { variant: "outline", size: "sm", className: "h-8", disabled: checksDisabled || moduleGranted === 0, onClick: () => setModuleAll(false), children: [_jsx(Eraser, { className: "mr-1.5 h-3.5 w-3.5" }), " Limpiar"] })] }))] }) }), _jsx(CardContent, { children: !activeRole ? (_jsx(EmptyHint, { text: "Selecciona un rol para configurar sus permisos." })) : loadingPerms ? (_jsx("div", { className: "grid gap-2 sm:grid-cols-2 xl:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (_jsx(Skeleton, { className: "h-11 w-full" }, i))) })) : !activeModule ? (_jsx(EmptyHint, { text: "Selecciona un m\u00F3dulo de la lista para ver sus acciones." })) : (_jsx(
|
|
448
|
-
const cap = moduleActionCapability(activeModule.key, action.key);
|
|
449
|
-
return (_jsx(CapabilityCheck, { checked: draft?.has(cap) ?? false, disabled: checksDisabled, onToggle: () => toggleCapability(cap), icon: action.icon || defaultActionIcon(action.key, action.kind), label: action.label }, action.key));
|
|
450
|
-
}) })) })] })] }), _jsx(AlertDialog, { open: pendingRoleId !== null, onOpenChange: (open) => !open && setPendingRoleId(null), children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Cambios sin guardar" }), _jsx(AlertDialogDescription, { children: "Tienes cambios sin guardar en este rol. Si cambias de rol se descartar\u00E1n." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancelar" }), _jsx(AlertDialogAction, { onClick: () => {
|
|
484
|
+
: 'Configura los permisos del módulo seleccionado.' })] }), activeRole && activeModule && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs(Badge, { variant: "secondary", className: "tabular-nums", children: [moduleGranted, "/", moduleTotal] }), _jsxs(Button, { variant: "outline", size: "sm", className: "h-8", disabled: checksDisabled || moduleGranted === moduleTotal, onClick: () => setModuleAll(true), children: [_jsx(CheckCheck, { className: "mr-1.5 h-3.5 w-3.5" }), " Marcar todo"] }), _jsxs(Button, { variant: "outline", size: "sm", className: "h-8", disabled: checksDisabled || moduleGranted === 0, onClick: () => setModuleAll(false), children: [_jsx(Eraser, { className: "mr-1.5 h-3.5 w-3.5" }), " Limpiar"] })] }))] }) }), _jsx(CardContent, { children: !activeRole ? (_jsx(EmptyHint, { text: "Selecciona un rol para configurar sus permisos." })) : loadingPerms ? (_jsx("div", { className: "grid gap-2 sm:grid-cols-2 xl:grid-cols-3", children: Array.from({ length: 6 }).map((_, i) => (_jsx(Skeleton, { className: "h-11 w-full" }, i))) })) : !activeModule ? (_jsx(EmptyHint, { text: "Selecciona un m\u00F3dulo de la lista para ver sus acciones." })) : (_jsx(ModuleActionsPanel, { module: activeModule, draft: draft, checksDisabled: checksDisabled, onToggle: toggleCapability })) })] })] }), _jsx(AlertDialog, { open: pendingRoleId !== null, onOpenChange: (open) => !open && setPendingRoleId(null), children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Cambios sin guardar" }), _jsx(AlertDialogDescription, { children: "Tienes cambios sin guardar en este rol. Si cambias de rol se descartar\u00E1n." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancelar" }), _jsx(AlertDialogAction, { onClick: () => {
|
|
451
485
|
setActiveRoleId(pendingRoleId);
|
|
452
486
|
setPendingRoleId(null);
|
|
453
487
|
}, children: "Descartar y cambiar" })] })] }) }), _jsx(Dialog, { open: roleDialog.open, onOpenChange: (open) => setRoleDialog((d) => ({ ...d, open })), children: _jsxs(DialogContent, { className: "sm:max-w-md", children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: roleDialog.mode === 'create' ? 'Nuevo rol' : 'Editar rol' }) }), _jsxs("div", { className: "flex flex-col gap-4 py-2", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "pm-role-name", children: "Nombre del rol" }), _jsx(Input, { id: "pm-role-name", value: roleDialog.label, placeholder: "Ej. Cajero", onChange: (e) => setRoleDialog((d) => ({ ...d, label: e.target.value })) })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: "Color" }), _jsx("div", { className: "flex flex-wrap gap-2", children: ROLE_COLORS.map((c) => (_jsx("button", { type: "button", "aria-label": `Color ${c}`, onClick: () => setRoleDialog((d) => ({ ...d, color: c })), className: cn('h-7 w-7 rounded-full border-2 transition-transform', roleDialog.color === c
|
|
@@ -461,6 +495,27 @@ export function PermissionsManager({ loadModules, loadRoles, loadRolePermissions
|
|
|
461
495
|
handleDeleteRole();
|
|
462
496
|
}, children: deleting ? 'Eliminando…' : 'Eliminar' })] })] }) })] }));
|
|
463
497
|
}
|
|
498
|
+
function ActionCheckGrid({ moduleKey, actions, draft, checksDisabled, onToggle, }) {
|
|
499
|
+
return (_jsx("div", { className: "grid gap-2 sm:grid-cols-2 xl:grid-cols-3", children: actions.map((action) => {
|
|
500
|
+
const cap = moduleActionCapability(moduleKey, action.key, action.capability);
|
|
501
|
+
return (_jsx(CapabilityCheck, { checked: draft?.has(cap) ?? false, disabled: checksDisabled, onToggle: () => onToggle(cap), icon: action.icon || defaultActionIcon(action.key, action.kind), label: action.label }, action.capability ?? action.key));
|
|
502
|
+
}) }));
|
|
503
|
+
}
|
|
504
|
+
/** Flat grid, or collapsible sections when actions declare `group`. */
|
|
505
|
+
function ModuleActionsPanel({ module, draft, checksDisabled, onToggle, }) {
|
|
506
|
+
const sections = React.useMemo(() => groupModuleActions(module.actions), [module.actions]);
|
|
507
|
+
const hasNamedGroups = sections.some((s) => s.title.length > 0);
|
|
508
|
+
if (!hasNamedGroups) {
|
|
509
|
+
return (_jsx(ActionCheckGrid, { moduleKey: module.key, actions: module.actions, draft: draft, checksDisabled: checksDisabled, onToggle: onToggle }));
|
|
510
|
+
}
|
|
511
|
+
return (_jsx("div", { className: "flex flex-col gap-3", children: sections.map((section) => {
|
|
512
|
+
if (!section.title) {
|
|
513
|
+
return (_jsx(ActionCheckGrid, { moduleKey: module.key, actions: section.actions, draft: draft, checksDisabled: checksDisabled, onToggle: onToggle }, "__ungrouped"));
|
|
514
|
+
}
|
|
515
|
+
const granted = section.actions.filter((a) => draft?.has(moduleActionCapability(module.key, a.key, a.capability))).length;
|
|
516
|
+
return (_jsxs(Collapsible, { defaultOpen: true, className: "rounded-md border border-border/60", children: [_jsxs(CollapsibleTrigger, { className: "flex w-full items-center gap-2 px-3 py-2.5 text-left text-sm font-medium hover:bg-muted/40 [&[data-state=open]>svg]:rotate-180", children: [_jsx(ChevronDown, { className: "h-4 w-4 shrink-0 text-muted-foreground transition-transform" }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: section.title }), _jsxs(Badge, { variant: "secondary", className: "tabular-nums", children: [granted, "/", section.actions.length] })] }), _jsx(CollapsibleContent, { className: "border-t border-border/60 px-3 py-3", children: _jsx(ActionCheckGrid, { moduleKey: module.key, actions: section.actions, draft: draft, checksDisabled: checksDisabled, onToggle: onToggle }) })] }, section.title));
|
|
517
|
+
}) }));
|
|
518
|
+
}
|
|
464
519
|
function EmptyHint({ text }) {
|
|
465
520
|
return (_jsxs("div", { className: "flex flex-col items-center justify-center gap-2 py-12 text-muted-foreground", children: [_jsx(Shield, { className: "h-8 w-8 opacity-40" }), _jsx("p", { className: "text-sm", children: text })] }));
|
|
466
521
|
}
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
flattenGroups,
|
|
15
15
|
filterModuleGroups,
|
|
16
16
|
defaultActionIcon,
|
|
17
|
+
groupModuleActions,
|
|
17
18
|
type PermissionsCatalog,
|
|
18
19
|
type GroupedPermissionsCatalog,
|
|
19
20
|
type FlatPermissionsCatalog,
|
|
@@ -118,6 +119,43 @@ describe('helpers puros', () => {
|
|
|
118
119
|
)
|
|
119
120
|
})
|
|
120
121
|
|
|
122
|
+
it('capability override grants the exact cross-module key', () => {
|
|
123
|
+
expect(
|
|
124
|
+
moduleActionCapability('screen.addons.pos.terminal', 'product.index', 'product.index'),
|
|
125
|
+
).toBe('product.index')
|
|
126
|
+
const mod = {
|
|
127
|
+
key: 'screen.addons.pos.terminal',
|
|
128
|
+
label: 'Terminal',
|
|
129
|
+
kind: 'screen' as const,
|
|
130
|
+
actions: [
|
|
131
|
+
{ key: 'access', label: 'Acceder', kind: 'screen' as const },
|
|
132
|
+
{
|
|
133
|
+
key: 'product.index',
|
|
134
|
+
label: 'Productos · Listar',
|
|
135
|
+
kind: 'dependency' as const,
|
|
136
|
+
capability: 'product.index',
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
}
|
|
140
|
+
expect(moduleCapabilities(mod)).toEqual([
|
|
141
|
+
'screen.addons.pos.terminal.access',
|
|
142
|
+
'product.index',
|
|
143
|
+
])
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('groupModuleActions keeps Acceder ungrouped and sections by group', () => {
|
|
147
|
+
const sections = groupModuleActions([
|
|
148
|
+
{ key: 'access', label: 'Acceder', kind: 'screen' },
|
|
149
|
+
{ key: 'product.index', label: 'Productos', group: 'Catálogo', capability: 'product.index' },
|
|
150
|
+
{ key: 'stock.index', label: 'Stock', group: 'Catálogo', capability: 'stock.index' },
|
|
151
|
+
{ key: 'salesorder.create', label: 'Venta', group: 'Ventas', capability: 'salesorder.create' },
|
|
152
|
+
])
|
|
153
|
+
expect(sections.map((s) => s.title)).toEqual(['', 'Catálogo', 'Ventas'])
|
|
154
|
+
expect(sections[0].actions).toHaveLength(1)
|
|
155
|
+
expect(sections[1].actions).toHaveLength(2)
|
|
156
|
+
expect(sections[2].actions).toHaveLength(1)
|
|
157
|
+
})
|
|
158
|
+
|
|
121
159
|
it('moduleCapabilities y grantedCountForModule', () => {
|
|
122
160
|
const mod = grouped.groups[1].modules[0] // pos_orders
|
|
123
161
|
expect(moduleCapabilities(mod)).toEqual([
|
package/src/index.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
Check,
|
|
29
29
|
ChevronsUpDown,
|
|
30
30
|
CheckCheck,
|
|
31
|
+
ChevronDown,
|
|
31
32
|
Eraser,
|
|
32
33
|
Pencil,
|
|
33
34
|
Plus,
|
|
@@ -73,6 +74,9 @@ import {
|
|
|
73
74
|
PopoverTrigger,
|
|
74
75
|
Separator,
|
|
75
76
|
Skeleton,
|
|
77
|
+
Collapsible,
|
|
78
|
+
CollapsibleContent,
|
|
79
|
+
CollapsibleTrigger,
|
|
76
80
|
} from '@asteby/metacore-ui/primitives'
|
|
77
81
|
import { DynamicIcon } from './dynamic-icon'
|
|
78
82
|
|
|
@@ -90,8 +94,23 @@ export interface PermissionActionDef {
|
|
|
90
94
|
/**
|
|
91
95
|
* `crud` for the derived CRUD set, `custom` for manifest actions,
|
|
92
96
|
* `screen` for the single `access` action of a non-model screen.
|
|
97
|
+
* `dependency` for a shortcut to another module's capability (see
|
|
98
|
+
* {@link capability}).
|
|
93
99
|
*/
|
|
94
|
-
kind?: 'crud' | 'custom' | 'screen' | string
|
|
100
|
+
kind?: 'crud' | 'custom' | 'screen' | 'dependency' | string
|
|
101
|
+
/**
|
|
102
|
+
* Full capability string override. When set, the grant uses this exact key
|
|
103
|
+
* instead of `${moduleKey}.${key}` — hosts use it so a screen (Terminal)
|
|
104
|
+
* can show checkboxes for other modules' caps (`product.index`, …) as
|
|
105
|
+
* shortcuts without inventing `screen….product.index`.
|
|
106
|
+
*/
|
|
107
|
+
capability?: string
|
|
108
|
+
/**
|
|
109
|
+
* Optional section title for the action grid (e.g. "Catálogo", "Ventas").
|
|
110
|
+
* When any action on a module sets `group`, the right-hand panel renders
|
|
111
|
+
* collapsible sections instead of one flat checkbox grid.
|
|
112
|
+
*/
|
|
113
|
+
group?: string
|
|
95
114
|
}
|
|
96
115
|
|
|
97
116
|
export interface PermissionModuleDef {
|
|
@@ -189,14 +208,60 @@ export interface PermissionsManagerProps {
|
|
|
189
208
|
// Pure helpers (exported for hosts/tests)
|
|
190
209
|
// ---------------------------------------------------------------------------
|
|
191
210
|
|
|
192
|
-
/** Capability for a catalog module action: `lowercase(moduleKey).actionKey
|
|
193
|
-
|
|
211
|
+
/** Capability for a catalog module action: `lowercase(moduleKey).actionKey`,
|
|
212
|
+
* or {@link PermissionActionDef.capability} when the action is a cross-module
|
|
213
|
+
* shortcut. */
|
|
214
|
+
export function moduleActionCapability(
|
|
215
|
+
moduleKey: string,
|
|
216
|
+
actionKey: string,
|
|
217
|
+
capability?: string,
|
|
218
|
+
): string {
|
|
219
|
+
if (capability) return capability
|
|
194
220
|
return `${moduleKey.toLowerCase()}.${actionKey}`
|
|
195
221
|
}
|
|
196
222
|
|
|
197
223
|
/** All capabilities of one module. */
|
|
198
224
|
export function moduleCapabilities(module: PermissionModuleDef): string[] {
|
|
199
|
-
return module.actions.map((a) =>
|
|
225
|
+
return module.actions.map((a) =>
|
|
226
|
+
moduleActionCapability(module.key, a.key, a.capability),
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface ActionGroupSection {
|
|
231
|
+
/** Empty string = ungrouped actions rendered above the collapsibles. */
|
|
232
|
+
title: string
|
|
233
|
+
actions: PermissionActionDef[]
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Split a module's actions into an optional ungrouped prefix + named sections
|
|
238
|
+
* (first-seen order of `action.group`). Modules without any `group` yield a
|
|
239
|
+
* single untitled section (flat grid, backward compatible).
|
|
240
|
+
*/
|
|
241
|
+
export function groupModuleActions(actions: PermissionActionDef[]): ActionGroupSection[] {
|
|
242
|
+
const ungrouped: PermissionActionDef[] = []
|
|
243
|
+
const byTitle = new Map<string, PermissionActionDef[]>()
|
|
244
|
+
const order: string[] = []
|
|
245
|
+
for (const action of actions) {
|
|
246
|
+
const title = (action.group ?? '').trim()
|
|
247
|
+
if (!title) {
|
|
248
|
+
ungrouped.push(action)
|
|
249
|
+
continue
|
|
250
|
+
}
|
|
251
|
+
let list = byTitle.get(title)
|
|
252
|
+
if (!list) {
|
|
253
|
+
list = []
|
|
254
|
+
byTitle.set(title, list)
|
|
255
|
+
order.push(title)
|
|
256
|
+
}
|
|
257
|
+
list.push(action)
|
|
258
|
+
}
|
|
259
|
+
const out: ActionGroupSection[] = []
|
|
260
|
+
if (ungrouped.length > 0) out.push({ title: '', actions: ungrouped })
|
|
261
|
+
for (const title of order) {
|
|
262
|
+
out.push({ title, actions: byTitle.get(title)! })
|
|
263
|
+
}
|
|
264
|
+
return out
|
|
200
265
|
}
|
|
201
266
|
|
|
202
267
|
/** How many of the module's capabilities are in the granted set. */
|
|
@@ -233,6 +298,7 @@ export function defaultActionIcon(actionKey: string, kind?: string): string {
|
|
|
233
298
|
default:
|
|
234
299
|
if (kind === 'crud') return 'List'
|
|
235
300
|
if (kind === 'screen') return 'Eye'
|
|
301
|
+
if (kind === 'dependency') return 'Link2'
|
|
236
302
|
return 'Zap'
|
|
237
303
|
}
|
|
238
304
|
}
|
|
@@ -1049,21 +1115,12 @@ export function PermissionsManager({
|
|
|
1049
1115
|
) : !activeModule ? (
|
|
1050
1116
|
<EmptyHint text="Selecciona un módulo de la lista para ver sus acciones." />
|
|
1051
1117
|
) : (
|
|
1052
|
-
<
|
|
1053
|
-
{activeModule
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
checked={draft?.has(cap) ?? false}
|
|
1059
|
-
disabled={checksDisabled}
|
|
1060
|
-
onToggle={() => toggleCapability(cap)}
|
|
1061
|
-
icon={action.icon || defaultActionIcon(action.key, action.kind)}
|
|
1062
|
-
label={action.label}
|
|
1063
|
-
/>
|
|
1064
|
-
)
|
|
1065
|
-
})}
|
|
1066
|
-
</div>
|
|
1118
|
+
<ModuleActionsPanel
|
|
1119
|
+
module={activeModule}
|
|
1120
|
+
draft={draft}
|
|
1121
|
+
checksDisabled={checksDisabled}
|
|
1122
|
+
onToggle={toggleCapability}
|
|
1123
|
+
/>
|
|
1067
1124
|
)}
|
|
1068
1125
|
</CardContent>
|
|
1069
1126
|
</Card>
|
|
@@ -1194,6 +1251,110 @@ export function PermissionsManager({
|
|
|
1194
1251
|
)
|
|
1195
1252
|
}
|
|
1196
1253
|
|
|
1254
|
+
function ActionCheckGrid({
|
|
1255
|
+
moduleKey,
|
|
1256
|
+
actions,
|
|
1257
|
+
draft,
|
|
1258
|
+
checksDisabled,
|
|
1259
|
+
onToggle,
|
|
1260
|
+
}: {
|
|
1261
|
+
moduleKey: string
|
|
1262
|
+
actions: PermissionActionDef[]
|
|
1263
|
+
draft: ReadonlySet<string> | null | undefined
|
|
1264
|
+
checksDisabled: boolean
|
|
1265
|
+
onToggle: (cap: string) => void
|
|
1266
|
+
}) {
|
|
1267
|
+
return (
|
|
1268
|
+
<div className="grid gap-2 sm:grid-cols-2 xl:grid-cols-3">
|
|
1269
|
+
{actions.map((action) => {
|
|
1270
|
+
const cap = moduleActionCapability(moduleKey, action.key, action.capability)
|
|
1271
|
+
return (
|
|
1272
|
+
<CapabilityCheck
|
|
1273
|
+
key={action.capability ?? action.key}
|
|
1274
|
+
checked={draft?.has(cap) ?? false}
|
|
1275
|
+
disabled={checksDisabled}
|
|
1276
|
+
onToggle={() => onToggle(cap)}
|
|
1277
|
+
icon={action.icon || defaultActionIcon(action.key, action.kind)}
|
|
1278
|
+
label={action.label}
|
|
1279
|
+
/>
|
|
1280
|
+
)
|
|
1281
|
+
})}
|
|
1282
|
+
</div>
|
|
1283
|
+
)
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
/** Flat grid, or collapsible sections when actions declare `group`. */
|
|
1287
|
+
function ModuleActionsPanel({
|
|
1288
|
+
module,
|
|
1289
|
+
draft,
|
|
1290
|
+
checksDisabled,
|
|
1291
|
+
onToggle,
|
|
1292
|
+
}: {
|
|
1293
|
+
module: PermissionModuleDef
|
|
1294
|
+
draft: ReadonlySet<string> | null | undefined
|
|
1295
|
+
checksDisabled: boolean
|
|
1296
|
+
onToggle: (cap: string) => void
|
|
1297
|
+
}) {
|
|
1298
|
+
const sections = React.useMemo(
|
|
1299
|
+
() => groupModuleActions(module.actions),
|
|
1300
|
+
[module.actions],
|
|
1301
|
+
)
|
|
1302
|
+
const hasNamedGroups = sections.some((s) => s.title.length > 0)
|
|
1303
|
+
if (!hasNamedGroups) {
|
|
1304
|
+
return (
|
|
1305
|
+
<ActionCheckGrid
|
|
1306
|
+
moduleKey={module.key}
|
|
1307
|
+
actions={module.actions}
|
|
1308
|
+
draft={draft}
|
|
1309
|
+
checksDisabled={checksDisabled}
|
|
1310
|
+
onToggle={onToggle}
|
|
1311
|
+
/>
|
|
1312
|
+
)
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
return (
|
|
1316
|
+
<div className="flex flex-col gap-3">
|
|
1317
|
+
{sections.map((section) => {
|
|
1318
|
+
if (!section.title) {
|
|
1319
|
+
return (
|
|
1320
|
+
<ActionCheckGrid
|
|
1321
|
+
key="__ungrouped"
|
|
1322
|
+
moduleKey={module.key}
|
|
1323
|
+
actions={section.actions}
|
|
1324
|
+
draft={draft}
|
|
1325
|
+
checksDisabled={checksDisabled}
|
|
1326
|
+
onToggle={onToggle}
|
|
1327
|
+
/>
|
|
1328
|
+
)
|
|
1329
|
+
}
|
|
1330
|
+
const granted = section.actions.filter((a) =>
|
|
1331
|
+
draft?.has(moduleActionCapability(module.key, a.key, a.capability)),
|
|
1332
|
+
).length
|
|
1333
|
+
return (
|
|
1334
|
+
<Collapsible key={section.title} defaultOpen className="rounded-md border border-border/60">
|
|
1335
|
+
<CollapsibleTrigger className="flex w-full items-center gap-2 px-3 py-2.5 text-left text-sm font-medium hover:bg-muted/40 [&[data-state=open]>svg]:rotate-180">
|
|
1336
|
+
<ChevronDown className="h-4 w-4 shrink-0 text-muted-foreground transition-transform" />
|
|
1337
|
+
<span className="min-w-0 flex-1 truncate">{section.title}</span>
|
|
1338
|
+
<Badge variant="secondary" className="tabular-nums">
|
|
1339
|
+
{granted}/{section.actions.length}
|
|
1340
|
+
</Badge>
|
|
1341
|
+
</CollapsibleTrigger>
|
|
1342
|
+
<CollapsibleContent className="border-t border-border/60 px-3 py-3">
|
|
1343
|
+
<ActionCheckGrid
|
|
1344
|
+
moduleKey={module.key}
|
|
1345
|
+
actions={section.actions}
|
|
1346
|
+
draft={draft}
|
|
1347
|
+
checksDisabled={checksDisabled}
|
|
1348
|
+
onToggle={onToggle}
|
|
1349
|
+
/>
|
|
1350
|
+
</CollapsibleContent>
|
|
1351
|
+
</Collapsible>
|
|
1352
|
+
)
|
|
1353
|
+
})}
|
|
1354
|
+
</div>
|
|
1355
|
+
)
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1197
1358
|
function EmptyHint({ text }: { text: string }) {
|
|
1198
1359
|
return (
|
|
1199
1360
|
<div className="flex flex-col items-center justify-center gap-2 py-12 text-muted-foreground">
|