@asteby/metacore-runtime-react 30.0.0 → 30.0.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @asteby/metacore-runtime-react
2
2
 
3
+ ## 30.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 0016511: PermissionActionDef.capability: atajos cross-módulo en el grid de permisos
8
+
3
9
  ## 30.0.0
4
10
 
5
11
  ### Patch Changes
@@ -9,8 +9,17 @@ 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;
14
23
  }
15
24
  export interface PermissionModuleDef {
16
25
  /**
@@ -94,8 +103,10 @@ export interface PermissionsManagerProps {
94
103
  title?: string;
95
104
  className?: string;
96
105
  }
97
- /** Capability for a catalog module action: `lowercase(moduleKey).actionKey`. */
98
- export declare function moduleActionCapability(moduleKey: string, actionKey: string): string;
106
+ /** Capability for a catalog module action: `lowercase(moduleKey).actionKey`,
107
+ * or {@link PermissionActionDef.capability} when the action is a cross-module
108
+ * shortcut. */
109
+ export declare function moduleActionCapability(moduleKey: string, actionKey: string, capability?: string): string;
99
110
  /** All capabilities of one module. */
100
111
  export declare function moduleCapabilities(module: PermissionModuleDef): string[];
101
112
  /** How many of the module's capabilities are in the granted set. */
@@ -1 +1 @@
1
- {"version":3,"file":"permissions-manager.d.ts","sourceRoot":"","sources":["../src/permissions-manager.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"permissions-manager.d.ts","sourceRoot":"","sources":["../src/permissions-manager.tsx"],"names":[],"mappings":"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"}
@@ -33,13 +33,17 @@ 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
- export function moduleActionCapability(moduleKey, actionKey) {
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));
43
47
  }
44
48
  /** How many of the module's capabilities are in the granted set. */
45
49
  export function grantedCountForModule(granted, module) {
@@ -75,6 +79,8 @@ export function defaultActionIcon(actionKey, kind) {
75
79
  return 'List';
76
80
  if (kind === 'screen')
77
81
  return 'Eye';
82
+ if (kind === 'dependency')
83
+ return 'Link2';
78
84
  return 'Zap';
79
85
  }
80
86
  }
@@ -445,8 +451,8 @@ export function PermissionsManager({ loadModules, loadRoles, loadRolePermissions
445
451
  (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
452
  ? `${activeModuleGroupTitle || 'Sistema'} · configura las acciones permitidas`
447
453
  : '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("div", { className: "grid gap-2 sm:grid-cols-2 xl:grid-cols-3", children: activeModule.actions.map((action) => {
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));
454
+ const cap = moduleActionCapability(activeModule.key, action.key, action.capability);
455
+ 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.capability ?? action.key));
450
456
  }) })) })] })] }), _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
457
  setActiveRoleId(pendingRoleId);
452
458
  setPendingRoleId(null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asteby/metacore-runtime-react",
3
- "version": "30.0.0",
3
+ "version": "30.0.1",
4
4
  "description": "React runtime for metacore hosts — renders addon contributions dynamically",
5
5
  "repository": {
6
6
  "type": "git",
@@ -118,6 +118,30 @@ describe('helpers puros', () => {
118
118
  )
119
119
  })
120
120
 
121
+ it('capability override grants the exact cross-module key', () => {
122
+ expect(
123
+ moduleActionCapability('screen.addons.pos.terminal', 'product.index', 'product.index'),
124
+ ).toBe('product.index')
125
+ const mod = {
126
+ key: 'screen.addons.pos.terminal',
127
+ label: 'Terminal',
128
+ kind: 'screen' as const,
129
+ actions: [
130
+ { key: 'access', label: 'Acceder', kind: 'screen' as const },
131
+ {
132
+ key: 'product.index',
133
+ label: 'Productos · Listar',
134
+ kind: 'dependency' as const,
135
+ capability: 'product.index',
136
+ },
137
+ ],
138
+ }
139
+ expect(moduleCapabilities(mod)).toEqual([
140
+ 'screen.addons.pos.terminal.access',
141
+ 'product.index',
142
+ ])
143
+ })
144
+
121
145
  it('moduleCapabilities y grantedCountForModule', () => {
122
146
  const mod = grouped.groups[1].modules[0] // pos_orders
123
147
  expect(moduleCapabilities(mod)).toEqual([
@@ -90,8 +90,17 @@ export interface PermissionActionDef {
90
90
  /**
91
91
  * `crud` for the derived CRUD set, `custom` for manifest actions,
92
92
  * `screen` for the single `access` action of a non-model screen.
93
+ * `dependency` for a shortcut to another module's capability (see
94
+ * {@link capability}).
93
95
  */
94
- kind?: 'crud' | 'custom' | 'screen' | string
96
+ kind?: 'crud' | 'custom' | 'screen' | 'dependency' | string
97
+ /**
98
+ * Full capability string override. When set, the grant uses this exact key
99
+ * instead of `${moduleKey}.${key}` — hosts use it so a screen (Terminal)
100
+ * can show checkboxes for other modules' caps (`product.index`, …) as
101
+ * shortcuts without inventing `screen….product.index`.
102
+ */
103
+ capability?: string
95
104
  }
96
105
 
97
106
  export interface PermissionModuleDef {
@@ -189,14 +198,23 @@ export interface PermissionsManagerProps {
189
198
  // Pure helpers (exported for hosts/tests)
190
199
  // ---------------------------------------------------------------------------
191
200
 
192
- /** Capability for a catalog module action: `lowercase(moduleKey).actionKey`. */
193
- export function moduleActionCapability(moduleKey: string, actionKey: string): string {
201
+ /** Capability for a catalog module action: `lowercase(moduleKey).actionKey`,
202
+ * or {@link PermissionActionDef.capability} when the action is a cross-module
203
+ * shortcut. */
204
+ export function moduleActionCapability(
205
+ moduleKey: string,
206
+ actionKey: string,
207
+ capability?: string,
208
+ ): string {
209
+ if (capability) return capability
194
210
  return `${moduleKey.toLowerCase()}.${actionKey}`
195
211
  }
196
212
 
197
213
  /** All capabilities of one module. */
198
214
  export function moduleCapabilities(module: PermissionModuleDef): string[] {
199
- return module.actions.map((a) => moduleActionCapability(module.key, a.key))
215
+ return module.actions.map((a) =>
216
+ moduleActionCapability(module.key, a.key, a.capability),
217
+ )
200
218
  }
201
219
 
202
220
  /** How many of the module's capabilities are in the granted set. */
@@ -233,6 +251,7 @@ export function defaultActionIcon(actionKey: string, kind?: string): string {
233
251
  default:
234
252
  if (kind === 'crud') return 'List'
235
253
  if (kind === 'screen') return 'Eye'
254
+ if (kind === 'dependency') return 'Link2'
236
255
  return 'Zap'
237
256
  }
238
257
  }
@@ -1051,10 +1070,14 @@ export function PermissionsManager({
1051
1070
  ) : (
1052
1071
  <div className="grid gap-2 sm:grid-cols-2 xl:grid-cols-3">
1053
1072
  {activeModule.actions.map((action) => {
1054
- const cap = moduleActionCapability(activeModule.key, action.key)
1073
+ const cap = moduleActionCapability(
1074
+ activeModule.key,
1075
+ action.key,
1076
+ action.capability,
1077
+ )
1055
1078
  return (
1056
1079
  <CapabilityCheck
1057
- key={action.key}
1080
+ key={action.capability ?? action.key}
1058
1081
  checked={draft?.has(cap) ?? false}
1059
1082
  disabled={checksDisabled}
1060
1083
  onToggle={() => toggleCapability(cap)}