@actuate-media/cms-admin 0.14.1 → 0.15.0
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/actuate-admin.css +1 -1
- package/dist/layout/Header.d.ts +14 -1
- package/dist/layout/Header.d.ts.map +1 -1
- package/dist/layout/Header.js +10 -3
- package/dist/layout/Header.js.map +1 -1
- package/dist/layout/Layout.d.ts.map +1 -1
- package/dist/layout/Layout.js +50 -2
- package/dist/layout/Layout.js.map +1 -1
- package/dist/layout/Sidebar.d.ts +7 -0
- package/dist/layout/Sidebar.d.ts.map +1 -1
- package/dist/layout/Sidebar.js +121 -46
- package/dist/layout/Sidebar.js.map +1 -1
- package/dist/views/Dashboard.d.ts.map +1 -1
- package/dist/views/Dashboard.js +136 -62
- package/dist/views/Dashboard.js.map +1 -1
- package/package.json +2 -2
- package/src/layout/Header.tsx +90 -43
- package/src/layout/Layout.tsx +110 -1
- package/src/layout/Sidebar.tsx +218 -98
- package/src/views/Dashboard.tsx +258 -131
package/dist/layout/Sidebar.d.ts
CHANGED
|
@@ -11,6 +11,13 @@ export interface NavItem {
|
|
|
11
11
|
path: string;
|
|
12
12
|
label: string;
|
|
13
13
|
icon: LucideIcon;
|
|
14
|
+
/**
|
|
15
|
+
* Section header. Items sharing the same `group` are grouped together
|
|
16
|
+
* under a header rendered on first encounter. Items without a `group`
|
|
17
|
+
* render at the top of the nav in document order.
|
|
18
|
+
*/
|
|
14
19
|
group?: string;
|
|
20
|
+
/** Indented children rendered immediately after this item. */
|
|
21
|
+
children?: NavItem[];
|
|
15
22
|
}
|
|
16
23
|
//# sourceMappingURL=Sidebar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../src/layout/Sidebar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../src/layout/Sidebar.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AA6G9C,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAA;IAClB,gBAAgB,EAAE,MAAM,IAAI,CAAA;IAC5B,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,MAAM,CAAC,EAAE,GAAG,CAAA;CACb;AAED,wBAAgB,OAAO,CAAC,EACtB,SAAS,EACT,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,MAAM,GACP,EAAE,YAAY,2CA+Cd;AAkGD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,UAAU,CAAA;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAA;CACrB"}
|
package/dist/layout/Sidebar.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { LayoutDashboard, FileText, File, Image, Settings,
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { LayoutDashboard, FileText, File, Image, Settings, ClipboardList, Users, Search as SearchIcon, Briefcase, FolderOpen, BookOpen, HelpCircle, Newspaper, PanelTop, PanelBottom, Layers, Code2, Library, KeyRound, PanelLeftClose, PanelLeftOpen, } from 'lucide-react';
|
|
4
4
|
import { ActuateBrandLogo } from '../assets/actuate-logo.js';
|
|
5
5
|
/**
|
|
6
6
|
* Compact mark used in the collapsed sidebar — just the "C" symbol from the
|
|
@@ -9,11 +9,6 @@ import { ActuateBrandLogo } from '../assets/actuate-logo.js';
|
|
|
9
9
|
function ActuateMark({ className }) {
|
|
10
10
|
return (_jsxs("svg", { viewBox: "0 0 40 44", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: className, "aria-hidden": "true", children: [_jsx("polygon", { points: "20,2 6,18 12,18 20,8 28,18 34,18", fill: "#F05E65" }), _jsx("rect", { x: "11", y: "20", width: "4", height: "22", rx: "1", fill: "#F05E65" }), _jsx("rect", { x: "18", y: "20", width: "4", height: "22", rx: "1", fill: "#F05E65" }), _jsx("rect", { x: "25", y: "20", width: "4", height: "22", rx: "1", fill: "#F05E65" })] }));
|
|
11
11
|
}
|
|
12
|
-
/**
|
|
13
|
-
* Full Actuate Media lockup. Inline SVG with a transparent background so it
|
|
14
|
-
* sits naturally on whatever surface the sidebar uses (light or dark theme,
|
|
15
|
-
* custom branding background, etc.).
|
|
16
|
-
*/
|
|
17
12
|
function ActuateWordmark({ className }) {
|
|
18
13
|
return _jsx(ActuateBrandLogo, { className: className });
|
|
19
14
|
}
|
|
@@ -40,80 +35,160 @@ function BrandLogo({ config, collapsed }) {
|
|
|
40
35
|
return _jsx(ActuateMark, { className: "h-8 w-8" });
|
|
41
36
|
}
|
|
42
37
|
if (customLogo) {
|
|
43
|
-
return (_jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [_jsx("img", { src: customLogo, alt: brandName ?? 'Admin', className: "h-8 w-auto shrink-0 object-contain" }), brandName && (_jsx("span", { className: "text-sidebar-foreground truncate text-sm font-
|
|
38
|
+
return (_jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [_jsx("img", { src: customLogo, alt: brandName ?? 'Admin', className: "h-8 w-auto shrink-0 object-contain" }), brandName && (_jsx("span", { className: "text-sidebar-foreground truncate text-sm font-medium", children: brandName }))] }));
|
|
44
39
|
}
|
|
45
40
|
if (brandName) {
|
|
46
|
-
return (_jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [_jsx(ActuateMark, { className: "h-7 w-7 shrink-0" }), _jsx("span", { className: "text-sidebar-foreground truncate text-sm font-
|
|
41
|
+
return (_jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [_jsx(ActuateMark, { className: "h-7 w-7 shrink-0" }), _jsx("span", { className: "text-sidebar-foreground truncate text-sm font-medium", children: brandName })] }));
|
|
47
42
|
}
|
|
48
43
|
return _jsx(ActuateWordmark, { className: "h-9" });
|
|
49
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Nav tree for the default (config-less) install. Mirrors the reference
|
|
47
|
+
* dashboard exactly: Dashboard / Posts / Pages (with Saved Sections +
|
|
48
|
+
* Templates as nested children), then a CONTENT group (Media / Forms /
|
|
49
|
+
* SEO / Script Tags), then a SETTINGS group (Users / API Keys /
|
|
50
|
+
* Settings). The group ordering is meaningful — the renderer emits a
|
|
51
|
+
* section header the first time it sees a new group.
|
|
52
|
+
*/
|
|
50
53
|
const defaultNavItems = [
|
|
51
54
|
{ path: '/', label: 'Dashboard', icon: LayoutDashboard },
|
|
52
|
-
{ path: '/pages', label: 'Pages', icon: File },
|
|
53
55
|
{ path: '/posts', label: 'Posts', icon: FileText },
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
{
|
|
57
|
+
path: '/pages',
|
|
58
|
+
label: 'Pages',
|
|
59
|
+
icon: File,
|
|
60
|
+
children: [
|
|
61
|
+
{ path: '/saved-sections', label: 'Saved Sections', icon: Library },
|
|
62
|
+
{ path: '/page-templates', label: 'Templates', icon: Layers },
|
|
63
|
+
],
|
|
64
|
+
},
|
|
65
|
+
{ path: '/media', label: 'Media', icon: Image, group: 'Content' },
|
|
66
|
+
{ path: '/forms', label: 'Forms', icon: ClipboardList, group: 'Content' },
|
|
67
|
+
{ path: '/seo', label: 'SEO', icon: SearchIcon, group: 'Content' },
|
|
68
|
+
{ path: '/script-tags', label: 'Script Tags', icon: Code2, group: 'Content' },
|
|
69
|
+
{ path: '/users', label: 'Users', icon: Users, group: 'Settings' },
|
|
70
|
+
{ path: '/api-keys', label: 'API Keys', icon: KeyRound, group: 'Settings' },
|
|
71
|
+
{ path: '/settings', label: 'Settings', icon: Settings, group: 'Settings' },
|
|
60
72
|
];
|
|
61
73
|
export function Sidebar({ collapsed, onToggleCollapse, currentPath, onNavigate, config, }) {
|
|
62
74
|
const navItems = buildNavItems(config);
|
|
63
|
-
return (_jsxs("aside", { className: `bg-sidebar border-sidebar-border h-full border-r transition-all duration-200 ${collapsed ? 'w-20' : 'w-64'}`, children: [
|
|
64
|
-
const Icon = item.icon;
|
|
65
|
-
const isActive = currentPath === item.path || (item.path !== '/' && currentPath.startsWith(item.path));
|
|
66
|
-
const prevGroup = idx > 0 ? navItems[idx - 1]?.group : undefined;
|
|
67
|
-
const showGroupLabel = item.group && item.group !== prevGroup;
|
|
68
|
-
return (_jsxs("div", { children: [showGroupLabel && !collapsed && (_jsx("div", { className: "px-3 pt-3 pb-1", children: _jsx("span", { className: "text-sidebar-foreground/50 text-[10px] font-semibold tracking-wider uppercase", children: item.group }) })), showGroupLabel && collapsed && (_jsx("div", { className: "flex justify-center pt-2 pb-1", children: _jsx("span", { className: "border-sidebar-foreground/20 w-4 border-t" }) })), _jsxs("button", { onClick: () => onNavigate(item.path), className: `flex w-full items-center gap-3 rounded-lg px-3 py-2.5 text-left transition-colors ${isActive
|
|
69
|
-
? 'bg-sidebar-accent text-sidebar-primary'
|
|
70
|
-
: 'text-sidebar-foreground hover:bg-sidebar-accent'} ${collapsed ? 'justify-center' : ''}`, title: collapsed ? item.label : '', children: [_jsx(Icon, { className: "h-5 w-5 shrink-0" }), !collapsed && _jsx("span", { className: "text-sm font-medium", children: item.label })] })] }, item.path));
|
|
71
|
-
}) })] }));
|
|
75
|
+
return (_jsxs("aside", { className: `bg-sidebar border-sidebar-border flex h-full flex-col border-r transition-all duration-200 ${collapsed ? 'w-20' : 'w-64'}`, children: [_jsx("div", { className: `border-sidebar-border flex h-14 shrink-0 items-center border-b px-4 ${collapsed ? 'justify-center' : ''}`, children: _jsx(BrandLogo, { config: config, collapsed: collapsed }) }), _jsx("nav", { className: "flex-1 space-y-1 overflow-y-auto p-3", "aria-label": "Primary", children: renderNavTree(navItems, { collapsed, currentPath, onNavigate }) }), _jsx("div", { className: "border-sidebar-border hidden shrink-0 border-t p-3 md:block", children: _jsx("button", { onClick: onToggleCollapse, className: `text-sidebar-foreground/80 hover:bg-sidebar-accent hover:text-sidebar-foreground flex w-full items-center gap-2.5 rounded-lg px-3 py-2 text-sm transition-colors ${collapsed ? 'justify-center' : ''}`, "aria-label": collapsed ? 'Expand sidebar' : 'Collapse sidebar', title: collapsed ? 'Expand sidebar' : 'Collapse sidebar', children: collapsed ? (_jsx(PanelLeftOpen, { className: "h-4 w-4 shrink-0", "aria-hidden": true })) : (_jsxs(_Fragment, { children: [_jsx(PanelLeftClose, { className: "h-4 w-4 shrink-0", "aria-hidden": true }), _jsx("span", { className: "font-medium", children: "Collapse sidebar" })] })) }) })] }));
|
|
72
76
|
}
|
|
77
|
+
function isPathActive(currentPath, itemPath) {
|
|
78
|
+
if (itemPath === '/')
|
|
79
|
+
return currentPath === '/';
|
|
80
|
+
// Use boundary match so /pages doesn't match /pages-something. Exact, or
|
|
81
|
+
// followed by a `/` separator.
|
|
82
|
+
return currentPath === itemPath || currentPath.startsWith(itemPath + '/');
|
|
83
|
+
}
|
|
84
|
+
function renderNavTree(items, ctx) {
|
|
85
|
+
const nodes = [];
|
|
86
|
+
let lastGroup = undefined;
|
|
87
|
+
for (const item of items) {
|
|
88
|
+
if (item.group && item.group !== lastGroup) {
|
|
89
|
+
nodes.push(ctx.collapsed ? (_jsx("div", { className: "flex justify-center pt-3 pb-1", children: _jsx("span", { className: "border-sidebar-foreground/20 w-4 border-t", "aria-hidden": true }) }, `g-${item.group}`)) : (_jsx("div", { className: "px-3 pt-4 pb-1", children: _jsx("span", { className: "text-sidebar-foreground/55 text-[10px] font-semibold tracking-wider uppercase", children: item.group }) }, `g-${item.group}`)));
|
|
90
|
+
lastGroup = item.group;
|
|
91
|
+
}
|
|
92
|
+
else if (!item.group) {
|
|
93
|
+
lastGroup = undefined;
|
|
94
|
+
}
|
|
95
|
+
nodes.push(_jsx(NavLink, { item: item, ctx: ctx }, item.path));
|
|
96
|
+
if (item.children && item.children.length > 0 && !ctx.collapsed) {
|
|
97
|
+
for (const child of item.children) {
|
|
98
|
+
nodes.push(_jsx(NavLink, { item: child, ctx: ctx, nested: true }, child.path));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return nodes;
|
|
103
|
+
}
|
|
104
|
+
function NavLink({ item, ctx, nested = false, }) {
|
|
105
|
+
const Icon = item.icon;
|
|
106
|
+
const isActive = isPathActive(ctx.currentPath, item.path);
|
|
107
|
+
return (_jsxs("button", { onClick: () => ctx.onNavigate(item.path), className: `flex w-full items-center gap-3 rounded-lg text-left transition-colors ${nested ? 'py-1.5 pr-3 pl-9' : 'px-3 py-2.5'} ${isActive
|
|
108
|
+
? 'bg-sidebar-accent text-sidebar-primary'
|
|
109
|
+
: 'text-sidebar-foreground hover:bg-sidebar-accent'} ${ctx.collapsed ? 'justify-center px-3' : ''}`, title: ctx.collapsed ? item.label : '', "aria-current": isActive ? 'page' : undefined, children: [!nested && _jsx(Icon, { className: "h-5 w-5 shrink-0", "aria-hidden": true }), nested && !ctx.collapsed && (_jsx(Icon, { className: "text-sidebar-foreground/60 h-4 w-4 shrink-0", "aria-hidden": true })), !ctx.collapsed && (_jsx("span", { className: `truncate font-medium ${nested ? 'text-[13px]' : 'text-sm'}`, children: item.label }))] }));
|
|
110
|
+
}
|
|
111
|
+
// ─── Config-driven nav builder ──────────────────────────────────────────────
|
|
73
112
|
function resolveIcon(collection) {
|
|
74
113
|
const mapped = collection.admin?.icon ? ICON_MAP[collection.admin.icon] : undefined;
|
|
75
114
|
if (mapped)
|
|
76
115
|
return mapped;
|
|
77
116
|
return collection.type === 'page' ? File : FileText;
|
|
78
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Build the sidebar nav tree from the CMS config. If no collections are
|
|
120
|
+
* configured, returns the curated `defaultNavItems` tree. When
|
|
121
|
+
* collections ARE configured, page-type collections inherit the
|
|
122
|
+
* Pages / Saved Sections / Templates child block, and every static
|
|
123
|
+
* destination (Media, Forms, SEO, Script Tags, Users, API Keys,
|
|
124
|
+
* Settings) is anchored under the right Content / Settings group.
|
|
125
|
+
*/
|
|
79
126
|
function buildNavItems(config) {
|
|
80
127
|
if (!config?.collections)
|
|
81
128
|
return defaultNavItems;
|
|
82
129
|
const raw = config.collections;
|
|
83
130
|
const collectionsList = Array.isArray(raw) ? raw : Object.values(raw);
|
|
84
131
|
const visible = collectionsList.filter((c) => !c.admin?.hidden);
|
|
85
|
-
const
|
|
132
|
+
const pages = visible.filter((c) => c.type === 'page' && !c.admin?.group);
|
|
133
|
+
const posts = visible.filter((c) => c.type === 'post' && !c.admin?.group);
|
|
134
|
+
const otherUngrouped = visible.filter((c) => c.type !== 'page' && c.type !== 'post' && !c.admin?.group);
|
|
86
135
|
const grouped = visible.filter((c) => c.admin?.group);
|
|
87
|
-
const pages = ungrouped.filter((c) => c.type === 'page');
|
|
88
|
-
const posts = ungrouped.filter((c) => c.type === 'post');
|
|
89
|
-
const other = ungrouped.filter((c) => c.type !== 'page' && c.type !== 'post');
|
|
90
|
-
const sortedUngrouped = [...pages, ...posts, ...other];
|
|
91
136
|
const items = [{ path: '/', label: 'Dashboard', icon: LayoutDashboard }];
|
|
92
|
-
|
|
137
|
+
// Posts-style collections come first (mirrors the reference layout).
|
|
138
|
+
for (const collection of posts) {
|
|
93
139
|
items.push({
|
|
94
140
|
label: collection.labels?.plural ?? collection.slug,
|
|
95
141
|
path: `/${collection.slug}`,
|
|
96
142
|
icon: resolveIcon(collection),
|
|
97
143
|
});
|
|
98
144
|
}
|
|
99
|
-
|
|
145
|
+
// Pages-style collections get the nested Saved Sections + Templates
|
|
146
|
+
// tree. We attach the children to the *first* page-type collection
|
|
147
|
+
// so we don't end up with three "Saved Sections" links if a project
|
|
148
|
+
// configures multiple page collections — admins editing custom
|
|
149
|
+
// page-style content still navigate to those secondary surfaces via
|
|
150
|
+
// the primary Pages parent.
|
|
151
|
+
pages.forEach((collection, idx) => {
|
|
152
|
+
const item = {
|
|
153
|
+
label: collection.labels?.plural ?? collection.slug,
|
|
154
|
+
path: `/${collection.slug}`,
|
|
155
|
+
icon: resolveIcon(collection),
|
|
156
|
+
};
|
|
157
|
+
if (idx === 0) {
|
|
158
|
+
item.children = [
|
|
159
|
+
{ path: '/saved-sections', label: 'Saved Sections', icon: Library },
|
|
160
|
+
{ path: '/page-templates', label: 'Templates', icon: Layers },
|
|
161
|
+
];
|
|
162
|
+
}
|
|
163
|
+
items.push(item);
|
|
164
|
+
});
|
|
165
|
+
for (const collection of otherUngrouped) {
|
|
166
|
+
items.push({
|
|
167
|
+
label: collection.labels?.plural ?? collection.slug,
|
|
168
|
+
path: `/${collection.slug}`,
|
|
169
|
+
icon: resolveIcon(collection),
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
// Config-supplied groups land before our standard Content/Settings
|
|
173
|
+
// groups so admin-defined sections take precedence.
|
|
174
|
+
const groupBuckets = new Map();
|
|
100
175
|
for (const col of grouped) {
|
|
101
176
|
const group = col.admin.group;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
path: `/${collection.slug}`,
|
|
111
|
-
icon: resolveIcon(collection),
|
|
112
|
-
group: groupName,
|
|
113
|
-
});
|
|
114
|
-
}
|
|
177
|
+
const bucket = groupBuckets.get(group) ?? [];
|
|
178
|
+
bucket.push({
|
|
179
|
+
label: col.labels?.plural ?? col.slug,
|
|
180
|
+
path: `/${col.slug}`,
|
|
181
|
+
icon: resolveIcon(col),
|
|
182
|
+
group,
|
|
183
|
+
});
|
|
184
|
+
groupBuckets.set(group, bucket);
|
|
115
185
|
}
|
|
116
|
-
|
|
186
|
+
for (const bucket of groupBuckets.values())
|
|
187
|
+
items.push(...bucket);
|
|
188
|
+
// Standard Content + Settings destinations. These are always
|
|
189
|
+
// present, regardless of which collections the admin configures,
|
|
190
|
+
// because they map to CMS features (not collections).
|
|
191
|
+
items.push({ path: '/media', label: 'Media', icon: Image, group: 'Content' }, { path: '/forms', label: 'Forms', icon: ClipboardList, group: 'Content' }, { path: '/seo', label: 'SEO', icon: SearchIcon, group: 'Content' }, { path: '/script-tags', label: 'Script Tags', icon: Code2, group: 'Content' }, { path: '/users', label: 'Users', icon: Users, group: 'Settings' }, { path: '/api-keys', label: 'API Keys', icon: KeyRound, group: 'Settings' }, { path: '/settings', label: 'Settings', icon: Settings, group: 'Settings' });
|
|
117
192
|
return items;
|
|
118
193
|
}
|
|
119
194
|
//# sourceMappingURL=Sidebar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sidebar.js","sourceRoot":"","sources":["../../src/layout/Sidebar.tsx"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Sidebar.js","sourceRoot":"","sources":["../../src/layout/Sidebar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dashboard.d.ts","sourceRoot":"","sources":["../../src/views/Dashboard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Dashboard.d.ts","sourceRoot":"","sources":["../../src/views/Dashboard.tsx"],"names":[],"mappings":"AAkGA,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,OAAO,CAAC,EAAE,GAAG,CAAA;IACb,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC;AA+ID,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,cAAc,2CAolBxE"}
|
package/dist/views/Dashboard.js
CHANGED
|
@@ -15,7 +15,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
15
15
|
* >= 1024 (desktop): stat cards 5-col, main grid is `1fr 320px`
|
|
16
16
|
*/
|
|
17
17
|
import { useMemo, useState } from 'react';
|
|
18
|
-
import { FileText, File as FileIcon, Image as ImageIcon, ClipboardList, Search, Plus, Upload, Globe, ExternalLink, Activity, AlertTriangle, Clock, Zap, Database, ChevronRight, Loader2, } from 'lucide-react';
|
|
18
|
+
import { FileText, File as FileIcon, Image as ImageIcon, ClipboardList, Search, Plus, Upload, Globe, ExternalLink, Activity, AlertTriangle, Clock, Zap, Database, ChevronRight, Loader2, TrendingUp, TrendingDown, Gauge, AlertCircle, } from 'lucide-react';
|
|
19
19
|
import { useApiData } from '../lib/useApiData.js';
|
|
20
20
|
// ─── helpers (kept top-level so they aren't re-created on every render) ──────
|
|
21
21
|
function resolveCollections(config) {
|
|
@@ -59,6 +59,27 @@ function timeOfDayGreeting() {
|
|
|
59
59
|
return 'Good afternoon';
|
|
60
60
|
return 'Good evening';
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Return the user's first name for the greeting. Falls back to the
|
|
64
|
+
* email local-part, then a generic "there". Strips role-style names
|
|
65
|
+
* like "Admin" / "Administrator" / "Editor" — a literal
|
|
66
|
+
* `Good morning, Admin` reads as bot-output, not a person.
|
|
67
|
+
*/
|
|
68
|
+
function firstNameForGreeting(session) {
|
|
69
|
+
const raw = (session?.user?.name ?? session?.name ?? '').trim();
|
|
70
|
+
const email = session?.user?.email ?? session?.email;
|
|
71
|
+
const generic = new Set(['admin', 'administrator', 'editor', 'user', 'root']);
|
|
72
|
+
if (raw) {
|
|
73
|
+
const first = raw.split(/\s+/)[0] ?? raw;
|
|
74
|
+
if (!generic.has(first.toLowerCase()))
|
|
75
|
+
return first;
|
|
76
|
+
}
|
|
77
|
+
if (typeof email === 'string' && email.length > 0) {
|
|
78
|
+
const local = email.split('@')[0] ?? email;
|
|
79
|
+
return local.charAt(0).toUpperCase() + local.slice(1);
|
|
80
|
+
}
|
|
81
|
+
return 'there';
|
|
82
|
+
}
|
|
62
83
|
function todayDateString() {
|
|
63
84
|
return new Date().toLocaleDateString('en-US', {
|
|
64
85
|
weekday: 'long',
|
|
@@ -124,9 +145,11 @@ export function Dashboard({ config, session, onNavigate }) {
|
|
|
124
145
|
const nav = (path) => onNavigate?.(path);
|
|
125
146
|
const { data: stats, loading, error, exhausted, refetch } = useApiData('/stats');
|
|
126
147
|
const { data: health } = useApiData('/health');
|
|
148
|
+
const { data: delivery, loading: deliveryLoading } = useApiData('/stats/api-delivery');
|
|
149
|
+
const { data: contentHealthData, loading: contentHealthLoading } = useApiData('/stats/content-health');
|
|
127
150
|
const greeting = useMemo(() => timeOfDayGreeting(), []);
|
|
128
151
|
const dateStr = useMemo(() => todayDateString(), []);
|
|
129
|
-
const userName =
|
|
152
|
+
const userName = useMemo(() => firstNameForGreeting(session), [session]);
|
|
130
153
|
const collections = useMemo(() => resolveCollections(config), [config]);
|
|
131
154
|
// ── Stat cards ──────────────────────────────────────────────────────────
|
|
132
155
|
const statCards = useMemo(() => {
|
|
@@ -217,18 +240,23 @@ export function Dashboard({ config, session, onNavigate }) {
|
|
|
217
240
|
return cards;
|
|
218
241
|
}, [stats, collections]);
|
|
219
242
|
// ── Quick actions ───────────────────────────────────────────────────────
|
|
220
|
-
//
|
|
221
|
-
//
|
|
222
|
-
//
|
|
243
|
+
// 5-button strip matching the reference dashboard. The "+ New Post" entry
|
|
244
|
+
// intentionally duplicates the top-bar primary action: the top bar
|
|
245
|
+
// surface is for chrome-level navigation, the quick-action row is the
|
|
246
|
+
// dashboard's content-creation toolbar. Order mirrors the natural
|
|
247
|
+
// authoring flow (post → page → media → form → integration).
|
|
223
248
|
const quickActions = useMemo(() => {
|
|
249
|
+
const posts = collections.find((c) => c.slug === 'posts' || c.type === 'post');
|
|
250
|
+
const postsSlug = posts?.slug ?? 'posts';
|
|
224
251
|
const pages = collections.find((c) => c.slug === 'pages' || c.type === 'page');
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
252
|
+
const pagesSlug = pages?.slug ?? 'pages';
|
|
253
|
+
const items = [
|
|
254
|
+
{ label: 'New Post', icon: Plus, onClick: () => nav(`/${postsSlug}/new`) },
|
|
255
|
+
{ label: 'New Page', icon: Plus, onClick: () => nav(`/${pagesSlug}/new`) },
|
|
256
|
+
{ label: 'Upload Media', icon: Upload, onClick: () => nav('/media') },
|
|
257
|
+
{ label: 'New Form', icon: Plus, onClick: () => nav('/forms') },
|
|
258
|
+
{ label: 'View API', icon: Globe, onClick: () => nav('/api-keys') },
|
|
259
|
+
];
|
|
232
260
|
return items;
|
|
233
261
|
}, [collections, onNavigate]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
234
262
|
// ── Recent activity ─────────────────────────────────────────────────────
|
|
@@ -264,57 +292,65 @@ export function Dashboard({ config, session, onNavigate }) {
|
|
|
264
292
|
};
|
|
265
293
|
});
|
|
266
294
|
}, [stats, collections]);
|
|
267
|
-
// ── Content health
|
|
295
|
+
// ── Content health (sourced from /stats/content-health) ─────────────────
|
|
296
|
+
// Persisted by the nightly content-health cron. The four issue rows
|
|
297
|
+
// map 1:1 to ContentIssueType in the schema; the labels are
|
|
298
|
+
// user-facing and intentionally read like the reference dashboard.
|
|
268
299
|
const contentHealth = useMemo(() => {
|
|
269
|
-
const
|
|
270
|
-
const
|
|
271
|
-
const
|
|
272
|
-
const
|
|
273
|
-
|
|
300
|
+
const counts = contentHealthData?.counts ?? {};
|
|
301
|
+
const score = contentHealthData?.score ?? 100;
|
|
302
|
+
const label = contentHealthData?.label ?? 'Good';
|
|
303
|
+
const tone = score >= 70 ? 'ok' : score >= 40 ? 'warn' : score > 0 ? 'err' : 'muted';
|
|
304
|
+
// Issue list — only render rows that have non-zero counts so the
|
|
305
|
+
// card stays compact when the corpus is healthy. The empty state
|
|
306
|
+
// below picks up when all four are zero.
|
|
274
307
|
const issues = [];
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
if (totalScheduled > 0) {
|
|
282
|
-
issues.push({ label: 'Scheduled to publish', count: totalScheduled, tone: 'muted' });
|
|
283
|
-
}
|
|
284
|
-
if (score > 0 && score < 70) {
|
|
308
|
+
const missingMeta = counts['MISSING_META_DESCRIPTION'] ?? 0;
|
|
309
|
+
const brokenLinks = counts['BROKEN_INTERNAL_LINK'] ?? 0;
|
|
310
|
+
const missingAlt = counts['MISSING_ALT_TEXT'] ?? 0;
|
|
311
|
+
const outdated = counts['OUTDATED_CONTENT'] ?? 0;
|
|
312
|
+
if (missingMeta > 0)
|
|
285
313
|
issues.push({
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
314
|
+
kind: 'MISSING_META_DESCRIPTION',
|
|
315
|
+
label: 'Missing meta descriptions',
|
|
316
|
+
count: missingMeta,
|
|
317
|
+
tone: 'warn',
|
|
318
|
+
});
|
|
319
|
+
if (brokenLinks > 0)
|
|
320
|
+
issues.push({
|
|
321
|
+
kind: 'BROKEN_INTERNAL_LINK',
|
|
322
|
+
label: 'Broken internal links',
|
|
323
|
+
count: brokenLinks,
|
|
324
|
+
tone: 'err',
|
|
325
|
+
});
|
|
326
|
+
if (missingAlt > 0)
|
|
327
|
+
issues.push({
|
|
328
|
+
kind: 'MISSING_ALT_TEXT',
|
|
329
|
+
label: 'Missing alt text',
|
|
330
|
+
count: missingAlt,
|
|
331
|
+
tone: 'warn',
|
|
332
|
+
});
|
|
333
|
+
if (outdated > 0)
|
|
334
|
+
issues.push({
|
|
335
|
+
kind: 'OUTDATED_CONTENT',
|
|
336
|
+
label: 'Outdated content (90+ days)',
|
|
337
|
+
count: outdated,
|
|
338
|
+
tone: 'warn',
|
|
289
339
|
});
|
|
290
|
-
}
|
|
291
340
|
return {
|
|
292
341
|
score,
|
|
293
|
-
label
|
|
294
|
-
tone
|
|
342
|
+
label,
|
|
343
|
+
tone,
|
|
295
344
|
issues,
|
|
345
|
+
hasData: contentHealthData !== null,
|
|
346
|
+
loading: contentHealthLoading,
|
|
296
347
|
};
|
|
297
|
-
}, [
|
|
298
|
-
// ── Content delivery tiles ──────────────────────────────────────────────
|
|
299
|
-
const delivery = useMemo(() => {
|
|
300
|
-
const sched = stats?.statusCounts?.['SCHEDULED'] ?? 0;
|
|
301
|
-
return {
|
|
302
|
-
totalDocs: stats?.totalDocuments ?? 0,
|
|
303
|
-
forms: stats?.formCount ?? 0,
|
|
304
|
-
scheduled: sched,
|
|
305
|
-
webhooks: {
|
|
306
|
-
total: stats?.webhookCount ?? 0,
|
|
307
|
-
active: stats?.webhookActiveCount ?? 0,
|
|
308
|
-
},
|
|
309
|
-
};
|
|
310
|
-
}, [stats]);
|
|
348
|
+
}, [contentHealthData, contentHealthLoading]);
|
|
311
349
|
const totalIssues = contentHealth.issues.reduce((s, i) => s + i.count, 0);
|
|
312
350
|
// ── Render ──────────────────────────────────────────────────────────────
|
|
313
351
|
if (loading && !stats) {
|
|
314
352
|
return (_jsx("div", { className: "flex h-64 items-center justify-center p-4 sm:p-6", children: _jsx(Loader2, { className: "h-6 w-6 animate-spin text-violet-600" }) }));
|
|
315
353
|
}
|
|
316
|
-
const heroPostSlug = collections.find((c) => c.slug === 'posts' || c.type === 'post')?.slug ?? 'posts';
|
|
317
|
-
const siteUrl = config?.site?.url ?? config?.seo?.siteUrl ?? null;
|
|
318
354
|
return (_jsxs("div", { className: "w-full space-y-5 p-4 sm:p-6 lg:px-8", children: [health && health.status === 'degraded' && (_jsxs("div", { className: "flex items-start gap-3 rounded-lg border border-blue-200 bg-blue-50 p-3 dark:border-blue-900 dark:bg-blue-950/40", children: [_jsx(Database, { className: "mt-0.5 h-5 w-5 shrink-0 text-blue-600 dark:text-blue-400" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "text-sm font-medium text-blue-900 dark:text-blue-200", children: "Database setup required" }), _jsx("p", { className: "mt-0.5 text-xs text-blue-700 dark:text-blue-300", children: !health.databaseConnected
|
|
319
355
|
? 'Cannot connect to the database. Check your DATABASE_URL environment variable.'
|
|
320
356
|
: !health.secretConfigured
|
|
@@ -322,7 +358,7 @@ export function Dashboard({ config, session, onNavigate }) {
|
|
|
322
358
|
: `Some CMS models are missing: ${Object.entries(health.models)
|
|
323
359
|
.filter(([, v]) => !v)
|
|
324
360
|
.map(([k]) => k)
|
|
325
|
-
.join(', ')}. Run your database migrations.` })] })] })), error && exhausted && (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-900 dark:bg-amber-950/40", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-amber-600 dark:text-amber-400" }), _jsx("span", { className: "flex-1 text-sm text-amber-800 dark:text-amber-200", children: "Some dashboard data may be unavailable." }), _jsx("button", { onClick: refetch, className: "rounded-lg border border-amber-300 px-3 py-1 text-sm text-amber-700 transition-colors hover:bg-amber-100 dark:border-amber-700 dark:text-amber-200 dark:hover:bg-amber-900/40", children: "Retry" })] })), _jsxs("div", { className: "flex flex-col gap-
|
|
361
|
+
.join(', ')}. Run your database migrations.` })] })] })), error && exhausted && (_jsxs("div", { className: "flex items-center gap-3 rounded-lg border border-amber-200 bg-amber-50 p-3 dark:border-amber-900 dark:bg-amber-950/40", children: [_jsx(AlertTriangle, { className: "h-5 w-5 shrink-0 text-amber-600 dark:text-amber-400" }), _jsx("span", { className: "flex-1 text-sm text-amber-800 dark:text-amber-200", children: "Some dashboard data may be unavailable." }), _jsx("button", { onClick: refetch, className: "rounded-lg border border-amber-300 px-3 py-1 text-sm text-amber-700 transition-colors hover:bg-amber-100 dark:border-amber-700 dark:text-amber-200 dark:hover:bg-amber-900/40", children: "Retry" })] })), _jsxs("div", { className: "flex flex-col gap-1 sm:gap-0.5", children: [_jsxs("h1", { className: "text-foreground text-xl font-semibold tracking-tight sm:text-2xl", children: [greeting, ", ", userName, " ", _jsx("span", { "aria-hidden": true, children: "\uD83D\uDC4B" })] }), _jsxs("p", { className: "text-muted-foreground text-sm", children: [dateStr, totalIssues > 0 && (_jsxs("span", { className: "hidden sm:inline", children: [' · ', totalIssues, " content item", totalIssues === 1 ? '' : 's', " need attention"] }))] })] }), _jsx("div", { className: "-mx-1 flex gap-2 overflow-x-auto px-1 pb-1 [scrollbar-width:thin]", children: quickActions.map((a) => (_jsxs("button", { onClick: a.onClick, className: "border-border bg-card inline-flex shrink-0 items-center gap-1.5 rounded-lg border px-3.5 py-2 text-sm shadow-sm transition-colors hover:border-violet-400 hover:bg-violet-50 hover:text-violet-700 dark:hover:bg-violet-950/40 dark:hover:text-violet-300", children: [_jsx(a.icon, { className: "h-3.5 w-3.5" }), a.label] }, a.label))) }), _jsx("div", { className: "grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5", children: statCards.map((card) => {
|
|
326
362
|
const Inner = (_jsxs(_Fragment, { children: [_jsx("div", { className: `mb-3 flex h-8 w-8 items-center justify-center rounded-lg ${card.iconBg}`, children: _jsx(card.icon, { className: `h-4 w-4 ${card.iconColor}` }) }), _jsxs("div", { className: "flex items-baseline gap-1", children: [_jsx("span", { className: "text-foreground text-2xl leading-none font-semibold tracking-tight", children: card.value }), card.unit && (_jsx("span", { className: "text-muted-foreground text-sm font-medium", children: card.unit }))] }), _jsx("p", { className: "text-muted-foreground mt-1 text-xs", children: card.label }), card.hint && (_jsx("p", { className: `mt-1.5 text-[11px] ${card.hintUp ? 'text-emerald-600 dark:text-emerald-400' : 'text-muted-foreground'}`, children: card.hint }))] }));
|
|
327
363
|
return card.href ? (_jsx("button", { type: "button", onClick: () => nav(card.href), className: "bg-card border-border rounded-xl border p-4 text-left shadow-sm transition-shadow hover:shadow-md", children: Inner }, card.label)) : (_jsx("div", { className: "bg-card border-border rounded-xl border p-4 shadow-sm", children: Inner }, card.label));
|
|
328
364
|
}) }), _jsxs("div", { className: "grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,1fr)_320px]", children: [_jsxs("section", { className: "bg-card border-border overflow-hidden rounded-xl border shadow-sm", children: [_jsxs("header", { className: "border-border flex items-center justify-between border-b px-4 py-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "text-foreground text-sm font-semibold", children: "Recent Activity" }), _jsx("p", { className: "text-muted-foreground mt-0.5 text-xs", children: "Last 7 days across all content" })] }), _jsx("button", { className: "text-xs font-medium text-violet-600 hover:underline dark:text-violet-400", onClick: () => setActivityLimit((n) => (n >= 20 ? 8 : 20)), children: activity.length >= 20 ? 'Show less' : 'View all' })] }), activity.length === 0 ? (_jsx(EmptyState, { icon: Activity, title: "No activity yet", subtitle: "Content changes will appear here as your team works." })) : (_jsx("ul", { role: "list", className: "divide-border divide-y", children: activity.map((it) => (_jsx("li", { className: "hover:bg-accent/50 cursor-pointer px-4 py-3 transition-colors", onClick: () => nav(`/${it.collection}/${it.id}`), children: _jsxs("div", { className: "flex min-w-0 items-start gap-3", children: [_jsx("div", { className: "mt-0.5 flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-[11px] font-bold text-white", style: { background: it.avatar.color }, "aria-hidden": true, children: it.avatar.initials }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("p", { className: "text-foreground truncate text-sm leading-snug", children: [_jsxs("span", { className: "font-semibold", children: ["\u201C", it.title || 'Untitled', "\u201D"] }), ' ', _jsxs("span", { className: "text-muted-foreground", children: ["\u2014 ", it.typeLabel] })] }), _jsxs("div", { className: "text-muted-foreground mt-1 flex flex-wrap items-center gap-2 text-[11px]", children: [_jsx("span", { className: `inline-flex items-center rounded px-1.5 py-0.5 text-[10px] font-medium ${it.statusInfo.cls}`, children: it.statusInfo.label }), _jsx("span", { className: "max-w-[120px] truncate", children: it.author }), _jsx("span", { "aria-hidden": true, children: "\u00B7" }), _jsx("span", { children: it.relTime })] })] })] }) }, it.id))) }))] }), _jsxs("aside", { className: "flex min-w-0 flex-col gap-4", children: [_jsxs("section", { className: "bg-card border-border overflow-hidden rounded-xl border shadow-sm", children: [_jsxs("header", { className: "border-border flex items-center justify-between border-b px-4 py-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "text-foreground text-sm font-semibold", children: "Publishing Queue" }), _jsxs("p", { className: "text-muted-foreground mt-0.5 text-xs", children: [publishQueue.length, " item", publishQueue.length === 1 ? '' : 's', " scheduled"] })] }), _jsx("button", { className: "text-xs font-medium text-violet-600 hover:underline disabled:cursor-default disabled:no-underline disabled:opacity-50 dark:text-violet-400", disabled: publishQueue.length === 0, onClick: () => {
|
|
@@ -352,21 +388,59 @@ export function Dashboard({ config, session, onNavigate }) {
|
|
|
352
388
|
? 'text-red-600 dark:text-red-400'
|
|
353
389
|
: iss.tone === 'warn'
|
|
354
390
|
? 'text-amber-600 dark:text-amber-400'
|
|
355
|
-
: 'text-muted-foreground'}`, children: iss.count }), _jsx(ChevronRight, { className: "text-muted-foreground/60 h-3.5 w-3.5 shrink-0" })] }, i))) }))] })] })] }), _jsxs("section", { className: "bg-card border-border overflow-hidden rounded-xl border shadow-sm", children: [_jsxs("header", { className: "border-border flex items-center justify-between border-b px-4 py-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "text-foreground text-sm font-semibold", children: "
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
391
|
+
: 'text-muted-foreground'}`, children: iss.count }), _jsx(ChevronRight, { className: "text-muted-foreground/60 h-3.5 w-3.5 shrink-0" })] }, i))) }))] })] })] }), _jsxs("section", { className: "bg-card border-border overflow-hidden rounded-xl border shadow-sm", children: [_jsxs("header", { className: "border-border flex items-center justify-between border-b px-4 py-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("h2", { className: "text-foreground text-sm font-semibold", children: "Delivery API" }), _jsx("p", { className: "text-muted-foreground mt-0.5 text-xs", children: "Headless content delivery \u00B7 last 24 hours" })] }), _jsxs("button", { className: "inline-flex items-center gap-1 text-xs font-medium text-violet-600 hover:underline dark:text-violet-400", onClick: () => nav('/api-keys'), children: ["API docs ", _jsx(ExternalLink, { className: "h-3 w-3" })] })] }), _jsx(DeliveryGrid, { delivery: delivery, loading: deliveryLoading })] })] }));
|
|
392
|
+
}
|
|
393
|
+
// ─── Delivery API grid ──────────────────────────────────────────────────────
|
|
394
|
+
function DeliveryGrid({ delivery, loading }) {
|
|
395
|
+
if (loading && !delivery) {
|
|
396
|
+
return (_jsx("div", { className: "divide-border grid grid-cols-2 divide-x divide-y lg:grid-cols-4 lg:divide-y-0", "aria-busy": true, children: [0, 1, 2, 3].map((i) => (_jsxs("div", { className: "px-4 py-3.5", children: [_jsx("div", { className: "bg-muted mb-2 h-3 w-24 rounded" }), _jsx("div", { className: "bg-muted mb-1.5 h-7 w-20 rounded" }), _jsx("div", { className: "bg-muted h-3 w-28 rounded" })] }, i))) }));
|
|
397
|
+
}
|
|
398
|
+
const hasData = delivery?.hasData ?? false;
|
|
399
|
+
const requests = delivery?.requests24h ?? 0;
|
|
400
|
+
const delta = delivery?.deltaPercent ?? null;
|
|
401
|
+
const errorRate = delivery?.errorRate ?? 0;
|
|
402
|
+
const avgLatency = delivery?.avgLatencyMs ?? 0;
|
|
403
|
+
const p95Latency = delivery?.p95LatencyMs ?? 0;
|
|
404
|
+
const webhookTotal = delivery?.webhookCount ?? 0;
|
|
405
|
+
const webhookActive = delivery?.webhookActiveCount ?? 0;
|
|
406
|
+
// Pretty-print large numbers (14_823 → "14.8K") so the tile stays
|
|
407
|
+
// readable at the dashboard's compact density.
|
|
408
|
+
const requestsLabel = formatLargeNumber(requests);
|
|
409
|
+
const errorRatePct = (errorRate * 100).toFixed(2);
|
|
410
|
+
return (_jsxs("div", { className: "divide-border grid grid-cols-2 divide-x divide-y lg:grid-cols-4 lg:divide-y-0", children: [_jsx(DeliveryTile, { icon: Activity, label: "API Requests (24h)", value: hasData ? requestsLabel : '—', sub: !hasData
|
|
411
|
+
? 'no traffic recorded yet'
|
|
412
|
+
: delta === null
|
|
413
|
+
? 'no prior baseline'
|
|
414
|
+
: `${delta >= 0 ? '+' : ''}${delta.toFixed(1)}% vs yesterday`, subIcon: hasData && typeof delta === 'number'
|
|
415
|
+
? delta >= 0
|
|
416
|
+
? TrendingUp
|
|
417
|
+
: TrendingDown
|
|
418
|
+
: undefined, tone: hasData ? (delta && delta >= 0 ? 'ok' : 'muted') : 'muted' }), _jsx(DeliveryTile, { icon: AlertCircle, label: "Error Rate", value: hasData ? `${errorRatePct}%` : '—', sub: !hasData
|
|
419
|
+
? 'no traffic recorded yet'
|
|
420
|
+
: errorRate < 0.005
|
|
421
|
+
? 'healthy'
|
|
422
|
+
: errorRate < 0.05
|
|
423
|
+
? 'elevated'
|
|
424
|
+
: 'investigate', tone: !hasData ? 'muted' : errorRate < 0.005 ? 'ok' : errorRate < 0.05 ? 'warn' : 'err' }), _jsx(DeliveryTile, { icon: Gauge, label: "Avg Response Time", value: hasData ? `${Math.round(avgLatency)}ms` : '—', sub: hasData ? `p95: ${p95Latency}ms` : 'no traffic recorded yet', tone: !hasData ? 'muted' : avgLatency < 200 ? 'ok' : avgLatency < 600 ? 'warn' : 'err' }), _jsx(DeliveryTile, { icon: Zap, label: "Active Webhooks", value: `${webhookActive} / ${webhookTotal}`, sub: webhookTotal === 0
|
|
425
|
+
? 'none configured'
|
|
426
|
+
: webhookActive === webhookTotal
|
|
427
|
+
? 'All active'
|
|
428
|
+
: `${webhookTotal - webhookActive} paused`, tone: webhookTotal === 0 ? 'muted' : webhookActive === webhookTotal ? 'ok' : 'warn' })] }));
|
|
429
|
+
}
|
|
430
|
+
function formatLargeNumber(n) {
|
|
431
|
+
if (n < 1000)
|
|
432
|
+
return n.toLocaleString();
|
|
433
|
+
if (n < 10_000)
|
|
434
|
+
return `${(n / 1000).toFixed(1)}K`;
|
|
435
|
+
if (n < 1_000_000)
|
|
436
|
+
return `${(n / 1000).toFixed(0)}K`;
|
|
437
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
364
438
|
}
|
|
365
439
|
// ─── Sub-components (kept in-file: smaller bundle, no extra module hops) ────
|
|
366
440
|
function EmptyState({ icon: Icon, title, subtitle, compact = false, }) {
|
|
367
441
|
return (_jsxs("div", { className: `flex flex-col items-center justify-center gap-1.5 text-center ${compact ? 'px-4 py-6' : 'px-6 py-10'}`, children: [_jsx(Icon, { className: "text-muted-foreground/50 mb-1 h-7 w-7", "aria-hidden": true }), _jsx("p", { className: "text-foreground text-sm font-semibold", children: title }), _jsx("p", { className: "text-muted-foreground max-w-xs text-xs", children: subtitle })] }));
|
|
368
442
|
}
|
|
369
|
-
function DeliveryTile({ icon: Icon, label, value, sub, tone = 'muted', }) {
|
|
443
|
+
function DeliveryTile({ icon: Icon, label, value, sub, subIcon: SubIcon, tone = 'muted', }) {
|
|
370
444
|
const subTone = tone === 'ok'
|
|
371
445
|
? 'text-emerald-600 dark:text-emerald-400'
|
|
372
446
|
: tone === 'warn'
|
|
@@ -374,6 +448,6 @@ function DeliveryTile({ icon: Icon, label, value, sub, tone = 'muted', }) {
|
|
|
374
448
|
: tone === 'err'
|
|
375
449
|
? 'text-red-600 dark:text-red-400'
|
|
376
450
|
: 'text-muted-foreground';
|
|
377
|
-
return (_jsxs("div", { className: "px-4 py-3.5", children: [_jsxs("div", { className: "text-muted-foreground mb-1 flex items-center gap-1.5", children: [_jsx(Icon, { className: "h-3.5 w-3.5", "aria-hidden": true }), _jsx("span", { className: "text-[11px] font-medium", children: label })] }), _jsx("p", { className: "text-foreground text-xl leading-tight font-semibold tracking-tight", children: value }), sub &&
|
|
451
|
+
return (_jsxs("div", { className: "px-4 py-3.5", children: [_jsxs("div", { className: "text-muted-foreground mb-1 flex items-center gap-1.5", children: [_jsx(Icon, { className: "h-3.5 w-3.5", "aria-hidden": true }), _jsx("span", { className: "text-[11px] font-medium", children: label })] }), _jsx("p", { className: "text-foreground text-xl leading-tight font-semibold tracking-tight", children: value }), sub && (_jsxs("p", { className: `mt-0.5 inline-flex items-center gap-1 text-[11px] ${subTone}`, children: [SubIcon && _jsx(SubIcon, { className: "h-3 w-3 shrink-0", "aria-hidden": true }), sub] }))] }));
|
|
378
452
|
}
|
|
379
453
|
//# sourceMappingURL=Dashboard.js.map
|