update
This commit is contained in:
@@ -224,12 +224,12 @@ async function handleResetFromStep(step) {
|
||||
await loadBlocks()
|
||||
}
|
||||
|
||||
async function handleBlocksClick({ instructions, abPhase = null, abStep = null }) {
|
||||
async function handleBlocksClick({ instructions, abPhase = null, abStep = null, toStep = null }) {
|
||||
if (!selectedTopic.value) return
|
||||
uiError.value = null
|
||||
try {
|
||||
// Source is already fixed here; abPhase/abStep control the re-run scope.
|
||||
await apiCreateBausteine(selectedTopic.value, instructions, provider.value, undefined, undefined, abPhase, abStep)
|
||||
// Source is already fixed here; abPhase/abStep set the start, toStep an optional end limit.
|
||||
await apiCreateBausteine(selectedTopic.value, instructions, provider.value, undefined, undefined, abPhase, abStep, toStep)
|
||||
} catch (e) {
|
||||
uiError.value = e.message
|
||||
return
|
||||
@@ -422,7 +422,7 @@ onMounted(async () => {
|
||||
:ready="blocks.ready"
|
||||
:partial="blocks.partial"
|
||||
@close="mainView = 'detail'"
|
||||
@restartFrom="(i) => handleBlocksClick({ instructions: '', abStep: i })"
|
||||
@restartFrom="(r) => handleBlocksClick({ instructions: '', abStep: r.from, toStep: r.to })"
|
||||
@resetFrom="handleResetFromStep"
|
||||
@restartAll="() => handleBlocksClick({ abPhase: blocks.ready ? 1 : null })"
|
||||
@removeAll="handleResetBlocks"
|
||||
|
||||
@@ -47,11 +47,11 @@ export async function fetchBlocksStatus(topic) {
|
||||
return res.json()
|
||||
}
|
||||
|
||||
export async function createBlocks(topic, instructions = '', provider = 'claude', sourceType = 'thema', sourceOrt = '', abPhase = null, abStep = null) {
|
||||
export async function createBlocks(topic, instructions = '', provider = 'claude', sourceType = 'thema', sourceOrt = '', abPhase = null, abStep = null, toStep = null) {
|
||||
const res = await fetch(`${BASE}/blocks`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ topic, instructions, provider, source_type: sourceType, source_location: sourceOrt, ab_phase: abPhase, ab_step: abStep }),
|
||||
body: JSON.stringify({ topic, instructions, provider, source_type: sourceType, source_location: sourceOrt, ab_phase: abPhase, ab_step: abStep, to_step: toStep }),
|
||||
})
|
||||
return jsonOrThrow(res)
|
||||
}
|
||||
|
||||
@@ -23,22 +23,32 @@ const phaseGroups = computed(() => {
|
||||
return out
|
||||
})
|
||||
|
||||
const selected = ref(null) // marked start point (step index)
|
||||
const startSel = ref(null) // marked start point (step index) — only ≤ current stand
|
||||
const endSel = ref(null) // optional end point (step index, > start) — generation stops there
|
||||
const confirm = ref(null) // which destructive action currently shows "Sure?"
|
||||
const selectedLabel = computed(() => props.steps[selected.value]?.label || '')
|
||||
const startLabel = computed(() => props.steps[startSel.value]?.label || '')
|
||||
const endLabel = computed(() => props.steps[endSel.value]?.label || '')
|
||||
|
||||
// Start is only valid up to the current stand: done/active steps, never a pending one (never ran).
|
||||
function startDisabled(idx) { return startSel.value === null && props.steps[idx]?.state === 'pending' }
|
||||
function inRange(idx) { return startSel.value !== null && endSel.value !== null && idx > startSel.value && idx < endSel.value }
|
||||
|
||||
function stepClick(idx) {
|
||||
if (props.generating) return
|
||||
selected.value = selected.value === idx ? null : idx
|
||||
if (props.generating || startDisabled(idx)) return
|
||||
confirm.value = null
|
||||
if (startSel.value === null) { startSel.value = idx; endSel.value = null } // 1st click → start
|
||||
else if (idx === startSel.value) { startSel.value = null; endSel.value = null } // re-click start → clear
|
||||
else if (idx > startSel.value) { endSel.value = endSel.value === idx ? null : idx } // later step → toggle end
|
||||
else if (props.steps[idx]?.state !== 'pending') { startSel.value = idx; endSel.value = null } // earlier → new start
|
||||
}
|
||||
function clearSel() { startSel.value = null; endSel.value = null; confirm.value = null }
|
||||
// 2-click confirmation for destructive actions: first click "arms", second runs it.
|
||||
function arm(action, fn) {
|
||||
if (confirm.value === action) { confirm.value = null; fn() }
|
||||
else confirm.value = action
|
||||
}
|
||||
function regenerateFromHere() { const i = selected.value; selected.value = null; confirm.value = null; emit('restartFrom', i) }
|
||||
function deleteFromHere() { const i = selected.value; selected.value = null; confirm.value = null; emit('resetFrom', i) }
|
||||
function regenerateFromHere() { const from = startSel.value, to = endSel.value; clearSel(); emit('restartFrom', { from, to }) }
|
||||
function deleteFromHere() { const from = startSel.value; clearSel(); emit('resetFrom', from) }
|
||||
|
||||
const items = ref([])
|
||||
const loading = ref(true)
|
||||
@@ -119,19 +129,19 @@ const subTotal = computed(() => items.value.reduce((n, b) => n + (b.subblocks?.l
|
||||
v-for="s in g.steps"
|
||||
:key="s.idx"
|
||||
class="bk-step"
|
||||
:class="[s.state, { sel: selected === s.idx }]"
|
||||
:disabled="generating"
|
||||
:title="`Choose start point «${s.label}»`"
|
||||
:class="[s.state, { sel: startSel === s.idx, end: endSel === s.idx, 'in-range': inRange(s.idx) }]"
|
||||
:disabled="generating || startDisabled(s.idx)"
|
||||
:title="startDisabled(s.idx) ? `«${s.label}» — not reached yet` : (startSel !== null && s.idx > startSel ? `End at «${s.label}»` : `Start at «${s.label}»`)"
|
||||
@click="stepClick(s.idx)"
|
||||
>{{ s.label }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selected !== null && !generating" class="bk-step-actions">
|
||||
<span class="bk-step-actions-label">From «{{ selectedLabel }}»:</span>
|
||||
<div v-if="startSel !== null && !generating" class="bk-step-actions">
|
||||
<span class="bk-step-actions-label">From «{{ startLabel }}»<span v-if="endSel !== null"> to «{{ endLabel }}»</span>:</span>
|
||||
<button class="bk-act play" @click="regenerateFromHere">↻ regenerate</button>
|
||||
<button class="bk-act danger" :class="{ armed: confirm === 'reset' }" @click="arm('reset', deleteFromHere)">{{ confirm === 'reset' ? 'Sure?' : '✕ delete all' }}</button>
|
||||
<button class="bk-act ghost" @click="selected = null; confirm = null">Cancel</button>
|
||||
<button class="bk-act ghost" @click="clearSel">Cancel</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -251,7 +261,10 @@ const subTotal = computed(() => items.value.reduce((n, b) => n + (b.subblocks?.l
|
||||
.bk-step.done { border-color: var(--success-border); color: var(--success); }
|
||||
.bk-step.active { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); font-weight: 600; }
|
||||
.bk-step.pending { color: var(--text-faint); }
|
||||
.bk-step.sel { border-color: var(--accent); color: var(--on-accent); background: var(--accent); font-weight: 700; box-shadow: 0 0 0 2px var(--accent-soft); }
|
||||
.bk-step.sel,
|
||||
.bk-step.end { border-color: var(--accent); color: var(--on-accent); background: var(--accent); font-weight: 700; box-shadow: 0 0 0 2px var(--accent-soft); }
|
||||
.bk-step.in-range { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
|
||||
.bk-step:disabled:not(.done):not(.active) { opacity: 0.45; }
|
||||
|
||||
/* Header: progress left, global buttons right */
|
||||
.bk-steps-top { display: flex; align-items: center; gap: 1rem; min-height: 1.9rem; margin-bottom: 0.7rem; }
|
||||
|
||||
Reference in New Issue
Block a user