diff --git a/.changeset/fn-7076-command-center-concurrency-counts.md b/.changeset/fn-7076-command-center-concurrency-counts.md new file mode 100644 index 0000000000..9d5dea81bb --- /dev/null +++ b/.changeset/fn-7076-command-center-concurrency-counts.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": minor +--- + +summary: Command Center Concurrency now shows running agents and current-use markers on global/project sliders. +category: feature +dev: CommandCenterControls reuses useGlobalConcurrency's currentlyActive/projectsActive (FN-7071) to render count readouts and clamped slider-track dots; no new backend routes. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index 1cc5482091..5f9387d877 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -839,7 +839,8 @@ Features: - Global date-range picker in the header scopes the analytics tabs; **Last 24h**, **Last 7 days**, **Last 30 days**, **All time**, and custom/open-ended ranges each request their selected analytics window. **Mission Control** remains live rather than historical. -- **Overview controls dashboard** sits at the top of the Overview landing surface on desktop and mobile. It includes AI engine stop/start backed by `globalPause`, live scheduler status from executor stats, range sliders for `maxConcurrent`, `maxTriageConcurrent`, and `maxWorktrees` that persist through `/api/settings`, and a compact theme dropdown with the same color-chip swatches and Shadcn variant list as Settings → Appearance. These controls reuse existing APIs and App-level theme setters; they do not add a new backend route or second theme owner. + +- **Overview controls dashboard** sits at the top of the Overview landing surface on desktop and mobile. It includes AI engine stop/start backed by `globalPause`, live scheduler status from executor stats, the shared Global Max Concurrent slider backed by `/api/global-concurrency`, range sliders for `maxConcurrent`, `maxTriageConcurrent`, and `maxWorktrees` that persist through `/api/settings`, and a compact theme dropdown with the same color-chip swatches and Shadcn variant list as Settings → Appearance. The global and current-project max-concurrent sliders show running-agent counts plus a current-use dot on the track once utilization data loads; triage and worktree sliders remain cap-only. These controls reuse existing APIs and App-level theme setters; they do not add a new backend route or second theme owner. - **Overview** summarizes token usage/cost, autonomy, active nodes, sessions, agent runs, tasks done, model breadth, and real open signals, and includes the SDLC throughput funnel for the selected range at the bottom of the Overview content in loading, error, empty, and populated states. Its token total and Live activity snapshot token metric refresh on a bounded live cadence and animate number changes while preserving reduced-motion preferences. The sessions card uses the selected-range `ActivityAnalytics.sessions` value already loaded for the overview. The Live activity snapshot also shows the current board-state count for tasks in progress, independent of the selected analytics date range. Overview includes a graph-rich software-factory snapshot with the existing tokens-by-model bar, tool-category bar, real recharts token-share pie, and the daily activity multi-series line chart placed before the daily activity sparkline/trend so the richer line graph sits higher in the chart grid. These reuse the already-loaded tokens, tools, activity, and signals analytics; the signals count comes from `/api/command-center/signals` and renders unavailable (`—`) while the incidents-backed response is loading or unavailable. The chart reveal/glow accents are decorative and disabled when reduced-motion preferences are active. The SDLC completion rate is shown as a radial gauge and is calculated as cohort conversion from in-range triage entrants, so the rate is capped at 100% even when older tasks finish during the range. diff --git a/packages/dashboard/app/components/command-center/CommandCenterControls.css b/packages/dashboard/app/components/command-center/CommandCenterControls.css index 323b836712..6162139c23 100644 --- a/packages/dashboard/app/components/command-center/CommandCenterControls.css +++ b/packages/dashboard/app/components/command-center/CommandCenterControls.css @@ -114,6 +114,24 @@ font-variant-numeric: tabular-nums; } +.cc-controls-range-wrap { + --cc-controls-range-thumb-size: var(--space-md); + position: relative; + display: flex; + align-items: center; +} + +/* FNXC:GlobalConcurrencyControls 2026-06-26-00:00: The Command Center current-use marker mirrors the footer marker, reuses the status-dot convention, uses logical inline positioning for RTL, and never intercepts range drags. */ +.cc-controls-use-marker { + --use-pct: 0%; + --use-offset: 0%; + position: absolute; + inset-block-start: 50%; + inset-inline-start: var(--use-offset, var(--use-pct)); + transform: translate(-50%, -50%); + pointer-events: none; +} + /* FNXC:CommandCenter 2026-06-20-00:25: Mobile users must be able to drag horizontal concurrency sliders without the page scroll gesture stealing the thumb movement. Scope touch-action to these range inputs and preserve desktop accent/full-width behavior while increasing the hit area with design tokens. @@ -143,6 +161,10 @@ Mobile users must be able to drag horizontal concurrency sliders without the pag grid-template-columns: minmax(0, 1fr); } + .cc-controls-range-wrap { + --cc-controls-range-thumb-size: var(--space-xl); + } + .cc-controls-slider input[type="range"], .cc-controls-touch-slider { min-block-size: var(--space-2xl); diff --git a/packages/dashboard/app/components/command-center/CommandCenterControls.tsx b/packages/dashboard/app/components/command-center/CommandCenterControls.tsx index fa63230378..982a08e730 100644 --- a/packages/dashboard/app/components/command-center/CommandCenterControls.tsx +++ b/packages/dashboard/app/components/command-center/CommandCenterControls.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, type CSSProperties } from "react"; import { useTranslation } from "react-i18next"; import { Power } from "lucide-react"; import { DEFAULT_PROJECT_SETTINGS, type ColorTheme, type ThemeMode } from "@fusion/core"; @@ -62,6 +62,18 @@ function getConcurrencySliderMax(key: keyof ConcurrencyValues, value: number) { return Math.max(CONCURRENCY_SLIDER_LIMITS[key].max, value); } +function getUseMarkerRatio(current: number, min: number, max: number) { + if (max <= min) return 0; + return clamp((current - min) / (max - min), 0, 1); +} + +function getUseMarkerStyle(ratio: number): CSSProperties { + return { + "--use-pct": `${ratio * 100}%`, + "--use-offset": `calc((var(--cc-controls-range-thumb-size) / 2) + ((100% - var(--cc-controls-range-thumb-size)) * ${ratio}))`, + } as CSSProperties; +} + function StatusPill({ paused, label }: { paused: boolean; label: string }) { return ( @@ -149,6 +161,11 @@ export function CommandCenterControls({ projectId, colorTheme, themeMode, shadcn const effectiveGlobalPaused = globalPaused; const concurrencyValues = concurrencyState.data ?? DEFAULT_CONCURRENCY_VALUES; + const globalCountsLoaded = gc.status === "loaded"; + const projectActive = gc.projectActiveCount(projectId); + const maxConcurrentSliderMax = getConcurrencySliderMax("maxConcurrent", concurrencyValues.maxConcurrent); + const globalUseMarkerRatio = getUseMarkerRatio(gc.currentlyActive, gc.min, gc.sliderMax); + const projectUseMarkerRatio = getUseMarkerRatio(projectActive, CONCURRENCY_SLIDER_LIMITS.maxConcurrent.min, maxConcurrentSliderMax); // FNXC:GlobalConcurrencyControls 2026-06-25-22:45: Mirror the per-project slider save-state labels for the shared global cap. // FNXC:GlobalConcurrencyControls 2026-06-26-06:05: Explicit load-error branch — a failed initial load leaves saveState "idle", so the label otherwise fell through to "Ready" while the slider was disabled and an error alert shown. const globalSaveLabel = gc.status === "loading" || gc.status === "idle" @@ -260,22 +277,41 @@ export function CommandCenterControls({ projectId, colorTheme, themeMode, shadcn FNXC:GlobalConcurrencyControls 2026-06-25-14:10: Operators need to adjust the global cross-project concurrency cap from the footer engine menu and the dashboard Concurrency card, not just the Settings modal; global cap is distinct from per-project maxConcurrent and persists via the central /api/global-concurrency endpoint. */} + {/** + FNXC:GlobalConcurrencyControls 2026-06-26-00:00: + The Command Center Concurrency card mirrors the footer's read-only utilization readouts from the shared global-concurrency hook. These counts are display-only capacity context and must never write running-agent totals back to settings. + */}