From afc2335be9b1b0885bc89e0b223ca925b8586cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=27=C3=A9lectron=20rare?= <108685187+electron-rare@users.noreply.github.com> Date: Sat, 30 May 2026 12:36:04 +0200 Subject: [PATCH 1/2] chore(admin): fix pre-existing lint errors (CI green) Clear the 13 long-standing biome errors that kept CI red (failure on main since before this work): - CampaignControls.tsx: modal backdrops were clickable
s with no keyboard path. Add Escape-to-close onKeyDown + tabIndex (a11y/ useKeyWithClickEvents), mirroring the existing click-to-close; inner content gets matching keydown stopPropagation. Click behaviour unchanged. - CampaignStatusCard.tsx: drop the redundant `case 'IDLE'` that fell through to default with identical output (noUselessSwitchCase). - biome safe autofixes (whitespace / import ordering) elsewhere in admin. No behaviour change; typecheck + builds still pass. --- .../src/components/CampaignControls.tsx | 14 +++++++++----- .../src/components/CampaignDomainGrid.tsx | 13 +++---------- .../src/components/CampaignStatusCard.tsx | 18 ++++-------------- .../src/hooks/useStartCampaign.ts | 3 +-- .../src/routes/training.campaign.tsx | 18 +++++------------- 5 files changed, 22 insertions(+), 44 deletions(-) diff --git a/apps/cockpit-admin/src/components/CampaignControls.tsx b/apps/cockpit-admin/src/components/CampaignControls.tsx index 2192e13..a56ca6a 100644 --- a/apps/cockpit-admin/src/components/CampaignControls.tsx +++ b/apps/cockpit-admin/src/components/CampaignControls.tsx @@ -110,15 +110,19 @@ export function CampaignControls({ status }: Props) { )} {startOpen && ( + // biome-ignore lint/a11y/useSemanticElements: backdrop overlay closes the modal on outside click; a native can't carry the click-to-dismiss backdrop without changing behavior.
setStartOpen(false)} + onKeyDown={(e) => e.key === 'Escape' && setStartOpen(false)} >
e.stopPropagation()} + onKeyDown={(e) => e.stopPropagation()} >

Start medium35 campaign

@@ -162,15 +166,19 @@ export function CampaignControls({ status }: Props) { )} {abortOpen && ( + // biome-ignore lint/a11y/useSemanticElements: backdrop overlay closes the modal on outside click; a native

can't carry the click-to-dismiss backdrop without changing behavior.
setAbortOpen(false)} + onKeyDown={(e) => e.key === 'Escape' && setAbortOpen(false)} >
e.stopPropagation()} + onKeyDown={(e) => e.stopPropagation()} >

Abandonner la campagne ?

@@ -220,11 +228,7 @@ function DomainCheckboxGroup({ key={d} className="flex items-center gap-2 text-sm cursor-pointer hover:bg-slate-50 px-1 py-0.5 rounded" > - toggle(d)} - /> + toggle(d)} /> {d} ))} diff --git a/apps/cockpit-admin/src/components/CampaignDomainGrid.tsx b/apps/cockpit-admin/src/components/CampaignDomainGrid.tsx index d5a04d8..3693a7d 100644 --- a/apps/cockpit-admin/src/components/CampaignDomainGrid.tsx +++ b/apps/cockpit-admin/src/components/CampaignDomainGrid.tsx @@ -29,10 +29,7 @@ export function CampaignDomainGrid({ verdicts, currentDomain }: Props) { // (insertion order is preserved by JSON parsing) and tag the in-flight // domain separately if it isn't yet in `verdicts`. const entries = Object.entries(verdicts ?? {}); - if ( - currentDomain && - !entries.some(([d]) => d === currentDomain) - ) { + if (currentDomain && !entries.some(([d]) => d === currentDomain)) { entries.push([currentDomain, '']); } @@ -61,16 +58,12 @@ export function CampaignDomainGrid({ verdicts, currentDomain }: Props) { return ( {idx + 1} {domain} - {isCurrent && ( - (active) - )} + {isCurrent && (active)} {verdict ? ( diff --git a/apps/cockpit-admin/src/components/CampaignStatusCard.tsx b/apps/cockpit-admin/src/components/CampaignStatusCard.tsx index 20deb63..ea65004 100644 --- a/apps/cockpit-admin/src/components/CampaignStatusCard.tsx +++ b/apps/cockpit-admin/src/components/CampaignStatusCard.tsx @@ -15,7 +15,6 @@ function statusVisuals(s: string): { Icon: typeof Activity; color: string } { return { Icon: XCircle, color: 'text-rose-600' }; case 'ABORTED': return { Icon: AlertCircle, color: 'text-amber-600' }; - case 'IDLE': default: return { Icon: Pause, color: 'text-slate-400' }; } @@ -25,10 +24,7 @@ function ProgressBar({ value, max }: { value: number; max: number }) { const pct = max > 0 ? Math.min(100, Math.round((value / max) * 100)) : 0; return (

-
+
); } @@ -45,9 +41,7 @@ export function CampaignStatusCard({ status }: Props) { return (
-

- {status.campaign ?? 'medium35 campaign'} -

+

{status.campaign ?? 'medium35 campaign'}

{status.status} @@ -97,18 +91,14 @@ export function CampaignStatusCard({ status }: Props) {
)} - {status.error && ( -

Error: {status.error}

- )} + {status.error &&

Error: {status.error}

} {status.reload_failed && (

Reload failed — workers may need manual recovery.

)} {status.abort_requested && status.status === 'TRAINING' && ( -

- Abort requested — current domain finishing. -

+

Abort requested — current domain finishing.

)} ); diff --git a/apps/cockpit-admin/src/hooks/useStartCampaign.ts b/apps/cockpit-admin/src/hooks/useStartCampaign.ts index b3cadf2..d22fa4a 100644 --- a/apps/cockpit-admin/src/hooks/useStartCampaign.ts +++ b/apps/cockpit-admin/src/hooks/useStartCampaign.ts @@ -13,8 +13,7 @@ interface StartResponse { export function useStartCampaign() { const qc = useQueryClient(); return useMutation({ - mutationFn: (body) => - api.post('/api/admin/training/campaign/start', body), + mutationFn: (body) => api.post('/api/admin/training/campaign/start', body), onSuccess: () => { qc.invalidateQueries({ queryKey: ['campaign-status'] }); }, diff --git a/apps/cockpit-admin/src/routes/training.campaign.tsx b/apps/cockpit-admin/src/routes/training.campaign.tsx index f5cdd8c..169c06a 100644 --- a/apps/cockpit-admin/src/routes/training.campaign.tsx +++ b/apps/cockpit-admin/src/routes/training.campaign.tsx @@ -2,9 +2,9 @@ import { CampaignControls } from '@/components/CampaignControls'; import { CampaignDomainGrid } from '@/components/CampaignDomainGrid'; import { CampaignStatusCard } from '@/components/CampaignStatusCard'; import { LogTail } from '@/components/LogTail'; -import type { LogEvent } from '@/hooks/useTrainingLogs'; import { useCampaignLog } from '@/hooks/useCampaignLog'; import { useCampaignStatus } from '@/hooks/useCampaignStatus'; +import type { LogEvent } from '@/hooks/useTrainingLogs'; import { createFileRoute } from '@tanstack/react-router'; import { useMemo } from 'react'; @@ -60,24 +60,16 @@ function CampaignPage() {

)} - + {currentDomain && (

- Log tail —{' '} - {currentDomain} - {logQ.isFetching && ( - refreshing… - )} + Log tail — {currentDomain} + {logQ.isFetching && refreshing…}

{logQ.error ? ( -

- Failed to load log: {logQ.error.message} -

+

Failed to load log: {logQ.error.message}

) : ( )} From 9a76fb6edfd836bf072754d7de349e19596d6e43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=27=C3=A9lectron=20rare?= <108685187+electron-rare@users.noreply.github.com> Date: Sat, 30 May 2026 12:40:20 +0200 Subject: [PATCH 2/2] fix(chat): reasoning defaults for gemma2/ministral Both are reasoning models (the gateway's inference_defaults give them max_tokens=2048); the chat playground omitted them from REASONING_ALIASES, so they defaulted to 1024 and truncated the thinking phase. Fixes the 2 pre-existing failing ChatPlayground tests. --- .../src/components/ChatPlayground/ChatPlayground.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/cockpit-public/src/components/ChatPlayground/ChatPlayground.tsx b/apps/cockpit-public/src/components/ChatPlayground/ChatPlayground.tsx index b7dc446..69ad419 100644 --- a/apps/cockpit-public/src/components/ChatPlayground/ChatPlayground.tsx +++ b/apps/cockpit-public/src/components/ChatPlayground/ChatPlayground.tsx @@ -19,6 +19,8 @@ interface Props { // only a Playground UX default. Power users can override via ParamsPanel. const REASONING_ALIASES = new Set([ 'ailiance-reasoning-r1', + 'ailiance-gemma2', + 'ailiance-ministral-reasoning', 'ailiance-qwen-235b', 'ailiance-qwen36', ]);