@kyro-cms/admin 0.1.5 → 0.1.7
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 +149 -51
- package/package.json +52 -5
- package/src/collections/auth/index.ts +2 -2
- package/src/collections/portfolio/index.ts +343 -0
- package/src/components/ActionBar.tsx +153 -16
- package/src/components/Admin.tsx +136 -27
- package/src/components/ApiExplorer.tsx +325 -0
- package/src/components/ApiKeysManager.tsx +563 -0
- package/src/components/AuditLogsPage.tsx +664 -0
- package/src/components/AutoForm.tsx +1417 -661
- package/src/components/BrandingHub.tsx +267 -0
- package/src/components/BulkActionsBar.tsx +3 -3
- package/src/components/CreateView.tsx +3 -3
- package/src/components/Dashboard.tsx +393 -0
- package/src/components/DetailView.tsx +199 -57
- package/src/components/DeveloperCenter.tsx +403 -0
- package/src/components/EnhancedListView.tsx +786 -0
- package/src/components/GraphQLExplorer.tsx +675 -0
- package/src/components/GraphQLPlayground.tsx +627 -0
- package/src/components/ListView.tsx +191 -53
- package/src/components/MediaGallery.tsx +1569 -0
- package/src/components/Modal.tsx +149 -0
- package/src/components/RestPlayground.tsx +951 -0
- package/src/components/Sidebar.astro +237 -0
- package/src/components/UserManagement.tsx +204 -0
- package/src/components/VersionHistoryPanel.tsx +3 -3
- package/src/components/WebhookManager.tsx +608 -0
- package/src/components/blocks/AccordionBlock.tsx +97 -0
- package/src/components/blocks/ArrayBlock.tsx +75 -0
- package/src/components/blocks/BlockEditModal.MARKER +12 -0
- package/src/components/blocks/BlockEditModal.tsx +774 -0
- package/src/components/blocks/ButtonBlock.tsx +165 -0
- package/src/components/blocks/ChildBlocksTree.tsx +551 -0
- package/src/components/blocks/CodeBlock.tsx +66 -0
- package/src/components/blocks/ColumnsBlock.tsx +151 -0
- package/src/components/blocks/DividerBlock.tsx +43 -0
- package/src/components/blocks/FileBlock.tsx +64 -0
- package/src/components/blocks/HeadingBlock.tsx +81 -0
- package/src/components/blocks/HeroBlock.tsx +157 -0
- package/src/components/blocks/ImageBlock.tsx +83 -0
- package/src/components/blocks/LinkBlock.tsx +71 -0
- package/src/components/blocks/ListBlock.tsx +39 -0
- package/src/components/blocks/ParagraphBlock.tsx +61 -0
- package/src/components/blocks/RelationshipBlock.tsx +279 -0
- package/src/components/blocks/VStackBlock.tsx +75 -0
- package/src/components/blocks/VideoBlock.tsx +45 -0
- package/src/components/blocks/index.ts +10 -0
- package/src/components/fields/BlocksField.tsx +323 -0
- package/src/components/fields/CheckboxField.tsx +15 -9
- package/src/components/fields/CodeField.tsx +234 -0
- package/src/components/fields/DateField.tsx +38 -11
- package/src/components/fields/EditorClient.tsx +271 -0
- package/src/components/fields/FileField.tsx +390 -0
- package/src/components/fields/HybridContentField.tsx +109 -0
- package/src/components/fields/ImageField.tsx +429 -0
- package/src/components/fields/JSONField.tsx +361 -0
- package/src/components/fields/MarkdownField.tsx +282 -0
- package/src/components/fields/NumberField.tsx +42 -12
- package/src/components/fields/PortableTextField.tsx +143 -0
- package/src/components/fields/PortableTextRenderer.tsx +68 -0
- package/src/components/fields/RelationshipField.tsx +231 -59
- package/src/components/fields/SelectField.tsx +25 -15
- package/src/components/fields/TextField.tsx +45 -14
- package/src/components/fields/extensions/blockComponents.tsx +237 -0
- package/src/components/fields/extensions/blocksStore.ts +273 -0
- package/src/components/fields/index.ts +13 -0
- package/src/components/index.ts +1 -2
- package/src/components/layout/Header.tsx +2 -2
- package/src/components/layout/Layout.tsx +2 -2
- package/src/components/ui/Badge.tsx +9 -4
- package/src/components/ui/BlockDrawer.tsx +79 -0
- package/src/components/ui/Button.tsx +1 -1
- package/src/components/ui/CommandPalette.tsx +362 -0
- package/src/components/ui/CommandPaletteWrapper.tsx +97 -0
- package/src/components/ui/Dropdown.tsx +1 -1
- package/src/components/ui/Modal.tsx +37 -12
- package/src/components/ui/PromptModal.tsx +94 -0
- package/src/components/ui/SlidePanel.tsx +43 -16
- package/src/components/ui/Toast.tsx +80 -14
- package/src/env.d.ts +16 -0
- package/src/env.ts +20 -0
- package/src/index.ts +0 -1
- package/src/layouts/AdminLayout.astro +164 -170
- package/src/layouts/AuthLayout.astro +50 -0
- package/src/lib/MediaService.ts +541 -0
- package/src/lib/auth/sqlite-adapter.ts +319 -0
- package/src/lib/config.ts +22 -6
- package/src/lib/dataStore.ts +132 -74
- package/src/lib/db/adapter.ts +54 -0
- package/src/lib/db/drizzle-mysql-adapter.ts +194 -0
- package/src/lib/db/drizzle-mysql-auth-adapter.ts +327 -0
- package/src/lib/db/drizzle-postgres-adapter.ts +202 -0
- package/src/lib/db/drizzle-postgres-auth-adapter.ts +304 -0
- package/src/lib/db/drizzle-sqlite-adapter.ts +227 -0
- package/src/lib/db/drizzle-sqlite-auth-adapter.ts +548 -0
- package/src/lib/db/index.ts +449 -0
- package/src/lib/db/mongodb-adapter.ts +207 -0
- package/src/lib/db/mongodb-auth-adapter.ts +305 -0
- package/src/lib/db/schema/mysql-auth.ts +113 -0
- package/src/lib/db/schema/mysql-content.ts +20 -0
- package/src/lib/db/schema/postgres-auth.ts +116 -0
- package/src/lib/db/schema/postgres-content.ts +35 -0
- package/src/lib/db/schema/postgres-media.ts +52 -0
- package/src/lib/db/schema/postgres-settings.ts +11 -0
- package/src/lib/db/schema/sqlite-auth.ts +112 -0
- package/src/lib/db/schema/sqlite-content.ts +20 -0
- package/src/lib/graphql/index.ts +1 -0
- package/src/lib/graphql/schema.ts +443 -0
- package/src/lib/rate-limit.ts +267 -0
- package/src/lib/storage.ts +374 -0
- package/src/lib/store.ts +85 -0
- package/src/middleware.ts +116 -28
- package/src/pages/[collection]/[id].astro +178 -122
- package/src/pages/[collection]/index.astro +24 -156
- package/src/pages/admin/api-explorer.astro +98 -0
- package/src/pages/admin/graphql-explorer.astro +40 -0
- package/src/pages/admin/graphql.astro +97 -0
- package/src/pages/admin/index.astro +286 -0
- package/src/pages/admin/keys.astro +8 -0
- package/src/pages/admin/rest-playground.astro +44 -0
- package/src/pages/admin/webhooks.astro +8 -0
- package/src/pages/api/[collection]/[id]/publish.ts +44 -0
- package/src/pages/api/[collection]/[id]/unpublish.ts +42 -0
- package/src/pages/api/[collection]/[id]/versions.ts +36 -0
- package/src/pages/api/[collection]/[id].ts +102 -159
- package/src/pages/api/[collection]/index.ts +151 -230
- package/src/pages/api/auth/[id].ts +48 -69
- package/src/pages/api/auth/audit-logs.ts +20 -43
- package/src/pages/api/auth/login.ts +159 -45
- package/src/pages/api/auth/logout.ts +50 -20
- package/src/pages/api/auth/refresh.ts +119 -0
- package/src/pages/api/auth/register.ts +110 -40
- package/src/pages/api/auth/users.ts +22 -97
- package/src/pages/api/collections.ts +59 -0
- package/src/pages/api/globals/[slug]/test.ts +172 -0
- package/src/pages/api/globals/[slug].ts +42 -0
- package/src/pages/api/graphql.ts +90 -0
- package/src/pages/api/health.ts +417 -40
- package/src/pages/api/keys/[id].ts +26 -0
- package/src/pages/api/keys/index.ts +75 -0
- package/src/pages/api/media/[id].ts +309 -0
- package/src/pages/api/media/folders.ts +609 -0
- package/src/pages/api/media/index.ts +146 -0
- package/src/pages/api/media/resize.ts +267 -0
- package/src/pages/api/search.ts +82 -0
- package/src/pages/api/slug-availability.ts +70 -0
- package/src/pages/api/storage-config.ts +20 -0
- package/src/pages/api/storage-status.ts +206 -0
- package/src/pages/api/upload.ts +334 -0
- package/src/pages/api/webhooks/index.ts +71 -0
- package/src/pages/audit/index.astro +2 -104
- package/src/pages/login.astro +82 -0
- package/src/pages/media.astro +10 -0
- package/src/pages/preview/[collection]/[id].astro +178 -0
- package/src/pages/register.astro +102 -0
- package/src/pages/roles/index.astro +21 -21
- package/src/pages/settings/[slug].astro +162 -0
- package/src/pages/settings/index.astro +9 -0
- package/src/pages/users/[id].astro +29 -21
- package/src/pages/users/index.astro +22 -17
- package/src/pages/users/new.astro +18 -17
- package/src/styles/main.css +553 -128
- package/src/components/layout/Sidebar.tsx +0 -497
- package/src/pages/index.astro +0 -225
|
@@ -34,6 +34,28 @@ export function ActionBar({
|
|
|
34
34
|
publishedAt,
|
|
35
35
|
updatedAt,
|
|
36
36
|
}: ActionBarProps) {
|
|
37
|
+
const styles = {
|
|
38
|
+
btn: {
|
|
39
|
+
padding: "0.5rem 1rem",
|
|
40
|
+
borderRadius: "0.75rem",
|
|
41
|
+
fontWeight: 600,
|
|
42
|
+
fontSize: "0.875rem",
|
|
43
|
+
transition: "all 0.2s",
|
|
44
|
+
border: "none",
|
|
45
|
+
cursor: "pointer",
|
|
46
|
+
},
|
|
47
|
+
idle: { backgroundColor: "#6b7280", color: "white" },
|
|
48
|
+
saving: {
|
|
49
|
+
backgroundColor: "#9ca3af",
|
|
50
|
+
color: "white",
|
|
51
|
+
opacity: 0.7,
|
|
52
|
+
cursor: "not-allowed",
|
|
53
|
+
},
|
|
54
|
+
saved: { backgroundColor: "#22c55e", color: "white" },
|
|
55
|
+
error: { backgroundColor: "#ef4444", color: "white" },
|
|
56
|
+
changes: { backgroundColor: "#eab308", color: "black" },
|
|
57
|
+
};
|
|
58
|
+
|
|
37
59
|
const getSaveStatusText = () => {
|
|
38
60
|
if (saveStatus === "saving") return "Saving...";
|
|
39
61
|
if (saveStatus === "saved") return "Saved";
|
|
@@ -42,18 +64,92 @@ export function ActionBar({
|
|
|
42
64
|
return null;
|
|
43
65
|
};
|
|
44
66
|
|
|
67
|
+
const getSaveButtonClass = () => {
|
|
68
|
+
const base = "kyro-btn kyro-btn-md";
|
|
69
|
+
if (saveStatus === "saving") return `${base} opacity-50 cursor-wait`;
|
|
70
|
+
if (saveStatus === "saved")
|
|
71
|
+
return `${base} bg-green-500 hover:bg-green-600 text-white`;
|
|
72
|
+
if (saveStatus === "error")
|
|
73
|
+
return `${base} bg-red-500 hover:bg-red-600 text-white`;
|
|
74
|
+
if (hasChanges)
|
|
75
|
+
return `${base} bg-yellow-500 hover:bg-yellow-600 text-black`;
|
|
76
|
+
return `${base} bg-gray-500 hover:bg-gray-600 text-white`;
|
|
77
|
+
};
|
|
78
|
+
|
|
45
79
|
const getStatusBadge = () => {
|
|
46
80
|
const statusConfig = {
|
|
47
|
-
draft: {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
81
|
+
draft: {
|
|
82
|
+
label: "Draft",
|
|
83
|
+
class: "bg-gray-100 text-gray-600 border-gray-200",
|
|
84
|
+
icon: (
|
|
85
|
+
<svg
|
|
86
|
+
width="12"
|
|
87
|
+
height="12"
|
|
88
|
+
viewBox="0 0 24 24"
|
|
89
|
+
fill="none"
|
|
90
|
+
stroke="currentColor"
|
|
91
|
+
strokeWidth="2.5"
|
|
92
|
+
>
|
|
93
|
+
<path d="M12 2v20M2 12h20" />
|
|
94
|
+
</svg>
|
|
95
|
+
),
|
|
96
|
+
},
|
|
97
|
+
published: {
|
|
98
|
+
label: "Published",
|
|
99
|
+
class: "bg-green-100 text-green-700 border-green-200",
|
|
100
|
+
icon: (
|
|
101
|
+
<svg
|
|
102
|
+
width="12"
|
|
103
|
+
height="12"
|
|
104
|
+
viewBox="0 0 24 24"
|
|
105
|
+
fill="none"
|
|
106
|
+
stroke="currentColor"
|
|
107
|
+
strokeWidth="2.5"
|
|
108
|
+
>
|
|
109
|
+
<path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" />
|
|
110
|
+
</svg>
|
|
111
|
+
),
|
|
112
|
+
},
|
|
113
|
+
scheduled: {
|
|
114
|
+
label: "Scheduled",
|
|
115
|
+
class: "bg-blue-100 text-blue-700 border-blue-200",
|
|
116
|
+
icon: (
|
|
117
|
+
<svg
|
|
118
|
+
width="12"
|
|
119
|
+
height="12"
|
|
120
|
+
viewBox="0 0 24 24"
|
|
121
|
+
fill="none"
|
|
122
|
+
stroke="currentColor"
|
|
123
|
+
strokeWidth="2.5"
|
|
124
|
+
>
|
|
125
|
+
<circle cx="12" cy="12" r="10" />
|
|
126
|
+
<path d="M12 6v6l4 2" />
|
|
127
|
+
</svg>
|
|
128
|
+
),
|
|
129
|
+
},
|
|
130
|
+
archived: {
|
|
131
|
+
label: "Archived",
|
|
132
|
+
class: "bg-yellow-100 text-yellow-700 border-yellow-200",
|
|
133
|
+
icon: (
|
|
134
|
+
<svg
|
|
135
|
+
width="12"
|
|
136
|
+
height="12"
|
|
137
|
+
viewBox="0 0 24 24"
|
|
138
|
+
fill="none"
|
|
139
|
+
stroke="currentColor"
|
|
140
|
+
strokeWidth="2.5"
|
|
141
|
+
>
|
|
142
|
+
<path d="M21 8v13H3V8M1 3h22v5H1zM10 12h4" />
|
|
143
|
+
</svg>
|
|
144
|
+
),
|
|
145
|
+
},
|
|
51
146
|
};
|
|
52
147
|
const config = statusConfig[status];
|
|
53
148
|
return (
|
|
54
149
|
<span
|
|
55
|
-
className={`inline-flex items-center px-2 py-
|
|
150
|
+
className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold border ${config.class}`}
|
|
56
151
|
>
|
|
152
|
+
{config.icon}
|
|
57
153
|
{config.label}
|
|
58
154
|
</span>
|
|
59
155
|
);
|
|
@@ -80,46 +176,87 @@ export function ActionBar({
|
|
|
80
176
|
</span>
|
|
81
177
|
)}
|
|
82
178
|
</div>
|
|
83
|
-
<div className="text-xs
|
|
84
|
-
{updatedAt &&
|
|
179
|
+
<div className="text-xs space-y-0.5">
|
|
180
|
+
{updatedAt && (
|
|
181
|
+
<div className="text-gray-400">
|
|
182
|
+
Updated: {formatDate(updatedAt)}
|
|
183
|
+
</div>
|
|
184
|
+
)}
|
|
85
185
|
{publishedAt && status === "published" && (
|
|
86
|
-
<div
|
|
186
|
+
<div className="text-[var(--kyro-primary)] font-medium">
|
|
187
|
+
Published: {formatDate(publishedAt)}
|
|
188
|
+
</div>
|
|
87
189
|
)}
|
|
88
190
|
</div>
|
|
89
191
|
</div>
|
|
90
192
|
|
|
91
193
|
<div className="flex items-center gap-2">
|
|
92
194
|
{status === "draft" && onPublish && (
|
|
93
|
-
<button
|
|
195
|
+
<button type="button"
|
|
94
196
|
onClick={onPublish}
|
|
95
197
|
disabled={saveStatus === "saving"}
|
|
96
|
-
className="kyro-
|
|
198
|
+
className="bg-[var(--kyro-primary)] hover:opacity-90 text-white kyro-btn-md flex items-center gap-2"
|
|
97
199
|
>
|
|
200
|
+
<svg
|
|
201
|
+
width="16"
|
|
202
|
+
height="16"
|
|
203
|
+
viewBox="0 0 24 24"
|
|
204
|
+
fill="none"
|
|
205
|
+
stroke="currentColor"
|
|
206
|
+
strokeWidth="2.5"
|
|
207
|
+
>
|
|
208
|
+
<path d="M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z" />
|
|
209
|
+
</svg>
|
|
98
210
|
Publish
|
|
99
211
|
</button>
|
|
100
212
|
)}
|
|
101
213
|
{status === "published" && onUnpublish && (
|
|
102
|
-
<button
|
|
214
|
+
<button type="button"
|
|
103
215
|
onClick={onUnpublish}
|
|
104
216
|
disabled={saveStatus === "saving"}
|
|
105
|
-
className="kyro-btn kyro-btn-
|
|
217
|
+
className="kyro-btn kyro-btn-warning kyro-btn-md flex items-center gap-2"
|
|
106
218
|
>
|
|
219
|
+
<svg
|
|
220
|
+
width="16"
|
|
221
|
+
height="16"
|
|
222
|
+
viewBox="0 0 24 24"
|
|
223
|
+
fill="none"
|
|
224
|
+
stroke="currentColor"
|
|
225
|
+
strokeWidth="2.5"
|
|
226
|
+
>
|
|
227
|
+
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8M3 3v5h5" />
|
|
228
|
+
</svg>
|
|
107
229
|
Unpublish
|
|
108
230
|
</button>
|
|
109
231
|
)}
|
|
110
|
-
<button
|
|
232
|
+
<button type="button"
|
|
111
233
|
onClick={onSave}
|
|
112
234
|
disabled={
|
|
113
235
|
saveStatus === "saving" || (!hasChanges && saveStatus !== "error")
|
|
114
236
|
}
|
|
115
|
-
|
|
237
|
+
style={{
|
|
238
|
+
...styles.btn,
|
|
239
|
+
...(saveStatus === "saving"
|
|
240
|
+
? styles.saving
|
|
241
|
+
: saveStatus === "saved"
|
|
242
|
+
? styles.saved
|
|
243
|
+
: saveStatus === "error"
|
|
244
|
+
? styles.error
|
|
245
|
+
: hasChanges
|
|
246
|
+
? styles.changes
|
|
247
|
+
: styles.idle),
|
|
248
|
+
}}
|
|
116
249
|
>
|
|
117
|
-
{saveStatus === "saving"
|
|
250
|
+
{saveStatus === "saving"
|
|
251
|
+
? "Saving..."
|
|
252
|
+
: saveStatus === "saved"
|
|
253
|
+
? "Saved"
|
|
254
|
+
: "Save"}
|
|
118
255
|
</button>
|
|
119
256
|
|
|
120
257
|
<Dropdown
|
|
121
258
|
trigger={
|
|
122
|
-
<button className="kyro-btn kyro-btn-ghost kyro-btn-md p-2">
|
|
259
|
+
<button type="button" className="kyro-btn kyro-btn-ghost kyro-btn-md p-2">
|
|
123
260
|
<svg
|
|
124
261
|
width="16"
|
|
125
262
|
height="16"
|
package/src/components/Admin.tsx
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
import { useState, useEffect } from "react";
|
|
2
2
|
import type { CollectionConfig, GlobalConfig } from "@kyro-cms/core";
|
|
3
|
-
import { Sidebar } from "./layout/Sidebar";
|
|
4
3
|
import { ListView } from "./ListView";
|
|
5
4
|
import { DetailView } from "./DetailView";
|
|
6
5
|
import { CreateView } from "./CreateView";
|
|
7
6
|
import { LoginPage } from "./LoginPage";
|
|
7
|
+
import { Dashboard } from "./Dashboard";
|
|
8
|
+
import { UserManagement } from "./UserManagement";
|
|
9
|
+
import { BrandingHub } from "./BrandingHub";
|
|
10
|
+
import { DeveloperCenter } from "./DeveloperCenter";
|
|
11
|
+
import { WebhookManager } from "./WebhookManager";
|
|
12
|
+
import { MediaGallery } from "./MediaGallery";
|
|
13
|
+
import { CommandPalette } from "./ui/CommandPalette";
|
|
8
14
|
import { Toast, ToastProvider } from "./ui/Toast";
|
|
9
15
|
import { ThemeProvider, type ThemeMode } from "./ThemeProvider";
|
|
10
16
|
import "../styles/main.css";
|
|
11
17
|
|
|
12
|
-
type View =
|
|
18
|
+
type View =
|
|
19
|
+
| "list"
|
|
20
|
+
| "detail"
|
|
21
|
+
| "create"
|
|
22
|
+
| "settings"
|
|
23
|
+
| "users"
|
|
24
|
+
| "roles"
|
|
25
|
+
| "audit"
|
|
26
|
+
| "media"
|
|
27
|
+
| "branding"
|
|
28
|
+
| "developer"
|
|
29
|
+
| "webhooks";
|
|
13
30
|
|
|
14
31
|
export interface KyroAdminConfig {
|
|
15
32
|
collections?: CollectionConfig[] | Record<string, CollectionConfig>;
|
|
@@ -82,10 +99,22 @@ export function Admin({ config, theme = "light", onThemeChange }: AdminProps) {
|
|
|
82
99
|
const [currentView, setCurrentView] = useState<View>("list");
|
|
83
100
|
const [selectedId, setSelectedId] = useState<string | null>(null);
|
|
84
101
|
const [toasts, setToasts] = useState<ToastMessage[]>([]);
|
|
102
|
+
const [showCommandPalette, setShowCommandPalette] = useState(false);
|
|
85
103
|
|
|
86
104
|
const collections = normalizeCollections(config.collections);
|
|
87
105
|
const globals = normalizeGlobals(config.globals);
|
|
88
106
|
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
109
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "k") {
|
|
110
|
+
e.preventDefault();
|
|
111
|
+
setShowCommandPalette((prev) => !prev);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
115
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
116
|
+
}, []);
|
|
117
|
+
|
|
89
118
|
useEffect(() => {
|
|
90
119
|
const token = localStorage.getItem("kyro_token");
|
|
91
120
|
const userStr = localStorage.getItem("kyro_user");
|
|
@@ -102,10 +131,7 @@ export function Admin({ config, theme = "light", onThemeChange }: AdminProps) {
|
|
|
102
131
|
}, []);
|
|
103
132
|
|
|
104
133
|
useEffect(() => {
|
|
105
|
-
|
|
106
|
-
if (collectionKeys.length > 0 && !activeCollection) {
|
|
107
|
-
setActiveCollection(collectionKeys[0]);
|
|
108
|
-
}
|
|
134
|
+
// No longer auto-selecting the first collection to allow Dashboard as home
|
|
109
135
|
}, [authenticated]);
|
|
110
136
|
|
|
111
137
|
const handleAuth = (token: string, user: AuthUser) => {
|
|
@@ -133,7 +159,37 @@ export function Admin({ config, theme = "light", onThemeChange }: AdminProps) {
|
|
|
133
159
|
}, 5000);
|
|
134
160
|
};
|
|
135
161
|
|
|
162
|
+
const removeToast = (id: string) => {
|
|
163
|
+
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
164
|
+
};
|
|
165
|
+
|
|
136
166
|
const handleCollectionChange = (collectionName: string) => {
|
|
167
|
+
if (!collectionName) {
|
|
168
|
+
setActiveCollection(null);
|
|
169
|
+
setActiveGlobal(null);
|
|
170
|
+
setCurrentView("list");
|
|
171
|
+
setSelectedId(null);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Check if it's a special governance or developer view
|
|
176
|
+
if (
|
|
177
|
+
[
|
|
178
|
+
"users",
|
|
179
|
+
"roles",
|
|
180
|
+
"audit",
|
|
181
|
+
"media",
|
|
182
|
+
"branding",
|
|
183
|
+
"developer",
|
|
184
|
+
"webhooks",
|
|
185
|
+
].includes(collectionName)
|
|
186
|
+
) {
|
|
187
|
+
setActiveCollection(null);
|
|
188
|
+
setActiveGlobal(null);
|
|
189
|
+
setCurrentView(collectionName as any);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
137
193
|
setActiveCollection(collectionName);
|
|
138
194
|
setActiveGlobal(null);
|
|
139
195
|
setCurrentView("list");
|
|
@@ -178,13 +234,54 @@ export function Admin({ config, theme = "light", onThemeChange }: AdminProps) {
|
|
|
178
234
|
config={{} as any}
|
|
179
235
|
global={global}
|
|
180
236
|
onBack={() => setCurrentView("list")}
|
|
181
|
-
onSave={() =>
|
|
237
|
+
onSave={() => addToast("success", "Configuration saved successfully")}
|
|
182
238
|
onError={handleError}
|
|
183
239
|
mode="global"
|
|
184
240
|
/>
|
|
185
241
|
);
|
|
186
242
|
}
|
|
187
243
|
|
|
244
|
+
if (!activeCollection && !activeGlobal) {
|
|
245
|
+
if (currentView === "users") return <UserManagement />;
|
|
246
|
+
if (currentView === "roles")
|
|
247
|
+
return (
|
|
248
|
+
<div className="p-6">
|
|
249
|
+
<h2 className="text-xl font-bold">Roles Management</h2>
|
|
250
|
+
<p className="text-gray-500 mt-2">
|
|
251
|
+
Configure user roles and permissions.
|
|
252
|
+
</p>
|
|
253
|
+
</div>
|
|
254
|
+
);
|
|
255
|
+
if (currentView === "audit")
|
|
256
|
+
return (
|
|
257
|
+
<div className="p-6">
|
|
258
|
+
<h2 className="text-xl font-bold">Audit Logs</h2>
|
|
259
|
+
<p className="text-gray-500 mt-2">
|
|
260
|
+
View system activity and changes.
|
|
261
|
+
</p>
|
|
262
|
+
</div>
|
|
263
|
+
);
|
|
264
|
+
if (currentView === "media") return <MediaGallery />;
|
|
265
|
+
if (currentView === "branding") return <BrandingHub />;
|
|
266
|
+
if (currentView === "developer")
|
|
267
|
+
return <DeveloperCenter collections={collections} />;
|
|
268
|
+
if (currentView === "webhooks") return <WebhookManager />;
|
|
269
|
+
|
|
270
|
+
return (
|
|
271
|
+
<Dashboard
|
|
272
|
+
collections={collections}
|
|
273
|
+
onNavigate={(view, collection) => {
|
|
274
|
+
if (collection) {
|
|
275
|
+
setActiveCollection(collection);
|
|
276
|
+
setActiveGlobal(null);
|
|
277
|
+
}
|
|
278
|
+
setCurrentView(view as any);
|
|
279
|
+
}}
|
|
280
|
+
user={currentUser}
|
|
281
|
+
/>
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
|
|
188
285
|
if (!activeCollection) return null;
|
|
189
286
|
|
|
190
287
|
const collection = collections[activeCollection];
|
|
@@ -231,33 +328,45 @@ export function Admin({ config, theme = "light", onThemeChange }: AdminProps) {
|
|
|
231
328
|
|
|
232
329
|
return (
|
|
233
330
|
<ThemeProvider defaultMode={theme}>
|
|
234
|
-
<ToastProvider
|
|
331
|
+
<ToastProvider
|
|
332
|
+
toasts={toasts}
|
|
333
|
+
addToast={addToast}
|
|
334
|
+
removeToast={removeToast}
|
|
335
|
+
>
|
|
235
336
|
<div className="kyro-admin">
|
|
236
|
-
<Sidebar
|
|
237
|
-
collections={collections}
|
|
238
|
-
globals={globals}
|
|
239
|
-
activeCollection={activeCollection}
|
|
240
|
-
activeGlobal={activeGlobal}
|
|
241
|
-
onCollectionClick={handleCollectionChange}
|
|
242
|
-
onGlobalClick={handleGlobalChange}
|
|
243
|
-
user={currentUser}
|
|
244
|
-
onLogout={handleLogout}
|
|
245
|
-
/>
|
|
246
337
|
<div className="kyro-main">
|
|
247
338
|
<div className="kyro-content">{renderContent()}</div>
|
|
248
339
|
</div>
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
340
|
+
<CommandPalette
|
|
341
|
+
isOpen={showCommandPalette}
|
|
342
|
+
onClose={() => setShowCommandPalette(false)}
|
|
343
|
+
collections={collections}
|
|
344
|
+
globals={globals}
|
|
345
|
+
onNavigate={(view, collection, id) => {
|
|
346
|
+
if (view === "list" && collection) {
|
|
347
|
+
handleCollectionChange(collection);
|
|
348
|
+
} else if (view === "settings" && collection) {
|
|
349
|
+
handleGlobalChange(collection);
|
|
350
|
+
} else if (view === "media") {
|
|
351
|
+
setActiveCollection(null);
|
|
352
|
+
setActiveGlobal(null);
|
|
353
|
+
setCurrentView("list"); // This might need a separate 'media' view state if implemented
|
|
354
|
+
} else if (view === "create" && collection) {
|
|
355
|
+
setActiveCollection(collection);
|
|
356
|
+
setCurrentView("create");
|
|
256
357
|
}
|
|
257
|
-
|
|
258
|
-
|
|
358
|
+
}}
|
|
359
|
+
/>
|
|
259
360
|
</div>
|
|
260
361
|
</ToastProvider>
|
|
362
|
+
{toasts.map((toast) => (
|
|
363
|
+
<Toast
|
|
364
|
+
key={toast.id}
|
|
365
|
+
type={toast.type}
|
|
366
|
+
message={toast.message}
|
|
367
|
+
onClose={() => removeToast(toast.id)}
|
|
368
|
+
/>
|
|
369
|
+
))}
|
|
261
370
|
</ThemeProvider>
|
|
262
371
|
);
|
|
263
372
|
}
|