This commit is contained in:
2026-07-10 19:52:06 +09:00
parent b98affbf99
commit 6b1583103f
19 changed files with 1515 additions and 98 deletions
@@ -100,6 +100,20 @@
background: var(--color-paper);
color: var(--color-text-secondary);
font-size: var(--text-caption);
border: 1px solid transparent;
cursor: default;
transition:
background-color var(--transition-base),
color var(--transition-base),
cursor var(--transition-base);
}
.ui-workflow-layout__step.is-enabled {
cursor: pointer;
}
.ui-workflow-layout__step.is-enabled:hover {
background: var(--color-paper-hover, var(--color-paper));
}
.ui-workflow-layout__step.is-active {
@@ -107,6 +121,28 @@
color: var(--color-accent);
}
.ui-workflow-layout__step:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.ui-workflow-layout__step.state-complete {
border-color: var(--color-success);
}
.ui-workflow-layout__step.state-in_progress {
border-color: var(--color-warning);
}
.ui-workflow-layout__step.state-stale {
border-color: var(--color-muted);
opacity: 0.7;
}
.ui-workflow-layout__step.state-failed {
border-color: var(--color-danger);
}
.ui-workflow-layout__body {
position: relative;
display: block;
+70 -7
View File
@@ -1,11 +1,20 @@
import "./ui_template_workflow_layout.css";
export interface WorkflowStage {
stage_no: number;
stage_key: string;
state: string;
}
export interface WorkflowLayoutOptions {
title: string;
steps: string[];
activeStep: number;
leftPanel: HTMLElement;
mainContent: HTMLElement;
stages?: WorkflowStage[];
routes?: string[];
onStepClick?: (stepIndex: number, route: string) => void;
onMenuToggle?: (isOpen: boolean) => void;
onHeaderToggle?: (isVisible: boolean) => void;
}
@@ -16,15 +25,62 @@ export interface WorkflowLayoutHandle {
setHeaderVisible: (isVisible: boolean) => void;
}
function createStepBar(steps: readonly string[], activeStep: number): HTMLElement {
function createStepBar(
steps: readonly string[],
activeStep: number,
options?: {
stages?: WorkflowStage[];
routes?: string[];
onStepClick?: (stepIndex: number, route: string) => void;
},
): HTMLElement {
const bar = document.createElement("div");
bar.className = "ui-workflow-layout__steps";
steps.forEach((step, index) => {
const item = document.createElement("span");
item.className = "ui-workflow-layout__step";
if (index === activeStep) item.classList.add("is-active");
item.textContent = step;
bar.append(item);
const button = document.createElement("button");
button.type = "button";
button.className = "ui-workflow-layout__step";
if (index === activeStep) button.classList.add("is-active");
button.textContent = step;
// DB state 기반 활성화 로직
let enabled = false;
if (options?.stages && options.stages.length > 0) {
enabled = index === 0 || options.stages[index - 1]?.state === "COMPLETE";
} else {
enabled = index <= activeStep;
}
button.disabled = !enabled;
if (enabled) {
button.classList.add("is-enabled");
}
// state 기반 스타일링
if (options?.stages && options.stages[index]) {
const state = options.stages[index].state;
button.classList.add(`state-${state.toLowerCase()}`);
if (state === "STALE") {
button.title = "Stale (하위 단계 변경으로 무효화됨)";
} else if (state === "FAILED") {
button.title = "Failed (실패)";
} else if (state === "COMPLETE") {
button.title = "Complete (완료)";
} else if (state === "IN_PROGRESS") {
button.title = "In Progress (진행 중)";
} else {
button.title = "Not Started (미실행)";
}
}
// 클릭 이벤트
if (enabled && options?.routes && options?.routes[index]) {
button.addEventListener("click", () => {
options.onStepClick?.(index, options.routes![index]);
});
}
bar.append(button);
});
return bar;
}
@@ -47,7 +103,14 @@ export function createWorkflowLayout(options: WorkflowLayoutOptions): WorkflowLa
const title = document.createElement("h2");
title.className = "ui-workflow-layout__title";
title.textContent = options.title;
titleWrap.append(title, createStepBar(options.steps, options.activeStep));
titleWrap.append(
title,
createStepBar(options.steps, options.activeStep, {
stages: options.stages,
routes: options.routes,
onStepClick: options.onStepClick,
}),
);
const headerHideButton = document.createElement("button");
headerHideButton.type = "button";