@kyro-cms/admin 0.3.1 → 0.3.4
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,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useEffect } from "react";
|
|
2
|
-
import { apiGet, apiPost, apiDelete } from "../lib/api";
|
|
2
|
+
import { apiGet, apiPost, apiDelete, resolveApi } from "../lib/api";
|
|
3
3
|
import {
|
|
4
4
|
Terminal,
|
|
5
5
|
Key,
|
|
@@ -13,11 +13,17 @@ import {
|
|
|
13
13
|
Lock,
|
|
14
14
|
Eye,
|
|
15
15
|
EyeOff,
|
|
16
|
-
} from "
|
|
16
|
+
} from "./ui/icons";
|
|
17
17
|
import CodeMirror from "@uiw/react-codemirror";
|
|
18
18
|
import { json } from "@codemirror/lang-json";
|
|
19
19
|
import { aura } from "@uiw/codemirror-theme-aura";
|
|
20
|
+
import { useUIStore } from "../lib/stores";
|
|
20
21
|
import { Modal, ModalContent, ModalActions } from "./ui/Modal";
|
|
22
|
+
import { PageHeader } from "./ui/PageHeader";
|
|
23
|
+
import { Badge } from "./ui/Badge";
|
|
24
|
+
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
const API_BASE = typeof __KYRO_API_PATH__ !== 'undefined' ? __KYRO_API_PATH__ : '/api';
|
|
21
27
|
|
|
22
28
|
interface ApiKey {
|
|
23
29
|
id: string;
|
|
@@ -27,17 +33,16 @@ interface ApiKey {
|
|
|
27
33
|
createdAt: string;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
|
-
export function DeveloperCenter({ collections }: { collections:
|
|
36
|
+
export function DeveloperCenter({ collections }: { collections: Record<string, unknown> }) {
|
|
31
37
|
const [keys, setKeys] = useState<ApiKey[]>([]);
|
|
32
38
|
const [loading, setLoading] = useState(false);
|
|
33
39
|
const [showKey, setShowKey] = useState<string | null>(null);
|
|
34
40
|
const [testEndpoint, setTestEndpoint] = useState("");
|
|
35
41
|
const [playgroundResult, setPlaygroundResult] = useState<unknown>(null);
|
|
36
42
|
const [exploring, setExploring] = useState(false);
|
|
43
|
+
const { confirm, alert } = useUIStore();
|
|
37
44
|
|
|
38
45
|
const [showCreateModal, setShowCreateModal] = useState(false);
|
|
39
|
-
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
|
40
|
-
const [deleteKeyId, setDeleteKeyId] = useState<string | null>(null);
|
|
41
46
|
const [newKeyName, setNewKeyName] = useState("");
|
|
42
47
|
|
|
43
48
|
const loadKeys = async () => {
|
|
@@ -63,35 +68,36 @@ export function DeveloperCenter({ collections }: { collections: any }) {
|
|
|
63
68
|
try {
|
|
64
69
|
await apiPost("/api/keys", { name: newKeyName });
|
|
65
70
|
loadKeys();
|
|
71
|
+
setShowCreateModal(false);
|
|
72
|
+
setNewKeyName("");
|
|
66
73
|
} catch (e) {
|
|
67
74
|
console.error(e);
|
|
75
|
+
alert({ title: "Error", message: "Failed to generate API key" });
|
|
68
76
|
}
|
|
69
|
-
setShowCreateModal(false);
|
|
70
|
-
setNewKeyName("");
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
const handleRevokeKey = async (id: string) => {
|
|
74
|
-
setDeleteKeyId(id);
|
|
75
|
-
setShowDeleteModal(true);
|
|
76
77
|
};
|
|
77
78
|
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
const handleRevokeKey = (id: string) => {
|
|
80
|
+
confirm({
|
|
81
|
+
title: "Revoke API Key",
|
|
82
|
+
message: "Are you sure you want to revoke this key? Any integrations using it will stop working.",
|
|
83
|
+
variant: "danger",
|
|
84
|
+
onConfirm: async () => {
|
|
85
|
+
try {
|
|
86
|
+
await apiDelete(`/api/keys/${id}`);
|
|
87
|
+
loadKeys();
|
|
88
|
+
} catch (e) {
|
|
89
|
+
console.error(e);
|
|
90
|
+
alert({ title: "Error", message: "Failed to revoke API key" });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
88
94
|
};
|
|
89
95
|
|
|
90
96
|
const handleRunTest = async () => {
|
|
91
97
|
if (!testEndpoint) return;
|
|
92
98
|
setExploring(true);
|
|
93
99
|
try {
|
|
94
|
-
const response = await fetch(`/api/${testEndpoint}`);
|
|
100
|
+
const response = await fetch(resolveApi(`/api/${testEndpoint}`));
|
|
95
101
|
const data = await response.json();
|
|
96
102
|
setPlaygroundResult(data);
|
|
97
103
|
} catch (e) {
|
|
@@ -104,219 +110,237 @@ export function DeveloperCenter({ collections }: { collections: any }) {
|
|
|
104
110
|
};
|
|
105
111
|
|
|
106
112
|
return (
|
|
107
|
-
<div className="w-full space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
type="button"
|
|
121
|
-
onClick={handleGenerateKey}
|
|
122
|
-
className="flex items-center gap-2 px-6 py-3 bg-[var(--kyro-sidebar-active)] text-[var(--kyro-sidebar-text-active)] rounded-full font-black text-sm shadow-xl hover:shadow-[var(--kyro-primary)] active:scale-95 transition-all"
|
|
123
|
-
>
|
|
124
|
-
<Key className="w-4 h-4" />
|
|
125
|
-
Generate New Key
|
|
126
|
-
</button>
|
|
127
|
-
</div>
|
|
128
|
-
</div>
|
|
113
|
+
<div className="w-full space-y-8 animate-in fade-in slide-in-from-bottom-4 duration-700 pb-32">
|
|
114
|
+
<PageHeader
|
|
115
|
+
title="Developer Center"
|
|
116
|
+
description="Provision access keys and explore the headless API ecosystem."
|
|
117
|
+
icon={Code2}
|
|
118
|
+
actions={[
|
|
119
|
+
{
|
|
120
|
+
label: "Generate Key",
|
|
121
|
+
onClick: handleGenerateKey,
|
|
122
|
+
icon: Key,
|
|
123
|
+
},
|
|
124
|
+
]}
|
|
125
|
+
/>
|
|
129
126
|
|
|
130
127
|
<div className="grid grid-cols-1 xl:grid-cols-3 gap-8">
|
|
131
128
|
{/* API Key List */}
|
|
132
129
|
<section className="xl:col-span-2 space-y-6">
|
|
133
|
-
<div className="flex items-center
|
|
134
|
-
<div className="
|
|
135
|
-
|
|
136
|
-
<span className="text-[10px] font-black uppercase tracking-widest opacity-40">
|
|
137
|
-
Access Credentials
|
|
138
|
-
</span>
|
|
139
|
-
</div>
|
|
130
|
+
<div className="flex items-center gap-2 px-2">
|
|
131
|
+
<div className="w-1 h-4 bg-[var(--kyro-primary)] rounded-full" />
|
|
132
|
+
<h2 className="text-sm font-medium tracking-[0.2em] opacity-40 uppercase">Access Credentials</h2>
|
|
140
133
|
</div>
|
|
141
134
|
|
|
142
135
|
<div className="space-y-4">
|
|
143
|
-
{keys.
|
|
144
|
-
<div
|
|
145
|
-
|
|
146
|
-
className="
|
|
147
|
-
>
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
136
|
+
{keys.length === 0 ? (
|
|
137
|
+
<div className="p-12 text-center rounded-[2rem] border-2 border-dashed border-[var(--kyro-border)] bg-[var(--kyro-surface-accent)]/30">
|
|
138
|
+
<Lock className="w-10 h-10 mx-auto mb-4 opacity-20" />
|
|
139
|
+
<p className="text-sm text-[var(--kyro-text-secondary)] opacity-50">No API keys found. Generate one to get started.</p>
|
|
140
|
+
</div>
|
|
141
|
+
) : (
|
|
142
|
+
keys.map((key) => (
|
|
143
|
+
<div
|
|
144
|
+
key={key.id}
|
|
145
|
+
className="group relative overflow-hidden bg-[var(--kyro-surface)] border border-[var(--kyro-border)] rounded-3xl p-6 hover:border-[var(--kyro-primary)]/50 transition-all duration-300"
|
|
146
|
+
>
|
|
147
|
+
<div className="flex flex-col md:flex-row md:items-center justify-between gap-6 relative z-10">
|
|
148
|
+
<div className="flex-1 min-w-0">
|
|
149
|
+
<div className="flex items-center gap-3 mb-4">
|
|
150
|
+
<div className="p-2.5 bg-[var(--kyro-surface-accent)] rounded-xl group-hover:bg-[var(--kyro-primary)]/10 transition-colors">
|
|
151
|
+
<Key className="w-5 h-5 text-[var(--kyro-text-secondary)] group-hover:text-[var(--kyro-primary)] transition-colors" />
|
|
152
|
+
</div>
|
|
153
|
+
<h3 className="text-lg font-bold group-hover:text-[var(--kyro-primary)] transition-colors truncate">
|
|
154
|
+
{key.name}
|
|
155
|
+
</h3>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
<div className="flex-1 bg-[var(--kyro-bg)] border border-[var(--kyro-border)] rounded-2xl px-4 py-3 flex items-center justify-between group/key overflow-hidden">
|
|
155
159
|
<code className="text-xs font-mono opacity-80 truncate mr-4">
|
|
156
160
|
{showKey === key.id
|
|
157
161
|
? key.key
|
|
158
162
|
: "••••••••••••••••••••••••••••••••"}
|
|
159
163
|
</code>
|
|
160
|
-
<div className="flex items-center gap-
|
|
164
|
+
<div className="flex items-center gap-2 shrink-0">
|
|
161
165
|
<button
|
|
162
166
|
type="button"
|
|
163
167
|
onClick={() =>
|
|
164
168
|
setShowKey(showKey === key.id ? null : key.id)
|
|
165
169
|
}
|
|
166
|
-
className="p-1.5 hover:bg-[var(--kyro-surface)] rounded-
|
|
170
|
+
className="p-1.5 hover:bg-[var(--kyro-surface-accent)] rounded-lg transition-all text-[var(--kyro-text-secondary)]"
|
|
167
171
|
>
|
|
168
172
|
{showKey === key.id ? (
|
|
169
|
-
<EyeOff className="w-
|
|
173
|
+
<EyeOff className="w-4 h-4" />
|
|
170
174
|
) : (
|
|
171
|
-
<Eye className="w-
|
|
175
|
+
<Eye className="w-4 h-4" />
|
|
172
176
|
)}
|
|
173
177
|
</button>
|
|
174
178
|
<button
|
|
175
179
|
type="button"
|
|
176
|
-
className="p-1.5 hover:bg-[var(--kyro-surface)] rounded-
|
|
180
|
+
className="p-1.5 hover:bg-[var(--kyro-surface-accent)] rounded-lg transition-all text-[var(--kyro-text-secondary)]"
|
|
181
|
+
onClick={() => {
|
|
182
|
+
navigator.clipboard.writeText(key.key);
|
|
183
|
+
alert({ title: "Success", message: "API key copied to clipboard" });
|
|
184
|
+
}}
|
|
177
185
|
>
|
|
178
|
-
<Copy className="w-
|
|
186
|
+
<Copy className="w-4 h-4" />
|
|
179
187
|
</button>
|
|
180
188
|
</div>
|
|
181
189
|
</div>
|
|
190
|
+
|
|
191
|
+
<div className="flex items-center gap-6 mt-4 text-[10px] font-bold opacity-30 uppercase tracking-widest">
|
|
192
|
+
<div className="flex items-center gap-2">
|
|
193
|
+
<span>Issued:</span>
|
|
194
|
+
<span>{new Date(key.createdAt).toLocaleDateString()}</span>
|
|
195
|
+
</div>
|
|
196
|
+
<div className="flex items-center gap-2">
|
|
197
|
+
<span>Status:</span>
|
|
198
|
+
<span className="text-green-500">Active</span>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
182
201
|
</div>
|
|
183
|
-
|
|
184
|
-
<span>
|
|
185
|
-
Created {new Date(key.createdAt).toLocaleDateString()}
|
|
186
|
-
</span>
|
|
187
|
-
<span>
|
|
188
|
-
Last used{" "}
|
|
189
|
-
{key.lastUsed
|
|
190
|
-
? new Date(key.lastUsed).toLocaleDateString()
|
|
191
|
-
: "Never"}
|
|
192
|
-
</span>
|
|
193
|
-
</div>
|
|
194
|
-
</div>
|
|
195
|
-
<div className="flex items-center gap-3">
|
|
202
|
+
|
|
196
203
|
<button
|
|
197
204
|
type="button"
|
|
198
205
|
onClick={() => handleRevokeKey(key.id)}
|
|
199
|
-
className="p-3 bg-red-500/5 text-red-500 rounded-
|
|
206
|
+
className="p-3.5 bg-red-500/5 text-red-500 rounded-2xl hover:bg-red-500/10 transition-all border border-transparent hover:border-red-500/30 self-start md:self-center"
|
|
200
207
|
title="Revoke Key"
|
|
201
208
|
>
|
|
202
|
-
<Trash2 className="w-
|
|
209
|
+
<Trash2 className="w-5 h-5" />
|
|
203
210
|
</button>
|
|
204
211
|
</div>
|
|
205
212
|
</div>
|
|
206
|
-
|
|
207
|
-
)
|
|
213
|
+
))
|
|
214
|
+
)}
|
|
208
215
|
</div>
|
|
209
216
|
</section>
|
|
210
217
|
|
|
211
|
-
{/* Sidebar
|
|
218
|
+
{/* Sidebar Info - Modernized */}
|
|
212
219
|
<section className="space-y-6">
|
|
213
|
-
<div className="
|
|
220
|
+
<div className="relative overflow-hidden rounded-[2.5rem] border border-[var(--kyro-border)] bg-gradient-to-br from-[var(--kyro-primary)] to-[var(--kyro-primary)]/80 p-8 group shadow-2xl shadow-[var(--kyro-primary)]/20">
|
|
221
|
+
<div className="absolute top-0 right-0 p-8 opacity-[0.1] pointer-events-none group-hover:scale-110 transition-transform duration-700">
|
|
222
|
+
<Terminal className="w-48 h-48 rotate-12" />
|
|
223
|
+
</div>
|
|
214
224
|
<div className="relative z-10">
|
|
215
|
-
<
|
|
216
|
-
|
|
225
|
+
<div className="w-12 h-12 bg-white/20 backdrop-blur-md rounded-2xl flex items-center justify-center mb-6">
|
|
226
|
+
<Terminal className="w-6 h-6 text-white" />
|
|
227
|
+
</div>
|
|
228
|
+
<h3 className="text-white text-2xl font-bold tracking-tight mb-3">
|
|
217
229
|
Endpoint Hub
|
|
218
230
|
</h3>
|
|
219
|
-
<p className="text-white/
|
|
220
|
-
|
|
221
|
-
keys to authorize requests.
|
|
231
|
+
<p className="text-white/80 text-sm font-medium leading-relaxed mb-8">
|
|
232
|
+
Kyro CMS is built for high-performance content delivery. Use these endpoints to power your headless frontends.
|
|
222
233
|
</p>
|
|
223
234
|
<button
|
|
224
235
|
type="button"
|
|
225
|
-
className="w-full py-
|
|
236
|
+
className="w-full py-4 bg-white text-[var(--kyro-primary)] rounded-[1.2rem] font-bold text-xs uppercase tracking-widest hover:shadow-xl transition-all flex items-center justify-center gap-2 active:scale-[0.98]"
|
|
226
237
|
>
|
|
227
|
-
|
|
238
|
+
Full API Documentation
|
|
228
239
|
<ExternalLink className="w-3.5 h-3.5" />
|
|
229
240
|
</button>
|
|
230
241
|
</div>
|
|
231
|
-
{/* Decorative glow */}
|
|
232
|
-
<div className="absolute -bottom-10 -right-10 w-40 h-40 bg-white opacity-10 blur-3xl group-hover:scale-150 transition-transform duration-700" />
|
|
233
242
|
</div>
|
|
234
243
|
|
|
235
|
-
<div className="
|
|
236
|
-
<h4 className="text-[10px] font-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
<
|
|
246
|
-
https://api.kyro.io/v1
|
|
247
|
-
|
|
248
|
-
|
|
244
|
+
<div className="rounded-[2.5rem] border border-[var(--kyro-border)] bg-[var(--kyro-surface)]/50 p-8 space-y-6">
|
|
245
|
+
<h4 className="text-[10px] font-bold uppercase tracking-[0.2em] opacity-40">Environment Matrix</h4>
|
|
246
|
+
<div className="space-y-5">
|
|
247
|
+
<div className="space-y-2">
|
|
248
|
+
<div className="flex items-center justify-between">
|
|
249
|
+
<span className="text-xs font-bold">Content API</span>
|
|
250
|
+
<Badge variant="outline" className="text-[8px] font-bold uppercase py-0.5">Production</Badge>
|
|
251
|
+
</div>
|
|
252
|
+
<div className="group relative">
|
|
253
|
+
<div className="absolute -inset-0.5 bg-gradient-to-r from-[var(--kyro-primary)]/30 to-transparent rounded-xl blur opacity-0 group-hover:opacity-100 transition-all"></div>
|
|
254
|
+
<div className="relative bg-[var(--kyro-bg)] p-3.5 rounded-xl border border-[var(--kyro-border)] flex items-center justify-between">
|
|
255
|
+
<code className="text-[10px] font-mono opacity-60">https://api.kyro.io/v1</code>
|
|
256
|
+
<Copy className="w-3.5 h-3.5 opacity-0 group-hover:opacity-40 cursor-pointer transition-opacity" onClick={() => navigator.clipboard.writeText('https://api.kyro.io/v1')} />
|
|
257
|
+
</div>
|
|
249
258
|
</div>
|
|
250
259
|
</div>
|
|
251
|
-
<div>
|
|
252
|
-
<
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
+
<div className="space-y-2">
|
|
261
|
+
<div className="flex items-center justify-between">
|
|
262
|
+
<span className="text-xs font-bold">Draft Explorer</span>
|
|
263
|
+
<Badge variant="outline" className="text-[8px] font-bold uppercase py-0.5">Staging</Badge>
|
|
264
|
+
</div>
|
|
265
|
+
<div className="group relative">
|
|
266
|
+
<div className="absolute -inset-0.5 bg-gradient-to-r from-amber-500/30 to-transparent rounded-xl blur opacity-0 group-hover:opacity-100 transition-all"></div>
|
|
267
|
+
<div className="relative bg-[var(--kyro-bg)] p-3.5 rounded-xl border border-[var(--kyro-border)] flex items-center justify-between">
|
|
268
|
+
<code className="text-[10px] font-mono opacity-60">https://preview.kyro.io/v1</code>
|
|
269
|
+
<Copy className="w-3.5 h-3.5 opacity-0 group-hover:opacity-40 cursor-pointer transition-opacity" onClick={() => navigator.clipboard.writeText('https://preview.kyro.io/v1')} />
|
|
270
|
+
</div>
|
|
260
271
|
</div>
|
|
261
272
|
</div>
|
|
262
273
|
</div>
|
|
263
274
|
</div>
|
|
264
275
|
</section>
|
|
265
276
|
|
|
266
|
-
{/* Playground Explorer */}
|
|
267
|
-
<section className="xl:col-span-3
|
|
268
|
-
<div className="
|
|
269
|
-
<
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
277
|
+
{/* Playground Explorer - High Fidelity */}
|
|
278
|
+
<section className="xl:col-span-3 rounded-[3rem] border border-[var(--kyro-border)] bg-[var(--kyro-surface)]/50 p-10 space-y-10 overflow-hidden relative">
|
|
279
|
+
<div className="absolute top-0 right-0 p-20 opacity-[0.02] pointer-events-none">
|
|
280
|
+
<PlayCircle className="w-96 h-96" />
|
|
281
|
+
</div>
|
|
282
|
+
|
|
283
|
+
<div className="flex flex-col lg:flex-row lg:items-center justify-between gap-10 relative z-10">
|
|
284
|
+
<div className="max-w-xl">
|
|
285
|
+
<h2 className="text-3xl font-bold tracking-tighter flex items-center gap-4 mb-3">
|
|
286
|
+
<div className="w-12 h-12 bg-[var(--kyro-primary)]/10 rounded-2xl flex items-center justify-center">
|
|
287
|
+
<PlayCircle className="w-7 h-7 text-[var(--kyro-primary)]" />
|
|
288
|
+
</div>
|
|
289
|
+
API <span className="text-[var(--kyro-primary)]">Explorer</span>
|
|
274
290
|
</h2>
|
|
275
|
-
<p className="text-[var(--kyro-text-secondary)] text-sm font-medium opacity-60">
|
|
276
|
-
Test your endpoints and analyze response payloads
|
|
291
|
+
<p className="text-[var(--kyro-text-secondary)] text-sm font-medium opacity-60 leading-relaxed">
|
|
292
|
+
Test your collection endpoints and analyze live response payloads.
|
|
293
|
+
Enter a collection slug to fetch its latest documents.
|
|
277
294
|
</p>
|
|
278
295
|
</div>
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
296
|
+
|
|
297
|
+
<div className="flex items-center gap-4 flex-1 lg:max-w-2xl bg-[var(--kyro-bg)] p-2 rounded-[2rem] border border-[var(--kyro-border)] shadow-2xl">
|
|
298
|
+
<div className="flex-1 relative flex items-center pl-6">
|
|
299
|
+
<span className="text-[11px] font-bold opacity-30 uppercase tracking-widest mr-2 whitespace-nowrap">
|
|
300
|
+
GET {API_BASE}/
|
|
283
301
|
</span>
|
|
284
302
|
<input
|
|
285
303
|
type="text"
|
|
286
304
|
value={testEndpoint}
|
|
287
305
|
onChange={(e) => setTestEndpoint(e.target.value)}
|
|
288
306
|
placeholder="collection-slug"
|
|
289
|
-
className="w-full
|
|
307
|
+
className="w-full py-4 bg-transparent focus:outline-none font-mono text-sm font-bold text-[var(--kyro-primary)]"
|
|
290
308
|
/>
|
|
291
309
|
</div>
|
|
292
310
|
<button
|
|
293
311
|
type="button"
|
|
294
312
|
onClick={handleRunTest}
|
|
295
313
|
disabled={exploring || !testEndpoint}
|
|
296
|
-
className="px-
|
|
314
|
+
className="px-8 py-4 bg-[var(--kyro-primary)] text-white rounded-[1.5rem] font-bold text-sm shadow-xl disabled:opacity-50 disabled:cursor-not-allowed hover:scale-[1.02] transition-all flex items-center gap-3 shrink-0"
|
|
297
315
|
>
|
|
298
316
|
{exploring ? (
|
|
299
|
-
<RefreshCcw className="w-
|
|
317
|
+
<RefreshCcw className="w-4 h-4 animate-spin" />
|
|
300
318
|
) : (
|
|
301
|
-
<ChevronRight className="w-
|
|
319
|
+
<ChevronRight className="w-5 h-5" />
|
|
302
320
|
)}
|
|
303
|
-
|
|
321
|
+
Run Query
|
|
304
322
|
</button>
|
|
305
323
|
</div>
|
|
306
324
|
</div>
|
|
307
325
|
|
|
308
326
|
{playgroundResult ? (
|
|
309
|
-
<div className="animate-in fade-in
|
|
310
|
-
<div className="flex items-center
|
|
311
|
-
<
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
</
|
|
327
|
+
<div className="animate-in fade-in zoom-in-95 duration-500 relative z-10">
|
|
328
|
+
<div className="flex items-center justify-between mb-4 px-2">
|
|
329
|
+
<div className="flex items-center gap-3">
|
|
330
|
+
<div className="w-1 h-3 bg-[var(--kyro-primary)] rounded-full" />
|
|
331
|
+
<span className="text-[10px] font-bold uppercase tracking-[0.2em] opacity-40">Response Payload</span>
|
|
332
|
+
</div>
|
|
333
|
+
<Badge variant="outline" className="text-[9px] font-mono px-3">200 OK</Badge>
|
|
315
334
|
</div>
|
|
316
|
-
<div className="rounded-
|
|
335
|
+
<div className="rounded-[2rem] overflow-hidden border border-[var(--kyro-border)] shadow-2xl bg-[#090b10]">
|
|
336
|
+
<div className="flex items-center gap-2 px-6 py-4 bg-[#11141d] border-b border-[var(--kyro-border)]/50">
|
|
337
|
+
<div className="w-2.5 h-2.5 rounded-full bg-red-500/20" />
|
|
338
|
+
<div className="w-2.5 h-2.5 rounded-full bg-amber-500/20" />
|
|
339
|
+
<div className="w-2.5 h-2.5 rounded-full bg-green-500/20" />
|
|
340
|
+
</div>
|
|
317
341
|
<CodeMirror
|
|
318
342
|
value={JSON.stringify(playgroundResult, null, 2)}
|
|
319
|
-
height="
|
|
343
|
+
height="450px"
|
|
320
344
|
theme={aura}
|
|
321
345
|
extensions={[json()]}
|
|
322
346
|
editable={false}
|
|
@@ -325,10 +349,12 @@ export function DeveloperCenter({ collections }: { collections: any }) {
|
|
|
325
349
|
</div>
|
|
326
350
|
</div>
|
|
327
351
|
) : (
|
|
328
|
-
<div className="h-
|
|
329
|
-
<
|
|
330
|
-
|
|
331
|
-
|
|
352
|
+
<div className="h-80 rounded-[3rem] border-2 border-dashed border-[var(--kyro-border)] flex flex-col items-center justify-center bg-[var(--kyro-surface-accent)]/20 transition-all duration-700">
|
|
353
|
+
<div className="w-20 h-20 bg-[var(--kyro-surface)] rounded-3xl flex items-center justify-center shadow-lg border border-[var(--kyro-border)] mb-6 opacity-20">
|
|
354
|
+
<Code2 className="w-10 h-10" />
|
|
355
|
+
</div>
|
|
356
|
+
<p className="font-bold text-sm opacity-30 uppercase tracking-[0.2em]">
|
|
357
|
+
Awaiting request dispatch...
|
|
332
358
|
</p>
|
|
333
359
|
</div>
|
|
334
360
|
)}
|
|
@@ -339,66 +365,42 @@ export function DeveloperCenter({ collections }: { collections: any }) {
|
|
|
339
365
|
<Modal
|
|
340
366
|
open={showCreateModal}
|
|
341
367
|
onClose={() => setShowCreateModal(false)}
|
|
342
|
-
title="
|
|
368
|
+
title="Generate Access Token"
|
|
369
|
+
size="lg"
|
|
343
370
|
>
|
|
344
371
|
<ModalContent>
|
|
345
|
-
<
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
372
|
+
<div className="space-y-6">
|
|
373
|
+
<p className="text-sm text-[var(--kyro-text-secondary)] opacity-70 leading-relaxed">
|
|
374
|
+
Define a name for this API key to identify its integration context.
|
|
375
|
+
Keys are encrypted at rest and should be treated with extreme caution.
|
|
376
|
+
</p>
|
|
377
|
+
<div className="space-y-2">
|
|
378
|
+
<label className="text-xs font-bold uppercase tracking-widest opacity-40 px-1">Token Name</label>
|
|
379
|
+
<input
|
|
380
|
+
type="text"
|
|
381
|
+
value={newKeyName}
|
|
382
|
+
onChange={(e) => setNewKeyName(e.target.value)}
|
|
383
|
+
placeholder="e.g., Mobile App SDK, Production Server"
|
|
384
|
+
className="w-full px-6 py-4 bg-[var(--kyro-bg)] border border-[var(--kyro-border)] rounded-2xl text-[var(--kyro-text-primary)] focus:outline-none focus:border-[var(--kyro-primary)] shadow-sm transition-all"
|
|
385
|
+
onKeyDown={(e) => e.key === "Enter" && confirmGenerateKey()}
|
|
386
|
+
/>
|
|
387
|
+
</div>
|
|
388
|
+
</div>
|
|
356
389
|
</ModalContent>
|
|
357
390
|
<ModalActions>
|
|
358
391
|
<button
|
|
359
392
|
type="button"
|
|
360
393
|
onClick={() => setShowCreateModal(false)}
|
|
361
|
-
className="px-
|
|
394
|
+
className="px-6 py-3 rounded-xl font-bold text-sm border border-[var(--kyro-border)] text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)] transition-all"
|
|
362
395
|
>
|
|
363
396
|
Cancel
|
|
364
397
|
</button>
|
|
365
398
|
<button
|
|
366
399
|
type="button"
|
|
367
400
|
onClick={confirmGenerateKey}
|
|
368
|
-
className="px-
|
|
369
|
-
>
|
|
370
|
-
Create
|
|
371
|
-
</button>
|
|
372
|
-
</ModalActions>
|
|
373
|
-
</Modal>
|
|
374
|
-
|
|
375
|
-
{/* Delete Confirmation Modal */}
|
|
376
|
-
<Modal
|
|
377
|
-
open={showDeleteModal}
|
|
378
|
-
onClose={() => setShowDeleteModal(false)}
|
|
379
|
-
title="Revoke API Key"
|
|
380
|
-
variant="danger"
|
|
381
|
-
>
|
|
382
|
-
<ModalContent>
|
|
383
|
-
<p className="text-sm text-[var(--kyro-text-secondary)]">
|
|
384
|
-
Are you sure you want to revoke this key? Any integrations using it
|
|
385
|
-
will stop working.
|
|
386
|
-
</p>
|
|
387
|
-
</ModalContent>
|
|
388
|
-
<ModalActions>
|
|
389
|
-
<button
|
|
390
|
-
type="button"
|
|
391
|
-
onClick={() => setShowDeleteModal(false)}
|
|
392
|
-
className="px-4 py-2 rounded-lg font-medium text-sm border border-[var(--kyro-border)] text-[var(--kyro-text-secondary)] hover:bg-[var(--kyro-surface-accent)] hover:text-[var(--kyro-text-primary)] transition-colors"
|
|
393
|
-
>
|
|
394
|
-
Cancel
|
|
395
|
-
</button>
|
|
396
|
-
<button
|
|
397
|
-
type="button"
|
|
398
|
-
onClick={confirmRevokeKey}
|
|
399
|
-
className="px-4 py-2 rounded-lg font-medium text-sm bg-red-500 text-white hover:bg-red-600 transition-colors"
|
|
401
|
+
className="px-8 py-3 rounded-xl font-bold text-sm bg-[var(--kyro-primary)] text-white hover:opacity-90 shadow-lg shadow-[var(--kyro-primary)]/20 transition-all"
|
|
400
402
|
>
|
|
401
|
-
|
|
403
|
+
Generate Token
|
|
402
404
|
</button>
|
|
403
405
|
</ModalActions>
|
|
404
406
|
</Modal>
|