Feat : added and tweaked state machine
All checks were successful
release / build (push) Successful in 39s
release / verify-windows (push) Successful in 1m17s

This commit is contained in:
jeanotx32
2026-08-11 23:21:35 +02:00
parent a5777ad920
commit 2380196169
14 changed files with 469 additions and 53 deletions

View File

@@ -112,7 +112,10 @@ export const api = {
body: JSON.stringify({ url, agentId }),
}),
updateTarget: (id: string, body: Partial<Pick<WatchTarget, 'label' | 'agentId' | 'notify'>>) =>
updateTarget: (
id: string,
body: Partial<Pick<WatchTarget, 'label' | 'agentId' | 'notify' | 'autoRecord'>>,
) =>
request<{ target: WatchTarget }>(`/watchlist/${id}`, {
method: 'PATCH',
body: JSON.stringify(body),

View File

@@ -1,7 +1,7 @@
import { useState } from 'react';
import type { AgentAction, AgentView, WatchState } from '@stream-control/shared';
import { findRecordingPreset } from '@stream-control/shared';
import { formatBytes, formatPercent, formatRelative, formatTimecode } from '../format';
import { formatBytes, formatDuration, formatPercent, formatRelative, formatTimecode } from '../format';
interface Props {
agent: AgentView;
@@ -237,6 +237,12 @@ function WatchStrip({
</button>
</div>
{watch.stopScheduledAt && (
<span className="small warn-text">
Hors-ligne clôture dans {formatDuration(watch.stopScheduledAt - Date.now())}
</span>
)}
{watch.lastError ? (
<span className="small error">Sonde en échec : {watch.lastError}</span>
) : (

View File

@@ -513,6 +513,33 @@ export function AgentSettings({ agent, targets, onClose, onCommand, notify }: Pr
</span>
</label>
<label className="checkbox">
<input
type="checkbox"
checked={watch.stopOnOffline}
onChange={(event) => patchWatch({ stopOnOffline: event.target.checked })}
/>
<span>Clore l'enregistrement quand le flux passe hors-ligne</span>
</label>
<label className="field">
<span>Attente avant clôture (minutes)</span>
<input
value={String(Math.round(watch.offlineStopDelayMs / 60_000))}
disabled={!watch.stopOnOffline}
onChange={(event) =>
patchWatch({ offlineStopDelayMs: (Number(event.target.value) || 0) * 60_000 })
}
inputMode="numeric"
/>
<span className="muted small">
Le passage hors-ligne met l'enregistrement en pause immédiatement l'écran
d'attente n'entre jamais dans le fichier. Ce délai ne décide que de la clôture :
en deçà, un retour du flux reprend le même fichier plutôt que d'en ouvrir un
second.
</span>
</label>
<label className="checkbox">
<input
type="checkbox"

View File

@@ -88,6 +88,20 @@ export function StreamersPage({
);
}
/**
* Explique, en une ligne, ce que l'automatisme fera ou pourquoi il ne fera rien.
* Un interrupteur coché qui reste sans effet est plus déroutant qu'un
* interrupteur absent.
*/
function autoRecordHint(target: WatchTarget, agent: AgentView | null): string {
if (!target.autoRecord) return ' — dès une minute de direct';
if (!agent) return ' — agent introuvable';
if (!agent.online) return ` — en attente : ${agent.name} est hors-ligne`;
if (agent.status.recording) return ` — en attente : ${agent.name} enregistre déjà`;
if (target.state === 'public') return ' — armé, direct en cours';
return ' — armé, en attente du prochain direct';
}
function StreamerCard({
target,
agents,
@@ -209,6 +223,25 @@ function StreamerCard({
</select>
</label>
<label className="checkbox">
<input
type="checkbox"
checked={target.autoRecord}
disabled={busy || !target.agentId}
onChange={(event) =>
void run(() => api.updateTarget(target.id, { autoRecord: event.target.checked }))
}
/>
<span>
Enregistrer automatiquement
<span className="muted small">
{!target.agentId
? ' assigne d\'abord un agent'
: autoRecordHint(target, agent)}
</span>
</span>
</label>
<div className="actions">
{recording ? (
<button