Design#2
Open
aaroncurtisyoga wants to merge 67 commits into
Open
Conversation
- replace globals.css with figma-make-output theme.css (dewberry brand vars, status enum, sidebar tokens, light/dark, hex chart colors) - align env vars with the open-source config model: NEXT_PUBLIC_API_URL (with NEXT_PUBLIC_SEPEX_BASE_URL fallback), API_DOCS_URL, DEV_BYPASS_AUTH, keycloak/nextauth placeholders - install next-auth@beta (wiring in bucket 2) - update landing copy: open-source framing, drop the dropped text-cta utility for text-dewberry-teal - gitignore design/ and untrack design/figma-make.md and design/scaffold-plan.md — internal iteration files don't ship publicly
- auth.js: NextAuth + Keycloak provider, mounted conditionally on KEYCLOAK_ISSUER so OSS clones / dev-bypass setups don't 500 on /api/auth/session with InvalidEndpoints - auth-helpers.js: getAuthUser / requireAuthUser, no DB lookup — Sepex Viewer is stateless and identifies users to Sepex via the X-SEPEX-User-Email header - devBypass.js: isDevBypass flag + devBypassUser stub gated on NODE_ENV=development && NEXT_PUBLIC_DEV_BYPASS_AUTH=true - [...nextauth]/route.js: re-export handlers (no basePath shim — sepex-viewer mounts at /, unlike reality-view) - providers.jsx: wrap with SessionProvider so client components can useSession() - .env.example: rename NEXTAUTH_SECRET/URL → AUTH_SECRET/URL (v5 naming) and document `npx auth secret` for generating one
Header right-side gains: cmd-k search button (lg+), light/dark theme toggle via next-themes (rendered after mount to avoid hydration drift), and a user popover backed by next-auth's useSession with sign-out and dev-bypass label. Header itself is now sticky/backdrop-blur to match the Make snapshot.
A small client component mounted in the dashboard layout listens for cmd/ctrl+k and navigates to /jobs?focus=search. The Jobs page reads that param, focuses its existing search input via a forwarded ref, then strips the param from the URL so reloads are clean. The header search button uses the same navigation, so click and shortcut behave identically.
Mirrors the Make snapshot's md:hidden nav strip below the header so small screens can still reach Dashboard/Builder/Jobs without the desktop nav. Lives in its own MobileNav.jsx alongside Header to keep Header focused.
Dashboard: the three jobs-driven charts (Jobs Over Time, Jobs by Process, Top Submitters) gain isLoading / isError props. They were silently showing 'No jobs in this window.' during the initial fetch, which read as 'no data' instead of 'still loading'. Now they show a skeleton while loading and a muted card while erroring. Jobs: the table's empty state now distinguishes 'no jobs match these filters' from 'no jobs have been submitted yet,' and the error state is a top-of-table banner instead of replacing the entire table contents. Job Detail: swap the loading state's hand-rolled animate-pulse divs for the shared Skeleton component to match the convention everywhere else.
Header was the only file in the new phase 4 work using "./Sibling" relative imports. Switch them to the @/app/_components/... alias to match the convention used everywhere else in src.
Header.jsx and MobileNav.jsx both held identical nav route lists. Move the array to its own module so adding/removing a route only needs one edit.
mock layer at client/src/app/api/mock lets the viewer run end-to-end with `npm run dev` alone. nine endpoints mirror the sepex ogc api - processes contract, with an in-memory store on globalThis so it survives turbopack hmr. newly-submitted jobs progress accepted -> running -> successful over time so polling code paths get exercised. mock_scenario env var picks between default / empty / error / lots-running / all-failed seeds. ui fidelity to the figma make designs: - run summary card shows elapsed alongside updated; new elapsed util reads created/updated and computes the duration string - jobsovertimechart switches to horizontal stacked bars (was vertical recharts barchart); jobsbyprocesschart switches to horizontal bar list (was donut) - new jobbreadcrumb replaces the back-link on the job detail page dev quality: - sheetdescription / dialogdescription added so radix stops warning, which clears the next dev-tools indicator on landing - landing themeswitcher defers theme-dependent rendering until mount to fix an aria-pressed hydration mismatch - playwright dev dep + capture-screenshots.mjs for repeatable visual diffs against figma make
color tokens - light --muted-foreground darkens #78716c -> #57534e. was 4.40:1 on muted bg (fail), now 6.99:1. lifts every muted caption, tag chip, secondary label across the app. - dark --dewberry-teal lightens #336b87 -> #5fa3c0. was 2.48:1 on the dark card (fail) for "open full page" link / icons / accents, now 5.16:1. light-mode value preserved. status pills - bright pills (successful / running / accepted / failed) switch from white text to black. white was 1.92-3.76:1 on these greens / yellows / reds — universal wcag fail. black hits 5.58-10.95:1. - outlined pills (dismissed / lost) now use slate-700/dark:slate-300 and purple-700/dark:purple-300 instead of the bare status color (pure status-lost was 3.96:1 on white). local fixes - logstab inactive level filter drops the text-muted-foreground/60 opacity tint (~2.9:1 fail) and rides the global muted bump. - failedjobsalert "view all failures" link uses red-700/dark:red-400 instead of text-status-failed (small 12px text needs full 4.5:1, status-failed only hit 3.76:1 on the alert tint). capture script - adds 390x844 mobile viewport. refactored to a pages x themes x devices matrix so the script outputs 21 shots covering both viewports in both themes from one run.
- /jobs/{id}/metadata now returns the OGC shape (@context, apiJobId,
process, image, commands, timestamps) that real Sepex emits; drops the
fabricated runtimeSeconds/workerHost/pluginVersion fields.
- /jobs/{id} GET no longer includes a `message` field. Real Sepex only
returns `message` on DELETE responses, not on JobRecord GETs.
- Replaces the hand-written 50-job seed with a deterministic generator
(~5k jobs, seeded LCG, statuses weighted by recency) so Dashboard
charts and Jobs pagination look like production scale.
- Adds a `lastErrorMessage` field on failed seed jobs for downstream
consumers; exposing it via the API is feature-flagged separately.
Adds a single env-var feature flag (default off) so the Viewer reflects what the current Sepex API can support today, but can flip on once items A/C/D/H/I from research/proposed-next-steps.md ship. Off (default — matches real Sepex): - Dashboard hides the time-range picker; subtitle notes the 100-job cap - Dashboard fetches cap at limit=100 (real Sepex silently clamps there) - FailedJobsAlert renders just job metadata; falls back to a "fetch logs to see the reason" note - ⌘K navigates to /jobs?focus=search (the v1 from pm-meeting.md §B) - Jobs pagination footer shows "Page N" only — no "of M" - Mock /jobs ignores ?q=, ?updatedAfter, ?updatedBefore; omits total/pages - Mock /jobs response strips lastErrorMessage even on failed jobs On: - Time-range picker visible, dashboard fetches 200/500/1000 by range - FailedJobsAlert shows inline lastErrorMessage per failed-job row - ⌘K opens a real cmdk command palette with server-side search across jobID/submitter/processID/tags + quick actions - Jobs pagination shows "Page 3 of 250" - Mock /jobs honors ?q=, ?updatedAfter, ?updatedBefore and returns total/pages Also adds two scripts under client/scripts/ for capturing proposed-state screenshots and eyeballing the degraded form, and documents the env var in docker-compose.yml.
Figma Make rendered status chips with white text on bright 500-level backgrounds. Commit fce7d9b reversed that to black text because white hit 1.92–3.76:1 on those colors — universal WCAG AA fail. Black passed contrast but the chips no longer matched the Figma reference, and the landing page LifecycleCard still used white text, so chips looked one way on / and another way on /jobs. Darkening the status tokens to 700-level shades restores the Figma's white-text aesthetic AND keeps every chip above 4.5:1: - successful #22c55e → #15803d (5.8:1) - running #eab308 → #b45309 (5.1:1) [shifts from yellow to amber] - accepted #0ea5e9 → #0369a1 (5.8:1) - failed #ef4444 → #b91c1c (6.6:1) dismissed and lost stay unchanged since they render as outline pills, not solid backgrounds.
JobIdLink shows jobID.slice(-8), assuming the 8-char hex format real Sepex emits (per the c5h0g1e4-style examples in proposed-next-steps.md). The earlier `mock-NNNNN-<processID>` seed format meant slice(-8) just showed the trailing process name, so every terrain-extract row read "extract", every report-pdf row read "port-pdf", etc. Switches the mock to deterministic 8-char hex IDs derived from the seed index, so the JobIdLink display works correctly and the mock looks more like production data. Logs/results/metadata generation now follows a new _seedIndex field on each job instead of parsing the jobID string. Also updates capture-screenshots.mjs to fetch a successful jobID from the API instead of hardcoding one, so it stays valid across seed regenerations.
Wired the client at the dewberryanalytics papi instance and removed
surfaces that either 404 or render perma-empty against the current
Sepex API. Each removal has a concrete API gap behind it; nothing
trimmed for aesthetics.
- compose: point client at papi.dewberryanalytics.com, comment out
local sepex/minio/postgres services
- dashboard: remove compute resources tile (/admin/resources 404);
un-gate time range picker so users aren't stuck on 24h;
swap toLocaleTimeString for compact relative time on activity rows
- job detail: drop Inputs tab and Elapsed field (neither field is
returned by /jobs/{id}); swallow 404 on /results and /metadata so
failed jobs show empty states instead of red error banners
- logs: read container_logs (real api) alongside process_logs (mock);
detect inline WARNING:/ERROR prefixes for level classification;
rename "Tail" to "Auto-scroll" with icon and tooltip; show per-level
counts on filter pills; skip Go zero-time timestamps
- results: handle the {outputs: {links, results}} envelope returned
by real Sepex (was treating top-level keys as outputs)
- jobs list: remove Tags column, "Run (from tags)" column, and tags
filter state — listing has no tags field
- builder: drop ExecutionModeCard (only async-execute is advertised
in jobControlOptions) and RecentPayloadsPopover (inputs aren't
echoed back so cloning was clearing the form); submit async-only
- command palette: stop sending ?q= since the api ignores it
- landing: trim copy claiming resource gauges and queue depth; hide
"view api docs" when no docs url is configured (papi has no /api)
- shared: link top submitters bars to /jobs?submitter= for parity
with the by-process drilldown
- delete client/.env.local + client/.env.example; all client-side vars now live in the root .env / .env.example (NEXT_PUBLIC_*, KEYCLOAK_*, AUTH_*). Docker-compose already loads the root file via env_file on the client service - drop NEXT_PUBLIC_DEV_BYPASS_AUTH — the dev-auth-bypass code path was removed in e9efc0c - drop startup-dev.sh and its wait-for-sepex TCP probe; the script was theatre against papi:443 and the local sepex service is commented out. CMD now runs `npm run dev` directly - docker-compose: remove SEPEX_HOST/SEPEX_PORT (no script to wait on) and the NEXT_PUBLIC_* environment block that duplicated .env - client/.gitignore: prune the .env* block since nothing lives in client/ anymore
- prefers-reduced-motion media query in globals.css - form labels associated via htmlFor/id (Submitter, SaveTemplate, DynamicInputField); aria-required, aria-invalid, aria-describedby on the controls and error/description nodes - LogsTab: aria-pressed on Process/Server toggles, aria-expanded + aria-controls on group collapse buttons - heading hierarchy: bumped section-level h3 → h2 across landing, dashboard, and builder pages so h1 → h2 → h3 holds - charts: SparklineCard and JobsOverTimeChart wrapped in role="img" with descriptive aria-label; decorative bars marked aria-hidden; list-style charts get section + aria-labelledby - ProcessPicker rebuilt on Popover + Command (cmdk) for full keyboard support, role="combobox", aria-expanded, aria-haspopup
Two papi processes had mismatches with the auto-generated form: - fdt + pyecho use dataType: "value" — a Sepex catch-all for free-form literals. The form was treating those as object/list and showing a JSON textarea, so users had to type quoted strings. Now treated as text-like (same path as "string") - dss_to_zarr.input_dss_keys (maxOccurs=100) and infer-ras-crs.counties (maxOccurs=9999) accept arrays, but the form sent a single value. Multi-occurrence inputs now render a one-per-line textarea; integer arrays are coerced to numbers at the submission boundary
… state
- skip-to-content link in root layout; id="main-content" on main landmarks
(landing + dashboard layout)
- per-section page titles via metadata template ("%s · Sepex Viewer"):
Dashboard, Jobs, Builder, and Job <id> via generateMetadata
- StatusIcon takes optional label prop; passed in RecentActivityFeed and
RunSummaryCard so SR users hear the job status (icon was the only cue)
- TimeRangePicker dropped tab/tablist roles (no roving tabindex was wired);
switched to button group with aria-pressed
- disabled buttons get cursor-not-allowed + grayscale on top of opacity-60
so the affordance reads instead of just looking faded
Pushes Lighthouse accessibility from 90/94/96/100 to 100 across landing,
dashboard, jobs, and builder.
Color contrast: status / destructive colors are deliberately darkened so
white-on-pill chips clear AA (5.8:1+). When the same tokens were used as
TEXT on dark cards they only hit ~2.9–3.7:1. Introduced paired -fg
variants (text-status-successful-fg, text-destructive-fg, etc.) that equal
the base in light mode and lighten in dark mode. Pill backgrounds are
unchanged; only text usages swap to -fg. Updated 12 call sites: error
banners, FailedJobsAlert, log line ERROR/WARN, validation summary, form
messages, the +12% sparkline label, and the destructive ghost buttons.
Combobox names: 4 role="combobox" triggers had no accessible name (the
visible value isn't a name per the combobox AAM rules). Added aria-label
on ProcessPicker and the three Radix Select triggers in JobsFilterBar
and PaginationFooter ("Process", "Filter by process", "Filter by status",
"Items per page").
Smoke-tested the builder by submitting one pyecho job to papi
(job 28313064). The submission succeeded and round-tripped, but the
Results tab would have rendered three garbage rows (jobID, updated,
outputs) because normalizeResults didn't handle a scalar `outputs`
field.
The Sepex API returns sync echo-style outputs as a flat string:
{ "outputs": "sepex-viewer smoke test 2026-05-11T..." }
Now scalar `outputs` (string/number/boolean) becomes one normalized
entry with a `value` field; the tab renders the value inline in a
<pre> block. Object-map entries with scalar values get the same
treatment. The hms-runner-style { outputs: { links, results } }
envelope still wins when present.
# Conflicts: # .gitignore # README.md
Collaborator
Author
|
@slawler Heads up — a lot of the new lines here are auto-generated. shadcn/ui writes component source directly into the repo when you run |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
client/)app/and its docker-compose service)