* feat(dashboard): nous-blue theme, bulk sessions, schedule picker
Batch of related dashboard improvements gathered on
austin/fix/dashboard-changes:
* Nous Blue theme — faithful port of the LENS_5I overlay system onto
the existing DashboardTheme. Lifts the foreground inversion layer to
z-index 200 to fix the long-standing hover / loading visual artifact,
adds an explicit swatchColors slot so the theme picker shows the
post-inversion preview, and migrates the legacy "lens-5i" theme key
from localStorage / API to "nous-blue" on first read.
* Theme-aware series colors: new --series-input-token /
--series-output-token CSS vars consumed by Analytics + Models
charts; ToolCall + ModelInfoCard switched to semantic
--color-success for diff lines and the Tools capability badge.
* Analytics + Models headers: consolidate period selector + refresh
next to the page title and drop the redundant period badge.
* Bulk session management — "Delete empty (N)" button + per-row
checkboxes with shift-click range select and a bulk-delete action
bar. Backed by SessionDB.delete_sessions() /
delete_empty_sessions() plus POST /api/sessions/bulk-delete and
DELETE /api/sessions/empty (registered before the templated
/api/sessions/{session_id} family so they don't get shadowed).
Hard cap of 500 IDs per bulk request. Full pytest coverage.
* Cron page — human-readable schedule picker (every-interval / daily
/ weekly / monthly / once / custom) replaces the raw cron
expression input; the job list now renders "Weekly on Mon, Wed,
Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals
for monthly schedules so non-English locales don't get incorrect
suffixes.
* example-dashboard plugin moved from plugins/ to tests/fixtures/ so
stock installs no longer ship the demo. Tests install it
dynamically via a pytest fixture that also reorders the FastAPI
routes.
* i18n: 40+ new keys for the bulk-select UI and schedule
picker/describer translated across all 16 locales.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(dashboard): dedupe memory provider picker
The memory provider <Select> lived on both /system and /plugins,
writing the same config.yaml field through two different endpoints
with no cross-page refresh. Remove the picker from /system in favor
of a read-only status row + link to /plugins, where it pairs with
the context-engine picker under "Plugin providers".
/system retains the destructive admin controls (file sizes, Reset
MEMORY.md / USER.md / all). The api.setMemoryProvider client and
PUT /api/memory/provider backend endpoint are left in place for
CLI / script callers.
Co-authored-by: Cursor <cursoragent@cursor.com>
* docs(dashboard): address Copilot review on PR #37383
- Backdrop layer-stack comment claimed LENS_5I-style themes override
--component-backdrop-bg-blend-mode to multiply, but our only
LENS_5I-style theme (nous-blue) keeps the default difference.
Reword to describe what the code actually does and present the
var as a forward-looking extension hook.
- /api/sessions/bulk-delete docstring promised the response would
echo back the list of deleted IDs, but the implementation only
returns {ok, deleted}. Tighten the docstring to match the wire
format; the client already knows what it asked to delete, so the
IDs aren't needed.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(dashboard): address copilot review on cron describe + bulk-select checkbox
- schedule.ts: restrict `describeCronExpression` to strictly 5-field cron
expressions. The backend `parse_schedule` also accepts the 6-field
`min hour dom month dow year` form, and humanising those by
destructuring only the first five fields would silently drop the year
(e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field
expressions now fall through to the raw-string fallback so the user
sees what's actually scheduled.
- SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's
``onClick`` directly instead of attaching it to a parent ``<span>``
with a no-op ``onCheckedChange``. Radix forwards onClick to the
underlying ``<button role=checkbox>``, so the same handler now drives
both mouse clicks (preserving shift-key state for range select) and
keyboard activation (Space on the focused checkbox, which the browser
synthesises as a click on the <button>). Improves a11y / keyboard UX
without changing the controlled-selection model.
- SessionsPage.tsx: also extend ``SessionRowProps`` with the new
``onRename`` / ``onExport`` props introduced on main so the row's
destructured prop types resolve after the merge.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
270 lines
9.5 KiB
CSS
270 lines
9.5 KiB
CSS
@import 'tailwindcss';
|
|
/* `fonts.css` must come BEFORE `globals.css`: as of @nous-research/ui 0.14.x,
|
|
`globals.css` only declares the `--font-*` CSS variables (Collapse, Rules
|
|
Compressed/Expanded, Mondwest). The `@font-face` registrations live in
|
|
`fonts.css`, so without this import the DS variables resolve to font
|
|
families the browser never loads and components fall back to a system
|
|
stack (Tabs, Segmented, Typography, Buttons, etc. all look unstyled). */
|
|
@import '@nous-research/ui/styles/fonts.css';
|
|
@import '@nous-research/ui/styles/globals.css';
|
|
|
|
/* Scan the published design-system bundle so its utility classes survive
|
|
Tailwind's JIT purge. */
|
|
@source '../node_modules/@nous-research/ui/dist';
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* JetBrains Mono — bundled for the embedded TUI (/chat tab). */
|
|
/* Gives the terminal a proper monospace font even on systems where */
|
|
/* the user doesn't have one installed locally; xterm.js picks it up */
|
|
/* via ChatPage's `fontFamily` option. */
|
|
/* Apache-2.0. */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
@font-face {
|
|
font-family: 'JetBrains Mono';
|
|
font-style: normal;
|
|
font-weight: 400;
|
|
font-display: swap;
|
|
src: url('/fonts-terminal/JetBrainsMono-Regular.woff2') format('woff2');
|
|
}
|
|
@font-face {
|
|
font-family: 'JetBrains Mono';
|
|
font-style: normal;
|
|
font-weight: 700;
|
|
font-display: swap;
|
|
src: url('/fonts-terminal/JetBrainsMono-Bold.woff2') format('woff2');
|
|
}
|
|
@font-face {
|
|
font-family: 'JetBrains Mono';
|
|
font-style: italic;
|
|
font-weight: 400;
|
|
font-display: swap;
|
|
src: url('/fonts-terminal/JetBrainsMono-Italic.woff2') format('woff2');
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Hermes Agent — Nous DS with the LENS_0 (Hermes teal) lens applied */
|
|
/* statically. Mirrors nousnet-web/(hermes-agent)/layout.tsx so the */
|
|
/* canonical Hermes palette is the default — teal canvas + cream */
|
|
/* accent — without relying on leva/gsap at runtime. */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
:root {
|
|
/* LENS_0 — from design-language/src/ui/components/overlays/index.tsx.
|
|
These are the defaults for the `default` (Hermes Teal) dashboard theme;
|
|
ThemeProvider rewrites them as inline styles when a user switches themes. */
|
|
--foreground: color-mix(in srgb, #ffffff 0%, transparent);
|
|
--foreground-base: #ffffff;
|
|
--foreground-alpha: 0;
|
|
--midground: color-mix(in srgb, #ffe6cb 100%, transparent);
|
|
--midground-base: #ffe6cb;
|
|
--midground-alpha: 1;
|
|
--background: color-mix(in srgb, #041c1c 100%, transparent);
|
|
--background-base: #041c1c;
|
|
--background-alpha: 1;
|
|
|
|
/* Consumed by <Backdrop />; also theme-switchable. */
|
|
--warm-glow: rgba(255, 189, 56, 0.35);
|
|
--noise-opacity-mul: 1;
|
|
|
|
/* Typography tokens — rewritten by ThemeProvider. Defaults match the
|
|
system stack so themes that don't override look native. */
|
|
--theme-font-sans: system-ui, -apple-system, "Segoe UI", Roboto,
|
|
"Helvetica Neue", Arial, sans-serif;
|
|
--theme-font-mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo,
|
|
Consolas, monospace;
|
|
--theme-font-display: var(--theme-font-sans);
|
|
--theme-base-size: 15px;
|
|
--theme-line-height: 1.55;
|
|
--theme-letter-spacing: 0;
|
|
|
|
/* Layout tokens. */
|
|
--radius: 0.5rem;
|
|
--theme-radius: 0.5rem;
|
|
--theme-spacing-mul: 1;
|
|
--theme-density: comfortable;
|
|
|
|
/* Data-series accents — consumed by Analytics + Models pages for the
|
|
input-vs-output token visualisations (chart bars, table values,
|
|
legend swatches). Defaults are tuned for the Hermes-teal LENS_0
|
|
look: cream input + emerald-400 output read as warm/cool against
|
|
the dark canvas. Themes override via ThemeProvider, which emits
|
|
these as `--series-input-token` / `--series-output-token`. */
|
|
--series-input-token: #ffe6cb;
|
|
--series-output-token: #34d399;
|
|
}
|
|
|
|
/* Theme tokens cascade into the document root so every descendant inherits
|
|
the font stack, base size, and letter spacing without explicit calls. */
|
|
html {
|
|
font-family: var(--theme-font-sans);
|
|
font-size: var(--theme-base-size);
|
|
line-height: var(--theme-line-height);
|
|
letter-spacing: var(--theme-letter-spacing);
|
|
height: 100dvh;
|
|
max-height: 100dvh;
|
|
overflow: hidden;
|
|
}
|
|
|
|
body {
|
|
font-family: var(--theme-font-sans);
|
|
min-height: 0;
|
|
height: 100%;
|
|
margin: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
code, kbd, pre, samp, .font-mono, .font-mono-ui {
|
|
font-family: var(--theme-font-mono);
|
|
}
|
|
|
|
/* Density: scale the shadcn spacing utilities via a multiplier. The DS
|
|
components use `p-N` / `gap-N` / `space-*` classes which resolve against
|
|
Tailwind's spacing scale; multiplying `--spacing` at :root scales them
|
|
all proportionally in Tailwind v4. */
|
|
@theme inline {
|
|
--spacing: calc(0.25rem * var(--theme-spacing-mul, 1));
|
|
--font-sans: var(--theme-font-sans);
|
|
--font-mono: var(--theme-font-mono);
|
|
}
|
|
|
|
#root {
|
|
min-height: 0;
|
|
height: 100%;
|
|
max-height: 100%;
|
|
overflow: hidden;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
html,
|
|
body,
|
|
#root {
|
|
min-height: 100dvh;
|
|
height: auto;
|
|
max-height: none;
|
|
overflow-x: hidden;
|
|
overflow-y: auto;
|
|
}
|
|
}
|
|
|
|
/* Nousnet's hermes-agent layout bumps `small` and `code` to readable
|
|
dashboard sizes. Keep in sync. */
|
|
small { font-size: 1.0625rem; }
|
|
code { font-size: 0.875rem; }
|
|
|
|
/* Shadcn-compat tokens.
|
|
The dashboard's page code predates the Nous DS and uses shadcn-style
|
|
utility classes (bg-card, text-muted-foreground, border-border, etc.)
|
|
extensively. Rather than rewrite every call site, we expose those
|
|
tokens on top of the Nous palette so classes continue to resolve. */
|
|
@theme inline {
|
|
/* Remap foreground to midground so `text-foreground` / `bg-foreground`
|
|
stay visible — in LENS_0, `--foreground` itself has alpha 0. */
|
|
--color-foreground: var(--midground);
|
|
|
|
--color-card: color-mix(in srgb, var(--midground-base) 4%, var(--background-base));
|
|
--color-card-foreground: var(--midground);
|
|
--color-primary: var(--midground);
|
|
--color-primary-foreground: var(--background-base);
|
|
--color-secondary: color-mix(in srgb, var(--midground-base) 6%, var(--background-base));
|
|
--color-secondary-foreground: var(--midground);
|
|
--color-muted: color-mix(in srgb, var(--midground-base) 8%, var(--background-base));
|
|
/* Routes the shadcn `muted-foreground` slot through the DS semantic
|
|
text-secondary token (defaults to midground 80%) so legacy call
|
|
sites that use `text-muted-foreground` get a readable color
|
|
instead of the old 55%-transparent default. */
|
|
--color-muted-foreground: var(--color-text-secondary);
|
|
--color-accent: color-mix(in srgb, var(--midground-base) 10%, var(--background-base));
|
|
--color-accent-foreground: var(--midground);
|
|
--color-destructive: #fb2c36;
|
|
--color-destructive-foreground: #ffffff;
|
|
--color-success: #4ade80;
|
|
--color-warning: #ffbd38;
|
|
--color-border: color-mix(in srgb, var(--midground-base) 15%, transparent);
|
|
--color-input: color-mix(in srgb, var(--midground-base) 15%, transparent);
|
|
--color-ring: var(--midground);
|
|
--color-popover: color-mix(in srgb, var(--midground-base) 4%, var(--background-base));
|
|
--color-popover-foreground: var(--midground);
|
|
|
|
--radius-sm: calc(var(--theme-radius) - 4px);
|
|
--radius-md: calc(var(--theme-radius) - 2px);
|
|
--radius-lg: var(--theme-radius);
|
|
--radius-xl: calc(var(--theme-radius) + 4px);
|
|
}
|
|
|
|
|
|
/* Collapsed sidebar tooltip entrance — skipped when moving between items. */
|
|
@keyframes sidebar-tooltip-in {
|
|
from { opacity: 0; transform: translateY(-50%) translateX(-4px); }
|
|
to { opacity: 1; transform: translateY(-50%) translateX(0); }
|
|
}
|
|
|
|
/* Toast animations used by `components/Toast.tsx`. */
|
|
@keyframes toast-in {
|
|
from { opacity: 0; transform: translateX(16px); }
|
|
to { opacity: 1; transform: translateX(0); }
|
|
}
|
|
@keyframes toast-out {
|
|
from { opacity: 1; transform: translateX(0); }
|
|
to { opacity: 0; transform: translateX(16px); }
|
|
}
|
|
|
|
/* Generic fade + dialog entrance used by popovers and confirm dialogs. */
|
|
@keyframes fade-in {
|
|
from { opacity: 0; }
|
|
to { opacity: 1; }
|
|
}
|
|
@keyframes dialog-in {
|
|
from { opacity: 0; transform: translateY(4px) scale(0.98); }
|
|
to { opacity: 1; transform: translateY(0) scale(1); }
|
|
}
|
|
|
|
/* Hide scrollbar utility — used by the header's overflow-x nav row. */
|
|
.scrollbar-none {
|
|
-ms-overflow-style: none;
|
|
scrollbar-width: none;
|
|
}
|
|
.scrollbar-none::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
/* Plus-lighter blend used by logos/titles for a subtle glow. */
|
|
.blend-lighter {
|
|
mix-blend-mode: plus-lighter;
|
|
}
|
|
|
|
/* System UI-monospace stack — distinct from `font-courier` (Courier
|
|
Prime), used for dense data readouts where the display font would
|
|
break the grid. Routes through the theme's mono stack so themes
|
|
with a different monospace (JetBrains Mono, IBM Plex Mono, etc.)
|
|
still apply here. */
|
|
.font-mono-ui {
|
|
font-family: var(--theme-font-mono);
|
|
}
|
|
|
|
/* Subtle grain overlay for badges. */
|
|
.grain {
|
|
position: relative;
|
|
}
|
|
.grain::after {
|
|
content: '';
|
|
position: absolute;
|
|
inset: 0;
|
|
opacity: 0.12;
|
|
pointer-events: none;
|
|
background: repeating-conic-gradient(currentColor 0% 25%, #0000 0% 50%) 0 0 /
|
|
2px 2px;
|
|
}
|
|
|
|
/* When a theme provides `assets.bg`, the backdrop's <div> renders it as
|
|
a CSS background; the default filler <img> is hidden to prevent
|
|
double-compositing. Unset → initial → empty, so the :not() selector
|
|
matches and the default image stays visible. */
|
|
:root:not([style*="--theme-asset-bg:"]) .theme-default-filler {
|
|
display: block;
|
|
}
|
|
:root[style*="--theme-asset-bg:"] .theme-default-filler {
|
|
display: none;
|
|
}
|
|
|