fix(tgu-ui): гасить «Создать черновик» для стартовавшего плана (replace→422)
Кнопка предлагала replace-черновик для уже стартовавшего плана, хотя бэк (CreateDraftUseCase.createReplaceDraft) возвращает 422 «окно выдачи заморожено». Гард canCreateDraftFromPlan теперь требует startInFuture (зеркалит редактор); для стартовавших eligible-планов вместо кнопки — amber-подсказка про fork-forward.
This commit is contained in:
@@ -82,14 +82,20 @@ export function TguPlanDetails({
|
|||||||
const duration = formatDuration(plan.endMs - plan.startMs);
|
const duration = formatDuration(plan.endMs - plan.startMs);
|
||||||
// Окно решения закрылось, если с момента старта плана прошло больше grace-периода.
|
// Окно решения закрылось, если с момента старта плана прошло больше grace-периода.
|
||||||
const decisionWindowClosed = Date.now() > plan.startMs + DECISION_GRACE_MINUTES * 60_000;
|
const decisionWindowClosed = Date.now() > plan.startMs + DECISION_GRACE_MINUTES * 60_000;
|
||||||
// Закладку нельзя подтверждать, пока начало плана ещё в будущем: план закладывается на КА
|
// Начало плана ещё в будущем. Нужно и для закладки (план закладывается по факту старта,
|
||||||
// по факту наступления своего старта, а не заранее.
|
// не заранее), и для replace-черновика (после старта окно выдачи заморожено — бэк вернёт 422).
|
||||||
const layinStartInFuture = plan.startMs > Date.now();
|
const startInFuture = plan.startMs > Date.now();
|
||||||
// «Создать черновик на основе плана» (replace, окно 1:1, все включения) доступно для
|
// «Создать черновик на основе плана» (replace, окно 1:1, все включения) доступно для
|
||||||
// персистентных правимых баз. DRAFT уже имеет свои действия; PLANNED — виртуальная проекция,
|
// персистентных правимых баз, у которых старт ещё не наступил. DRAFT уже имеет свои действия;
|
||||||
// не база; LAID_IN — replace 1:1 запрещён (слот зафиксирован, только fork-forward).
|
// PLANNED — виртуальная проекция, не база; LAID_IN — replace 1:1 запрещён (слот зафиксирован);
|
||||||
const canCreateDraftFromPlan =
|
// стартовавший план — окно выдачи заморожено (CreateDraftUseCase.createReplaceDraft → 422),
|
||||||
|
// продолжение возможно только fork-forward (отдельный поток). Гард зеркалит редактор, чтобы
|
||||||
|
// не предлагать кнопку, которая заведомо упадёт «Unprocessable Content».
|
||||||
|
const draftableStatus =
|
||||||
plan.status !== "DRAFT" && plan.status !== "PLANNED" && plan.status !== "LAID_IN";
|
plan.status !== "DRAFT" && plan.status !== "PLANNED" && plan.status !== "LAID_IN";
|
||||||
|
const canCreateDraftFromPlan = draftableStatus && startInFuture;
|
||||||
|
// Статус позволял бы replace-черновик, но план уже стартовал — объясняем, почему кнопки нет.
|
||||||
|
const draftBlockedByStart = draftableStatus && !startInFuture;
|
||||||
|
|
||||||
const reject = () => {
|
const reject = () => {
|
||||||
const reason = window.prompt("Reason для REJECTED", "UI_TEST_REJECTED");
|
const reason = window.prompt("Reason для REJECTED", "UI_TEST_REJECTED");
|
||||||
@@ -229,15 +235,23 @@ export function TguPlanDetails({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{draftBlockedByStart && (
|
||||||
|
<div className="tgu-alert tgu-alert--warning">
|
||||||
|
Черновик-копию (replace, то же окно) можно создать только до старта плана — окно
|
||||||
|
выдачи уже заморожено. Продолжение цепочки на будущую ЗРВ (fork-forward) выполняется
|
||||||
|
отдельно.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{plan.status === "AWAITING_LAYIN" && onConfirmLayin && (
|
{plan.status === "AWAITING_LAYIN" && onConfirmLayin && (
|
||||||
<div className="tgu-details__test-block">
|
<div className="tgu-details__test-block">
|
||||||
<div className="tgu-details__test-label">ТЕСТОВЫЙ ФУНКЦИОНАЛ</div>
|
<div className="tgu-details__test-label">ТЕСТОВЫЙ ФУНКЦИОНАЛ</div>
|
||||||
<button
|
<button
|
||||||
className="tgu-button tgu-button--accept"
|
className="tgu-button tgu-button--accept"
|
||||||
type="button"
|
type="button"
|
||||||
disabled={decisionInFlight || layinConflict || layinStartInFuture}
|
disabled={decisionInFlight || layinConflict || startInFuture}
|
||||||
title={
|
title={
|
||||||
layinStartInFuture
|
startInFuture
|
||||||
? "Начало плана ещё не наступило — подтвердить закладку можно только после его старта"
|
? "Начало плана ещё не наступило — подтвердить закладку можно только после его старта"
|
||||||
: layinConflict
|
: layinConflict
|
||||||
? "По КА уже заложен план со стартом в пределах ±10 минут — закладка недоступна"
|
? "По КА уже заложен план со стартом в пределах ±10 минут — закладка недоступна"
|
||||||
@@ -247,12 +261,12 @@ export function TguPlanDetails({
|
|||||||
>
|
>
|
||||||
Подтвердить закладку
|
Подтвердить закладку
|
||||||
</button>
|
</button>
|
||||||
{layinStartInFuture && (
|
{startInFuture && (
|
||||||
<div className="tgu-details__test-hint">
|
<div className="tgu-details__test-hint">
|
||||||
Начало плана ещё в будущем — подтвердить закладку можно только после наступления его старта.
|
Начало плана ещё в будущем — подтвердить закладку можно только после наступления его старта.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{!layinStartInFuture && layinConflict && (
|
{!startInFuture && layinConflict && (
|
||||||
<div className="tgu-details__test-hint">
|
<div className="tgu-details__test-hint">
|
||||||
По КА уже есть заложенный план со стартом в пределах ±10 минут — подтвердить нельзя.
|
По КА уже есть заложенный план со стартом в пределах ±10 минут — подтвердить нельзя.
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user