Add a "Global Max Concurrent" slider to the footer engine menu and the Command Center Concurrency card, and group the Scheduling settings by Global vs Project scope so the global cap isn't mistaken for a per-project setting (clearer on mobile). Both sliders are backed by a single shared `useGlobalConcurrency` hook (module-level store) so they read/write one source of truth and revalidate after every PUT /api/global-concurrency — fixing the last-writer-wins and stale-clobber races a per-component cache would cause. The hook treats a fetch error as non-interactive (slider disabled, not stuck at 1), surfaces a save-state indicator, and flushes a pending edit on menu close / unmount so a quick drag-then-dismiss is never silently dropped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
169 lines
3.6 KiB
CSS
169 lines
3.6 KiB
CSS
.cc-controls {
|
|
min-inline-size: 0;
|
|
}
|
|
|
|
.cc-controls-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
gap: var(--space-md);
|
|
align-items: stretch;
|
|
}
|
|
|
|
.cc-controls-card {
|
|
min-inline-size: 0;
|
|
padding: var(--space-md);
|
|
border: 1px solid var(--border-subtle);
|
|
border-radius: var(--radius-md);
|
|
background: var(--surface-1);
|
|
}
|
|
|
|
.cc-controls-card--concurrency {
|
|
grid-column: 1 / -1;
|
|
}
|
|
|
|
.cc-controls-card-header {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: var(--space-md);
|
|
margin-block-end: var(--space-md);
|
|
}
|
|
|
|
.cc-controls-card-header h3 {
|
|
margin: 0;
|
|
color: var(--text);
|
|
font-size: 0.9375rem;
|
|
}
|
|
|
|
.cc-controls-card-header p,
|
|
.cc-controls-muted {
|
|
margin: var(--space-xs) 0 0;
|
|
color: var(--text-muted);
|
|
font-size: 0.8125rem;
|
|
}
|
|
|
|
.cc-controls-error {
|
|
margin: 0;
|
|
color: var(--color-error);
|
|
font-size: 0.8125rem;
|
|
}
|
|
|
|
.cc-controls-status-pill {
|
|
display: inline-flex;
|
|
flex: 0 0 auto;
|
|
align-items: center;
|
|
gap: var(--space-xs);
|
|
color: var(--text-muted);
|
|
font-size: 0.8125rem;
|
|
}
|
|
|
|
.cc-controls-action {
|
|
gap: var(--space-xs);
|
|
}
|
|
|
|
.cc-controls-save-state {
|
|
flex: 0 0 auto;
|
|
color: var(--text-muted);
|
|
font-size: 0.8125rem;
|
|
}
|
|
|
|
.cc-controls-save-state--saved {
|
|
color: var(--color-success);
|
|
}
|
|
|
|
.cc-controls-save-state--error {
|
|
color: var(--color-error);
|
|
}
|
|
|
|
.cc-controls-sliders {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
gap: var(--space-md);
|
|
}
|
|
|
|
.cc-controls-slider {
|
|
display: flex;
|
|
min-inline-size: 0;
|
|
flex-direction: column;
|
|
gap: var(--space-sm);
|
|
color: var(--text);
|
|
font-size: 0.8125rem;
|
|
}
|
|
|
|
/* FNXC:GlobalConcurrencyControls 2026-06-25-14:10: The global cap is a cross-project setting; span it full-width at the top of the Concurrency card and separate it from the per-project sliders with a divider plus an "Across all projects" caption. */
|
|
.cc-controls-slider--global {
|
|
grid-column: 1 / -1;
|
|
padding-bottom: var(--space-md);
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
|
|
.cc-controls-slider-caption {
|
|
color: var(--text-muted);
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.cc-controls-slider-label {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: var(--space-sm);
|
|
}
|
|
|
|
.cc-controls-slider-label strong {
|
|
color: var(--accent);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
|
|
/*
|
|
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.
|
|
*/
|
|
.cc-controls-slider input[type="range"],
|
|
.cc-controls-touch-slider {
|
|
inline-size: 100%;
|
|
min-block-size: var(--space-xl);
|
|
accent-color: var(--accent);
|
|
touch-action: pan-y;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.cc-controls-grid {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
}
|
|
|
|
.cc-controls-card {
|
|
padding: var(--space-sm);
|
|
}
|
|
|
|
.cc-controls-card-header {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.cc-controls-sliders {
|
|
grid-template-columns: minmax(0, 1fr);
|
|
}
|
|
|
|
.cc-controls-slider input[type="range"],
|
|
.cc-controls-touch-slider {
|
|
min-block-size: var(--space-2xl);
|
|
}
|
|
|
|
.cc-controls-slider input[type="range"]::-webkit-slider-thumb,
|
|
.cc-controls-touch-slider::-webkit-slider-thumb {
|
|
inline-size: var(--space-xl);
|
|
block-size: var(--space-xl);
|
|
}
|
|
|
|
.cc-controls-slider input[type="range"]::-moz-range-thumb,
|
|
.cc-controls-touch-slider::-moz-range-thumb {
|
|
inline-size: var(--space-xl);
|
|
block-size: var(--space-xl);
|
|
}
|
|
|
|
.cc-controls-action {
|
|
justify-content: center;
|
|
inline-size: 100%;
|
|
}
|
|
|
|
}
|