@postxl/generators 1.3.0 → 1.3.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/dist/backend-core/template/.gitignore.template +40 -0
- package/dist/base/template/.gitignore.template +471 -0
- package/dist/base/template/sonar-project.properties +2 -2
- package/dist/e2e/template/e2e/.gitignore.template +11 -0
- package/dist/frontend-admin/generators/admin-sidebar.generator.js +118 -110
- package/dist/frontend-admin/generators/admin-sidebar.generator.js.map +1 -1
- package/dist/frontend-admin/generators/audit-log-sidebar.generator.js +161 -131
- package/dist/frontend-admin/generators/audit-log-sidebar.generator.js.map +1 -1
- package/dist/frontend-admin/generators/data-management-page.generator.js +5 -4
- package/dist/frontend-admin/generators/data-management-page.generator.js.map +1 -1
- package/dist/frontend-admin/generators/model-admin-page.generator.js +34 -18
- package/dist/frontend-admin/generators/model-admin-page.generator.js.map +1 -1
- package/dist/frontend-core/frontend.generator.js +1 -1
- package/dist/frontend-core/frontend.generator.js.map +1 -1
- package/dist/frontend-core/template/.gitignore.template +27 -0
- package/package.json +4 -4
|
@@ -45,145 +45,153 @@ function generateAdminSidebar({ context }) {
|
|
|
45
45
|
.from(Generator.toBackendModuleLocation('@ui/admin/AdminSidebar'))
|
|
46
46
|
.addImport({
|
|
47
47
|
from: Generator.toPackageName('react'),
|
|
48
|
-
items: [Generator.toFunctionName('
|
|
48
|
+
items: [Generator.toFunctionName('ComponentProps')],
|
|
49
49
|
})
|
|
50
50
|
.addImport({
|
|
51
|
-
from: Generator.toPackageName('
|
|
52
|
-
items: [
|
|
53
|
-
Generator.toFunctionName('ChevronRightIcon'),
|
|
54
|
-
Generator.toFunctionName('ChevronDownIcon'),
|
|
55
|
-
Generator.toFunctionName('ChevronLeftIcon'),
|
|
56
|
-
],
|
|
51
|
+
from: Generator.toPackageName('lucide-react'),
|
|
52
|
+
items: [Generator.toFunctionName('ChevronRight'), Generator.toFunctionName('Home')],
|
|
57
53
|
});
|
|
58
54
|
const { schemas: sortedSchemas, modelsBySchema } = (0, utils_1.groupAndSortModelsBySchema)(context);
|
|
55
|
+
// Generate schema keys for collapse state (lowercase for valid JS identifiers)
|
|
56
|
+
const schemaKeys = sortedSchemas.map((schema) => schema.toLowerCase());
|
|
57
|
+
// Generate the CollapseState type properties
|
|
58
|
+
const collapseStateTypeProps = [...schemaKeys, 'advanced'].map((key) => ` ${key}: boolean`).join('\n');
|
|
59
|
+
// Generate the defaultCollapseState properties
|
|
60
|
+
const defaultCollapseStateProps = [...schemaKeys, 'advanced'].map((key) => ` ${key}: true,`).join('\n');
|
|
59
61
|
// Generate the schema sections
|
|
60
62
|
const schemaSections = sortedSchemas
|
|
61
63
|
.map((schema) => {
|
|
62
64
|
const models = modelsBySchema.get(schema);
|
|
63
65
|
const modelLinks = models
|
|
64
66
|
.map((model) => `
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
67
|
+
<SidebarMenuSubItem key="${model.name}">
|
|
68
|
+
<SidebarMenuSubButton asChild>
|
|
69
|
+
<Link
|
|
70
|
+
to="${model.route}"
|
|
71
|
+
className="block px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded transition-colors"
|
|
72
|
+
>
|
|
73
|
+
${model.userFriendlyName}
|
|
74
|
+
</Link>
|
|
75
|
+
</SidebarMenuSubButton>
|
|
76
|
+
</SidebarMenuSubItem>
|
|
77
|
+
`)
|
|
73
78
|
.join('');
|
|
79
|
+
const schemaKey = schema.toLowerCase();
|
|
74
80
|
return `
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
81
|
+
<Collapse open={collapseState.${schemaKey}} onOpenChange={setOpen('${schemaKey}')} className="group/collapsible-${schemaKey}" key="${schemaKey}">
|
|
82
|
+
<SidebarGroup>
|
|
83
|
+
<SidebarGroupLabel asChild>
|
|
84
|
+
<CollapseTrigger asChild>
|
|
85
|
+
<SidebarMenuButton>
|
|
86
|
+
${schema}
|
|
87
|
+
<ChevronRight className="ml-auto transition-transform group-data-[state=open]/collapsible-${schemaKey}:rotate-90" />
|
|
88
|
+
</SidebarMenuButton>
|
|
89
|
+
</CollapseTrigger>
|
|
90
|
+
</SidebarGroupLabel>
|
|
91
|
+
|
|
92
|
+
<CollapseContent>
|
|
93
|
+
<SidebarGroupContent>
|
|
94
|
+
<SidebarMenuSub>
|
|
95
|
+
${modelLinks}
|
|
96
|
+
</SidebarMenuSub>
|
|
97
|
+
</SidebarGroupContent>
|
|
98
|
+
</CollapseContent>
|
|
99
|
+
</SidebarGroup>
|
|
100
|
+
</Collapse>`;
|
|
93
101
|
})
|
|
94
102
|
.join('');
|
|
95
103
|
return `
|
|
96
104
|
import { Link } from '@tanstack/react-router'
|
|
105
|
+
import useSessionStorageState from 'use-session-storage-state'
|
|
106
|
+
import {
|
|
107
|
+
Collapse,
|
|
108
|
+
CollapseContent,
|
|
109
|
+
CollapseTrigger,
|
|
110
|
+
Sidebar,
|
|
111
|
+
SidebarContent,
|
|
112
|
+
SidebarGroup,
|
|
113
|
+
SidebarGroupContent,
|
|
114
|
+
SidebarGroupLabel,
|
|
115
|
+
SidebarHeader,
|
|
116
|
+
SidebarMenu,
|
|
117
|
+
SidebarMenuButton,
|
|
118
|
+
SidebarMenuItem,
|
|
119
|
+
SidebarMenuSub,
|
|
120
|
+
SidebarMenuSubButton,
|
|
121
|
+
SidebarMenuSubItem,
|
|
122
|
+
} from '@postxl/ui-components'
|
|
97
123
|
${imports.generate()}
|
|
98
124
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
125
|
+
const STORAGE_KEY = 'admin-sidebar-collapse-state'
|
|
126
|
+
|
|
127
|
+
type CollapseState = {
|
|
128
|
+
${collapseStateTypeProps}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const defaultCollapseState: CollapseState = {
|
|
132
|
+
${defaultCollapseStateProps}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function AdminSidebar({ ...props }: ComponentProps<typeof Sidebar>) {
|
|
136
|
+
const [collapseState, setCollapseState] = useSessionStorageState<CollapseState>(STORAGE_KEY, {
|
|
137
|
+
defaultValue: defaultCollapseState,
|
|
105
138
|
})
|
|
106
139
|
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
...prev,
|
|
110
|
-
[schema]: !prev[schema],
|
|
111
|
-
}))
|
|
140
|
+
const setOpen = (key: keyof CollapseState) => (open: boolean) => {
|
|
141
|
+
setCollapseState((prev) => ({ ...prev, [key]: open }))
|
|
112
142
|
}
|
|
113
|
-
|
|
143
|
+
|
|
114
144
|
return (
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
</button>
|
|
124
|
-
|
|
125
|
-
{/* Sidebar */}
|
|
126
|
-
<aside
|
|
127
|
-
className={\`
|
|
128
|
-
fixed md:sticky top-0 left-0 h-screen bg-sidebar border-r border-sidebar-border
|
|
129
|
-
overflow-y-auto transition-all duration-300 z-40
|
|
130
|
-
\${isOpen ? 'translate-x-0' : '-translate-x-full md:translate-x-0'}
|
|
131
|
-
\${isCollapsed ? 'w-16 min-w-16' : 'w-64 min-w-64'}
|
|
132
|
-
\`}
|
|
133
|
-
>
|
|
134
|
-
<div className="p-4">
|
|
135
|
-
<div className="flex items-center justify-between mb-4">
|
|
136
|
-
{!isCollapsed && (
|
|
137
|
-
<Link to="/admin" className="text-lg font-bold hover:text-sidebar-primary transition-colors">
|
|
138
|
-
Admin
|
|
145
|
+
<Sidebar className="h-svh border-r" {...props}>
|
|
146
|
+
<SidebarHeader>
|
|
147
|
+
<SidebarMenu>
|
|
148
|
+
<SidebarMenuItem>
|
|
149
|
+
<SidebarMenuButton asChild>
|
|
150
|
+
<Link to="/admin" className="hover:text-sidebar-primary transition-colors">
|
|
151
|
+
<Home size={16} className="mr-2" />
|
|
152
|
+
<span className="text-lg font-bold">Admin</span>
|
|
139
153
|
</Link>
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
{
|
|
150
|
-
<
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
{expandedSchemas['Advanced'] && (
|
|
166
|
-
<ul className="mt-2 ml-2 space-y-1">
|
|
167
|
-
<li key="DataManagement">
|
|
154
|
+
</SidebarMenuButton>
|
|
155
|
+
</SidebarMenuItem>
|
|
156
|
+
</SidebarMenu>
|
|
157
|
+
</SidebarHeader>
|
|
158
|
+
|
|
159
|
+
<SidebarContent>
|
|
160
|
+
${schemaSections}
|
|
161
|
+
|
|
162
|
+
{import.meta.env.VITE_PUBLIC_ALLOW_ADMIN === 'true' && (
|
|
163
|
+
<Collapse open={collapseState.advanced} onOpenChange={setOpen('advanced')} className="group/collapsible-advanced">
|
|
164
|
+
<SidebarGroup>
|
|
165
|
+
<SidebarGroupLabel asChild>
|
|
166
|
+
<CollapseTrigger asChild>
|
|
167
|
+
<SidebarMenuButton>
|
|
168
|
+
Advanced
|
|
169
|
+
<ChevronRight className="ml-auto transition-transform group-data-[state=open]/collapsible-advanced:rotate-90" />
|
|
170
|
+
</SidebarMenuButton>
|
|
171
|
+
</CollapseTrigger>
|
|
172
|
+
</SidebarGroupLabel>
|
|
173
|
+
|
|
174
|
+
<CollapseContent>
|
|
175
|
+
<SidebarGroupContent>
|
|
176
|
+
<SidebarMenuSub>
|
|
177
|
+
<SidebarMenuSubItem key="DataManagement">
|
|
178
|
+
<SidebarMenuSubButton asChild>
|
|
168
179
|
<Link
|
|
169
180
|
to="/admin/data-management"
|
|
170
181
|
className="block px-4 py-2 hover:bg-sidebar-accent rounded transition-colors"
|
|
171
182
|
>
|
|
172
183
|
Data Management
|
|
173
184
|
</Link>
|
|
174
|
-
</
|
|
175
|
-
</
|
|
176
|
-
|
|
177
|
-
</
|
|
178
|
-
|
|
179
|
-
</
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
</
|
|
183
|
-
|
|
184
|
-
{/* Overlay for mobile */}
|
|
185
|
-
{isOpen && <div role="button" className="fixed inset-0 bg-sidebar/20 z-30 md:hidden h-full" onClick={() => setIsOpen(false)} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { setIsOpen(false) } }} tabIndex={-1} />}
|
|
186
|
-
</>
|
|
185
|
+
</SidebarMenuSubButton>
|
|
186
|
+
</SidebarMenuSubItem>
|
|
187
|
+
</SidebarMenuSub>
|
|
188
|
+
</SidebarGroupContent>
|
|
189
|
+
</CollapseContent>
|
|
190
|
+
</SidebarGroup>
|
|
191
|
+
</Collapse>
|
|
192
|
+
)}
|
|
193
|
+
</SidebarContent>
|
|
194
|
+
</Sidebar>
|
|
187
195
|
)
|
|
188
196
|
}
|
|
189
197
|
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admin-sidebar.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/admin-sidebar.generator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,
|
|
1
|
+
{"version":3,"file":"admin-sidebar.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/admin-sidebar.generator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,oDAqKC;AA7KD,6DAA8C;AAG9C,oCAAqD;AAErD;;GAEG;AACH,SAAgB,oBAAoB,CAAC,EAAE,OAAO,EAA8B;IAC1E,MAAM,OAAO,GAAG,SAAS,CAAC,eAAe;QACvC,EAAE;SACD,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,wBAAwB,CAAC,CAAC;SACjE,SAAS,CAAC;QACT,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC;QACtC,KAAK,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC;KACpD,CAAC;SACD,SAAS,CAAC;QACT,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,cAAc,CAAC;QAC7C,KAAK,EAAE,CAAC,SAAS,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;KACpF,CAAC,CAAA;IAEJ,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,GAAG,IAAA,kCAA0B,EAAC,OAAO,CAAC,CAAA;IAEtF,+EAA+E;IAC/E,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAA;IAEtE,6CAA6C;IAC7C,MAAM,sBAAsB,GAAG,CAAC,GAAG,UAAU,EAAE,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAEvG,+CAA+C;IAC/C,MAAM,yBAAyB,GAAG,CAAC,GAAG,UAAU,EAAE,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAExG,+BAA+B;IAC/B,MAAM,cAAc,GAAG,aAAa;SACjC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACd,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,MAAM,CAAE,CAAA;QAC1C,MAAM,UAAU,GAAG,MAAM;aACtB,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CAAC;uCACkB,KAAK,CAAC,IAAI;;;wBAGzB,KAAK,CAAC,KAAK;;;oBAGf,KAAK,CAAC,gBAAgB;;;;WAI/B,CACF;aACA,IAAI,CAAC,EAAE,CAAC,CAAA;QAEX,MAAM,SAAS,GAAG,MAAM,CAAC,WAAW,EAAE,CAAA;QACtC,OAAO;wCAC2B,SAAS,4BAA4B,SAAS,oCAAoC,SAAS,UAAU,SAAS;;;;;oBAKlI,MAAM;8GACoF,SAAS;;;;;;;;sBAQjG,UAAU;;;;;oBAKZ,CAAA;IAChB,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAA;IAEX,OAAO;;;;;;;;;;;;;;;;;;;;EAoBP,OAAO,CAAC,QAAQ,EAAE;;;;;EAKlB,sBAAsB;;;;EAItB,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA4BjB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCvB,CAAA;AACD,CAAC"}
|
|
@@ -46,6 +46,7 @@ function generateAuditLogSidebar({ context }) {
|
|
|
46
46
|
.addImport({
|
|
47
47
|
from: Generator.toPackageName('react'),
|
|
48
48
|
items: [
|
|
49
|
+
Generator.toFunctionName('ComponentProps'),
|
|
49
50
|
Generator.toFunctionName('useState'),
|
|
50
51
|
Generator.toFunctionName('useMemo'),
|
|
51
52
|
Generator.toFunctionName('useCallback'),
|
|
@@ -55,10 +56,9 @@ function generateAuditLogSidebar({ context }) {
|
|
|
55
56
|
from: Generator.toPackageName('@radix-ui/react-icons'),
|
|
56
57
|
items: [
|
|
57
58
|
Generator.toFunctionName('ChevronRightIcon'),
|
|
58
|
-
Generator.toFunctionName('ChevronLeftIcon'),
|
|
59
|
-
Generator.toFunctionName('ReloadIcon'),
|
|
60
|
-
Generator.toFunctionName('PersonIcon'),
|
|
61
59
|
Generator.toFunctionName('ClockIcon'),
|
|
60
|
+
Generator.toFunctionName('PersonIcon'),
|
|
61
|
+
Generator.toFunctionName('ReloadIcon'),
|
|
62
62
|
],
|
|
63
63
|
})
|
|
64
64
|
.addImport({
|
|
@@ -80,6 +80,25 @@ function generateAuditLogSidebar({ context }) {
|
|
|
80
80
|
}
|
|
81
81
|
return `
|
|
82
82
|
${imports.generate()}
|
|
83
|
+
import {
|
|
84
|
+
Breadcrumb,
|
|
85
|
+
BreadcrumbItem,
|
|
86
|
+
BreadcrumbLink,
|
|
87
|
+
BreadcrumbList,
|
|
88
|
+
BreadcrumbPage,
|
|
89
|
+
BreadcrumbSeparator,
|
|
90
|
+
Select,
|
|
91
|
+
SelectContent,
|
|
92
|
+
SelectItem,
|
|
93
|
+
SelectTrigger,
|
|
94
|
+
SelectValue,
|
|
95
|
+
Sidebar,
|
|
96
|
+
SidebarContent,
|
|
97
|
+
SidebarGroup,
|
|
98
|
+
SidebarGroupContent,
|
|
99
|
+
SidebarSeparator,
|
|
100
|
+
useSidebar,
|
|
101
|
+
} from '@postxl/ui-components'
|
|
83
102
|
|
|
84
103
|
/**
|
|
85
104
|
* Map of custom action labels from the schema
|
|
@@ -371,39 +390,60 @@ function BreadcrumbNavigation({
|
|
|
371
390
|
const entityCountText = getEntityCountText(entityCount)
|
|
372
391
|
|
|
373
392
|
return (
|
|
374
|
-
<
|
|
375
|
-
<
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
<ChevronRightIcon className="w-3 h-3 text-muted-foreground" />
|
|
381
|
-
{hasFieldFilter ? (
|
|
382
|
-
<button onClick={onClearField} className="text-sidebar-primary hover:underline">
|
|
383
|
-
{entityCountText}
|
|
393
|
+
<Breadcrumb>
|
|
394
|
+
<BreadcrumbList className="text-xs">
|
|
395
|
+
<BreadcrumbItem>
|
|
396
|
+
<BreadcrumbLink asChild>
|
|
397
|
+
<button onClick={onClearEntity} className="hover:underline">
|
|
398
|
+
All {model}s
|
|
384
399
|
</button>
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
400
|
+
</BreadcrumbLink>
|
|
401
|
+
</BreadcrumbItem>
|
|
402
|
+
{hasEntityFilter && (
|
|
403
|
+
<>
|
|
404
|
+
<BreadcrumbSeparator />
|
|
405
|
+
<BreadcrumbItem>
|
|
406
|
+
{hasFieldFilter ? (
|
|
407
|
+
<BreadcrumbLink asChild>
|
|
408
|
+
<button onClick={onClearField} className="hover:underline">
|
|
409
|
+
{entityCountText}
|
|
410
|
+
</button>
|
|
411
|
+
</BreadcrumbLink>
|
|
412
|
+
) : (
|
|
413
|
+
<BreadcrumbPage>{entityCountText}</BreadcrumbPage>
|
|
414
|
+
)}
|
|
415
|
+
</BreadcrumbItem>
|
|
416
|
+
</>
|
|
417
|
+
)}
|
|
418
|
+
{hasFieldFilter && (
|
|
419
|
+
<>
|
|
420
|
+
<BreadcrumbSeparator />
|
|
421
|
+
<BreadcrumbItem>
|
|
422
|
+
<BreadcrumbPage>{field}</BreadcrumbPage>
|
|
423
|
+
</BreadcrumbItem>
|
|
424
|
+
</>
|
|
425
|
+
)}
|
|
426
|
+
</BreadcrumbList>
|
|
427
|
+
</Breadcrumb>
|
|
397
428
|
)
|
|
398
429
|
}
|
|
399
430
|
|
|
400
431
|
/**
|
|
401
432
|
* Audit Log Sidebar component for admin pages
|
|
402
433
|
*/
|
|
403
|
-
export function AuditLogSidebar({
|
|
404
|
-
|
|
434
|
+
export function AuditLogSidebar({
|
|
435
|
+
model,
|
|
436
|
+
entityId,
|
|
437
|
+
entityIds,
|
|
438
|
+
field,
|
|
439
|
+
labelField: _labelField = 'name',
|
|
440
|
+
onClearField,
|
|
441
|
+
onClearEntity,
|
|
442
|
+
...props
|
|
443
|
+
}: AuditLogSidebarProps & ComponentProps<typeof Sidebar>) {
|
|
405
444
|
const [limit, setLimit] = useState(20)
|
|
406
445
|
const [expandedEntries, setExpandedEntries] = useState<Set<string>>(new Set())
|
|
446
|
+
const { open: isOpen } = useSidebar()
|
|
407
447
|
|
|
408
448
|
const trpc = ${context.trpcClient.name}()
|
|
409
449
|
const queryClient = useQueryClient()
|
|
@@ -484,127 +524,117 @@ export function AuditLogSidebar({ model, entityId, entityIds, field, labelField:
|
|
|
484
524
|
const showBreadcrumbs = hasEntityFilter || hasFieldFilter
|
|
485
525
|
|
|
486
526
|
return (
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
className={\`
|
|
492
|
-
fixed right-0 top-1/2 -translate-y-1/2 z-40
|
|
493
|
-
flex items-center justify-center
|
|
494
|
-
w-6 h-24 bg-sidebar
|
|
495
|
-
border border-r-0 border-sidebar-border
|
|
496
|
-
rounded-l-lg shadow-lg
|
|
497
|
-
hover:bg-sidebar-accent
|
|
498
|
-
transition-colors
|
|
499
|
-
\${isOpen ? 'right-80' : 'right-0'}
|
|
500
|
-
\`}
|
|
501
|
-
aria-label={isOpen ? 'Close audit log' : 'Open audit log'}
|
|
502
|
-
>
|
|
503
|
-
{isOpen ? (
|
|
504
|
-
<ChevronRightIcon className="w-4 h-4 text-sidebar-accent-foreground" />
|
|
505
|
-
) : (
|
|
506
|
-
<ChevronLeftIcon className="w-4 h-4 text-sidebar-accent-foreground" />
|
|
507
|
-
)}
|
|
508
|
-
</button>
|
|
509
|
-
|
|
510
|
-
{/* Sidebar */}
|
|
511
|
-
<aside
|
|
512
|
-
className={\`
|
|
513
|
-
fixed right-0 top-0 h-screen w-80 bg-sidebar
|
|
514
|
-
border-l border-sidebar-border
|
|
515
|
-
overflow-hidden transition-transform duration-300 z-30
|
|
516
|
-
\${isOpen ? 'translate-x-0' : 'translate-x-full'}
|
|
517
|
-
\`}
|
|
518
|
-
>
|
|
519
|
-
<div className="flex flex-col h-full">
|
|
520
|
-
{/* Header */}
|
|
521
|
-
<div className="p-4 border-b border-sidebar-border">
|
|
527
|
+
<Sidebar {...props}>
|
|
528
|
+
<SidebarContent>
|
|
529
|
+
<SidebarGroup>
|
|
530
|
+
<SidebarGroupContent className="p-2">
|
|
522
531
|
<div className="flex items-center justify-between">
|
|
523
532
|
<h3 className="text-lg font-semibold text-sidebar-foreground">Audit Log</h3>
|
|
524
533
|
<button
|
|
525
534
|
onClick={() => void refetch()}
|
|
526
535
|
disabled={isFetching}
|
|
527
|
-
className="
|
|
536
|
+
className="hover:bg-sidebar-accent rounded transition-colors disabled:opacity-50"
|
|
528
537
|
aria-label="Refresh"
|
|
529
538
|
>
|
|
530
539
|
<ReloadIcon className={\`w-4 h-4 \${isFetching ? 'animate-spin' : ''}\`} />
|
|
531
540
|
</button>
|
|
532
541
|
</div>
|
|
542
|
+
|
|
533
543
|
<p className="mt-1 text-sm text-muted-foreground">{filterDescription}</p>
|
|
534
544
|
{data && (
|
|
535
545
|
<p className="mt-1 text-xs text-muted-foreground">
|
|
536
546
|
{data.total} {data.total === 1 ? 'change' : 'changes'} found
|
|
537
547
|
</p>
|
|
538
548
|
)}
|
|
539
|
-
</
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
<select
|
|
558
|
-
value={limit}
|
|
559
|
-
onChange={(e) => setLimit(Number(e.target.value))}
|
|
560
|
-
className="ml-1 px-2 py-1 text-xs border border-sidebar-border rounded bg-background"
|
|
561
|
-
>
|
|
562
|
-
<option value={10}>10</option>
|
|
563
|
-
<option value={20}>20</option>
|
|
564
|
-
<option value={50}>50</option>
|
|
565
|
-
<option value={100}>100</option>
|
|
566
|
-
</select>
|
|
567
|
-
</label>
|
|
568
|
-
</div>
|
|
569
|
-
{/* Content */}
|
|
570
|
-
<div className="flex-1 overflow-y-auto">
|
|
571
|
-
{isLoading && (
|
|
572
|
-
<div className="flex items-center justify-center h-32">
|
|
573
|
-
<ReloadIcon className="w-6 h-6 animate-spin text-muted-foreground" />
|
|
574
|
-
</div>
|
|
549
|
+
</SidebarGroupContent>
|
|
550
|
+
</SidebarGroup>
|
|
551
|
+
|
|
552
|
+
<SidebarSeparator className="mx-0" />
|
|
553
|
+
|
|
554
|
+
<SidebarGroup>
|
|
555
|
+
<SidebarGroupContent className="p-2">
|
|
556
|
+
<p className="font-bold mb-2">Breadcrumb navigation</p>
|
|
557
|
+
{showBreadcrumbs && (
|
|
558
|
+
<BreadcrumbNavigation
|
|
559
|
+
model={model}
|
|
560
|
+
hasEntityFilter={hasEntityFilter}
|
|
561
|
+
hasFieldFilter={hasFieldFilter}
|
|
562
|
+
entityCount={entityCount}
|
|
563
|
+
field={field}
|
|
564
|
+
onClearEntity={handleClearEntity}
|
|
565
|
+
onClearField={handleClearField}
|
|
566
|
+
/>
|
|
575
567
|
)}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
568
|
+
</SidebarGroupContent>
|
|
569
|
+
</SidebarGroup>
|
|
570
|
+
|
|
571
|
+
<SidebarSeparator className="mx-0" />
|
|
572
|
+
|
|
573
|
+
<SidebarGroup>
|
|
574
|
+
<SidebarGroupContent className="p-2">
|
|
575
|
+
<p className="font-bold mb-2">Limit selector</p>
|
|
576
|
+
<label className="flex gap-2 items-center text-xs text-muted-foreground">
|
|
577
|
+
<span>Show:</span>
|
|
578
|
+
<Select defaultValue={limit.toString()}>
|
|
579
|
+
<SelectTrigger className="w-[70px]" variant="simple" size="xs">
|
|
580
|
+
<SelectValue placeholder="Limit" />
|
|
581
|
+
</SelectTrigger>
|
|
582
|
+
<SelectContent>
|
|
583
|
+
{[10, 20, 50, 100].map((option) => (
|
|
584
|
+
<SelectItem key={option} value={option.toString()}>
|
|
585
|
+
{option}
|
|
586
|
+
</SelectItem>
|
|
587
|
+
))}
|
|
588
|
+
</SelectContent>
|
|
589
|
+
</Select>
|
|
590
|
+
</label>
|
|
591
|
+
</SidebarGroupContent>
|
|
592
|
+
</SidebarGroup>
|
|
593
|
+
|
|
594
|
+
<SidebarSeparator className="mx-0" />
|
|
595
|
+
|
|
596
|
+
<SidebarGroup>
|
|
597
|
+
<SidebarGroupContent className="p-2">
|
|
598
|
+
<p className="font-bold mb-2">Content</p>
|
|
599
|
+
<div className="flex-1 overflow-y-auto">
|
|
600
|
+
{isLoading && (
|
|
601
|
+
<div className="flex items-center justify-center h-32">
|
|
602
|
+
<ReloadIcon className="w-6 h-6 animate-spin text-muted-foreground" />
|
|
603
|
+
</div>
|
|
604
|
+
)}
|
|
605
|
+
{!isLoading && data?.entries.length === 0 && (
|
|
606
|
+
<div className="flex flex-col text-muted-foreground">
|
|
607
|
+
<p className="text-sm font-bold">No changes found</p>
|
|
608
|
+
<p className="text-sm mt-1">Changes will appear here when entities are modified</p>
|
|
609
|
+
</div>
|
|
610
|
+
)}
|
|
611
|
+
{!isLoading && data && data.entries.length > 0 && (
|
|
612
|
+
<div>
|
|
613
|
+
{data.entries.map((entry: AuditLogEntry) => (
|
|
614
|
+
<AuditLogEntryCard
|
|
615
|
+
key={entry.id}
|
|
616
|
+
entry={entry}
|
|
617
|
+
isExpanded={expandedEntries.has(entry.id)}
|
|
618
|
+
onToggle={() => toggleEntry(entry.id)}
|
|
619
|
+
/>
|
|
620
|
+
))}
|
|
621
|
+
{data.hasMore && (
|
|
622
|
+
<div className="p-3">
|
|
623
|
+
<button
|
|
624
|
+
onClick={loadMore}
|
|
625
|
+
className="w-full py-2 text-sm text-primary hover:bg-sidebar-accent rounded transition-colors"
|
|
626
|
+
>
|
|
627
|
+
Load more...
|
|
628
|
+
</button>
|
|
629
|
+
</div>
|
|
630
|
+
)}
|
|
631
|
+
</div>
|
|
632
|
+
)}
|
|
633
|
+
</div>
|
|
634
|
+
</SidebarGroupContent>
|
|
635
|
+
</SidebarGroup>
|
|
636
|
+
</SidebarContent>
|
|
637
|
+
</Sidebar>
|
|
608
638
|
)
|
|
609
639
|
}
|
|
610
640
|
`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit-log-sidebar.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/audit-log-sidebar.generator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,
|
|
1
|
+
{"version":3,"file":"audit-log-sidebar.generator.js","sourceRoot":"","sources":["../../../src/frontend-admin/generators/audit-log-sidebar.generator.ts"],"names":[],"mappings":"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"}
|