@kyro-cms/admin 0.12.20 → 0.12.22
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/index.cjs +24 -24
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +19 -19
- package/package.json +6 -6
- package/src/components/ApiKeysManager.tsx +177 -227
- package/src/components/AuditLogsPage.tsx +7 -7
- package/src/components/AuthorDashboard.tsx +235 -0
- package/src/components/AutoForm.tsx +14 -4
- package/src/components/CustomerDashboard.tsx +213 -0
- package/src/components/Dashboard.tsx +1 -1
- package/src/components/DashboardMetrics.tsx +74 -9
- package/src/components/DashboardQuickSections.tsx +237 -0
- package/src/components/ListView.tsx +3 -3
- package/src/components/MediaGallery.tsx +2 -2
- package/src/components/PluginsManager.tsx +1 -1
- package/src/components/SessionsManager.tsx +15 -15
- package/src/components/Sidebar.astro +564 -116
- package/src/components/UserManagement.tsx +43 -9
- package/src/components/UserMenu.tsx +123 -61
- package/src/components/autoform/AutoFormEditView.tsx +4 -4
- package/src/components/autoform/AutoFormHeader.tsx +2 -2
- package/src/components/ui/CommandPalette.tsx +1 -1
- package/src/components/ui/Dropdown.tsx +71 -16
- package/src/components/ui/PageHeader.tsx +1 -1
- package/src/components/ui/Pagination.tsx +1 -1
- package/src/components/ui/Toast.tsx +3 -2
- package/src/components/ui/Toaster.tsx +1 -1
- package/src/components/users/UserDetail.tsx +74 -29
- package/src/components/users/UserForm.tsx +1 -1
- package/src/components/users/UsersList.tsx +2 -2
- package/src/integration.ts +4 -0
- package/src/layouts/AdminLayout.astro +26 -34
- package/src/layouts/AuthLayout.astro +18 -9
- package/src/lib/auth-server.ts +99 -0
- package/src/pages/403.astro +54 -35
- package/src/pages/[collection]/[id].astro +8 -0
- package/src/pages/[collection]/index.astro +7 -0
- package/src/pages/audit/index.astro +4 -1
- package/src/pages/auth/check-email.astro +146 -0
- package/src/pages/auth/forgot-password.astro +95 -0
- package/src/pages/auth/login.astro +29 -12
- package/src/pages/auth/register.astro +38 -12
- package/src/pages/auth/reset-password.astro +125 -0
- package/src/pages/auth/verify-email.astro +87 -0
- package/src/pages/index.astro +220 -121
- package/src/pages/keys.astro +3 -1
- package/src/pages/media.astro +3 -1
- package/src/pages/preview/[collection]/[id].astro +23 -73
- package/src/pages/roles/index.astro +134 -101
- package/src/pages/settings/[slug].astro +43 -3
- package/src/pages/users/[id].astro +5 -1
- package/src/pages/users/index.astro +4 -0
- package/src/pages/users/new.astro +4 -0
- package/src/pages/webhooks.astro +3 -1
- package/src/routes.ts +16 -0
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
import AdminLayout from "../../layouts/AdminLayout.astro";
|
|
3
3
|
import i18next from "../../lib/i18n";
|
|
4
|
+
import { requireAuthServer } from "../../lib/auth-server";
|
|
5
|
+
|
|
6
|
+
const redirect = await requireAuthServer(Astro.request, { requireSuperAdmin: true });
|
|
7
|
+
if (redirect) return redirect;
|
|
4
8
|
|
|
5
9
|
const defaultRoles = [
|
|
6
10
|
{
|
|
@@ -58,52 +62,83 @@ const permissions: Record<string, string[]> = {
|
|
|
58
62
|
---
|
|
59
63
|
|
|
60
64
|
<AdminLayout title={i18next.t("pages." + "Roles".replace(/ /g, ""), { defaultValue: "Roles" })}>
|
|
61
|
-
<div class="flex-1 overflow-y-auto space-y-
|
|
65
|
+
<div class="flex-1 overflow-y-auto space-y-6">
|
|
62
66
|
<!-- Header -->
|
|
63
|
-
<div
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
<div
|
|
68
|
+
class="surface-tile p-6 rounded-lg border border-[var(--kyro-border)] flex flex-col md:flex-row md:items-center justify-between gap-4"
|
|
69
|
+
>
|
|
70
|
+
<div>
|
|
71
|
+
<h1 class="text-lg font-semibold text-[var(--kyro-text-primary)]">Roles & Access Control</h1>
|
|
72
|
+
<p class="text-xs text-[var(--kyro-text-secondary)] mt-0.5">
|
|
73
|
+
Role hierarchy, inheritance rules, and system-wide permission assignments.
|
|
74
|
+
</p>
|
|
75
|
+
</div>
|
|
76
|
+
<div
|
|
77
|
+
class="flex items-center gap-2 text-xs font-medium text-[var(--kyro-text-secondary)] bg-[var(--kyro-surface-accent)] px-3 py-1.5 rounded-lg border border-[var(--kyro-border)]"
|
|
78
|
+
>
|
|
79
|
+
<svg class="w-4 h-4 text-emerald-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
80
|
+
<path
|
|
81
|
+
stroke-linecap="round"
|
|
82
|
+
stroke-linejoin="round"
|
|
83
|
+
stroke-width="2"
|
|
84
|
+
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
|
|
85
|
+
></path>
|
|
86
|
+
</svg>
|
|
87
|
+
<span>6 System Roles Defined</span>
|
|
88
|
+
</div>
|
|
68
89
|
</div>
|
|
69
90
|
|
|
70
|
-
<!-- Role
|
|
91
|
+
<!-- Role Cards Grid -->
|
|
71
92
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
72
93
|
{
|
|
73
94
|
defaultRoles.map((role) => (
|
|
74
|
-
<div class=
|
|
75
|
-
<div
|
|
76
|
-
<
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
95
|
+
<div class="surface-tile p-5 rounded-lg border border-[var(--kyro-border)] flex flex-col justify-between transition-all hover:border-[var(--kyro-text-secondary)]/30">
|
|
96
|
+
<div>
|
|
97
|
+
<div class="flex items-center justify-between gap-2 mb-2">
|
|
98
|
+
<div class="flex items-center gap-2">
|
|
99
|
+
<h3 class="text-sm font-semibold text-[var(--kyro-text-primary)] capitalize">
|
|
100
|
+
{role.name.replace("_", " ")}
|
|
101
|
+
</h3>
|
|
102
|
+
{role.name === "super_admin" && (
|
|
103
|
+
<span class="px-2 py-0.5 text-[10px] font-semibold tracking-wide uppercase bg-amber-500/10 text-amber-600 dark:text-amber-400 rounded-md border border-amber-500/20">
|
|
104
|
+
Root
|
|
105
|
+
</span>
|
|
106
|
+
)}
|
|
107
|
+
</div>
|
|
108
|
+
<span class="px-2.5 py-0.5 rounded-full text-xs font-medium bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-secondary)] border border-[var(--kyro-border)]">
|
|
109
|
+
Lvl {role.level}
|
|
110
|
+
</span>
|
|
111
|
+
</div>
|
|
112
|
+
<p class="text-xs text-[var(--kyro-text-secondary)] leading-relaxed mb-4">{role.description}</p>
|
|
80
113
|
</div>
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
<
|
|
85
|
-
|
|
114
|
+
|
|
115
|
+
<div class="space-y-3 pt-3 border-t border-[var(--kyro-border)]">
|
|
116
|
+
{role.inherits.length > 0 && (
|
|
117
|
+
<div>
|
|
118
|
+
<span class="text-[11px] font-medium text-[var(--kyro-text-muted)] uppercase tracking-wider">
|
|
119
|
+
Inherits From
|
|
120
|
+
</span>
|
|
121
|
+
<div class="flex flex-wrap gap-1.5 mt-1">
|
|
122
|
+
{role.inherits.map((parent) => (
|
|
123
|
+
<span class="px-2 py-0.5 bg-[var(--kyro-surface-accent)] rounded text-xs font-mono font-medium text-[var(--kyro-text-secondary)] border border-[var(--kyro-border)]">
|
|
124
|
+
{parent}
|
|
125
|
+
</span>
|
|
126
|
+
))}
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
)}
|
|
130
|
+
<div>
|
|
131
|
+
<span class="text-[11px] font-medium text-[var(--kyro-text-muted)] uppercase tracking-wider">
|
|
132
|
+
Granted Scope
|
|
86
133
|
</span>
|
|
87
|
-
<div class="flex gap-
|
|
88
|
-
{role.
|
|
89
|
-
<span class="px-2 py-
|
|
90
|
-
{
|
|
134
|
+
<div class="flex flex-wrap gap-1 mt-1">
|
|
135
|
+
{(permissions[role.name] || []).map((perm) => (
|
|
136
|
+
<span class="px-2 py-0.5 bg-[var(--kyro-surface-accent)] rounded text-[11px] font-mono text-[var(--kyro-text-primary)] border border-[var(--kyro-border)]">
|
|
137
|
+
{perm}
|
|
91
138
|
</span>
|
|
92
139
|
))}
|
|
93
140
|
</div>
|
|
94
141
|
</div>
|
|
95
|
-
)}
|
|
96
|
-
<div>
|
|
97
|
-
<span class="text-xs font-bold text-[var(--kyro-text-secondary)] tracking-[0.1em] opacity-50">
|
|
98
|
-
Permissions:
|
|
99
|
-
</span>
|
|
100
|
-
<div class="flex flex-wrap gap-1.5 mt-2">
|
|
101
|
-
{(permissions[role.name] || []).map((perm) => (
|
|
102
|
-
<span class="px-2 py-0.5 bg-[var(--kyro-surface-accent)] rounded text-[10px] font-medium text-[var(--kyro-text-primary)]">
|
|
103
|
-
{perm}
|
|
104
|
-
</span>
|
|
105
|
-
))}
|
|
106
|
-
</div>
|
|
107
142
|
</div>
|
|
108
143
|
</div>
|
|
109
144
|
))
|
|
@@ -111,75 +146,73 @@ const permissions: Record<string, string[]> = {
|
|
|
111
146
|
</div>
|
|
112
147
|
|
|
113
148
|
<!-- Permission Matrix -->
|
|
114
|
-
<div class="surface-tile overflow-hidden">
|
|
115
|
-
<div class="p-
|
|
116
|
-
<h2 class="text-
|
|
149
|
+
<div class="surface-tile rounded-lg border border-[var(--kyro-border)] overflow-hidden">
|
|
150
|
+
<div class="p-5 border-b border-[var(--kyro-border)]">
|
|
151
|
+
<h2 class="text-sm font-semibold text-[var(--kyro-text-primary)]">Permission Matrix</h2>
|
|
152
|
+
<p class="text-xs text-[var(--kyro-text-secondary)] mt-0.5">
|
|
153
|
+
Resource capability distribution across system roles
|
|
154
|
+
</p>
|
|
117
155
|
</div>
|
|
118
|
-
<
|
|
119
|
-
<
|
|
120
|
-
<
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
</tr>
|
|
126
|
-
</thead>
|
|
127
|
-
<tbody class="divide-y divide-[var(--kyro-border)]">
|
|
128
|
-
{
|
|
129
|
-
[
|
|
156
|
+
<div class="overflow-x-auto">
|
|
157
|
+
<table class="w-full text-left border-collapse">
|
|
158
|
+
<thead>
|
|
159
|
+
<tr
|
|
160
|
+
class="bg-[var(--kyro-surface-accent)] border-b border-[var(--kyro-border)] text-xs font-medium text-[var(--kyro-text-secondary)]"
|
|
161
|
+
>
|
|
162
|
+
<th class="px-5 py-3">Resource</th>
|
|
130
163
|
{
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
resource: "Media",
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
<
|
|
169
|
-
fill
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
)
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
</
|
|
182
|
-
</
|
|
164
|
+
defaultRoles.map((role) => (
|
|
165
|
+
<th class="px-4 py-3 text-center capitalize font-semibold">{role.name.replace("_", " ")}</th>
|
|
166
|
+
))
|
|
167
|
+
}
|
|
168
|
+
</tr>
|
|
169
|
+
</thead>
|
|
170
|
+
<tbody class="divide-y divide-[var(--kyro-border)] text-xs">
|
|
171
|
+
{
|
|
172
|
+
[
|
|
173
|
+
{ resource: "Users", key: "users" },
|
|
174
|
+
{ resource: "Roles & Access", key: "roles" },
|
|
175
|
+
{ resource: "Content Collections", key: "content" },
|
|
176
|
+
{ resource: "Media Library", key: "media" },
|
|
177
|
+
{ resource: "Global Settings", key: "settings" },
|
|
178
|
+
{ resource: "Audit Logs", key: "audit" },
|
|
179
|
+
].map((row) => (
|
|
180
|
+
<tr class="hover:bg-[var(--kyro-surface-accent)]/50 transition-colors">
|
|
181
|
+
<td class="px-5 py-3 font-medium text-[var(--kyro-text-primary)]">{row.resource}</td>
|
|
182
|
+
{defaultRoles.map((role) => {
|
|
183
|
+
const hasAll = permissions[role.name]?.includes("*");
|
|
184
|
+
const hasResource = permissions[role.name]?.some(
|
|
185
|
+
(p) => p.startsWith(row.key + ":") || p === "*" || p.startsWith(row.resource.toLowerCase() + ":"),
|
|
186
|
+
);
|
|
187
|
+
return (
|
|
188
|
+
<td class="px-4 py-3 text-center">
|
|
189
|
+
{hasAll || hasResource ? (
|
|
190
|
+
<span class="inline-flex items-center justify-center w-5 h-5 rounded-full bg-emerald-500/10 text-emerald-600 dark:text-emerald-400">
|
|
191
|
+
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
192
|
+
<path
|
|
193
|
+
stroke-linecap="round"
|
|
194
|
+
stroke-linejoin="round"
|
|
195
|
+
stroke-width="2.5"
|
|
196
|
+
d="M5 13l4 4L19 7"
|
|
197
|
+
/>
|
|
198
|
+
</svg>
|
|
199
|
+
</span>
|
|
200
|
+
) : (
|
|
201
|
+
<span class="inline-flex items-center justify-center w-5 h-5 rounded-full bg-[var(--kyro-surface-accent)] text-[var(--kyro-text-muted)] opacity-50">
|
|
202
|
+
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
203
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 12H4" />
|
|
204
|
+
</svg>
|
|
205
|
+
</span>
|
|
206
|
+
)}
|
|
207
|
+
</td>
|
|
208
|
+
);
|
|
209
|
+
})}
|
|
210
|
+
</tr>
|
|
211
|
+
))
|
|
212
|
+
}
|
|
213
|
+
</tbody>
|
|
214
|
+
</table>
|
|
215
|
+
</div>
|
|
183
216
|
</div>
|
|
184
217
|
</div>
|
|
185
218
|
</AdminLayout>
|
|
@@ -6,6 +6,10 @@ import { SettingsPage } from "../../components/SettingsPage";
|
|
|
6
6
|
import { getGlobal } from "../../lib/globals";
|
|
7
7
|
|
|
8
8
|
import { adminPath } from "../../lib/paths";
|
|
9
|
+
import { requireAuthServer } from "../../lib/auth-server";
|
|
10
|
+
|
|
11
|
+
const redirect = await requireAuthServer(Astro.request, { requireAdmin: true });
|
|
12
|
+
if (redirect) return redirect;
|
|
9
13
|
|
|
10
14
|
const slug = Astro.props.slug || Astro.params.slug || Astro.params.id;
|
|
11
15
|
|
|
@@ -30,7 +34,7 @@ const description =
|
|
|
30
34
|
<AdminLayout title={`Settings - ${title}`}>
|
|
31
35
|
<div class="flex-1 overflow-y-auto">
|
|
32
36
|
{ !hasVersioning && (
|
|
33
|
-
<div class="surface-tile p-8 pb-0 mb-6">
|
|
37
|
+
<div class="surface-tile p-8 pb-0 mb-6 rounded-lg">
|
|
34
38
|
<div class="flex items-center justify-between mb-8">
|
|
35
39
|
<div>
|
|
36
40
|
<h1
|
|
@@ -61,6 +65,7 @@ const description =
|
|
|
61
65
|
allGlobals.map((g) => (
|
|
62
66
|
<a
|
|
63
67
|
href={`${adminPath}/settings/${g.slug}`}
|
|
68
|
+
data-global-tab={g.slug}
|
|
64
69
|
class={`pb-4 text-sm font-bold transition-all border-b-2 whitespace-nowrap ${
|
|
65
70
|
activeSlug === g.slug
|
|
66
71
|
? "text-[var(--kyro-text-primary)] border-[var(--kyro-text-primary)]"
|
|
@@ -76,7 +81,7 @@ const description =
|
|
|
76
81
|
)}
|
|
77
82
|
|
|
78
83
|
<!-- Form Section -->
|
|
79
|
-
<div class={hasVersioning ? "" : "surface-tile p-10 pt-4 mb-6 rounded-
|
|
84
|
+
<div class={hasVersioning ? "" : "surface-tile p-10 pt-4 mb-6 rounded-lg"}>
|
|
80
85
|
{ !hasVersioning && (
|
|
81
86
|
<div class="mb-8">
|
|
82
87
|
<h2
|
|
@@ -120,7 +125,42 @@ const description =
|
|
|
120
125
|
});
|
|
121
126
|
};
|
|
122
127
|
|
|
123
|
-
|
|
128
|
+
const pruneGlobalTabs = (user?: any, permissions?: any) => {
|
|
129
|
+
if (!user) {
|
|
130
|
+
// @ts-ignore
|
|
131
|
+
user = window.__kyroAuth?.user;
|
|
132
|
+
// @ts-ignore
|
|
133
|
+
permissions = window.__kyroAuth?.permissions;
|
|
134
|
+
}
|
|
135
|
+
if (!user) return;
|
|
136
|
+
const userRole = user.role || "";
|
|
137
|
+
const isAdmin = userRole === "admin" || userRole === "super_admin";
|
|
138
|
+
|
|
139
|
+
const tabs = document.querySelectorAll("[data-global-tab]");
|
|
140
|
+
tabs.forEach((tab) => {
|
|
141
|
+
const globalSlug = tab.getAttribute("data-global-tab");
|
|
142
|
+
if (!globalSlug) return;
|
|
143
|
+
const hasRead = isAdmin || permissions?.globals?.[globalSlug]?.read === true;
|
|
144
|
+
if (!hasRead) {
|
|
145
|
+
(tab as HTMLElement).style.display = "none";
|
|
146
|
+
} else {
|
|
147
|
+
(tab as HTMLElement).style.display = "";
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const runInitAndPrune = () => {
|
|
153
|
+
initSettingsPage();
|
|
154
|
+
pruneGlobalTabs();
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
document.addEventListener("astro:page-load", runInitAndPrune);
|
|
158
|
+
runInitAndPrune();
|
|
159
|
+
|
|
160
|
+
window.addEventListener("kyro:auth-ready", (event: any) => {
|
|
161
|
+
const { user, permissions } = event.detail || {};
|
|
162
|
+
pruneGlobalTabs(user, permissions);
|
|
163
|
+
});
|
|
124
164
|
|
|
125
165
|
// Global listeners should only be attached once
|
|
126
166
|
// @ts-ignore
|
|
@@ -4,6 +4,10 @@ import i18next from '../../lib/i18n';
|
|
|
4
4
|
import { UserDetail } from "../../components/users/UserDetail";
|
|
5
5
|
|
|
6
6
|
import { adminPath, apiPath } from "../../lib/paths";
|
|
7
|
+
import { requireAuthServer } from "../../lib/auth-server";
|
|
8
|
+
|
|
9
|
+
const redirect = await requireAuthServer(Astro.request, { collectionRead: 'users' });
|
|
10
|
+
if (redirect) return redirect;
|
|
7
11
|
|
|
8
12
|
const { id } = Astro.params;
|
|
9
13
|
let user: any = null;
|
|
@@ -39,7 +43,7 @@ if (id) {
|
|
|
39
43
|
</div>
|
|
40
44
|
) : user ? (
|
|
41
45
|
<UserDetail
|
|
42
|
-
client:
|
|
46
|
+
client:only="react"
|
|
43
47
|
user={user}
|
|
44
48
|
apiPath={apiPath}
|
|
45
49
|
adminPath={adminPath}
|
|
@@ -4,6 +4,10 @@ import i18next from '../../lib/i18n';
|
|
|
4
4
|
import { UsersList } from "../../components/users/UsersList";
|
|
5
5
|
|
|
6
6
|
import { adminPath, apiPath } from "../../lib/paths";
|
|
7
|
+
import { requireAuthServer } from "../../lib/auth-server";
|
|
8
|
+
|
|
9
|
+
const redirect = await requireAuthServer(Astro.request, { collectionRead: 'users' });
|
|
10
|
+
if (redirect) return redirect;
|
|
7
11
|
|
|
8
12
|
let users: any[] = [];
|
|
9
13
|
let totalUsers = 0;
|
|
@@ -4,6 +4,10 @@ import i18next from '../../lib/i18n';
|
|
|
4
4
|
import { UserForm } from "../../components/users/UserForm";
|
|
5
5
|
|
|
6
6
|
import { adminPath, apiPath } from "../../lib/paths";
|
|
7
|
+
import { requireAuthServer } from "../../lib/auth-server";
|
|
8
|
+
|
|
9
|
+
const redirect = await requireAuthServer(Astro.request, { collectionCreate: 'users' });
|
|
10
|
+
if (redirect) return redirect;
|
|
7
11
|
---
|
|
8
12
|
|
|
9
13
|
<AdminLayout title={i18next.t("pages." + "New User".replace(/ /g, ""), { defaultValue: "New User" })}>
|
package/src/pages/webhooks.astro
CHANGED
|
@@ -3,8 +3,10 @@ import AdminLayout from "../layouts/AdminLayout.astro";
|
|
|
3
3
|
import i18next from '../lib/i18n';
|
|
4
4
|
import { WebhookManager } from "../components/WebhookManager";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { requireAuthServer } from '../lib/auth-server';
|
|
7
7
|
|
|
8
|
+
const redirect = await requireAuthServer(Astro.request, { requireAdmin: true });
|
|
9
|
+
if (redirect) return redirect;
|
|
8
10
|
---
|
|
9
11
|
|
|
10
12
|
<AdminLayout title={i18next.t("pages." + "Webhooks".replace(/ /g, ""), { defaultValue: "Webhooks" })}>
|
package/src/routes.ts
CHANGED
|
@@ -32,6 +32,22 @@ export const ADMIN_ROUTES = [
|
|
|
32
32
|
pattern: "/register",
|
|
33
33
|
entrypoint: "@kyro-cms/admin/src/pages/auth/register.astro",
|
|
34
34
|
},
|
|
35
|
+
{
|
|
36
|
+
pattern: "/auth/check-email",
|
|
37
|
+
entrypoint: "@kyro-cms/admin/src/pages/auth/check-email.astro",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
pattern: "/auth/forgot-password",
|
|
41
|
+
entrypoint: "@kyro-cms/admin/src/pages/auth/forgot-password.astro",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
pattern: "/auth/reset-password",
|
|
45
|
+
entrypoint: "@kyro-cms/admin/src/pages/auth/reset-password.astro",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
pattern: "/auth/verify-email",
|
|
49
|
+
entrypoint: "@kyro-cms/admin/src/pages/auth/verify-email.astro",
|
|
50
|
+
},
|
|
35
51
|
{ pattern: "/media", entrypoint: "@kyro-cms/admin/src/pages/media.astro" },
|
|
36
52
|
{
|
|
37
53
|
pattern: "/users",
|