0.10.2-16 Frontend Features

This commit is contained in:
2026-03-17 10:51:28 +00:00
parent 7615cf0b47
commit 17b3aeb94e
11 changed files with 114 additions and 20 deletions
+48 -8
View File
@@ -143,7 +143,14 @@ function normalizeRuntimeActivitiesPayload(rawPayload) {
jobId: Number.isFinite(Number(source.jobId)) && Number(source.jobId) > 0 ? Math.trunc(Number(source.jobId)) : null,
cronJobId: Number.isFinite(Number(source.cronJobId)) && Number(source.cronJobId) > 0 ? Math.trunc(Number(source.cronJobId)) : null,
canCancel: Boolean(source.canCancel),
canNextStep: Boolean(source.canNextStep)
canNextStep: Boolean(source.canNextStep),
parentActivityId: Number.isFinite(Number(source.parentActivityId)) && Number(source.parentActivityId) > 0
? Math.trunc(Number(source.parentActivityId))
: null,
stepIndex: Number.isFinite(Number(source.stepIndex)) ? Math.trunc(Number(source.stepIndex)) : null,
stepTotal: Number.isFinite(Number(source.stepTotal)) && Number(source.stepTotal) > 0
? Math.trunc(Number(source.stepTotal))
: null
};
};
const active = (Array.isArray(payload.active) ? payload.active : []).map(normalizeItem);
@@ -2109,6 +2116,18 @@ export default function DashboardPage({
? runtimeActivities.recent.slice(0, 8)
: [];
// Group chain activities with their current child script — hide child scripts from top level
const activeChainChildIds = new Set(
runtimeActiveItems.filter((i) => i.parentActivityId != null).map((i) => i.id)
);
const activeItemsDisplay = runtimeActiveItems.filter((i) => !activeChainChildIds.has(i.id));
const findActiveChainChild = (chainId) => runtimeActiveItems.find((i) => i.parentActivityId === chainId) || null;
const recentChainChildIds = new Set(
runtimeRecentItems.filter((i) => i.parentActivityId != null).map((i) => i.id)
);
const recentItemsDisplay = runtimeRecentItems.filter((i) => !recentChainChildIds.has(i.id));
return (
<div className="page-grid">
<Toast ref={toastRef} />
@@ -2209,6 +2228,11 @@ export default function DashboardPage({
disabled={!canOpenMetadataModal}
/>
</div>
<div className="dashboard-drive-state">
{device
? <Tag value="Disk eingelegt" severity="success" icon="pi pi-circle-fill" />
: <Tag value="Laufwerk leer" severity="secondary" icon="pi pi-circle" />}
</div>
{device ? (
<div className="device-meta">
<div>
@@ -2690,12 +2714,20 @@ export default function DashboardPage({
<small className="queue-empty-hint">Keine laufenden Skript-/Ketten-/Cron-Ausführungen.</small>
) : (
<div className="runtime-activity-list">
{runtimeActiveItems.map((item, index) => {
{activeItemsDisplay.map((item, index) => {
const isChain = String(item?.type || '').trim().toLowerCase() === 'chain';
const chainChild = isChain ? findActiveChainChild(item?.id) : null;
const outputItem = chainChild || item;
const statusMeta = runtimeStatusMeta(item?.status);
const canCancel = Boolean(item?.canCancel);
const canNextStep = String(item?.type || '').trim().toLowerCase() === 'chain' && Boolean(item?.canNextStep);
const canNextStep = isChain && Boolean(item?.canNextStep);
const cancelBusy = isRuntimeActionBusy(item?.id, 'cancel');
const nextStepBusy = isRuntimeActionBusy(item?.id, 'next-step');
const stepLabel = item?.stepIndex != null && item?.stepTotal != null
? `Schritt ${item.stepIndex + 1}/${item.stepTotal}`
: item?.currentStep
? 'Schritt'
: null;
return (
<div key={`runtime-active-${item?.id || index}`} className="runtime-activity-item running">
<div className="runtime-activity-head">
@@ -2710,11 +2742,19 @@ export default function DashboardPage({
{item?.jobId ? ` | Job #${item.jobId}` : ''}
{item?.cronJobId ? ` | Cron #${item.cronJobId}` : ''}
</small>
{item?.currentStep ? <small>Schritt: {item.currentStep}</small> : null}
{item?.currentScriptName ? <small>Laufendes Skript: {item.currentScriptName}</small> : null}
{item?.message ? <small>{item.message}</small> : null}
{isChain && (chainChild || item?.currentStep || item?.currentScriptName) ? (
<div className="runtime-chain-current">
<small>
{stepLabel ? <strong>{stepLabel}: </strong> : null}
{chainChild?.name || item?.currentScriptName || item?.currentStep || null}
</small>
{chainChild?.message ? <small>{chainChild.message}</small> : null}
</div>
) : null}
{!isChain && item?.currentStep ? <small>Schritt: {item.currentStep}</small> : null}
{!isChain && item?.message ? <small>{item.message}</small> : null}
<RuntimeActivityDetails
item={item}
item={outputItem}
summary="Live-Ausgabe anzeigen"
/>
<small>Gestartet: {formatUpdatedAt(item?.startedAt)}</small>
@@ -2765,7 +2805,7 @@ export default function DashboardPage({
<small className="queue-empty-hint">Keine abgeschlossenen Einträge vorhanden.</small>
) : (
<div className="runtime-activity-list">
{runtimeRecentItems.map((item, index) => {
{recentItemsDisplay.map((item, index) => {
const outcomeMeta = runtimeOutcomeMeta(item?.outcome, item?.status);
return (
<div key={`runtime-recent-${item?.id || index}`} className="runtime-activity-item done">
+15
View File
@@ -367,6 +367,10 @@ body {
flex-wrap: wrap;
}
.dashboard-drive-state {
margin: 0.5rem 0;
}
.settings-expert-toggle {
display: inline-flex;
align-items: center;
@@ -3808,6 +3812,17 @@ body {
margin-top: 0.2rem;
}
.runtime-chain-current {
display: flex;
flex-direction: column;
gap: 0.1rem;
padding: 0.3rem 0.45rem;
border-left: 2px solid var(--rip-border);
margin: 0.1rem 0;
background: var(--rip-surface);
border-radius: 0 0.3rem 0.3rem 0;
}
.runtime-activity-details summary {
cursor: pointer;
font-size: 0.82rem;