refactor(settings): canonical usePreviewCommit for maintenance preview→commit tiles (#753)
Frontend pattern-consistency sweep (note #1026, the last DRY-thread item). TagMaintenanceCard (4 flows) + PostMaintenanceCard (2 flows) each hand-rolled the same sync preview→commit state machine: a previewData/previewing/committing triple + onPreview/onCommit that dry-run-previews, then applies and collapses the projection (the apply shares the backend predicate, so afterward it's empty). Extract usePreviewCommit({preview, commit, emptyPreview}) owning that lifecycle. The 6 flows become declarative: supply the two thunks + the collapse shape. The normalize flow (commit dispatches a self-resuming background task, not a sync apply) omits emptyPreview so the projection stays and a truthy result = queued. Composable returns are aliased to the cards' existing local names, so the templates only change where they read the apply result (the success badges). Long-Celery-task cards (GatedPurge/VideoDedup) keep useMaintenanceTask — a different pattern (navigable-away task lifecycle), deliberately not merged. Exhaustiveness: no card hand-rolls the refs anymore; the only dryRun:false callers are these two cards, both via the composable. Added a vitest spec for the primitive (collapse static + fn, dispatch-variant, re-preview clears result). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
// Canonical sync preview→commit flow for a maintenance tile: the operator
|
||||
// previews (dry-run) → sees the projection → commits (apply), where the apply
|
||||
// returns its result inline (no long Celery task). Owns the shared lifecycle —
|
||||
// the two loading flags, the preview payload, and the apply result — so each
|
||||
// tile stops hand-rolling its own `preview`/`loading`/`committing` refs +
|
||||
// onPreview/onCommit handlers (this was duplicated across 6 maintenance flows;
|
||||
// DRY pass #753).
|
||||
//
|
||||
// The tile supplies the `preview`/`commit` thunks (which call the right store
|
||||
// action with dryRun true/false) and, optionally, `emptyPreview`: the shape to
|
||||
// collapse the preview to after a successful apply — the apply uses the SAME
|
||||
// backend predicate as the preview, so afterward there's nothing left. Pass a
|
||||
// function to derive it from the apply result; omit it entirely for a commit
|
||||
// that dispatches a background task and should leave the preview in place.
|
||||
//
|
||||
// Errors surface via the store's own lastError (shown in the tile's alert), so
|
||||
// they're intentionally NOT captured here. For an apply that runs as a LONG
|
||||
// Celery task the operator can navigate away from, use useMaintenanceTask.
|
||||
export function usePreviewCommit ({ preview, commit, emptyPreview = null }) {
|
||||
const previewData = ref(null)
|
||||
const previewing = ref(false)
|
||||
const committing = ref(false)
|
||||
const result = ref(null)
|
||||
|
||||
async function runPreview () {
|
||||
previewing.value = true
|
||||
result.value = null // clear any prior apply badge when re-previewing
|
||||
try {
|
||||
previewData.value = await preview()
|
||||
} finally {
|
||||
previewing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function runCommit () {
|
||||
committing.value = true
|
||||
try {
|
||||
result.value = await commit()
|
||||
if (emptyPreview !== null) {
|
||||
previewData.value = typeof emptyPreview === 'function'
|
||||
? emptyPreview(result.value)
|
||||
: emptyPreview
|
||||
}
|
||||
} finally {
|
||||
committing.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return { previewData, previewing, committing, result, runPreview, runCommit }
|
||||
}
|
||||
Reference in New Issue
Block a user