@kyro-cms/admin 0.3.2 → 0.3.5
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/EditorClient-XEUOVAAC.js +466 -0
- package/dist/EditorClient-XEUOVAAC.js.map +1 -0
- package/dist/EditorClient-YLCGVDXY.cjs +468 -0
- package/dist/EditorClient-YLCGVDXY.cjs.map +1 -0
- package/dist/chunk-7KPIUCGT.js +384 -0
- package/dist/chunk-7KPIUCGT.js.map +1 -0
- package/dist/chunk-GOACG6R7.cjs +473 -0
- package/dist/chunk-GOACG6R7.cjs.map +1 -0
- package/dist/index.cjs +14861 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +1661 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +563 -0
- package/dist/index.js +14784 -0
- package/dist/index.js.map +1 -0
- package/package.json +19 -19
- package/src/components/ActionBar.tsx +7 -43
- package/src/components/Admin.tsx +138 -277
- package/src/components/ApiKeysManager.tsx +428 -419
- package/src/components/AuditLogsPage.tsx +35 -39
- package/src/components/AuthBridge.tsx +51 -0
- package/src/components/AutoForm.tsx +495 -1230
- package/src/components/BrandingHub.tsx +18 -19
- package/src/components/BulkActionsBar.tsx +1 -1
- package/src/components/CreateView.tsx +22 -36
- package/src/components/Dashboard.tsx +60 -84
- package/src/components/DetailView.tsx +113 -91
- package/src/components/DeveloperCenter.tsx +200 -198
- package/src/components/FieldRenderer.tsx +206 -0
- package/src/components/GraphQLPlayground.tsx +340 -480
- package/src/components/ListView.tsx +828 -254
- package/src/components/LoginPage.tsx +3 -4
- package/src/components/MarketplaceManager.tsx +254 -0
- package/src/components/MediaGallery.tsx +856 -1192
- package/src/components/PluginsManager.tsx +277 -0
- package/src/components/RestPlayground.tsx +398 -560
- package/src/components/SessionsManager.tsx +211 -0
- package/src/components/Sidebar.astro +179 -151
- package/src/components/ThemeProvider.tsx +7 -161
- package/src/components/UserManagement.tsx +162 -146
- package/src/components/UserMenu.tsx +110 -0
- package/src/components/WebhookManager.tsx +305 -367
- package/src/components/blocks/AccordionBlock.tsx +4 -4
- package/src/components/blocks/ArrayBlock.tsx +3 -3
- package/src/components/blocks/BlockEditModal.tsx +8 -8
- package/src/components/blocks/BlockWrapper.tsx +61 -0
- package/src/components/blocks/ButtonBlock.tsx +4 -4
- package/src/components/blocks/ChildBlocksTree.tsx +23 -25
- package/src/components/blocks/CodeBlock.tsx +15 -15
- package/src/components/blocks/ColumnsBlock.tsx +6 -44
- package/src/components/blocks/DividerBlock.tsx +3 -3
- package/src/components/blocks/FileBlock.tsx +4 -4
- package/src/components/blocks/HeadingBlock.tsx +6 -38
- package/src/components/blocks/HeroBlock.tsx +4 -4
- package/src/components/blocks/ImageBlock.tsx +4 -4
- package/src/components/blocks/LinkBlock.tsx +4 -4
- package/src/components/blocks/ListBlock.tsx +3 -3
- package/src/components/blocks/ParagraphBlock.tsx +12 -42
- package/src/components/blocks/RelationshipBlock.tsx +4 -4
- package/src/components/blocks/RichTextBlock.tsx +4 -4
- package/src/components/blocks/VStackBlock.tsx +5 -37
- package/src/components/blocks/VideoBlock.tsx +4 -4
- package/src/components/blocks/types.ts +11 -0
- package/src/components/fields/AccordionField.tsx +1 -1
- package/src/components/fields/ArrayField.tsx +2 -2
- package/src/components/fields/ArrayLayout.tsx +93 -0
- package/src/components/fields/BlocksField.tsx +122 -111
- package/src/components/fields/ButtonField.tsx +1 -1
- package/src/components/fields/CheckboxField.tsx +14 -15
- package/src/components/fields/ChildrenField.tsx +2 -2
- package/src/components/fields/CodeField.tsx +3 -3
- package/src/components/fields/ColumnsField.tsx +2 -2
- package/src/components/fields/DateField.tsx +13 -26
- package/src/components/fields/EditorClient.tsx +26 -28
- package/src/components/fields/FieldLayout.tsx +52 -0
- package/src/components/fields/GroupLayout.tsx +35 -0
- package/src/components/fields/JSONField.tsx +7 -7
- package/src/components/fields/LinkField.tsx +1 -1
- package/src/components/fields/MarkdownField.tsx +1 -1
- package/src/components/fields/NumberField.tsx +13 -26
- package/src/components/fields/PortableTextField.tsx +4 -4
- package/src/components/fields/PortableTextRenderer.tsx +1 -1
- package/src/components/fields/RelationshipBlockField.tsx +31 -23
- package/src/components/fields/RelationshipField.tsx +14 -14
- package/src/components/fields/SelectField.tsx +17 -26
- package/src/components/fields/TabsLayout.tsx +69 -0
- package/src/components/fields/TextField.tsx +85 -38
- package/src/components/fields/UploadField.tsx +71 -41
- package/src/components/fields/VideoField.tsx +1 -1
- package/src/components/fields/extensions/blockComponents.tsx +2 -2
- package/src/components/fields/extensions/blocksStore.ts +207 -193
- package/src/components/fields/types.ts +22 -0
- package/src/components/layout/Layout.tsx +1 -1
- package/src/components/ui/ActionMenu.tsx +63 -0
- package/src/components/ui/Badge.tsx +59 -5
- package/src/components/ui/BlockDrawer.tsx +4 -5
- package/src/components/ui/CommandPalette.tsx +58 -36
- package/src/components/ui/CommandPaletteWrapper.tsx +18 -17
- package/src/components/ui/Dropdown.tsx +18 -16
- package/src/components/ui/EmptyState.tsx +25 -0
- package/src/components/ui/GlobalModal.tsx +49 -0
- package/src/components/ui/IconButton.tsx +44 -0
- package/src/components/ui/Modal.tsx +19 -20
- package/src/components/ui/PageHeader.tsx +158 -0
- package/src/components/ui/Pagination.tsx +61 -0
- package/src/components/ui/PromptModal.tsx +1 -1
- package/src/components/ui/SearchInput.tsx +57 -0
- package/src/components/ui/SeoPreview.tsx +31 -0
- package/src/components/ui/SessionModal.tsx +0 -0
- package/src/components/ui/SlidePanel.tsx +2 -0
- package/src/components/ui/Toast.tsx +65 -122
- package/src/components/ui/Toaster.tsx +18 -0
- package/src/components/ui/icons.tsx +112 -0
- package/src/components/users/UserDetail.tsx +290 -0
- package/src/components/users/UserForm.tsx +242 -0
- package/src/components/users/UsersList.tsx +338 -0
- package/src/env.d.ts +13 -13
- package/src/fields/index.ts +2 -1
- package/src/global.d.ts +7 -0
- package/src/hooks/data.ts +2 -9
- package/src/hooks/useAsyncData.ts +36 -0
- package/src/hooks/useAutoFormState.ts +527 -0
- package/src/hooks/useSelection.ts +49 -0
- package/src/hooks/useSession.ts +0 -0
- package/src/index.ts +11 -1
- package/src/integration.ts +86 -11
- package/src/kyro-cms.d.ts +209 -0
- package/src/layouts/AdminLayout.astro +128 -11
- package/src/layouts/AuthLayout.astro +21 -5
- package/src/lib/api.ts +175 -55
- package/src/lib/autoform-store.ts +435 -0
- package/src/lib/config.ts +82 -34
- package/src/lib/createRegistry.ts +29 -0
- package/src/lib/default-kyro-config.ts +4 -0
- package/src/lib/globals.ts +50 -0
- package/src/lib/media-utils.ts +18 -0
- package/src/lib/object-utils.ts +77 -0
- package/src/lib/paths.ts +61 -0
- package/src/lib/stores/index.ts +370 -0
- package/src/lib/types.ts +43 -0
- package/src/lib/useResourceManager.ts +105 -0
- package/src/pages/403.astro +67 -0
- package/src/pages/[collection]/[id].astro +14 -180
- package/src/pages/[collection]/index.astro +11 -6
- package/src/pages/api-explorer.astro +173 -0
- package/src/pages/audit/index.astro +2 -0
- package/src/pages/auth/login.astro +122 -0
- package/src/pages/auth/register.astro +167 -0
- package/src/pages/graphql-explorer.astro +59 -0
- package/src/pages/{admin/graphql.astro → graphql.astro} +51 -17
- package/src/pages/index.astro +577 -0
- package/src/pages/index_ALT.astro +3 -0
- package/src/pages/keys.astro +11 -0
- package/src/pages/marketplace.astro +11 -0
- package/src/pages/media.astro +3 -0
- package/src/pages/plugins.astro +8 -0
- package/src/pages/preview/[collection]/[id].astro +188 -123
- package/src/pages/rest-playground.astro +62 -0
- package/src/pages/roles/index.astro +183 -76
- package/src/pages/sessions.astro +8 -0
- package/src/pages/settings/[slug].astro +92 -114
- package/src/pages/settings/index.astro +5 -3
- package/src/pages/users/[id].astro +25 -154
- package/src/pages/users/index.astro +19 -130
- package/src/pages/users/new.astro +9 -86
- package/src/pages/webhooks.astro +11 -0
- package/src/routes.ts +80 -0
- package/src/styles/main.css +119 -79
- package/src/theme/tokens.ts +1 -0
- package/src/vite-env.d.ts +14 -0
- package/src/collections/auth/index.ts +0 -155
- package/src/collections/portfolio/index.ts +0 -343
- package/src/components/ApiExplorer.tsx +0 -325
- package/src/components/EnhancedListView.tsx +0 -889
- package/src/components/GraphQLExplorer.tsx +0 -675
- package/src/components/Icons.tsx +0 -23
- package/src/components/StatusBadge.tsx +0 -76
- package/src/lib/MediaService.ts +0 -541
- package/src/lib/auth/sqlite-adapter.ts +0 -319
- package/src/lib/dataStore.ts +0 -226
- package/src/lib/db/adapter.ts +0 -54
- package/src/lib/db/drizzle-mysql-adapter.ts +0 -194
- package/src/lib/db/drizzle-mysql-auth-adapter.ts +0 -327
- package/src/lib/db/drizzle-postgres-adapter.ts +0 -202
- package/src/lib/db/drizzle-postgres-auth-adapter.ts +0 -304
- package/src/lib/db/drizzle-sqlite-adapter.ts +0 -227
- package/src/lib/db/drizzle-sqlite-auth-adapter.ts +0 -548
- package/src/lib/db/index.ts +0 -449
- package/src/lib/db/mongodb-adapter.ts +0 -207
- package/src/lib/db/mongodb-auth-adapter.ts +0 -305
- package/src/lib/db/schema/mysql-auth.ts +0 -113
- package/src/lib/db/schema/mysql-content.ts +0 -20
- package/src/lib/db/schema/postgres-auth.ts +0 -116
- package/src/lib/db/schema/postgres-content.ts +0 -35
- package/src/lib/db/schema/postgres-media.ts +0 -52
- package/src/lib/db/schema/postgres-settings.ts +0 -11
- package/src/lib/db/schema/sqlite-auth.ts +0 -112
- package/src/lib/db/schema/sqlite-content.ts +0 -20
- package/src/lib/db/version-adapter.ts +0 -248
- package/src/lib/graphql/index.ts +0 -1
- package/src/lib/graphql/schema.ts +0 -443
- package/src/lib/rate-limit.ts +0 -267
- package/src/lib/storage.ts +0 -374
- package/src/lib/store.ts +0 -85
- package/src/middleware.ts +0 -177
- package/src/pages/admin/api-explorer.astro +0 -98
- package/src/pages/admin/graphql-explorer.astro +0 -40
- package/src/pages/admin/index.astro +0 -286
- package/src/pages/admin/keys.astro +0 -8
- package/src/pages/admin/rest-playground.astro +0 -44
- package/src/pages/admin/webhooks.astro +0 -8
- package/src/pages/api/[collection]/[id]/publish.ts +0 -52
- package/src/pages/api/[collection]/[id]/unpublish.ts +0 -42
- package/src/pages/api/[collection]/[id]/versions.ts +0 -66
- package/src/pages/api/[collection]/[id].ts +0 -213
- package/src/pages/api/[collection]/index.ts +0 -209
- package/src/pages/api/auth/[id].ts +0 -121
- package/src/pages/api/auth/audit-logs.ts +0 -57
- package/src/pages/api/auth/login.ts +0 -211
- package/src/pages/api/auth/logout.ts +0 -66
- package/src/pages/api/auth/me.ts +0 -36
- package/src/pages/api/auth/refresh.ts +0 -119
- package/src/pages/api/auth/register.ts +0 -188
- package/src/pages/api/auth/users.ts +0 -97
- package/src/pages/api/collections.ts +0 -59
- package/src/pages/api/globals/[slug].ts +0 -42
- package/src/pages/api/graphql.ts +0 -90
- package/src/pages/api/health.ts +0 -426
- package/src/pages/api/keys/[id].ts +0 -26
- package/src/pages/api/keys/index.ts +0 -75
- package/src/pages/api/media/[id].ts +0 -309
- package/src/pages/api/media/folders.ts +0 -609
- package/src/pages/api/media/index.ts +0 -146
- package/src/pages/api/media/resize.ts +0 -267
- package/src/pages/api/search.ts +0 -82
- package/src/pages/api/slug-availability.ts +0 -70
- package/src/pages/api/storage-config.ts +0 -20
- package/src/pages/api/storage-status.ts +0 -206
- package/src/pages/api/upload.ts +0 -334
- package/src/pages/api/webhooks/index.ts +0 -71
- package/src/pages/login.astro +0 -82
- package/src/pages/register.astro +0 -102
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback
|
|
1
|
+
import React, { useState, useEffect, useCallback } from "react";
|
|
2
2
|
import { apiGet, apiPatch, apiPost, apiDelete } from "../lib/api";
|
|
3
3
|
import type {
|
|
4
4
|
KyroConfig,
|
|
@@ -7,9 +7,13 @@ import type {
|
|
|
7
7
|
} from "@kyro-cms/core/client";
|
|
8
8
|
import { AutoForm } from "./AutoForm";
|
|
9
9
|
import { ActionBar, type DocumentStatus, type SaveStatus } from "./ActionBar";
|
|
10
|
-
import { ConfirmModal } from "./ui/Modal";
|
|
11
10
|
import { Spinner } from "./ui/Spinner";
|
|
12
11
|
import { useToast } from "./ui/Toast";
|
|
12
|
+
import { useUIStore } from "../lib/stores";
|
|
13
|
+
import { PageHeader } from "./ui/PageHeader";
|
|
14
|
+
import { Badge } from "./ui/Badge";
|
|
15
|
+
import { adminPath } from "../lib/paths";
|
|
16
|
+
|
|
13
17
|
|
|
14
18
|
interface DetailViewProps {
|
|
15
19
|
config: KyroConfig;
|
|
@@ -21,8 +25,6 @@ interface DetailViewProps {
|
|
|
21
25
|
onDelete?: () => void;
|
|
22
26
|
onError: (message: string) => void;
|
|
23
27
|
mode?: "collection" | "global";
|
|
24
|
-
autosave?: boolean;
|
|
25
|
-
autosaveDelay?: number;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
export function DetailView({
|
|
@@ -35,26 +37,21 @@ export function DetailView({
|
|
|
35
37
|
onDelete,
|
|
36
38
|
onError,
|
|
37
39
|
mode = "collection",
|
|
38
|
-
autosave = true,
|
|
39
|
-
autosaveDelay = 2000,
|
|
40
40
|
}: DetailViewProps) {
|
|
41
41
|
const { addToast } = useToast();
|
|
42
|
+
const { confirm, alert } = useUIStore();
|
|
42
43
|
const [data, setData] = useState<Record<string, unknown>>({});
|
|
43
44
|
const [originalData, setOriginalData] = useState<Record<string, unknown>>({});
|
|
44
45
|
const [loading, setLoading] = useState(true);
|
|
45
46
|
const [saving, setSaving] = useState(false);
|
|
46
47
|
const [saveStatus, setSaveStatus] = useState<SaveStatus>("idle");
|
|
47
48
|
const [deleting, setDeleting] = useState(false);
|
|
48
|
-
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
|
49
49
|
const [status, setStatus] = useState<DocumentStatus>("draft");
|
|
50
50
|
const [createdAt, setCreatedAt] = useState<string | null>(null);
|
|
51
51
|
const [updatedAt, setUpdatedAt] = useState<string | null>(null);
|
|
52
52
|
const [publishedAt, setPublishedAt] = useState<string | null>(null);
|
|
53
53
|
const [justSaved, setJustSaved] = useState(false);
|
|
54
54
|
|
|
55
|
-
const autosaveTimerRef = useRef<NodeJS.Timeout | null>(null);
|
|
56
|
-
const hasChangesRef = useRef(false);
|
|
57
|
-
|
|
58
55
|
const fields = global?.fields || collection?.fields || [];
|
|
59
56
|
const label = global?.label || collection?.label || "Document";
|
|
60
57
|
const slug = global?.slug || collection?.slug || "";
|
|
@@ -80,39 +77,23 @@ export function DetailView({
|
|
|
80
77
|
} else if (documentId) {
|
|
81
78
|
loadDocument();
|
|
82
79
|
}
|
|
83
|
-
}, [documentId, mode]);
|
|
84
|
-
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
hasChangesRef.current = hasChanges;
|
|
87
|
-
}, [hasChanges]);
|
|
88
|
-
|
|
89
|
-
useEffect(() => {
|
|
90
|
-
if (autosave && hasChanges && !loading) {
|
|
91
|
-
if (autosaveTimerRef.current) {
|
|
92
|
-
clearTimeout(autosaveTimerRef.current);
|
|
93
|
-
}
|
|
94
|
-
autosaveTimerRef.current = setTimeout(() => {
|
|
95
|
-
if (hasChangesRef.current) {
|
|
96
|
-
handleSave(true);
|
|
97
|
-
}
|
|
98
|
-
}, autosaveDelay);
|
|
99
|
-
}
|
|
80
|
+
}, [documentId, mode, slug]);
|
|
100
81
|
|
|
101
|
-
return () => {
|
|
102
|
-
if (autosaveTimerRef.current) {
|
|
103
|
-
clearTimeout(autosaveTimerRef.current);
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
}, [data, autosave, autosaveDelay]);
|
|
107
82
|
|
|
108
83
|
const loadDocument = async () => {
|
|
109
84
|
try {
|
|
110
85
|
setLoading(true);
|
|
111
|
-
const result = await apiGet(`/api/${slug}/${documentId}
|
|
86
|
+
const result = (await apiGet(`/api/${slug}/${documentId}`, { autoToast: false }) as {
|
|
87
|
+
data?: Record<string, unknown>;
|
|
88
|
+
status?: string;
|
|
89
|
+
createdAt?: string;
|
|
90
|
+
updatedAt?: string;
|
|
91
|
+
publishedAt?: string;
|
|
92
|
+
});
|
|
112
93
|
const docData = result.data || {};
|
|
113
94
|
setData(docData);
|
|
114
95
|
setOriginalData(docData);
|
|
115
|
-
setStatus(result.status || "draft");
|
|
96
|
+
setStatus((result.status || "draft") as DocumentStatus);
|
|
116
97
|
setCreatedAt(result.createdAt || null);
|
|
117
98
|
setUpdatedAt(result.updatedAt || null);
|
|
118
99
|
setPublishedAt(result.publishedAt || null);
|
|
@@ -126,7 +107,11 @@ export function DetailView({
|
|
|
126
107
|
const loadGlobal = async () => {
|
|
127
108
|
try {
|
|
128
109
|
setLoading(true);
|
|
129
|
-
const result = await apiGet(`/api/globals/${slug}
|
|
110
|
+
const result = (await apiGet(`/api/globals/${slug}`, { autoToast: false }) as {
|
|
111
|
+
data?: Record<string, unknown>;
|
|
112
|
+
createdAt?: string;
|
|
113
|
+
updatedAt?: string;
|
|
114
|
+
});
|
|
130
115
|
const globalData = result.data || {};
|
|
131
116
|
setData(globalData);
|
|
132
117
|
setOriginalData(globalData);
|
|
@@ -148,12 +133,15 @@ export function DetailView({
|
|
|
148
133
|
? `/api/globals/${slug}`
|
|
149
134
|
: `/api/${slug}/${documentId}`;
|
|
150
135
|
|
|
151
|
-
await apiPatch(endpoint, data);
|
|
136
|
+
const result = (await apiPatch(endpoint, data) as { data?: Record<string, unknown> });
|
|
137
|
+
const savedData = (result && (result.data || result)) || data;
|
|
152
138
|
|
|
153
139
|
if (!isAutosave) {
|
|
154
|
-
setOriginalData(
|
|
140
|
+
setOriginalData(savedData);
|
|
155
141
|
onSave();
|
|
156
142
|
}
|
|
143
|
+
|
|
144
|
+
setData(savedData);
|
|
157
145
|
setSaveStatus("saved");
|
|
158
146
|
setUpdatedAt(new Date().toISOString());
|
|
159
147
|
|
|
@@ -162,7 +150,7 @@ export function DetailView({
|
|
|
162
150
|
setTimeout(() => setJustSaved(false), 3000);
|
|
163
151
|
|
|
164
152
|
if (!isAutosave) {
|
|
165
|
-
addToast("success", "Saved successfully");
|
|
153
|
+
addToast?.("success", "Saved successfully");
|
|
166
154
|
}
|
|
167
155
|
|
|
168
156
|
setTimeout(() => {
|
|
@@ -172,7 +160,7 @@ export function DetailView({
|
|
|
172
160
|
setSaveStatus("error");
|
|
173
161
|
if (!isAutosave) {
|
|
174
162
|
onError("Failed to save changes");
|
|
175
|
-
addToast("error", "Failed to save changes");
|
|
163
|
+
addToast?.("error", "Failed to save changes");
|
|
176
164
|
}
|
|
177
165
|
} finally {
|
|
178
166
|
setSaving(false);
|
|
@@ -187,10 +175,10 @@ export function DetailView({
|
|
|
187
175
|
await apiPost(`/api/${slug}/${documentId}/publish`);
|
|
188
176
|
setStatus("published");
|
|
189
177
|
setPublishedAt(new Date().toISOString());
|
|
190
|
-
addToast("success", "Published successfully");
|
|
178
|
+
addToast?.("success", "Published successfully");
|
|
191
179
|
} catch {
|
|
192
180
|
onError("Failed to publish");
|
|
193
|
-
addToast("error", "Failed to publish");
|
|
181
|
+
addToast?.("error", "Failed to publish");
|
|
194
182
|
} finally {
|
|
195
183
|
setSaving(false);
|
|
196
184
|
}
|
|
@@ -210,24 +198,36 @@ export function DetailView({
|
|
|
210
198
|
|
|
211
199
|
const handleDuplicate = async () => {
|
|
212
200
|
try {
|
|
213
|
-
|
|
201
|
+
console.log(`[Duplicate] Calling /api/${slug}/${documentId}/duplicate`);
|
|
202
|
+
const result = await apiPost(`/api/${slug}/${documentId}/duplicate`);
|
|
203
|
+
console.log("[Duplicate] Success:", result);
|
|
214
204
|
onError("Document duplicated successfully");
|
|
215
|
-
|
|
216
|
-
|
|
205
|
+
} catch (err: unknown) {
|
|
206
|
+
console.error("[Duplicate] Error:", err);
|
|
207
|
+
const message = err instanceof Error ? err.message : "Failed to duplicate document";
|
|
208
|
+
onError(message);
|
|
217
209
|
}
|
|
218
210
|
};
|
|
219
211
|
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
212
|
+
const handleDeleteTrigger = () => {
|
|
213
|
+
confirm({
|
|
214
|
+
title: `Delete ${label}?`,
|
|
215
|
+
message: "This action cannot be undone.",
|
|
216
|
+
variant: "danger",
|
|
217
|
+
onConfirm: async () => {
|
|
218
|
+
try {
|
|
219
|
+
setDeleting(true);
|
|
220
|
+
await apiDelete(`/api/${slug}/${documentId}`);
|
|
221
|
+
onDelete?.();
|
|
222
|
+
} catch (err: unknown) {
|
|
223
|
+
console.error("[Delete] Error:", err);
|
|
224
|
+
const message = err instanceof Error ? err.message : "Failed to delete document";
|
|
225
|
+
alert({ title: "Error", message });
|
|
226
|
+
} finally {
|
|
227
|
+
setDeleting(false);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
231
|
};
|
|
232
232
|
|
|
233
233
|
if (loading) {
|
|
@@ -245,7 +245,33 @@ export function DetailView({
|
|
|
245
245
|
|
|
246
246
|
return (
|
|
247
247
|
<div className="kyro-detail">
|
|
248
|
+
<PageHeader
|
|
249
|
+
back={{ onClick: onBack }}
|
|
250
|
+
breadcrumbs={[
|
|
251
|
+
{ label: mode === "global" ? "Globals" : "Collections" },
|
|
252
|
+
{
|
|
253
|
+
label: label,
|
|
254
|
+
href: mode === "collection" ? `${adminPath}/${slug}` : undefined
|
|
255
|
+
},
|
|
256
|
+
{ label: mode === "global" ? "Edit" : documentId ? "Edit" : "New" }
|
|
257
|
+
]}
|
|
258
|
+
title={
|
|
259
|
+
(mode === "global" ? label : (data[collection?.admin?.useAsTitle || "title"] as string || data.name as string || documentId || `New ${collection?.singularLabel || label}`))
|
|
260
|
+
}
|
|
261
|
+
metadata={[
|
|
262
|
+
<Badge
|
|
263
|
+
key="status"
|
|
264
|
+
variant={status === "published" ? "success" : "warning"}
|
|
265
|
+
dot
|
|
266
|
+
className="text-[10px] font-bold "
|
|
267
|
+
>
|
|
268
|
+
{status}
|
|
269
|
+
</Badge>
|
|
270
|
+
]}
|
|
271
|
+
/>
|
|
272
|
+
|
|
248
273
|
{!isSingleLayout && (
|
|
274
|
+
|
|
249
275
|
<ActionBar
|
|
250
276
|
status={status}
|
|
251
277
|
saveStatus={saveStatus}
|
|
@@ -254,11 +280,13 @@ export function DetailView({
|
|
|
254
280
|
onPublish={handlePublish}
|
|
255
281
|
onUnpublish={status === "published" ? handleUnpublish : undefined}
|
|
256
282
|
onDuplicate={handleDuplicate}
|
|
257
|
-
onViewHistory={() => {
|
|
283
|
+
onViewHistory={() => {
|
|
284
|
+
window.dispatchEvent(new CustomEvent('kyro:show-version-history'));
|
|
285
|
+
}}
|
|
258
286
|
onPreview={() =>
|
|
259
287
|
window.open(`/preview/${slug}/${documentId}`, "_blank")
|
|
260
288
|
}
|
|
261
|
-
onDelete={
|
|
289
|
+
onDelete={handleDeleteTrigger}
|
|
262
290
|
publishedAt={publishedAt}
|
|
263
291
|
updatedAt={updatedAt}
|
|
264
292
|
/>
|
|
@@ -274,7 +302,7 @@ export function DetailView({
|
|
|
274
302
|
<div className="space-y-8 min-w-0">
|
|
275
303
|
<div className="surface-tile p-8">
|
|
276
304
|
<div className="flex items-center justify-between mb-8 px-1">
|
|
277
|
-
<h2 className="text-[10px] font-
|
|
305
|
+
<h2 className="text-[10px] font-bold tracking-[0.2em] opacity-40">
|
|
278
306
|
Core Configuration
|
|
279
307
|
</h2>
|
|
280
308
|
<div className="h-px flex-1 bg-[var(--kyro-border)] ml-6 opacity-30" />
|
|
@@ -288,8 +316,10 @@ export function DetailView({
|
|
|
288
316
|
data={data}
|
|
289
317
|
onChange={setData}
|
|
290
318
|
layout={isSingleLayout ? "single" : "split"}
|
|
291
|
-
|
|
292
|
-
|
|
319
|
+
globalSlug={mode === "global" ? slug : undefined}
|
|
320
|
+
collectionSlug={mode === "collection" ? slug : undefined}
|
|
321
|
+
onActionSuccess={(message) => addToast?.("success", message)}
|
|
322
|
+
onActionError={(message) => addToast?.("error", message)}
|
|
293
323
|
documentStatus={status}
|
|
294
324
|
justSaved={justSaved}
|
|
295
325
|
/>
|
|
@@ -298,8 +328,8 @@ export function DetailView({
|
|
|
298
328
|
{mode === "collection" && documentId && (
|
|
299
329
|
<button
|
|
300
330
|
type="button"
|
|
301
|
-
onClick={
|
|
302
|
-
className="
|
|
331
|
+
onClick={handleDeleteTrigger}
|
|
332
|
+
className="kyro-btn kyro-btn-lg kyro-btn-ghost text-[var(--kyro-error)]"
|
|
303
333
|
>
|
|
304
334
|
Delete
|
|
305
335
|
</button>
|
|
@@ -308,7 +338,7 @@ export function DetailView({
|
|
|
308
338
|
type="button"
|
|
309
339
|
onClick={() => handleSave(false)}
|
|
310
340
|
disabled={saving}
|
|
311
|
-
className="
|
|
341
|
+
className="kyro-btn kyro-btn-lg kyro-btn-primary shadow-xl flex items-center gap-2"
|
|
312
342
|
>
|
|
313
343
|
{saving ? (
|
|
314
344
|
<svg
|
|
@@ -347,51 +377,51 @@ export function DetailView({
|
|
|
347
377
|
{!isSingleLayout && (
|
|
348
378
|
<div className="space-y-6 animate-in fade-in slide-in-from-right-4 duration-500">
|
|
349
379
|
<div className="surface-tile p-8">
|
|
350
|
-
<h3 className="text-[10px] font-
|
|
380
|
+
<h3 className="text-[10px] font-bold tracking-[0.2em] opacity-40 mb-6">
|
|
351
381
|
Metadata
|
|
352
382
|
</h3>
|
|
353
383
|
<div className="space-y-6">
|
|
354
384
|
<div className="flex flex-col gap-2">
|
|
355
|
-
<span className="text-[10px] font-
|
|
385
|
+
<span className="text-[10px] font-bold tracking-widest opacity-40">
|
|
356
386
|
Dynamic Status
|
|
357
387
|
</span>
|
|
358
388
|
<div>
|
|
359
389
|
<span
|
|
360
|
-
className={`inline-flex items-center px-3 py-1 rounded-full text-[9px] font-
|
|
390
|
+
className={`inline-flex items-center px-3 py-1 rounded-full text-[9px] font-bold tracking-widest ${status === "published" ? "bg-green-500/10 text-green-500" : "bg-amber-500/10 text-amber-500"}`}
|
|
361
391
|
>
|
|
362
392
|
{status || "draft"}
|
|
363
393
|
</span>
|
|
364
394
|
</div>
|
|
365
395
|
</div>
|
|
366
396
|
<div className="flex flex-col gap-2">
|
|
367
|
-
<span className="text-[10px] font-
|
|
397
|
+
<span className="text-[10px] font-bold tracking-widest opacity-40">
|
|
368
398
|
Date Created
|
|
369
399
|
</span>
|
|
370
400
|
<span className="text-sm font-bold text-[var(--kyro-text-secondary)]">
|
|
371
401
|
{createdAt
|
|
372
402
|
? new Date(createdAt).toLocaleString("en-US", {
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
403
|
+
dateStyle: "medium",
|
|
404
|
+
timeStyle: "short",
|
|
405
|
+
})
|
|
376
406
|
: "N/A"}
|
|
377
407
|
</span>
|
|
378
408
|
</div>
|
|
379
409
|
<div className="flex flex-col gap-2">
|
|
380
|
-
<span className="text-[10px] font-
|
|
410
|
+
<span className="text-[10px] font-bold tracking-widest opacity-40">
|
|
381
411
|
Last Modified
|
|
382
412
|
</span>
|
|
383
413
|
<span className="text-sm font-bold text-[var(--kyro-text-secondary)]">
|
|
384
414
|
{updatedAt
|
|
385
415
|
? new Date(updatedAt).toLocaleString("en-US", {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
416
|
+
dateStyle: "medium",
|
|
417
|
+
timeStyle: "short",
|
|
418
|
+
})
|
|
389
419
|
: "Just now"}
|
|
390
420
|
</span>
|
|
391
421
|
</div>
|
|
392
422
|
{publishedAt && (
|
|
393
423
|
<div className="flex flex-col gap-2">
|
|
394
|
-
<span className="text-[10px] font-
|
|
424
|
+
<span className="text-[10px] font-bold tracking-widest opacity-40">
|
|
395
425
|
Public At
|
|
396
426
|
</span>
|
|
397
427
|
<span className="text-sm font-bold text-[var(--kyro-text-secondary)]">
|
|
@@ -406,25 +436,28 @@ export function DetailView({
|
|
|
406
436
|
</div>
|
|
407
437
|
|
|
408
438
|
<div className="surface-tile p-8 bg-[var(--kyro-bg-secondary)]">
|
|
409
|
-
<h3 className="text-[10px] font-
|
|
439
|
+
<h3 className="text-[10px] font-bold tracking-[0.2em] opacity-40 mb-4">
|
|
410
440
|
Quick Links
|
|
411
441
|
</h3>
|
|
412
442
|
<div className="space-y-3">
|
|
413
443
|
<button
|
|
414
444
|
type="button"
|
|
415
|
-
|
|
445
|
+
onClick={handleDuplicate}
|
|
446
|
+
className="kyro-btn kyro-btn-sm kyro-btn-ghost w-full justify-start"
|
|
416
447
|
>
|
|
417
448
|
Duplicate Document
|
|
418
449
|
</button>
|
|
419
450
|
<button
|
|
420
451
|
type="button"
|
|
421
|
-
|
|
452
|
+
onClick={() => window.open(`/preview/${slug}/${documentId}`, "_blank")}
|
|
453
|
+
className="kyro-btn kyro-btn-sm kyro-btn-ghost w-full justify-start"
|
|
422
454
|
>
|
|
423
455
|
View Public Page
|
|
424
456
|
</button>
|
|
425
457
|
<button
|
|
426
458
|
type="button"
|
|
427
|
-
|
|
459
|
+
onClick={handleDeleteTrigger}
|
|
460
|
+
className="kyro-btn kyro-btn-sm kyro-btn-ghost w-full justify-start text-[var(--kyro-error)] hover:bg-[var(--kyro-danger-bg)]"
|
|
428
461
|
>
|
|
429
462
|
Delete Entry
|
|
430
463
|
</button>
|
|
@@ -433,17 +466,6 @@ export function DetailView({
|
|
|
433
466
|
</div>
|
|
434
467
|
)}
|
|
435
468
|
</div>
|
|
436
|
-
|
|
437
|
-
<ConfirmModal
|
|
438
|
-
open={showDeleteConfirm}
|
|
439
|
-
onClose={() => setShowDeleteConfirm(false)}
|
|
440
|
-
onConfirm={handleDelete}
|
|
441
|
-
title={`Delete ${label}?`}
|
|
442
|
-
message="This action cannot be undone."
|
|
443
|
-
confirmLabel="Delete"
|
|
444
|
-
variant="danger"
|
|
445
|
-
loading={deleting}
|
|
446
|
-
/>
|
|
447
469
|
</div>
|
|
448
470
|
);
|
|
449
471
|
}
|