Workers P3: Nachträge aus der P2-Endprüfung (Kennungen, JWT-Sperre, Abmelden, Bestätigung)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-18 09:36:00 +00:00
1 parent c6c022678f
commit 777d5272bf
6 files changed
+279 -19

No files matched your search

+40 -4
View File
@@ -1,5 +1,6 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import Button from '../ui/Button'
import Dialog from '../ui/Dialog'
import EmptyState from '../ui/EmptyState'
import { useWorkerTrace, useWorkersFeed } from '../../hooks/useWorkersFeed'
import { indexWorkers, reduceEvents } from '../../lib/workersEvents'
@@ -34,6 +35,7 @@ export default function WorkersBoard({ api, isAdmin, stageRef }) {
const [settingsOpen, setSettingsOpen] = useState(false)
const [pausing, setPausing] = useState(false)
const [pauseError, setPauseError] = useState('')
const [confirmOpen, setConfirmOpen] = useState(false)
useEffect(() => {
aliveRef.current = true
@@ -53,6 +55,12 @@ export default function WorkersBoard({ api, isAdmin, stageRef }) {
const { trace, loading: traceLoading, error: traceError } = useWorkerTrace(api, selectedId)
// Hat inzwischen jemand anderes angehalten, entfällt die Frage; sie darf nach einem späteren Fortsetzen nicht wieder auftauchen
const haltedByState = Boolean(state?.paused)
useEffect(() => {
if (haltedByState) setConfirmOpen(false)
}, [haltedByState])
if (!loaded || !state) {
if (error) {
return (
@@ -82,13 +90,15 @@ export default function WorkersBoard({ api, isAdmin, stageRef }) {
}
}
// Pause für alle Mitarbeiter: der Dienst bekommt den Zielwert, danach wird der Zustand sofort neu geholt
const togglePause = async () => {
// Pause für alle Mitarbeiter: der Dienst bekommt den Zielwert (true = anhalten), danach wird der Zustand sofort neu geholt.
// Der Zielwert wird übergeben und nicht aus dem Zustand abgeleitet: ein offener Dialog darf nie fortsetzen, falls inzwischen
// jemand anderes angehalten hat.
const setPause = async (target) => {
if (pausing) return
setPausing(true)
setPauseError('')
try {
await api.pause(!paused)
await api.pause(target)
refresh()
} catch (err) {
if (aliveRef.current) setPauseError(err?.message || PAUSE_FAILED_TEXT)
@@ -96,12 +106,22 @@ export default function WorkersBoard({ api, isAdmin, stageRef }) {
if (aliveRef.current) setPausing(false)
}
// Anhalten betrifft alle Mitarbeiter sofort und fragt deshalb vorher nach; Fortsetzen ist harmlos und geht ohne Rückfrage
const requestPause = () => {
if (paused) setPause(false)
else setConfirmOpen(true)
}
const confirmHalt = () => {
setConfirmOpen(false)
setPause(true)
}
return (
<>
<div className="wk-toolbar">
<span className="wk-status">{paused ? PAUSED_TEXT : RUNNING_TEXT}</span>
<span className="grow" />
<Button type="button" onClick={togglePause} disabled={pausing}>{pauseLabel(paused)}</Button>
<Button type="button" onClick={requestPause} disabled={pausing}>{pauseLabel(paused)}</Button>
{isAdmin && <Button type="button" onClick={() => setSettingsOpen(true)}>Einstellungen</Button>}
</div>
@@ -133,6 +153,22 @@ export default function WorkersBoard({ api, isAdmin, stageRef }) {
{isAdmin && settingsOpen && (
<WorkersSettingsDialog api={api} onClose={() => setSettingsOpen(false)} onSaved={() => refresh()} />
)}
{confirmOpen && !paused && (
<Dialog
title="Alles anhalten?"
onClose={() => setConfirmOpen(false)}
footer={
<>
<span className="grow" />
<Button type="button" onClick={() => setConfirmOpen(false)}>Abbrechen</Button>
<Button variant="primary" type="button" onClick={confirmHalt}>Anhalten</Button>
</>
}
>
<p>Die Worker hören sofort auf, bis jemand fortsetzt.</p>
</Dialog>
)}
</>
)
}