@questpie/admin 0.0.1 → 1.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/README.md +439 -424
- package/dist/auth-layout-M8K8_q5R.mjs +181 -0
- package/dist/auth-layout-M8K8_q5R.mjs.map +1 -0
- package/dist/bulk-upload-dialog-D7w7W1Hl.mjs +273 -0
- package/dist/bulk-upload-dialog-D7w7W1Hl.mjs.map +1 -0
- package/dist/{components/ui/card.mjs → card-BKHjBQfw.mjs} +8 -8
- package/dist/card-BKHjBQfw.mjs.map +1 -0
- package/dist/client/styles/index.css +434 -0
- package/dist/client-DbpZKSgH.d.mts +13585 -0
- package/dist/client-DbpZKSgH.d.mts.map +1 -0
- package/dist/client-njX1rZmi.mjs +22612 -0
- package/dist/client-njX1rZmi.mjs.map +1 -0
- package/dist/client.d.mts +3 -0
- package/dist/client.mjs +13 -0
- package/dist/content-locales-provider-BXvuIgfg.mjs +1650 -0
- package/dist/content-locales-provider-BXvuIgfg.mjs.map +1 -0
- package/dist/dashboard-page-B4PGEdc2.mjs +2500 -0
- package/dist/dashboard-page-B4PGEdc2.mjs.map +1 -0
- package/dist/dashboard-page-mCY0pgZv.mjs +3 -0
- package/dist/dropzone-Do3awXKd.mjs +634 -0
- package/dist/dropzone-Do3awXKd.mjs.map +1 -0
- package/dist/{views/auth/forgot-password-form.mjs → forgot-password-page-Bcp-An4Y.mjs} +87 -14
- package/dist/forgot-password-page-Bcp-An4Y.mjs.map +1 -0
- package/dist/forgot-password-page-CEwsdLwn.mjs +3 -0
- package/dist/index-B9Xwk4hi.d.mts +2753 -0
- package/dist/index-B9Xwk4hi.d.mts.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +13 -0
- package/dist/login-page-BUnpCbCa.mjs +3 -0
- package/dist/login-page-CP4gA-dl.mjs +298 -0
- package/dist/login-page-CP4gA-dl.mjs.map +1 -0
- package/dist/preview-utils-BKQ9-TMa.mjs +65 -0
- package/dist/preview-utils-BKQ9-TMa.mjs.map +1 -0
- package/dist/{views/auth/reset-password-form.mjs → reset-password-page-BqfDmLxA.mjs} +111 -14
- package/dist/reset-password-page-BqfDmLxA.mjs.map +1 -0
- package/dist/reset-password-page-CufHz3h3.mjs +3 -0
- package/dist/runtime-6VZM878K.mjs +69 -0
- package/dist/runtime-6VZM878K.mjs.map +1 -0
- package/dist/saved-views.types-BMsz5mCy.d.mts +42 -0
- package/dist/saved-views.types-BMsz5mCy.d.mts.map +1 -0
- package/dist/server.d.mts +250 -0
- package/dist/server.d.mts.map +1 -0
- package/dist/server.mjs +832 -0
- package/dist/server.mjs.map +1 -0
- package/dist/setup-page-BNNzt_Z6.mjs +3 -0
- package/dist/setup-page-YAP_fzqh.mjs +264 -0
- package/dist/setup-page-YAP_fzqh.mjs.map +1 -0
- package/dist/shared.d.mts +57 -0
- package/dist/shared.d.mts.map +1 -0
- package/dist/shared.mjs +3 -0
- package/dist/{hooks/use-auth.mjs → use-auth-BoLmWtmU.mjs} +42 -30
- package/dist/use-auth-BoLmWtmU.mjs.map +1 -0
- package/package.json +48 -198
- package/.turbo/turbo-build.log +0 -108
- package/CHANGELOG.md +0 -10
- package/STATUS.md +0 -917
- package/VALIDATION.md +0 -602
- package/components.json +0 -24
- package/dist/__tests__/setup.mjs +0 -38
- package/dist/__tests__/test-utils.mjs +0 -45
- package/dist/__tests__/vitest.d.mjs +0 -3
- package/dist/components/admin-app.mjs +0 -69
- package/dist/components/fields/array-field.mjs +0 -190
- package/dist/components/fields/checkbox-field.mjs +0 -34
- package/dist/components/fields/custom-field.mjs +0 -32
- package/dist/components/fields/date-field.mjs +0 -41
- package/dist/components/fields/datetime-field.mjs +0 -42
- package/dist/components/fields/email-field.mjs +0 -37
- package/dist/components/fields/embedded-collection.mjs +0 -253
- package/dist/components/fields/field-types.mjs +0 -1
- package/dist/components/fields/field-utils.mjs +0 -10
- package/dist/components/fields/field-wrapper.mjs +0 -34
- package/dist/components/fields/index.mjs +0 -23
- package/dist/components/fields/json-field.mjs +0 -243
- package/dist/components/fields/locale-badge.mjs +0 -16
- package/dist/components/fields/number-field.mjs +0 -39
- package/dist/components/fields/password-field.mjs +0 -37
- package/dist/components/fields/relation-field.mjs +0 -104
- package/dist/components/fields/relation-picker.mjs +0 -229
- package/dist/components/fields/relation-select.mjs +0 -188
- package/dist/components/fields/rich-text-editor/index.mjs +0 -897
- package/dist/components/fields/select-field.mjs +0 -41
- package/dist/components/fields/switch-field.mjs +0 -34
- package/dist/components/fields/text-field.mjs +0 -38
- package/dist/components/fields/textarea-field.mjs +0 -38
- package/dist/components/index.mjs +0 -59
- package/dist/components/primitives/checkbox-input.mjs +0 -127
- package/dist/components/primitives/date-input.mjs +0 -303
- package/dist/components/primitives/index.mjs +0 -12
- package/dist/components/primitives/number-input.mjs +0 -104
- package/dist/components/primitives/select-input.mjs +0 -177
- package/dist/components/primitives/tag-input.mjs +0 -135
- package/dist/components/primitives/text-input.mjs +0 -39
- package/dist/components/primitives/textarea-input.mjs +0 -37
- package/dist/components/primitives/toggle-input.mjs +0 -31
- package/dist/components/primitives/types.mjs +0 -12
- package/dist/components/ui/accordion.mjs +0 -55
- package/dist/components/ui/avatar.mjs +0 -54
- package/dist/components/ui/badge.mjs +0 -34
- package/dist/components/ui/button.mjs +0 -48
- package/dist/components/ui/checkbox.mjs +0 -21
- package/dist/components/ui/combobox.mjs +0 -163
- package/dist/components/ui/dialog.mjs +0 -95
- package/dist/components/ui/dropdown-menu.mjs +0 -138
- package/dist/components/ui/field.mjs +0 -113
- package/dist/components/ui/input-group.mjs +0 -82
- package/dist/components/ui/input.mjs +0 -17
- package/dist/components/ui/label.mjs +0 -15
- package/dist/components/ui/popover.mjs +0 -56
- package/dist/components/ui/scroll-area.mjs +0 -38
- package/dist/components/ui/select.mjs +0 -100
- package/dist/components/ui/separator.mjs +0 -16
- package/dist/components/ui/sheet.mjs +0 -90
- package/dist/components/ui/sidebar.mjs +0 -387
- package/dist/components/ui/skeleton.mjs +0 -14
- package/dist/components/ui/spinner.mjs +0 -16
- package/dist/components/ui/switch.mjs +0 -22
- package/dist/components/ui/table.mjs +0 -68
- package/dist/components/ui/tabs.mjs +0 -48
- package/dist/components/ui/textarea.mjs +0 -15
- package/dist/components/ui/tooltip.mjs +0 -44
- package/dist/config/component-registry.mjs +0 -38
- package/dist/config/index.mjs +0 -129
- package/dist/hooks/admin-provider.mjs +0 -70
- package/dist/hooks/index.mjs +0 -7
- package/dist/hooks/store.mjs +0 -178
- package/dist/hooks/use-collection-db.mjs +0 -146
- package/dist/hooks/use-collection.mjs +0 -112
- package/dist/hooks/use-global.mjs +0 -46
- package/dist/hooks/use-mobile.mjs +0 -20
- package/dist/lib/utils.mjs +0 -10
- package/dist/styles/index.css +0 -336
- package/dist/styles/index.mjs +0 -1
- package/dist/utils/index.mjs +0 -9
- package/dist/views/auth/auth-layout.mjs +0 -52
- package/dist/views/auth/index.mjs +0 -6
- package/dist/views/auth/login-form.mjs +0 -156
- package/dist/views/collection/auto-form-fields.mjs +0 -525
- package/dist/views/collection/collection-form.mjs +0 -91
- package/dist/views/collection/collection-list.mjs +0 -76
- package/dist/views/collection/form-field.mjs +0 -42
- package/dist/views/collection/index.mjs +0 -6
- package/dist/views/common/index.mjs +0 -4
- package/dist/views/common/locale-switcher.mjs +0 -39
- package/dist/views/common/version-history.mjs +0 -272
- package/dist/views/index.mjs +0 -9
- package/dist/views/layout/admin-layout.mjs +0 -40
- package/dist/views/layout/admin-router.mjs +0 -95
- package/dist/views/layout/admin-sidebar.mjs +0 -63
- package/dist/views/layout/index.mjs +0 -5
- package/src/__tests__/setup.ts +0 -44
- package/src/__tests__/test-utils.tsx +0 -49
- package/src/__tests__/vitest.d.ts +0 -9
- package/src/components/admin-app.tsx +0 -221
- package/src/components/fields/array-field.tsx +0 -237
- package/src/components/fields/checkbox-field.tsx +0 -47
- package/src/components/fields/custom-field.tsx +0 -50
- package/src/components/fields/date-field.tsx +0 -65
- package/src/components/fields/datetime-field.tsx +0 -67
- package/src/components/fields/email-field.tsx +0 -51
- package/src/components/fields/embedded-collection.tsx +0 -315
- package/src/components/fields/field-types.ts +0 -162
- package/src/components/fields/field-utils.ts +0 -6
- package/src/components/fields/field-wrapper.tsx +0 -52
- package/src/components/fields/index.ts +0 -66
- package/src/components/fields/json-field.tsx +0 -440
- package/src/components/fields/locale-badge.tsx +0 -15
- package/src/components/fields/number-field.tsx +0 -57
- package/src/components/fields/password-field.tsx +0 -51
- package/src/components/fields/relation-field.tsx +0 -243
- package/src/components/fields/relation-picker.tsx +0 -402
- package/src/components/fields/relation-select.tsx +0 -327
- package/src/components/fields/rich-text-editor/index.tsx +0 -1337
- package/src/components/fields/select-field.tsx +0 -61
- package/src/components/fields/switch-field.tsx +0 -47
- package/src/components/fields/text-field.tsx +0 -55
- package/src/components/fields/textarea-field.tsx +0 -55
- package/src/components/index.ts +0 -40
- package/src/components/primitives/checkbox-input.tsx +0 -193
- package/src/components/primitives/date-input.tsx +0 -401
- package/src/components/primitives/index.ts +0 -24
- package/src/components/primitives/number-input.tsx +0 -132
- package/src/components/primitives/select-input.tsx +0 -296
- package/src/components/primitives/tag-input.tsx +0 -200
- package/src/components/primitives/text-input.tsx +0 -49
- package/src/components/primitives/textarea-input.tsx +0 -46
- package/src/components/primitives/toggle-input.tsx +0 -36
- package/src/components/primitives/types.ts +0 -235
- package/src/components/ui/accordion.tsx +0 -72
- package/src/components/ui/avatar.tsx +0 -106
- package/src/components/ui/badge.tsx +0 -48
- package/src/components/ui/button.tsx +0 -53
- package/src/components/ui/card.tsx +0 -94
- package/src/components/ui/checkbox.tsx +0 -27
- package/src/components/ui/combobox.tsx +0 -290
- package/src/components/ui/dialog.tsx +0 -151
- package/src/components/ui/dropdown-menu.tsx +0 -254
- package/src/components/ui/field.tsx +0 -227
- package/src/components/ui/input-group.tsx +0 -149
- package/src/components/ui/input.tsx +0 -20
- package/src/components/ui/label.tsx +0 -18
- package/src/components/ui/popover.tsx +0 -88
- package/src/components/ui/scroll-area.tsx +0 -53
- package/src/components/ui/select.tsx +0 -192
- package/src/components/ui/separator.tsx +0 -23
- package/src/components/ui/sheet.tsx +0 -127
- package/src/components/ui/sidebar.tsx +0 -723
- package/src/components/ui/skeleton.tsx +0 -13
- package/src/components/ui/spinner.tsx +0 -10
- package/src/components/ui/switch.tsx +0 -32
- package/src/components/ui/table.tsx +0 -99
- package/src/components/ui/tabs.tsx +0 -82
- package/src/components/ui/textarea.tsx +0 -18
- package/src/components/ui/tooltip.tsx +0 -70
- package/src/config/component-registry.ts +0 -190
- package/src/config/index.ts +0 -1099
- package/src/hooks/README.md +0 -269
- package/src/hooks/admin-provider.tsx +0 -110
- package/src/hooks/index.ts +0 -41
- package/src/hooks/store.ts +0 -248
- package/src/hooks/use-auth.ts +0 -168
- package/src/hooks/use-collection-db.ts +0 -209
- package/src/hooks/use-collection.ts +0 -156
- package/src/hooks/use-global.ts +0 -69
- package/src/hooks/use-mobile.ts +0 -21
- package/src/lib/utils.ts +0 -6
- package/src/styles/index.css +0 -340
- package/src/utils/index.ts +0 -6
- package/src/views/auth/auth-layout.tsx +0 -77
- package/src/views/auth/forgot-password-form.tsx +0 -192
- package/src/views/auth/index.ts +0 -21
- package/src/views/auth/login-form.tsx +0 -229
- package/src/views/auth/reset-password-form.tsx +0 -232
- package/src/views/collection/auto-form-fields.tsx +0 -982
- package/src/views/collection/collection-form.tsx +0 -186
- package/src/views/collection/collection-list.tsx +0 -223
- package/src/views/collection/form-field.tsx +0 -52
- package/src/views/collection/index.ts +0 -15
- package/src/views/common/index.ts +0 -8
- package/src/views/common/locale-switcher.tsx +0 -45
- package/src/views/common/version-history.tsx +0 -406
- package/src/views/index.ts +0 -25
- package/src/views/layout/admin-layout.tsx +0 -117
- package/src/views/layout/admin-router.tsx +0 -206
- package/src/views/layout/admin-sidebar.tsx +0 -185
- package/src/views/layout/index.ts +0 -12
- package/tsconfig.json +0 -13
- package/tsconfig.tsbuildinfo +0 -1
- package/tsdown.config.ts +0 -13
- package/vitest.config.ts +0 -29
|
@@ -1,406 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* VersionHistory Component
|
|
3
|
-
*
|
|
4
|
-
* Displays version history and audit log for a collection item
|
|
5
|
-
* - Shows all versions with timestamps
|
|
6
|
-
* - Displays who made changes
|
|
7
|
-
* - Allows comparing versions
|
|
8
|
-
* - Shows diff between versions
|
|
9
|
-
* - Ability to restore previous versions
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import * as React from "react";
|
|
13
|
-
import { useQuery } from "@tanstack/react-query";
|
|
14
|
-
import {
|
|
15
|
-
ClockCounterClockwise,
|
|
16
|
-
User,
|
|
17
|
-
Clock,
|
|
18
|
-
CaretDown,
|
|
19
|
-
CaretRight,
|
|
20
|
-
ArrowCounterClockwise,
|
|
21
|
-
} from "@phosphor-icons/react";
|
|
22
|
-
import { Button } from "../../components/ui/button";
|
|
23
|
-
import {
|
|
24
|
-
Card,
|
|
25
|
-
CardContent,
|
|
26
|
-
CardDescription,
|
|
27
|
-
CardHeader,
|
|
28
|
-
CardTitle,
|
|
29
|
-
} from "../../components/ui/card";
|
|
30
|
-
import { Badge } from "../../components/ui/badge";
|
|
31
|
-
import { Separator } from "../../components/ui/separator";
|
|
32
|
-
import { Spinner } from "../../components/ui/spinner";
|
|
33
|
-
import { useAdminContext } from "../../hooks/admin-provider";
|
|
34
|
-
import type { Questpie } from "questpie";
|
|
35
|
-
|
|
36
|
-
export interface VersionHistoryProps<T extends Questpie<any>> {
|
|
37
|
-
/**
|
|
38
|
-
* Collection name
|
|
39
|
-
*/
|
|
40
|
-
collection: string;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Item ID
|
|
44
|
-
*/
|
|
45
|
-
itemId: string;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Show restore buttons
|
|
49
|
-
*/
|
|
50
|
-
allowRestore?: boolean;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Callback when version is restored
|
|
54
|
-
*/
|
|
55
|
-
onRestore?: (versionId: string) => void;
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Custom render for version data
|
|
59
|
-
*/
|
|
60
|
-
renderVersion?: (version: any) => React.ReactNode;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Show full diff or summary
|
|
64
|
-
*/
|
|
65
|
-
showFullDiff?: boolean;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
interface Version {
|
|
69
|
-
id: string;
|
|
70
|
-
versionNumber: number;
|
|
71
|
-
createdAt: string;
|
|
72
|
-
createdBy?: {
|
|
73
|
-
id: string;
|
|
74
|
-
name?: string;
|
|
75
|
-
email?: string;
|
|
76
|
-
};
|
|
77
|
-
changes?: {
|
|
78
|
-
field: string;
|
|
79
|
-
oldValue: any;
|
|
80
|
-
newValue: any;
|
|
81
|
-
}[];
|
|
82
|
-
action: "created" | "updated" | "deleted" | "restored";
|
|
83
|
-
data: Record<string, any>;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function VersionHistory<T extends Questpie<any>>({
|
|
87
|
-
collection,
|
|
88
|
-
itemId,
|
|
89
|
-
allowRestore = false,
|
|
90
|
-
onRestore,
|
|
91
|
-
renderVersion,
|
|
92
|
-
showFullDiff = false,
|
|
93
|
-
}: VersionHistoryProps<T>) {
|
|
94
|
-
const { client, locale } = useAdminContext<T>();
|
|
95
|
-
const localeKey = locale ?? "default";
|
|
96
|
-
const [expandedVersions, setExpandedVersions] = React.useState<Set<string>>(
|
|
97
|
-
new Set(),
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
// Fetch version history
|
|
101
|
-
const {
|
|
102
|
-
data: versions,
|
|
103
|
-
isLoading,
|
|
104
|
-
error,
|
|
105
|
-
} = useQuery({
|
|
106
|
-
queryKey: ["version-history", collection, itemId, localeKey],
|
|
107
|
-
queryFn: async () => {
|
|
108
|
-
// TODO: Implement actual version history endpoint
|
|
109
|
-
// For now, return mock data structure
|
|
110
|
-
// const result = await client.collections[collection].getVersionHistory(itemId);
|
|
111
|
-
// return result;
|
|
112
|
-
|
|
113
|
-
// Mock data for demonstration
|
|
114
|
-
return [
|
|
115
|
-
{
|
|
116
|
-
id: "v3",
|
|
117
|
-
versionNumber: 3,
|
|
118
|
-
createdAt: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(),
|
|
119
|
-
createdBy: {
|
|
120
|
-
id: "user1",
|
|
121
|
-
name: "John Doe",
|
|
122
|
-
email: "john@example.com",
|
|
123
|
-
},
|
|
124
|
-
action: "updated",
|
|
125
|
-
changes: [
|
|
126
|
-
{ field: "status", oldValue: "pending", newValue: "confirmed" },
|
|
127
|
-
],
|
|
128
|
-
data: {},
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
id: "v2",
|
|
132
|
-
versionNumber: 2,
|
|
133
|
-
createdAt: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
|
|
134
|
-
createdBy: {
|
|
135
|
-
id: "user2",
|
|
136
|
-
name: "Jane Smith",
|
|
137
|
-
email: "jane@example.com",
|
|
138
|
-
},
|
|
139
|
-
action: "updated",
|
|
140
|
-
changes: [
|
|
141
|
-
{
|
|
142
|
-
field: "scheduledAt",
|
|
143
|
-
oldValue: "2025-01-15T10:00:00",
|
|
144
|
-
newValue: "2025-01-20T14:00:00",
|
|
145
|
-
},
|
|
146
|
-
],
|
|
147
|
-
data: {},
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
id: "v1",
|
|
151
|
-
versionNumber: 1,
|
|
152
|
-
createdAt: new Date(
|
|
153
|
-
Date.now() - 7 * 24 * 60 * 60 * 1000,
|
|
154
|
-
).toISOString(),
|
|
155
|
-
createdBy: {
|
|
156
|
-
id: "user1",
|
|
157
|
-
name: "John Doe",
|
|
158
|
-
email: "john@example.com",
|
|
159
|
-
},
|
|
160
|
-
action: "created",
|
|
161
|
-
changes: [],
|
|
162
|
-
data: {},
|
|
163
|
-
},
|
|
164
|
-
] as Version[];
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
const toggleVersion = (versionId: string) => {
|
|
169
|
-
setExpandedVersions((prev) => {
|
|
170
|
-
const next = new Set(prev);
|
|
171
|
-
if (next.has(versionId)) {
|
|
172
|
-
next.delete(versionId);
|
|
173
|
-
} else {
|
|
174
|
-
next.add(versionId);
|
|
175
|
-
}
|
|
176
|
-
return next;
|
|
177
|
-
});
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
const handleRestore = (versionId: string) => {
|
|
181
|
-
onRestore?.(versionId);
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const formatDate = (dateString: string) => {
|
|
185
|
-
const date = new Date(dateString);
|
|
186
|
-
const now = new Date();
|
|
187
|
-
const diffMs = now.getTime() - date.getTime();
|
|
188
|
-
const diffMins = Math.floor(diffMs / 60000);
|
|
189
|
-
const diffHours = Math.floor(diffMs / 3600000);
|
|
190
|
-
const diffDays = Math.floor(diffMs / 86400000);
|
|
191
|
-
|
|
192
|
-
if (diffMins < 1) return "Just now";
|
|
193
|
-
if (diffMins < 60)
|
|
194
|
-
return `${diffMins} minute${diffMins > 1 ? "s" : ""} ago`;
|
|
195
|
-
if (diffHours < 24)
|
|
196
|
-
return `${diffHours} hour${diffHours > 1 ? "s" : ""} ago`;
|
|
197
|
-
if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? "s" : ""} ago`;
|
|
198
|
-
return date.toLocaleDateString();
|
|
199
|
-
};
|
|
200
|
-
|
|
201
|
-
const getActionBadge = (action: Version["action"]) => {
|
|
202
|
-
const variants: Record<Version["action"], { variant: any; label: string }> =
|
|
203
|
-
{
|
|
204
|
-
created: { variant: "default", label: "Created" },
|
|
205
|
-
updated: { variant: "secondary", label: "Updated" },
|
|
206
|
-
deleted: { variant: "destructive", label: "Deleted" },
|
|
207
|
-
restored: { variant: "outline", label: "Restored" },
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
const config = variants[action];
|
|
211
|
-
return <Badge variant={config.variant}>{config.label}</Badge>;
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
const formatValue = (value: any): string => {
|
|
215
|
-
if (value === null || value === undefined) return "—";
|
|
216
|
-
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
217
|
-
if (typeof value === "object") return JSON.stringify(value);
|
|
218
|
-
return String(value);
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
if (isLoading) {
|
|
222
|
-
return (
|
|
223
|
-
<Card>
|
|
224
|
-
<CardHeader>
|
|
225
|
-
<CardTitle className="flex items-center gap-2">
|
|
226
|
-
<ClockCounterClockwise className="h-5 w-5" />
|
|
227
|
-
Version History
|
|
228
|
-
</CardTitle>
|
|
229
|
-
</CardHeader>
|
|
230
|
-
<CardContent className="flex items-center justify-center p-8">
|
|
231
|
-
<Spinner className="h-6 w-6" />
|
|
232
|
-
</CardContent>
|
|
233
|
-
</Card>
|
|
234
|
-
);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
if (error) {
|
|
238
|
-
return (
|
|
239
|
-
<Card>
|
|
240
|
-
<CardHeader>
|
|
241
|
-
<CardTitle className="flex items-center gap-2">
|
|
242
|
-
<ClockCounterClockwise className="h-5 w-5" />
|
|
243
|
-
Version History
|
|
244
|
-
</CardTitle>
|
|
245
|
-
</CardHeader>
|
|
246
|
-
<CardContent>
|
|
247
|
-
<p className="text-sm text-destructive">
|
|
248
|
-
Failed to load version history:{" "}
|
|
249
|
-
{error instanceof Error ? error.message : "Unknown error"}
|
|
250
|
-
</p>
|
|
251
|
-
</CardContent>
|
|
252
|
-
</Card>
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
if (!versions || versions.length === 0) {
|
|
257
|
-
return (
|
|
258
|
-
<Card>
|
|
259
|
-
<CardHeader>
|
|
260
|
-
<CardTitle className="flex items-center gap-2">
|
|
261
|
-
<ClockCounterClockwise className="h-5 w-5" />
|
|
262
|
-
Version History
|
|
263
|
-
</CardTitle>
|
|
264
|
-
</CardHeader>
|
|
265
|
-
<CardContent>
|
|
266
|
-
<p className="text-sm text-muted-foreground">
|
|
267
|
-
No version history available
|
|
268
|
-
</p>
|
|
269
|
-
</CardContent>
|
|
270
|
-
</Card>
|
|
271
|
-
);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return (
|
|
275
|
-
<Card>
|
|
276
|
-
<CardHeader>
|
|
277
|
-
<CardTitle className="flex items-center gap-2">
|
|
278
|
-
<ClockCounterClockwise className="h-5 w-5" />
|
|
279
|
-
Version History
|
|
280
|
-
</CardTitle>
|
|
281
|
-
<CardDescription>
|
|
282
|
-
{versions.length} version{versions.length !== 1 ? "s" : ""}
|
|
283
|
-
</CardDescription>
|
|
284
|
-
</CardHeader>
|
|
285
|
-
<CardContent className="space-y-4">
|
|
286
|
-
{versions.map((version, index) => {
|
|
287
|
-
const isExpanded = expandedVersions.has(version.id);
|
|
288
|
-
const isLatest = index === 0;
|
|
289
|
-
|
|
290
|
-
return (
|
|
291
|
-
<div key={version.id}>
|
|
292
|
-
{index > 0 && <Separator className="my-4" />}
|
|
293
|
-
|
|
294
|
-
<div className="space-y-2">
|
|
295
|
-
<div className="flex items-start gap-3">
|
|
296
|
-
<Button
|
|
297
|
-
variant="ghost"
|
|
298
|
-
size="icon"
|
|
299
|
-
className="h-6 w-6 shrink-0"
|
|
300
|
-
onClick={() => toggleVersion(version.id)}
|
|
301
|
-
>
|
|
302
|
-
{isExpanded ? (
|
|
303
|
-
<CaretDown className="h-4 w-4" />
|
|
304
|
-
) : (
|
|
305
|
-
<CaretRight className="h-4 w-4" />
|
|
306
|
-
)}
|
|
307
|
-
</Button>
|
|
308
|
-
|
|
309
|
-
<div className="flex-1 space-y-1">
|
|
310
|
-
{/* Version Header */}
|
|
311
|
-
<div className="flex items-center gap-2">
|
|
312
|
-
<span className="text-sm font-medium">
|
|
313
|
-
Version {version.versionNumber}
|
|
314
|
-
</span>
|
|
315
|
-
{getActionBadge(version.action)}
|
|
316
|
-
{isLatest && <Badge variant="outline">Current</Badge>}
|
|
317
|
-
</div>
|
|
318
|
-
|
|
319
|
-
{/* Metadata */}
|
|
320
|
-
<div className="flex items-center gap-4 text-xs text-muted-foreground">
|
|
321
|
-
<div className="flex items-center gap-1">
|
|
322
|
-
<Clock className="h-3 w-3" />
|
|
323
|
-
{formatDate(version.createdAt)}
|
|
324
|
-
</div>
|
|
325
|
-
{version.createdBy && (
|
|
326
|
-
<div className="flex items-center gap-1">
|
|
327
|
-
<User className="h-3 w-3" />
|
|
328
|
-
{version.createdBy.name || version.createdBy.email}
|
|
329
|
-
</div>
|
|
330
|
-
)}
|
|
331
|
-
</div>
|
|
332
|
-
|
|
333
|
-
{/* Changes Summary */}
|
|
334
|
-
{version.changes &&
|
|
335
|
-
version.changes.length > 0 &&
|
|
336
|
-
!isExpanded && (
|
|
337
|
-
<p className="text-xs text-muted-foreground">
|
|
338
|
-
{version.changes.length} field
|
|
339
|
-
{version.changes.length !== 1 ? "s" : ""} changed
|
|
340
|
-
</p>
|
|
341
|
-
)}
|
|
342
|
-
|
|
343
|
-
{/* Expanded Changes */}
|
|
344
|
-
{isExpanded && (
|
|
345
|
-
<div className="mt-3 space-y-2">
|
|
346
|
-
{version.changes && version.changes.length > 0 ? (
|
|
347
|
-
<div className="rounded-lg border bg-muted/50 p-3 space-y-2">
|
|
348
|
-
{version.changes.map((change, changeIndex) => (
|
|
349
|
-
<div key={changeIndex} className="text-xs">
|
|
350
|
-
<div className="font-medium text-foreground mb-1">
|
|
351
|
-
{change.field}
|
|
352
|
-
</div>
|
|
353
|
-
<div className="grid grid-cols-2 gap-2">
|
|
354
|
-
<div>
|
|
355
|
-
<div className="text-muted-foreground">
|
|
356
|
-
Old value:
|
|
357
|
-
</div>
|
|
358
|
-
<div className="font-mono rounded bg-background p-1 mt-1">
|
|
359
|
-
{formatValue(change.oldValue)}
|
|
360
|
-
</div>
|
|
361
|
-
</div>
|
|
362
|
-
<div>
|
|
363
|
-
<div className="text-muted-foreground">
|
|
364
|
-
New value:
|
|
365
|
-
</div>
|
|
366
|
-
<div className="font-mono rounded bg-background p-1 mt-1">
|
|
367
|
-
{formatValue(change.newValue)}
|
|
368
|
-
</div>
|
|
369
|
-
</div>
|
|
370
|
-
</div>
|
|
371
|
-
</div>
|
|
372
|
-
))}
|
|
373
|
-
</div>
|
|
374
|
-
) : (
|
|
375
|
-
<p className="text-xs text-muted-foreground">
|
|
376
|
-
No changes recorded
|
|
377
|
-
</p>
|
|
378
|
-
)}
|
|
379
|
-
|
|
380
|
-
{/* Custom Version Render */}
|
|
381
|
-
{renderVersion && renderVersion(version)}
|
|
382
|
-
|
|
383
|
-
{/* Restore Button */}
|
|
384
|
-
{allowRestore && !isLatest && (
|
|
385
|
-
<Button
|
|
386
|
-
variant="outline"
|
|
387
|
-
size="sm"
|
|
388
|
-
onClick={() => handleRestore(version.id)}
|
|
389
|
-
className="mt-2"
|
|
390
|
-
>
|
|
391
|
-
<ArrowCounterClockwise className="mr-2 h-3 w-3" />
|
|
392
|
-
Restore this version
|
|
393
|
-
</Button>
|
|
394
|
-
)}
|
|
395
|
-
</div>
|
|
396
|
-
)}
|
|
397
|
-
</div>
|
|
398
|
-
</div>
|
|
399
|
-
</div>
|
|
400
|
-
</div>
|
|
401
|
-
);
|
|
402
|
-
})}
|
|
403
|
-
</CardContent>
|
|
404
|
-
</Card>
|
|
405
|
-
);
|
|
406
|
-
}
|
package/src/views/index.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @questpie/admin Views
|
|
3
|
-
*
|
|
4
|
-
* Full-page and section-level view components.
|
|
5
|
-
* Views are smart components that handle routing, data fetching, and state.
|
|
6
|
-
*
|
|
7
|
-
* Architecture:
|
|
8
|
-
* - ui/ - Headless/styled primitives (Button, Card, Input)
|
|
9
|
-
* - primitives/ - Generic input wrappers with callback API
|
|
10
|
-
* - fields/ - react-hook-form connected field components
|
|
11
|
-
* - views/ - Route-level components with business logic (this directory)
|
|
12
|
-
* - features/ - Complex feature modules (Puck editor, media library)
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
// Auth views
|
|
16
|
-
export * from "./auth";
|
|
17
|
-
|
|
18
|
-
// Layout views
|
|
19
|
-
export * from "./layout";
|
|
20
|
-
|
|
21
|
-
// Collection views
|
|
22
|
-
export * from "./collection";
|
|
23
|
-
|
|
24
|
-
// Common/utility views
|
|
25
|
-
export * from "./common";
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AdminLayout Component
|
|
3
|
-
*
|
|
4
|
-
* Complete admin layout generated from config
|
|
5
|
-
* - Sidebar navigation
|
|
6
|
-
* - Main content area
|
|
7
|
-
* - Optional header/footer
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import * as React from "react";
|
|
11
|
-
import { cn } from "../../lib/utils";
|
|
12
|
-
import { AdminSidebar, type AdminSidebarProps } from "./admin-sidebar";
|
|
13
|
-
|
|
14
|
-
export interface AdminLayoutProps {
|
|
15
|
-
/**
|
|
16
|
-
* Admin configuration
|
|
17
|
-
*/
|
|
18
|
-
config: AdminSidebarProps["config"] & {
|
|
19
|
-
app?: {
|
|
20
|
-
header?: {
|
|
21
|
-
show?: boolean;
|
|
22
|
-
component?: React.ComponentType;
|
|
23
|
-
};
|
|
24
|
-
footer?: {
|
|
25
|
-
show?: boolean;
|
|
26
|
-
component?: React.ComponentType;
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Current active route
|
|
33
|
-
*/
|
|
34
|
-
activeRoute?: string;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Link component (router-specific)
|
|
38
|
-
*/
|
|
39
|
-
LinkComponent: AdminSidebarProps["LinkComponent"];
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Main content to render
|
|
43
|
-
*/
|
|
44
|
-
children: React.ReactNode;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Custom layout className
|
|
48
|
-
*/
|
|
49
|
-
className?: string;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Custom sidebar props
|
|
53
|
-
*/
|
|
54
|
-
sidebarProps?: Partial<AdminSidebarProps>;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Custom header content
|
|
58
|
-
*/
|
|
59
|
-
renderHeader?: () => React.ReactNode;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Custom footer content
|
|
63
|
-
*/
|
|
64
|
-
renderFooter?: () => React.ReactNode;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function AdminLayout({
|
|
68
|
-
config,
|
|
69
|
-
activeRoute,
|
|
70
|
-
LinkComponent,
|
|
71
|
-
children,
|
|
72
|
-
className,
|
|
73
|
-
sidebarProps,
|
|
74
|
-
renderHeader,
|
|
75
|
-
renderFooter,
|
|
76
|
-
}: AdminLayoutProps): React.ReactElement {
|
|
77
|
-
const showHeader = config.app?.header?.show ?? false;
|
|
78
|
-
const showFooter = config.app?.footer?.show ?? false;
|
|
79
|
-
const HeaderComponent = config.app?.header?.component;
|
|
80
|
-
const FooterComponent = config.app?.footer?.component;
|
|
81
|
-
|
|
82
|
-
return (
|
|
83
|
-
<div className={cn("flex h-screen flex-col", className)}>
|
|
84
|
-
{/* Header (optional) */}
|
|
85
|
-
{showHeader && (
|
|
86
|
-
<header className="border-b">
|
|
87
|
-
{renderHeader
|
|
88
|
-
? renderHeader()
|
|
89
|
-
: HeaderComponent && <HeaderComponent />}
|
|
90
|
-
</header>
|
|
91
|
-
)}
|
|
92
|
-
|
|
93
|
-
{/* Main Layout */}
|
|
94
|
-
<div className="flex flex-1 overflow-hidden">
|
|
95
|
-
{/* Sidebar */}
|
|
96
|
-
<AdminSidebar
|
|
97
|
-
config={config}
|
|
98
|
-
activeRoute={activeRoute}
|
|
99
|
-
LinkComponent={LinkComponent}
|
|
100
|
-
{...sidebarProps}
|
|
101
|
-
/>
|
|
102
|
-
|
|
103
|
-
{/* Main Content */}
|
|
104
|
-
<main className="flex-1 overflow-auto">{children}</main>
|
|
105
|
-
</div>
|
|
106
|
-
|
|
107
|
-
{/* Footer (optional) */}
|
|
108
|
-
{showFooter && (
|
|
109
|
-
<footer className="border-t">
|
|
110
|
-
{renderFooter
|
|
111
|
-
? renderFooter()
|
|
112
|
-
: FooterComponent && <FooterComponent />}
|
|
113
|
-
</footer>
|
|
114
|
-
)}
|
|
115
|
-
</div>
|
|
116
|
-
);
|
|
117
|
-
}
|