@asteby/metacore-runtime-react 39.1.0 → 39.2.0
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/LICENSE +201 -0
- package/dist/apply-sidebar-layout.d.ts +86 -0
- package/dist/apply-sidebar-layout.d.ts.map +1 -0
- package/dist/apply-sidebar-layout.js +226 -0
- package/dist/dynamic-form-schema.d.ts +1 -1
- package/dist/dynamic-table.d.ts.map +1 -1
- package/dist/dynamic-table.js +32 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/sidebar-layout-manager.d.ts +36 -0
- package/dist/sidebar-layout-manager.d.ts.map +1 -0
- package/dist/sidebar-layout-manager.js +204 -0
- package/package.json +7 -7
- package/src/__tests__/apply-sidebar-layout.test.ts +74 -0
- package/src/__tests__/dynamic-table-forbidden.test.tsx +67 -0
- package/src/apply-sidebar-layout.ts +290 -0
- package/src/dynamic-table.tsx +51 -6
- package/src/index.ts +23 -0
- package/src/sidebar-layout-manager.tsx +522 -0
package/dist/index.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export { PermissionsProvider, useCan, usePermissionsActive, makeCan, capabilityF
|
|
|
33
33
|
export { useDynamicRowActions, type UseDynamicRowActionsParams, type DynamicRowActions, } from './dynamic-row-actions';
|
|
34
34
|
export { ColorPickerField, DEFAULT_ROLE_COLOR, normalizeHex } from './color-picker-field';
|
|
35
35
|
export { PermissionsManager, moduleActionCapability, moduleCapabilities, grantedCountForModule, capabilitySetsEqual, defaultActionIcon, suggestRoleIcon, 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';
|
|
36
|
+
export { applySidebarLayout, collectFolderKeys, folderAccessCapability, coreRefKey, addonModelRefKey, addonUrlRefKey, urlRefKey, leafRefFor, normalizeNavPath, slugifyFolderKey, isValidFolderKey, layoutTreeFromNavGroups, type CatalogLeaf, type SidebarLayoutDoc, type SidebarLayoutNode, type AppliedNavGroup, type AppliedNavItem, } from './apply-sidebar-layout';
|
|
37
|
+
export { SidebarLayoutManager, type SidebarLayoutManagerProps, } from './sidebar-layout-manager';
|
|
36
38
|
export * from './org-runtime-context';
|
|
37
39
|
export * from './org-runtime-provider';
|
|
38
40
|
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
|
@@ -38,6 +38,8 @@ export { PermissionsProvider, useCan, usePermissionsActive, makeCan, capabilityF
|
|
|
38
38
|
export { useDynamicRowActions, } from './dynamic-row-actions';
|
|
39
39
|
export { ColorPickerField, DEFAULT_ROLE_COLOR, normalizeHex } from './color-picker-field';
|
|
40
40
|
export { PermissionsManager, moduleActionCapability, moduleCapabilities, grantedCountForModule, capabilitySetsEqual, defaultActionIcon, suggestRoleIcon, normalizeCatalogGroups, flattenGroups, filterModuleGroups, groupModuleActions, } from './permissions-manager';
|
|
41
|
+
export { applySidebarLayout, collectFolderKeys, folderAccessCapability, coreRefKey, addonModelRefKey, addonUrlRefKey, urlRefKey, leafRefFor, normalizeNavPath, slugifyFolderKey, isValidFolderKey, layoutTreeFromNavGroups, } from './apply-sidebar-layout';
|
|
42
|
+
export { SidebarLayoutManager, } from './sidebar-layout-manager';
|
|
41
43
|
export * from './org-runtime-context';
|
|
42
44
|
export * from './org-runtime-provider';
|
|
43
45
|
export * from './navigation-builder';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SidebarLayoutManager — admin editor for the org-wide sidebar overlay.
|
|
3
|
+
* Transport-agnostic (loaders/mutators via props), same pattern as
|
|
4
|
+
* PermissionsManager. Hosts wire fetchers to /api/org/sidebar-layout.
|
|
5
|
+
*/
|
|
6
|
+
import * as React from 'react';
|
|
7
|
+
import { type CatalogLeaf, type SidebarLayoutDoc, type SidebarLayoutNode } from './apply-sidebar-layout';
|
|
8
|
+
export interface SidebarLayoutManagerProps {
|
|
9
|
+
loadLayout: () => Promise<SidebarLayoutDoc>;
|
|
10
|
+
saveLayout: (doc: SidebarLayoutDoc) => Promise<void>;
|
|
11
|
+
resetLayout: () => Promise<void>;
|
|
12
|
+
/** Live catalog of every leaf the shell can show (core + addons). */
|
|
13
|
+
catalog: CatalogLeaf[];
|
|
14
|
+
/**
|
|
15
|
+
* Optional: current live nav groups — used by "Partir del menú actual" to
|
|
16
|
+
* seed a tree when the org has no layout yet.
|
|
17
|
+
*/
|
|
18
|
+
currentGroups?: Array<{
|
|
19
|
+
title: string;
|
|
20
|
+
items: Array<{
|
|
21
|
+
title: string;
|
|
22
|
+
url: string;
|
|
23
|
+
icon?: string;
|
|
24
|
+
items?: Array<{
|
|
25
|
+
title: string;
|
|
26
|
+
url: string;
|
|
27
|
+
icon?: string;
|
|
28
|
+
}>;
|
|
29
|
+
}>;
|
|
30
|
+
}>;
|
|
31
|
+
title?: string;
|
|
32
|
+
description?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function SidebarLayoutManager({ loadLayout, saveLayout, resetLayout, catalog, currentGroups, title, description, }: SidebarLayoutManagerProps): React.JSX.Element;
|
|
35
|
+
export type { CatalogLeaf, SidebarLayoutDoc, SidebarLayoutNode };
|
|
36
|
+
//# sourceMappingURL=sidebar-layout-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sidebar-layout-manager.d.ts","sourceRoot":"","sources":["../src/sidebar-layout-manager.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA2B9B,OAAO,EAML,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACvB,MAAM,wBAAwB,CAAA;AAE/B,MAAM,WAAW,yBAAyB;IACxC,UAAU,EAAE,MAAM,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAC3C,UAAU,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACpD,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAChC,qEAAqE;IACrE,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB;;;OAGG;IACH,aAAa,CAAC,EAAE,KAAK,CAAC;QACpB,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,KAAK,CAAC;YACX,KAAK,EAAE,MAAM,CAAA;YACb,GAAG,EAAE,MAAM,CAAA;YACX,IAAI,CAAC,EAAE,MAAM,CAAA;YACb,KAAK,CAAC,EAAE,KAAK,CAAC;gBAAE,KAAK,EAAE,MAAM,CAAC;gBAAC,GAAG,EAAE,MAAM,CAAC;gBAAC,IAAI,CAAC,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAC7D,CAAC,CAAA;KACH,CAAC,CAAA;IACF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAmED,wBAAgB,oBAAoB,CAAC,EACnC,UAAU,EACV,UAAU,EACV,WAAW,EACX,OAAO,EACP,aAAa,EACb,KAAsB,EACtB,WAAsI,GACvI,EAAE,yBAAyB,qBA4X3B;AAED,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,CAAA"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* SidebarLayoutManager — admin editor for the org-wide sidebar overlay.
|
|
4
|
+
* Transport-agnostic (loaders/mutators via props), same pattern as
|
|
5
|
+
* PermissionsManager. Hosts wire fetchers to /api/org/sidebar-layout.
|
|
6
|
+
*/
|
|
7
|
+
import * as React from 'react';
|
|
8
|
+
import { ChevronDown, ChevronRight, FolderPlus, GripVertical, RotateCcw, Save, Trash2, Eye, EyeOff, Folder, FileText, } from 'lucide-react';
|
|
9
|
+
import { toast } from 'sonner';
|
|
10
|
+
import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Label, ScrollArea, Badge, } from '@asteby/metacore-ui/primitives';
|
|
11
|
+
import { applySidebarLayout, collectFolderKeys, folderAccessCapability, layoutTreeFromNavGroups, slugifyFolderKey, } from './apply-sidebar-layout';
|
|
12
|
+
function collectUsedRefs(tree) {
|
|
13
|
+
const used = new Set();
|
|
14
|
+
const walk = (nodes) => {
|
|
15
|
+
for (const n of nodes) {
|
|
16
|
+
if (n.type === 'leaf' && n.ref)
|
|
17
|
+
used.add(n.ref);
|
|
18
|
+
if (n.children)
|
|
19
|
+
walk(n.children);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
walk(tree);
|
|
23
|
+
return used;
|
|
24
|
+
}
|
|
25
|
+
function updateAt(tree, path, fn) {
|
|
26
|
+
if (path.length === 0)
|
|
27
|
+
return tree;
|
|
28
|
+
const [head, ...rest] = path;
|
|
29
|
+
return tree
|
|
30
|
+
.map((n, i) => {
|
|
31
|
+
if (i !== head)
|
|
32
|
+
return n;
|
|
33
|
+
if (rest.length === 0)
|
|
34
|
+
return fn(n);
|
|
35
|
+
const kids = updateAt(n.children ?? [], rest, fn);
|
|
36
|
+
return { ...n, children: kids };
|
|
37
|
+
})
|
|
38
|
+
.filter((n) => n != null);
|
|
39
|
+
}
|
|
40
|
+
function removeAt(tree, path) {
|
|
41
|
+
return updateAt(tree, path, () => null).filter(Boolean);
|
|
42
|
+
}
|
|
43
|
+
function moveSibling(tree, path, dir) {
|
|
44
|
+
if (path.length === 0)
|
|
45
|
+
return tree;
|
|
46
|
+
const parentPath = path.slice(0, -1);
|
|
47
|
+
const idx = path[path.length - 1];
|
|
48
|
+
const getList = (nodes, p) => {
|
|
49
|
+
if (p.length === 0)
|
|
50
|
+
return nodes;
|
|
51
|
+
let cur = nodes;
|
|
52
|
+
for (const i of p) {
|
|
53
|
+
cur = cur[i]?.children ?? [];
|
|
54
|
+
}
|
|
55
|
+
return cur;
|
|
56
|
+
};
|
|
57
|
+
const list = [...getList(tree, parentPath)];
|
|
58
|
+
const j = idx + dir;
|
|
59
|
+
if (j < 0 || j >= list.length)
|
|
60
|
+
return tree;
|
|
61
|
+
[list[idx], list[j]] = [list[j], list[idx]];
|
|
62
|
+
if (parentPath.length === 0)
|
|
63
|
+
return list;
|
|
64
|
+
return updateAt(tree, parentPath, (n) => ({ ...n, children: list }));
|
|
65
|
+
}
|
|
66
|
+
function appendChild(tree, parentPath, child) {
|
|
67
|
+
if (parentPath.length === 0)
|
|
68
|
+
return [...tree, child];
|
|
69
|
+
return updateAt(tree, parentPath, (n) => ({
|
|
70
|
+
...n,
|
|
71
|
+
children: [...(n.children ?? []), child],
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
export function SidebarLayoutManager({ loadLayout, saveLayout, resetLayout, catalog, currentGroups, title = 'Menú lateral', description = 'Organizá carpetas y el orden del sidebar para toda la organización. Los permisos de cada carpeta aparecen en Permisos.', }) {
|
|
75
|
+
const [tree, setTree] = React.useState([]);
|
|
76
|
+
const [baseline, setBaseline] = React.useState('[]');
|
|
77
|
+
const [loading, setLoading] = React.useState(true);
|
|
78
|
+
const [saving, setSaving] = React.useState(false);
|
|
79
|
+
const [newFolderTitle, setNewFolderTitle] = React.useState('');
|
|
80
|
+
const [expanded, setExpanded] = React.useState({});
|
|
81
|
+
const reload = React.useCallback(async () => {
|
|
82
|
+
setLoading(true);
|
|
83
|
+
try {
|
|
84
|
+
const doc = await loadLayout();
|
|
85
|
+
const t = doc.tree ?? [];
|
|
86
|
+
setTree(t);
|
|
87
|
+
setBaseline(JSON.stringify(t));
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
toast.error(e instanceof Error ? e.message : 'No se pudo cargar el layout');
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
setLoading(false);
|
|
94
|
+
}
|
|
95
|
+
}, [loadLayout]);
|
|
96
|
+
React.useEffect(() => {
|
|
97
|
+
void reload();
|
|
98
|
+
}, [reload]);
|
|
99
|
+
const dirty = JSON.stringify(tree) !== baseline;
|
|
100
|
+
const used = React.useMemo(() => collectUsedRefs(tree), [tree]);
|
|
101
|
+
const unused = React.useMemo(() => catalog.filter((l) => !used.has(l.ref) && !(l.aliases ?? []).some((a) => used.has(a))), [catalog, used]);
|
|
102
|
+
const folderKeys = React.useMemo(() => collectFolderKeys(tree), [tree]);
|
|
103
|
+
const preview = React.useMemo(() => applySidebarLayout(catalog, tree), [catalog, tree]);
|
|
104
|
+
const pathKey = (path) => path.join('.');
|
|
105
|
+
const handleSave = async () => {
|
|
106
|
+
setSaving(true);
|
|
107
|
+
try {
|
|
108
|
+
await saveLayout({ version: 1, tree });
|
|
109
|
+
setBaseline(JSON.stringify(tree));
|
|
110
|
+
toast.success('Menú guardado para toda la organización');
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
toast.error(e instanceof Error ? e.message : 'Error al guardar');
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
setSaving(false);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const handleReset = async () => {
|
|
120
|
+
setSaving(true);
|
|
121
|
+
try {
|
|
122
|
+
await resetLayout();
|
|
123
|
+
setTree([]);
|
|
124
|
+
setBaseline('[]');
|
|
125
|
+
toast.success('Menú restaurado al default (addons + core)');
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
toast.error(e instanceof Error ? e.message : 'Error al resetear');
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
setSaving(false);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const seedFromCurrent = () => {
|
|
135
|
+
if (!currentGroups?.length) {
|
|
136
|
+
toast.message('No hay menú actual para copiar');
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const seeded = layoutTreeFromNavGroups(currentGroups);
|
|
140
|
+
setTree(seeded);
|
|
141
|
+
toast.message('Árbol partido del menú actual — guardá para aplicar');
|
|
142
|
+
};
|
|
143
|
+
const addRootFolder = () => {
|
|
144
|
+
const titleText = newFolderTitle.trim() || 'Nueva carpeta';
|
|
145
|
+
const key = slugifyFolderKey(titleText);
|
|
146
|
+
setTree((t) => [
|
|
147
|
+
...t,
|
|
148
|
+
{
|
|
149
|
+
type: 'group',
|
|
150
|
+
key: `group_${key}`,
|
|
151
|
+
title: titleText,
|
|
152
|
+
children: [{ type: 'folder', key, title: titleText, icon: 'Folder', children: [] }],
|
|
153
|
+
},
|
|
154
|
+
]);
|
|
155
|
+
setNewFolderTitle('');
|
|
156
|
+
};
|
|
157
|
+
const addLeafTo = (parentPath, leaf) => {
|
|
158
|
+
setTree((t) => appendChild(t, parentPath, {
|
|
159
|
+
type: 'leaf',
|
|
160
|
+
ref: leaf.ref,
|
|
161
|
+
title: leaf.title,
|
|
162
|
+
icon: leaf.icon,
|
|
163
|
+
}));
|
|
164
|
+
};
|
|
165
|
+
const renderNode = (node, path) => {
|
|
166
|
+
const k = pathKey(path);
|
|
167
|
+
const isOpen = expanded[k] ?? true;
|
|
168
|
+
const isFolderish = node.type === 'group' || node.type === 'folder';
|
|
169
|
+
return (_jsxs("div", { className: "border-border/60 rounded-md border bg-background/50", children: [_jsxs("div", { className: "flex items-center gap-1 px-2 py-1.5", children: [isFolderish ? (_jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground p-0.5", onClick: () => setExpanded((e) => ({ ...e, [k]: !isOpen })), children: isOpen ? _jsx(ChevronDown, { className: "size-4" }) : _jsx(ChevronRight, { className: "size-4" }) })) : (_jsx(GripVertical, { className: "text-muted-foreground size-4 shrink-0 opacity-40" })), node.type === 'folder' ? (_jsx(Folder, { className: "text-amber-600 size-4 shrink-0" })) : node.type === 'leaf' ? (_jsx(FileText, { className: "text-muted-foreground size-4 shrink-0" })) : null, _jsx("span", { className: "min-w-0 flex-1 truncate text-sm font-medium", children: node.title || node.key || node.ref }), node.type === 'folder' && node.key ? (_jsx(Badge, { variant: "outline", className: "font-mono text-[10px]", children: folderAccessCapability(node.key) })) : null, _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "size-7", title: node.hidden ? 'Mostrar' : 'Ocultar', onClick: () => setTree((t) => updateAt(t, path, (n) => ({ ...n, hidden: !n.hidden }))), children: node.hidden ? _jsx(EyeOff, { className: "size-3.5" }) : _jsx(Eye, { className: "size-3.5" }) }), _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "size-7", onClick: () => setTree((t) => moveSibling(t, path, -1)), children: "\u2191" }), _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "size-7", onClick: () => setTree((t) => moveSibling(t, path, 1)), children: "\u2193" }), _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "text-destructive size-7", onClick: () => setTree((t) => removeAt(t, path)), children: _jsx(Trash2, { className: "size-3.5" }) })] }), isFolderish && isOpen ? (_jsxs("div", { className: "border-border/40 space-y-1 border-t px-2 py-2 pl-6", children: [(node.children ?? []).map((child, i) => renderNode(child, [...path, i])), unused.length > 0 ? (_jsxs("select", { className: "border-input bg-background w-full rounded-md border px-2 py-1 text-xs", defaultValue: "", onChange: (e) => {
|
|
170
|
+
const ref = e.target.value;
|
|
171
|
+
e.target.value = '';
|
|
172
|
+
const leaf = catalog.find((l) => l.ref === ref);
|
|
173
|
+
if (leaf)
|
|
174
|
+
addLeafTo(path, leaf);
|
|
175
|
+
}, children: [_jsx("option", { value: "", children: "+ Agregar \u00EDtem\u2026" }), unused.map((l) => (_jsxs("option", { value: l.ref, children: [l.title, " (", l.ref, ")"] }, l.ref)))] })) : null, node.type === 'group' ? (_jsxs(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 text-xs", onClick: () => {
|
|
176
|
+
const titleText = 'Nueva carpeta';
|
|
177
|
+
const key = slugifyFolderKey(`${titleText}_${path.join('')}_${Date.now() % 1000}`);
|
|
178
|
+
setTree((t) => appendChild(t, path, {
|
|
179
|
+
type: 'folder',
|
|
180
|
+
key,
|
|
181
|
+
title: titleText,
|
|
182
|
+
icon: 'Folder',
|
|
183
|
+
children: [],
|
|
184
|
+
}));
|
|
185
|
+
}, children: [_jsx(FolderPlus, { className: "mr-1 size-3.5" }), "Subcarpeta"] })) : null] })) : null] }, k));
|
|
186
|
+
};
|
|
187
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("h2", { className: "text-xl font-semibold tracking-tight", children: title }), _jsx("p", { className: "text-muted-foreground max-w-2xl text-sm", children: description })] }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: seedFromCurrent, children: "Partir del men\u00FA actual" }), _jsxs(Button, { type: "button", variant: "outline", size: "sm", disabled: saving, onClick: () => void handleReset(), children: [_jsx(RotateCcw, { className: "mr-1 size-3.5" }), "Restaurar default"] }), _jsxs(Button, { type: "button", size: "sm", disabled: !dirty || saving, onClick: () => void handleSave(), children: [_jsx(Save, { className: "mr-1 size-3.5" }), saving ? 'Guardando…' : dirty ? 'Guardar' : 'Guardado'] })] })] }), loading ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "Cargando\u2026" })) : (_jsxs("div", { className: "grid gap-4 lg:grid-cols-2", children: [_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "\u00C1rbol del men\u00FA" }), _jsxs(CardDescription, { children: ["Carpetas nuevas otorgan el permiso", ' ', _jsx("code", { className: "text-xs", children: "folder.<key>.access" }), "."] })] }), _jsxs(CardContent, { className: "space-y-3", children: [_jsxs("div", { className: "flex gap-2", children: [_jsxs("div", { className: "flex-1 space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Nueva secci\u00F3n + carpeta" }), _jsx(Input, { value: newFolderTitle, onChange: (e) => setNewFolderTitle(e.target.value), placeholder: "Configuraci\u00F3n" })] }), _jsxs(Button, { type: "button", className: "mt-5", size: "sm", onClick: addRootFolder, children: [_jsx(FolderPlus, { className: "mr-1 size-3.5" }), "Crear"] })] }), _jsx(ScrollArea, { className: "h-[420px] pr-2", children: _jsx("div", { className: "space-y-2", children: tree.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "Sin overlay \u2014 el sidebar usa el merge default. Part\u00ED del men\u00FA actual o cre\u00E1 una carpeta." })) : (tree.map((n, i) => renderNode(n, [i]))) }) }), folderKeys.length > 0 ? (_jsxs("p", { className: "text-muted-foreground text-xs", children: ["Carpetas con permiso: ", folderKeys.map((k) => folderAccessCapability(k)).join(', ')] })) : null] })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-base", children: "Cat\u00E1logo sin usar / vista previa" }), _jsx(CardDescription, { children: "\u00CDtems disponibles para colocar. La vista previa aplica el overlay sobre el cat\u00E1logo vivo." })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsx(ScrollArea, { className: "h-[200px] rounded-md border p-2", children: unused.length === 0 ? (_jsx("p", { className: "text-muted-foreground text-xs", children: "Todos los \u00EDtems est\u00E1n en el \u00E1rbol." })) : (_jsx("ul", { className: "space-y-1", children: unused.map((l) => (_jsxs("li", { className: "flex items-center justify-between gap-2 text-xs", children: [_jsxs("span", { className: "truncate", children: [l.title, ' ', _jsx("span", { className: "text-muted-foreground font-mono", children: l.ref })] }), _jsx(Button, { type: "button", size: "sm", variant: "ghost", className: "h-6 shrink-0 text-xs", onClick: () => {
|
|
188
|
+
if (tree.length === 0) {
|
|
189
|
+
setTree([
|
|
190
|
+
{
|
|
191
|
+
type: 'group',
|
|
192
|
+
key: 'sidebar.general',
|
|
193
|
+
title: 'sidebar.general',
|
|
194
|
+
children: [
|
|
195
|
+
{ type: 'leaf', ref: l.ref, title: l.title, icon: l.icon },
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
]);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
addLeafTo([0], l);
|
|
202
|
+
}
|
|
203
|
+
}, children: "+" })] }, l.ref))) })) }), _jsxs("div", { children: [_jsx("p", { className: "mb-2 text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "Preview" }), !preview ? (_jsx("p", { className: "text-muted-foreground text-sm", children: "Default merge (sin overlay)." })) : (_jsx("ul", { className: "space-y-2 text-sm", children: preview.map((g) => (_jsxs("li", { children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold uppercase tracking-wide", children: g.title }), _jsx("ul", { className: "mt-1 space-y-0.5 pl-2", children: g.items.map((it) => (_jsxs("li", { children: [it.folderKey ? `📁 ${it.title}` : it.title, it.items?.length ? (_jsx("ul", { className: "text-muted-foreground pl-4 text-xs", children: it.items.map((c) => (_jsx("li", { children: c.title }, c.ref || c.url))) })) : null] }, `${it.title}-${it.url}`))) })] }, g.title))) }))] })] })] })] }))] }));
|
|
204
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asteby/metacore-runtime-react",
|
|
3
|
-
"version": "39.
|
|
3
|
+
"version": "39.2.0",
|
|
4
4
|
"description": "React runtime for metacore hosts — renders addon contributions dynamically",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
"zod": "^4.3.0"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
+
"@asteby/metacore-sdk": "^3.8.0",
|
|
30
|
+
"@asteby/metacore-ui": "^2.18.1",
|
|
29
31
|
"@tanstack/react-query": ">=5",
|
|
30
32
|
"@tanstack/react-router": ">=1.100",
|
|
31
33
|
"@tanstack/react-table": ">=8",
|
|
@@ -37,9 +39,7 @@
|
|
|
37
39
|
"react-dom": ">=18",
|
|
38
40
|
"react-i18next": ">=13",
|
|
39
41
|
"sonner": ">=1.7",
|
|
40
|
-
"zustand": ">=5"
|
|
41
|
-
"@asteby/metacore-sdk": "^3.8.0",
|
|
42
|
-
"@asteby/metacore-ui": "^2.18.1"
|
|
42
|
+
"zustand": ">=5"
|
|
43
43
|
},
|
|
44
44
|
"peerDependenciesMeta": {
|
|
45
45
|
"@tanstack/react-router": {
|
|
@@ -50,6 +50,8 @@
|
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
+
"@asteby/metacore-sdk": "3.8.0",
|
|
54
|
+
"@asteby/metacore-ui": "2.18.1",
|
|
53
55
|
"@tanstack/react-query": "^5.95.0",
|
|
54
56
|
"@tanstack/react-router": "^1.168.0",
|
|
55
57
|
"@tanstack/react-table": "^8.20.0",
|
|
@@ -67,9 +69,7 @@
|
|
|
67
69
|
"tsx": "^4.21.0",
|
|
68
70
|
"typescript": "^6.0.0",
|
|
69
71
|
"vitest": "^4.0.0",
|
|
70
|
-
"zustand": "^5.0.0"
|
|
71
|
-
"@asteby/metacore-sdk": "3.8.0",
|
|
72
|
-
"@asteby/metacore-ui": "2.18.1"
|
|
72
|
+
"zustand": "^5.0.0"
|
|
73
73
|
},
|
|
74
74
|
"scripts": {
|
|
75
75
|
"build": "tsc -p tsconfig.json",
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
applySidebarLayout,
|
|
4
|
+
coreRefKey,
|
|
5
|
+
folderAccessCapability,
|
|
6
|
+
leafRefFor,
|
|
7
|
+
slugifyFolderKey,
|
|
8
|
+
type CatalogLeaf,
|
|
9
|
+
type SidebarLayoutNode,
|
|
10
|
+
} from './apply-sidebar-layout'
|
|
11
|
+
|
|
12
|
+
describe('applySidebarLayout', () => {
|
|
13
|
+
const catalog: CatalogLeaf[] = [
|
|
14
|
+
{ ref: coreRefKey('/'), title: 'Dashboard', url: '/' },
|
|
15
|
+
{ ref: 'addon:crm/model:prices', title: 'Precios', url: '/m/prices', aliases: ['url:/m/prices'] },
|
|
16
|
+
{ ref: coreRefKey('/organization'), title: 'Org', url: '/organization' },
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
it('returns null for empty tree', () => {
|
|
20
|
+
expect(applySidebarLayout(catalog, [])).toBeNull()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('moves prices under a configuration folder', () => {
|
|
24
|
+
const tree: SidebarLayoutNode[] = [
|
|
25
|
+
{
|
|
26
|
+
type: 'group',
|
|
27
|
+
title: 'Sistema',
|
|
28
|
+
children: [
|
|
29
|
+
{
|
|
30
|
+
type: 'folder',
|
|
31
|
+
key: 'configuracion',
|
|
32
|
+
title: 'Configuración',
|
|
33
|
+
children: [
|
|
34
|
+
{ type: 'leaf', ref: coreRefKey('/organization') },
|
|
35
|
+
{ type: 'leaf', ref: 'addon:crm/model:prices' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
]
|
|
41
|
+
const groups = applySidebarLayout(catalog, tree)
|
|
42
|
+
expect(groups).toHaveLength(1)
|
|
43
|
+
expect(groups![0].items[0].folderKey).toBe('configuracion')
|
|
44
|
+
expect(groups![0].items[0].items?.map((i) => i.url)).toEqual([
|
|
45
|
+
'/organization',
|
|
46
|
+
'/m/prices',
|
|
47
|
+
])
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('resolves url: alias', () => {
|
|
51
|
+
const tree: SidebarLayoutNode[] = [
|
|
52
|
+
{
|
|
53
|
+
type: 'group',
|
|
54
|
+
title: 'G',
|
|
55
|
+
children: [{ type: 'leaf', ref: 'url:/m/prices' }],
|
|
56
|
+
},
|
|
57
|
+
]
|
|
58
|
+
const groups = applySidebarLayout(catalog, tree)
|
|
59
|
+
expect(groups![0].items[0].url).toBe('/m/prices')
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
describe('helpers', () => {
|
|
64
|
+
it('slugifies folder keys', () => {
|
|
65
|
+
expect(slugifyFolderKey('Mi Config')).toBe('mi_config')
|
|
66
|
+
})
|
|
67
|
+
it('folder capability', () => {
|
|
68
|
+
expect(folderAccessCapability('configuracion')).toBe('folder.configuracion.access')
|
|
69
|
+
})
|
|
70
|
+
it('leafRefFor model pages', () => {
|
|
71
|
+
expect(leafRefFor('/m/prices')).toBe('url:/m/prices')
|
|
72
|
+
expect(leafRefFor('/organization')).toBe('core:/organization')
|
|
73
|
+
})
|
|
74
|
+
})
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
//
|
|
3
|
+
// Un 403 en el endpoint de lista NO debe verse como "sin resultados": se
|
|
4
|
+
// muestra "Sin permiso para ver este módulo" y no hay bucle de refetch.
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
6
|
+
import { cleanup, render, screen } from '@testing-library/react'
|
|
7
|
+
|
|
8
|
+
vi.mock('@tanstack/react-router', () => ({ useNavigate: () => () => {} }))
|
|
9
|
+
|
|
10
|
+
import { ApiProvider, type ApiClient } from '../api-context'
|
|
11
|
+
import { useMetadataCache } from '../metadata-cache'
|
|
12
|
+
import { DynamicCRUDPage } from '../dynamic-crud-page'
|
|
13
|
+
import type { TableMetadata } from '../types'
|
|
14
|
+
|
|
15
|
+
afterEach(cleanup)
|
|
16
|
+
|
|
17
|
+
const meta = {
|
|
18
|
+
title: 'Ajustes',
|
|
19
|
+
endpoint: '/data/stock_adjustments',
|
|
20
|
+
columns: [],
|
|
21
|
+
actions: [],
|
|
22
|
+
perPageOptions: [10],
|
|
23
|
+
defaultPerPage: 10,
|
|
24
|
+
searchPlaceholder: 'Buscar...',
|
|
25
|
+
enableCRUDActions: false,
|
|
26
|
+
hasActions: false,
|
|
27
|
+
} as unknown as TableMetadata
|
|
28
|
+
|
|
29
|
+
function mount(listBehavior: 'forbidden' | 'empty', model: string) {
|
|
30
|
+
useMetadataCache.getState().setMetadata(model, meta)
|
|
31
|
+
let listCalls = 0
|
|
32
|
+
const client: ApiClient = {
|
|
33
|
+
get: vi.fn(async (url: string) => {
|
|
34
|
+
if (url.startsWith('/metadata/table/')) return { data: { success: true, data: meta } }
|
|
35
|
+
listCalls++
|
|
36
|
+
if (listBehavior === 'forbidden') {
|
|
37
|
+
throw Object.assign(new Error('403'), { response: { status: 403 } })
|
|
38
|
+
}
|
|
39
|
+
return { data: { success: true, data: [], meta: { total: 0 } } }
|
|
40
|
+
}),
|
|
41
|
+
post: vi.fn(async () => ({ data: { success: true, data: null } })),
|
|
42
|
+
put: vi.fn(async () => ({ data: { success: true, data: null } })),
|
|
43
|
+
delete: vi.fn(async () => ({ data: { success: true, data: null } })),
|
|
44
|
+
}
|
|
45
|
+
render(
|
|
46
|
+
<ApiProvider client={client}>
|
|
47
|
+
<DynamicCRUDPage model={model} />
|
|
48
|
+
</ApiProvider>,
|
|
49
|
+
)
|
|
50
|
+
return () => listCalls
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe('DynamicTable — 403 en la lista', () => {
|
|
54
|
+
it('muestra "Sin permiso" y no "No se encontraron resultados"', async () => {
|
|
55
|
+
const calls = mount('forbidden', 'forb_a')
|
|
56
|
+
expect((await screen.findAllByText('Sin permiso para ver este módulo')).length).toBeGreaterThan(0)
|
|
57
|
+
expect(screen.queryByText('No se encontraron resultados')).toBeNull()
|
|
58
|
+
await new Promise((r) => setTimeout(r, 200))
|
|
59
|
+
expect(calls()).toBeLessThanOrEqual(2) // sin bucle de refetch
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('lista vacía real sigue diciendo "No se encontraron resultados"', async () => {
|
|
63
|
+
mount('empty', 'forb_b')
|
|
64
|
+
expect((await screen.findAllByText('No se encontraron resultados')).length).toBeGreaterThan(0)
|
|
65
|
+
expect(screen.queryByText('Sin permiso para ver este módulo')).toBeNull()
|
|
66
|
+
})
|
|
67
|
+
})
|