web-ui: добавлена страница группового удаления загрузок
- выбор → поимённое подтверждение → отчёт: пачка до 20 загрузок, гарды входа на обеих границах, потолок времени и остановка после трёх подряд отказов внешнего сервиса - допуск полного удаления сведён в единую точку store.State.CanDelete() — worker, страница загрузки и Telegram больше не держат своих перечней
This commit is contained in:
@@ -48,22 +48,20 @@ func (b *Bot) renderCard(rd *worker.ReviewData) (string, *tgbotapi.InlineKeyboar
|
||||
case store.StateLinking:
|
||||
return "⏳ Раскладываю #" + idCode(id) + "…", nil
|
||||
case store.StateDone:
|
||||
return b.renderDone(rd), b.deletableKeyboard(id)
|
||||
return b.renderDone(rd), b.stateKeyboard(id, state)
|
||||
default:
|
||||
// state — внутренний enum состояния (не внешний ввод), экранировать не нужно.
|
||||
text := fmt.Sprintf("Задача #%s — %s.", idCode(id), state)
|
||||
if msg := rd.Download.ErrorMsg.String; msg != "" {
|
||||
text += "\n" + esc(msg)
|
||||
}
|
||||
switch state {
|
||||
case store.StateFailed, store.StateStuck:
|
||||
if state == store.StateFailed || state == store.StateStuck {
|
||||
// failed/stuck — даём кнопку повтора.
|
||||
return text, b.retryKeyboard(id)
|
||||
case store.StateOrphaned, store.StateTargetMissing:
|
||||
// Рассинхрон — можно подчистить остатки полным удалением.
|
||||
return text, b.deletableKeyboard(id)
|
||||
}
|
||||
return text, b.webOnly(id)
|
||||
// Рассинхрон (orphaned/target_missing) — можно подчистить остатки полным
|
||||
// удалением; какие именно состояния это допускают, знает домен.
|
||||
return text, b.stateKeyboard(id, state)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,6 +290,18 @@ func (b *Bot) retryKeyboard(id string) *tgbotapi.InlineKeyboardMarkup {
|
||||
return &kb
|
||||
}
|
||||
|
||||
// stateKeyboard выбирает клавиатуру по допуску удаления: своего перечня
|
||||
// состояний транспорт не держит, предикат живёт в домене (см.
|
||||
// openspec/specs/state-reconciliation, «Полное удаление загрузки
|
||||
// пользователем»). Допуск в ядре это не заменяет — worker.Delete проверяет его
|
||||
// сам.
|
||||
func (b *Bot) stateKeyboard(id string, state store.State) *tgbotapi.InlineKeyboardMarkup {
|
||||
if state.CanDelete() {
|
||||
return b.deletableKeyboard(id)
|
||||
}
|
||||
return b.webOnly(id)
|
||||
}
|
||||
|
||||
// deletableKeyboard — клавиатура состояний, откуда доступно полное удаление
|
||||
// (done/orphaned/target_missing): ссылка в веб (опц.) + «Закрыть» (стоп-кран, лишь
|
||||
// статус) + «Удалить» (снос раздачи+файлов). Обе команды двухшаговые — кнопка
|
||||
|
||||
Reference in New Issue
Block a user