Files
Aislo/B05_Profile/B05_Profile_UI_Drainage_Run.ts
T
eomsangdonandClaude Opus 5.5 a5c36a4a29 feat(B05 배수유역): 347-2 자동/수동 다시 셈 · ⚙ 설정 창 · 347-3 제안 목록 · [적용]
- 계산 묶음 drainage 단계(pipelineStage · 붙이기 = 묶음 쪽) — 노선 초안 · 관이 바뀌면 낡음 · 자동 = 3 s 조용한 뒤 「지금 노선으로 셈」 · 수동 = 칸만 흐림 + 가운데 [업데이트] · 구석 「계산 중」 · 다시 조작하면 요청 끊고 처음으로 · 덮개 없음
- ⚙ 설정 창(배수유역 칸 머리 · openModal) 수동(기본) / 자동 · 계정 화면 설정 drainage-mode(b_page_state 등록표 한 줄 · build:corridor 다시 지음)
- 늦은 답 버림 = 차례 번호 · 서버 superseded · 세부유역 요청 감싸기와 같은 차례(B05_Profile_UI_Drainage_Run 으로 나눔)
- 제안 = 관경(Ø→Ø) · 시설(BOX암거 · 세월교) · 관 자리 후보(지도 점선 원) · [적용] 한 번에 관 초안 · 자동 바꿈 없음
- [확정] savePipes(confirm) = PUT ?recompute=true · [저장] = 낡음 달고 저장 · 패널 691줄
- 순수 규칙 logic/B05_Profile_Drainage_Live · _Suggest · 시험 test_347_2_drainage_live_ui · typecheck 통과

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
2026-10-16 11:47:55 +09:00

73 lines
3.0 KiB
TypeScript

/* =============================================================================
* B05_Profile_UI_Drainage_Run.ts
* 세부유역 요청 한 번 감싸기 — 버튼 잠금 · 진행 문구 · 오류 표기 · 최신 응답만 채택(차례 번호).
*
* 패널 본체(B05_Profile_UI_Drainage_Panel)가 700줄이라 나눔(347-2). 「지금 노선으로 셈」 답도
* 같은 차례 번호를 타서, 늦게 온 세부유역 답이 새 답을 덮지 않음 — `quiet` 이면 버튼 · 가운데 진행
* 원 · 상태 글을 안 건드림(칸 구석 「계산 중」은 부르는 쪽 · 조작을 막지 않음).
* ========================================================================== */
import type { DetailBasinResponse } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
import { analyzeFailed } from "./B05_Profile_UI_Drainage_Parts";
type StatusKey =
| "B05_Drainage_Status_Analyzing"
| "B05_Drainage_Status_NoBasin"
| "B05_Drainage_Status_AnalyzeFailed";
export interface DetailRunnerDeps {
projectId: () => string | null;
analyzeButton: HTMLButtonElement;
status: HTMLElement;
showProgress: (ratio: number | null, label: string | null) => void;
apply: (response: DetailBasinResponse) => void;
basinCount: () => number;
scheduleDraw: () => void;
label: (key: StatusKey) => string;
}
export interface DetailRunner {
projectId: () => string | null;
/** 요청 하나 — 답을 화면에 올렸으면 true(뒤에 보낸 요청이 있으면 false). */
run(request: () => Promise<DetailBasinResponse>, quiet?: boolean): Promise<boolean>;
}
export function createDetailRunner(deps: DetailRunnerDeps): DetailRunner {
const { analyzeButton, status, showProgress, label } = deps;
let requestSeq = 0; // 세부유역 요청 — 최신 응답만 채택
return {
projectId: deps.projectId,
async run(request, quiet = false) {
if (!deps.projectId()) return false;
if (!quiet) {
analyzeButton.disabled = true;
status.hidden = false;
status.textContent = label("B05_Drainage_Status_Analyzing");
showProgress(null, label("B05_Drainage_Status_Analyzing"));
}
const seq = ++requestSeq;
try {
const response = await request();
if (seq !== requestSeq) return false; // 뒤에 보낸 요청이 있음 — 그 응답을 기다림
deps.apply(response);
status.hidden = deps.basinCount() > 0;
if (!deps.basinCount())
status.textContent = response.stale ?? label("B05_Drainage_Status_NoBasin");
deps.scheduleDraw();
return true;
} catch (error) {
if (seq !== requestSeq) return false;
if (error instanceof DOMException && error.name === "AbortError") return false;
status.hidden = false;
status.textContent = analyzeFailed(error, label("B05_Drainage_Status_AnalyzeFailed"));
return false;
} finally {
if (seq === requestSeq) {
analyzeButton.disabled = false;
showProgress(null, null);
}
}
},
};
}