0.12.0-2 Checkable Infrastructure
This commit is contained in:
@@ -742,16 +742,23 @@ export const api = {
|
||||
},
|
||||
async deleteJobEntry(jobId, target = 'none', options = {}) {
|
||||
const includeRelated = Boolean(options?.includeRelated);
|
||||
const resetDriveState = Boolean(options?.resetDriveState);
|
||||
const selectedMoviePaths = Array.isArray(options?.selectedMoviePaths)
|
||||
? options.selectedMoviePaths
|
||||
.map((item) => String(item || '').trim())
|
||||
.filter(Boolean)
|
||||
: null;
|
||||
const hasKeepDetectedDevice = options?.keepDetectedDevice !== undefined;
|
||||
const keepDetectedDevice = hasKeepDetectedDevice
|
||||
? Boolean(options.keepDetectedDevice)
|
||||
: null;
|
||||
const result = await request(`/history/${jobId}/delete`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
target,
|
||||
includeRelated,
|
||||
resetDriveState,
|
||||
...(hasKeepDetectedDevice ? { keepDetectedDevice } : {}),
|
||||
...(selectedMoviePaths ? { selectedMoviePaths } : {})
|
||||
})
|
||||
});
|
||||
|
||||
@@ -129,6 +129,7 @@ export default function AudiobookConfigPanel({
|
||||
onStart,
|
||||
onCancel,
|
||||
onRetry,
|
||||
onDeleteJob,
|
||||
busy
|
||||
}) {
|
||||
const context = pipeline?.context && typeof pipeline.context === 'object' ? pipeline.context : {};
|
||||
@@ -353,6 +354,17 @@ export default function AudiobookConfigPanel({
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{jobId ? (
|
||||
<Button
|
||||
label="Job löschen"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
outlined
|
||||
onClick={() => onDeleteJob?.(jobId)}
|
||||
loading={busy}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{isRunning ? (
|
||||
<Button
|
||||
label="Abbrechen"
|
||||
|
||||
@@ -229,6 +229,7 @@ export default function CdRipConfigPanel({
|
||||
onRetry,
|
||||
onRestartReview,
|
||||
onOpenMetadata,
|
||||
onDeleteJob,
|
||||
busy
|
||||
}) {
|
||||
const context = pipeline?.context && typeof pipeline.context === 'object' ? pipeline.context : {};
|
||||
@@ -809,6 +810,16 @@ export default function CdRipConfigPanel({
|
||||
onClick={() => onCancel && onCancel()}
|
||||
disabled={busy}
|
||||
/>
|
||||
{jobId ? (
|
||||
<Button
|
||||
label="Job löschen"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
outlined
|
||||
onClick={() => onDeleteJob && onDeleteJob(jobId)}
|
||||
disabled={busy}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
{isTerminalFailure ? (
|
||||
@@ -851,6 +862,16 @@ export default function CdRipConfigPanel({
|
||||
loading={busy}
|
||||
/>
|
||||
) : null}
|
||||
{jobId ? (
|
||||
<Button
|
||||
label="Job löschen"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
outlined
|
||||
onClick={() => onDeleteJob && onDeleteJob(jobId)}
|
||||
loading={busy}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -1297,6 +1318,16 @@ export default function CdRipConfigPanel({
|
||||
disabled={busy}
|
||||
/>
|
||||
) : null}
|
||||
{jobId ? (
|
||||
<Button
|
||||
label="Job löschen"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
outlined
|
||||
onClick={() => onDeleteJob && onDeleteJob(jobId)}
|
||||
disabled={busy}
|
||||
/>
|
||||
) : null}
|
||||
<Button
|
||||
label="Abbrechen"
|
||||
severity="secondary"
|
||||
|
||||
@@ -313,6 +313,7 @@ export default function PipelineStatusCard({
|
||||
onSelectHandBrakeTitle,
|
||||
onCancel,
|
||||
onRetry,
|
||||
onDeleteJob,
|
||||
isQueued = false,
|
||||
busy,
|
||||
liveJobLog = ''
|
||||
@@ -832,6 +833,16 @@ export default function PipelineStatusCard({
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
{retryJobId && typeof onDeleteJob === 'function' ? (
|
||||
<Button
|
||||
label="Job löschen"
|
||||
icon="pi pi-trash"
|
||||
severity="danger"
|
||||
outlined
|
||||
onClick={() => onDeleteJob?.(retryJobId)}
|
||||
loading={busy}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
{running ? (
|
||||
|
||||
@@ -731,6 +731,16 @@ function buildPipelineFromJob(job, currentPipeline, currentPipelineJobId) {
|
||||
&& !processingStates.includes(jobStatus)
|
||||
&& resolvedMediaType !== 'audiobook'
|
||||
);
|
||||
const cdSkipRipReady = Boolean(
|
||||
resolvedMediaType === 'cd'
|
||||
&& (
|
||||
Boolean(encodePlan?.skipRip)
|
||||
|| (
|
||||
Number(job?.rip_successful || 0) === 1
|
||||
&& Boolean(String(job?.raw_path || '').trim())
|
||||
)
|
||||
)
|
||||
);
|
||||
const computedContext = {
|
||||
jobId,
|
||||
rawPath: job?.raw_path || null,
|
||||
@@ -741,6 +751,7 @@ function buildPipelineFromJob(job, currentPipeline, currentPipelineJobId) {
|
||||
devicePath,
|
||||
cdparanoiaCmd,
|
||||
cdparanoiaCommandPreview,
|
||||
skipRip: cdSkipRipReady ? true : undefined,
|
||||
cdRipConfig,
|
||||
tracks: cdTracks,
|
||||
inputPath,
|
||||
@@ -1777,6 +1788,58 @@ export default function DashboardPage({
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteDashboardJob = async (jobId) => {
|
||||
const normalizedJobId = normalizeJobId(jobId);
|
||||
if (!normalizedJobId) {
|
||||
return;
|
||||
}
|
||||
const job = dashboardJobs.find((item) => normalizeJobId(item?.id) === normalizedJobId) || null;
|
||||
const title = String(job?.title || job?.detected_title || `Job #${normalizedJobId}`).trim();
|
||||
const confirmed = window.confirm(
|
||||
`Job #${normalizedJobId} wirklich löschen?\n` +
|
||||
`${title}\n\n` +
|
||||
'Hinweis: Dateien bleiben erhalten. Das zugeordnete Laufwerk wird freigegeben und auf Leerzustand zurückgesetzt.'
|
||||
);
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
setJobBusy(normalizedJobId, true);
|
||||
try {
|
||||
const statusBeforeDelete = String(job?.status || '').trim().toUpperCase();
|
||||
if (processingStates.includes(statusBeforeDelete)) {
|
||||
await api.cancelPipeline(normalizedJobId);
|
||||
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
for (let attempt = 0; attempt < 12; attempt += 1) {
|
||||
const latest = await api.getJob(normalizedJobId, { lite: true, forceRefresh: true }).catch(() => null);
|
||||
const latestStatus = String(latest?.job?.status || latest?.job?.last_state || '').trim().toUpperCase();
|
||||
if (!processingStates.includes(latestStatus)) {
|
||||
break;
|
||||
}
|
||||
await wait(250);
|
||||
}
|
||||
}
|
||||
await api.deleteJobEntry(normalizedJobId, 'none', {
|
||||
includeRelated: false,
|
||||
resetDriveState: true,
|
||||
keepDetectedDevice: false
|
||||
});
|
||||
await refreshPipeline();
|
||||
await loadDashboardJobs();
|
||||
setExpandedJobId((prev) => (normalizeJobId(prev) === normalizedJobId ? null : prev));
|
||||
toastRef.current?.show({
|
||||
severity: 'success',
|
||||
summary: 'Job gelöscht',
|
||||
detail: `Job #${normalizedJobId} wurde entfernt.`,
|
||||
life: 3200
|
||||
});
|
||||
} catch (error) {
|
||||
showError(error);
|
||||
} finally {
|
||||
setJobBusy(normalizedJobId, false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRestartEncodeWithLastSettings = async (jobId) => {
|
||||
const job = dashboardJobs.find((item) => normalizeJobId(item?.id) === normalizeJobId(jobId)) || null;
|
||||
const title = job?.title || job?.detected_title || `Job #${jobId}`;
|
||||
@@ -2702,6 +2765,7 @@ export default function DashboardPage({
|
||||
onCancel={() => handleCancel(jobId, jobState)}
|
||||
onRetry={() => handleRetry(jobId)}
|
||||
onRestartReview={() => handleRestartCdReviewFromRaw(jobId)}
|
||||
onDeleteJob={() => handleDeleteDashboardJob(jobId)}
|
||||
onOpenMetadata={() => {
|
||||
const ctx = pipelineForJob?.context && typeof pipelineForJob.context === 'object'
|
||||
? pipelineForJob.context
|
||||
@@ -2733,6 +2797,7 @@ export default function DashboardPage({
|
||||
onStart={(config) => handleAudiobookStart(jobId, config)}
|
||||
onCancel={() => handleCancel(jobId, jobState)}
|
||||
onRetry={() => handleRetry(jobId)}
|
||||
onDeleteJob={() => handleDeleteDashboardJob(jobId)}
|
||||
busy={busyJobIds.has(jobId) || needsBytes}
|
||||
/>
|
||||
</>
|
||||
@@ -2755,6 +2820,7 @@ export default function DashboardPage({
|
||||
onSelectHandBrakeTitle={handleSelectHandBrakeTitle}
|
||||
onCancel={handleCancel}
|
||||
onRetry={handleRetry}
|
||||
onDeleteJob={handleDeleteDashboardJob}
|
||||
onRemoveFromQueue={handleRemoveQueuedJob}
|
||||
isQueued={isQueued}
|
||||
busy={busyJobIds.has(jobId)}
|
||||
|
||||
@@ -15,7 +15,7 @@ const STATUS_LABELS = {
|
||||
ERROR: 'Fehler',
|
||||
CD_ANALYZING: 'CD-Analyse',
|
||||
CD_METADATA_SELECTION: 'CD-Metadatenauswahl',
|
||||
CD_READY_TO_RIP: 'CD bereit zum Rippen',
|
||||
CD_READY_TO_RIP: 'CD bereit (Rip/Encode)',
|
||||
CD_RIPPING: 'CD rippen',
|
||||
CD_ENCODING: 'CD encodieren'
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user