refactor(ui): settings-card primitives + fix threshold clamp / card misgroup (#161)
Tier-3 frontend DRY for the ML settings cards, plus the F-D2 clamp bug and the F-D3 card misgrouping. New primitives (components/common + composables): - <SettingToggleRow> — the accent-icon + .fc-section-h label + right-aligned switch row (HeadsCard x3, CropProposersCard). iconColor prop absorbs the on/off dim. - <SettingNumberField> — compact numeric field that CLAMPS to [min,max] on commit. This fixes F-D2: HeadsCard/CropProposersCard previously sent Number(raw) straight to the API, so an out-of-range threshold bounced off the 400 validator (only TranslationCard clamped). density prop for the grid cards. - useSettingSave(patchFn) — the busy + patch + toast + revert-on-failure flow each card hand-rolled (HeadsCard x6 handlers, CropProposersCard, MLBackfillCard, VideoEmbeddingCard). Returns ok/false for the optimistic-switch revert. Adopted in HeadsCard, CropProposersCard, MLBackfillCard (handler only — its plain labelled switch is a different affordance), VideoEmbeddingCard. F-D3: MLThresholdSliders.vue actually rendered a "Video embedding" (frame- sampling) card but sat under "Tagging → Suggestion thresholds". Renamed it VideoEmbeddingCard.vue and moved it to the "GPU agent & embeddings" section. Left deliberately (over-DRY guard): TranslationCard uses an inline error ALERT (not a toast), already clamps its confidence with a NaN fallback, and lives on the ImportStore — a genuinely different save pattern, so forcing it onto useSettingSave would change its UX. Behaviour-preserving refactor; CI has no Vue type-check so this needs a live UI pass (toggles persist + revert on failure, thresholds clamp on blur, video card now under Embeddings). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsmJSQxnNxGgtM5Yz4GAqi
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import { ref } from 'vue'
|
||||
import { toast } from '../utils/toast.js'
|
||||
|
||||
// The shared "persist a settings patch" flow for the ML settings cards. Flips a
|
||||
// busy flag, calls the store's patch (which rethrows on failure), toasts
|
||||
// success/error, and returns true/false so a toggle handler can revert its
|
||||
// optimistic switch on failure. Centralises the try/catch/toast the cards each
|
||||
// hand-rolled (HeadsCard x6, CropProposersCard, MLBackfillCard) — and where the
|
||||
// threshold-clamp drifted; the clamp now lives in <SettingNumberField>.
|
||||
//
|
||||
// Pass the store's patch fn, e.g. useSettingSave(ml.patchSettings).
|
||||
export function useSettingSave(patchFn) {
|
||||
const busy = ref(false)
|
||||
|
||||
// opts.successMessage — toast on success (toggles announce their new state;
|
||||
// silent field-saves omit it). opts.errorPrefix — the failure toast prefix
|
||||
// ("Could not save" default; toggles used "Could not update").
|
||||
async function save(patch, { successMessage = '', errorPrefix = 'Could not save' } = {}) {
|
||||
busy.value = true
|
||||
try {
|
||||
await patchFn(patch)
|
||||
if (successMessage) toast({ text: successMessage, type: 'success' })
|
||||
return true
|
||||
} catch (e) {
|
||||
toast({ text: `${errorPrefix}: ${e.message}`, type: 'error' })
|
||||
return false
|
||||
} finally {
|
||||
busy.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return { busy, save }
|
||||
}
|
||||
Reference in New Issue
Block a user