ERP-node/frontend/components/pop/designer/panels/ConnectionEditor.tsx

471 lines
15 KiB
TypeScript
Raw Normal View History

"use client";
import React from "react";
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
import { ArrowRight, Link2, Unlink2, Plus, Trash2, Pencil, X, Loader2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
import { Checkbox } from "@/components/ui/checkbox";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
PopComponentDefinitionV5,
PopDataConnection,
} from "../types/pop-layout";
import {
PopComponentRegistry,
} from "@/lib/registry/PopComponentRegistry";
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
import { getTableColumns } from "@/lib/api/tableManagement";
// ========================================
// Props
// ========================================
interface ConnectionEditorProps {
component: PopComponentDefinitionV5;
allComponents: PopComponentDefinitionV5[];
connections: PopDataConnection[];
onAddConnection?: (conn: Omit<PopDataConnection, "id">) => void;
onUpdateConnection?: (connectionId: string, conn: Omit<PopDataConnection, "id">) => void;
onRemoveConnection?: (connectionId: string) => void;
}
// ========================================
// ConnectionEditor
// ========================================
export default function ConnectionEditor({
component,
allComponents,
connections,
onAddConnection,
onUpdateConnection,
onRemoveConnection,
}: ConnectionEditorProps) {
const registeredComp = PopComponentRegistry.getComponent(component.type);
const meta = registeredComp?.connectionMeta;
const outgoing = connections.filter(
(c) => c.sourceComponent === component.id
);
const incoming = connections.filter(
(c) => c.targetComponent === component.id
);
const hasSendable = meta?.sendable && meta.sendable.length > 0;
const hasReceivable = meta?.receivable && meta.receivable.length > 0;
if (!hasSendable && !hasReceivable) {
return (
<div className="space-y-4">
<div className="rounded-lg bg-gray-50 p-4 text-center">
<Link2 className="mx-auto mb-2 h-8 w-8 text-muted-foreground" />
<p className="text-sm font-medium text-gray-700"> </p>
<p className="mt-1 text-xs text-muted-foreground">
</p>
</div>
</div>
);
}
return (
<div className="space-y-6">
{hasSendable && (
<SendSection
component={component}
allComponents={allComponents}
outgoing={outgoing}
onAddConnection={onAddConnection}
onUpdateConnection={onUpdateConnection}
onRemoveConnection={onRemoveConnection}
/>
)}
{hasReceivable && (
<ReceiveSection
component={component}
allComponents={allComponents}
incoming={incoming}
/>
)}
</div>
);
}
// ========================================
// 보내기 섹션
// ========================================
interface SendSectionProps {
component: PopComponentDefinitionV5;
allComponents: PopComponentDefinitionV5[];
outgoing: PopDataConnection[];
onAddConnection?: (conn: Omit<PopDataConnection, "id">) => void;
onUpdateConnection?: (connectionId: string, conn: Omit<PopDataConnection, "id">) => void;
onRemoveConnection?: (connectionId: string) => void;
}
function SendSection({
component,
allComponents,
outgoing,
onAddConnection,
onUpdateConnection,
onRemoveConnection,
}: SendSectionProps) {
const [editingId, setEditingId] = React.useState<string | null>(null);
return (
<div className="space-y-3">
<Label className="flex items-center gap-1 text-xs font-medium">
<ArrowRight className="h-3 w-3 text-blue-500" />
</Label>
{outgoing.map((conn) => (
<div key={conn.id}>
{editingId === conn.id ? (
<SimpleConnectionForm
component={component}
allComponents={allComponents}
initial={conn}
onSubmit={(data) => {
onUpdateConnection?.(conn.id, data);
setEditingId(null);
}}
onCancel={() => setEditingId(null)}
submitLabel="수정"
/>
) : (
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
<div className="space-y-1 rounded border bg-blue-50/50 px-3 py-2">
<div className="flex items-center gap-1">
<span className="flex-1 truncate text-xs">
{conn.label || `${allComponents.find((c) => c.id === conn.targetComponent)?.label || conn.targetComponent}`}
</span>
<button
onClick={() => setEditingId(conn.id)}
className="shrink-0 p-0.5 text-muted-foreground hover:text-primary"
>
<Pencil className="h-3 w-3" />
</button>
{onRemoveConnection && (
<button
onClick={() => onRemoveConnection(conn.id)}
className="shrink-0 p-0.5 text-muted-foreground hover:text-destructive"
>
<Trash2 className="h-3 w-3" />
</button>
)}
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
</div>
{conn.filterConfig?.targetColumn && (
<div className="flex flex-wrap gap-1">
<span className="rounded bg-white px-1.5 py-0.5 text-[9px] text-muted-foreground">
{conn.filterConfig.targetColumn}
</span>
<span className="rounded bg-white px-1.5 py-0.5 text-[9px] text-muted-foreground">
{conn.filterConfig.filterMode}
</span>
{conn.filterConfig.isSubTable && (
<span className="rounded bg-amber-100 px-1.5 py-0.5 text-[9px] text-amber-700">
</span>
)}
</div>
)}
</div>
)}
</div>
))}
<SimpleConnectionForm
component={component}
allComponents={allComponents}
onSubmit={(data) => onAddConnection?.(data)}
submitLabel="연결 추가"
/>
</div>
);
}
// ========================================
// 단순 연결 폼 (이벤트 타입: "어디로" 1개만)
// ========================================
interface SimpleConnectionFormProps {
component: PopComponentDefinitionV5;
allComponents: PopComponentDefinitionV5[];
initial?: PopDataConnection;
onSubmit: (data: Omit<PopDataConnection, "id">) => void;
onCancel?: () => void;
submitLabel: string;
}
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
function extractSubTableName(comp: PopComponentDefinitionV5): string | null {
const cfg = comp.config as Record<string, unknown> | undefined;
if (!cfg) return null;
const grid = cfg.cardGrid as { cells?: Array<{ timelineSource?: { processTable?: string } }> } | undefined;
if (grid?.cells) {
for (const cell of grid.cells) {
if (cell.timelineSource?.processTable) return cell.timelineSource.processTable;
}
}
return null;
}
function SimpleConnectionForm({
component,
allComponents,
initial,
onSubmit,
onCancel,
submitLabel,
}: SimpleConnectionFormProps) {
const [selectedTargetId, setSelectedTargetId] = React.useState(
initial?.targetComponent || ""
);
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
const [isSubTable, setIsSubTable] = React.useState(
initial?.filterConfig?.isSubTable || false
);
const [targetColumn, setTargetColumn] = React.useState(
initial?.filterConfig?.targetColumn || ""
);
const [filterMode, setFilterMode] = React.useState<string>(
initial?.filterConfig?.filterMode || "equals"
);
const [subColumns, setSubColumns] = React.useState<string[]>([]);
const [loadingColumns, setLoadingColumns] = React.useState(false);
const targetCandidates = allComponents.filter((c) => {
if (c.id === component.id) return false;
const reg = PopComponentRegistry.getComponent(c.type);
return reg?.connectionMeta?.receivable && reg.connectionMeta.receivable.length > 0;
});
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
const sourceReg = PopComponentRegistry.getComponent(component.type);
const targetComp = allComponents.find((c) => c.id === selectedTargetId);
const targetReg = targetComp ? PopComponentRegistry.getComponent(targetComp.type) : null;
const isFilterConnection = sourceReg?.connectionMeta?.sendable?.some((s) => s.type === "filter_value")
&& targetReg?.connectionMeta?.receivable?.some((r) => r.type === "filter_value");
const subTableName = targetComp ? extractSubTableName(targetComp) : null;
React.useEffect(() => {
if (!isSubTable || !subTableName) {
setSubColumns([]);
return;
}
setLoadingColumns(true);
getTableColumns(subTableName)
.then((res) => {
const cols = res.success && res.data?.columns;
if (Array.isArray(cols)) {
setSubColumns(cols.map((c) => c.columnName || "").filter(Boolean));
}
})
.catch(() => setSubColumns([]))
.finally(() => setLoadingColumns(false));
}, [isSubTable, subTableName]);
const handleSubmit = () => {
if (!selectedTargetId) return;
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
const tComp = allComponents.find((c) => c.id === selectedTargetId);
const srcLabel = component.label || component.id;
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
const tgtLabel = tComp?.label || tComp?.id || "?";
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
const conn: Omit<PopDataConnection, "id"> = {
sourceComponent: component.id,
sourceField: "",
sourceOutput: "_auto",
targetComponent: selectedTargetId,
targetField: "",
targetInput: "_auto",
label: `${srcLabel}${tgtLabel}`,
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
};
if (isFilterConnection && isSubTable && targetColumn) {
conn.filterConfig = {
targetColumn,
filterMode: filterMode as "equals" | "contains" | "starts_with" | "range",
isSubTable: true,
};
}
onSubmit(conn);
if (!initial) {
setSelectedTargetId("");
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
setIsSubTable(false);
setTargetColumn("");
setFilterMode("equals");
}
};
return (
<div className="space-y-2 rounded border border-dashed p-3">
{onCancel && (
<div className="flex items-center justify-between">
<p className="text-[10px] font-medium text-muted-foreground"> </p>
<button onClick={onCancel} className="text-muted-foreground hover:text-foreground">
<X className="h-3 w-3" />
</button>
</div>
)}
{!onCancel && (
<p className="text-[10px] font-medium text-muted-foreground"> </p>
)}
<div className="space-y-1">
<span className="text-[10px] text-muted-foreground">?</span>
<Select
value={selectedTargetId}
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
onValueChange={(v) => {
setSelectedTargetId(v);
setIsSubTable(false);
setTargetColumn("");
}}
>
<SelectTrigger className="h-7 text-xs">
<SelectValue placeholder="컴포넌트 선택" />
</SelectTrigger>
<SelectContent>
{targetCandidates.map((c) => (
<SelectItem key={c.id} value={c.id} className="text-xs">
{c.label || c.id}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
feat(pop): 공정 상태 자동 계산 + 하위 필터 연동 + 타임라인 연동 상태배지 공정 필터 선택 시 상태 뱃지/카운트/버튼이 공정 상태 기준으로 동작하도록 파생 상태 자동 계산, 하위 필터 __subStatus__ 주입, 접수 버튼 공정 행 특정 로직을 구현한다. [파생 상태 자동 계산] - types.ts: StatusValueMapping.isDerived 필드 추가 isDerived=true면 DB에 없는 상태로, 이전 공정 완료 시 자동 변환 - PopCardListV2Component: injectProcessFlow에 derivedRules 기반 변환 로직 같은 semantic의 원본 상태를 자동 추론 (waiting → acceptable) - TimelineProcessStep에 processId, rawData 필드 추가 [하위 필터 __subStatus__ 주입] - PopCardListV2Component: filteredRows를 2단계로 분리 1단계: 하위 테이블(work_order_process) 필터 → 매칭 공정의 상태를 VIRTUAL_SUB_STATUS/SEMANTIC/PROCESS/SEQ 가상 컬럼으로 주입 2단계: 메인 필터에서 status 컬럼을 __subStatus__로 자동 대체 - cell-renderers: StatusBadgeCell/ActionButtonsCell이 __subStatus__ 우선 참조 하드코딩된 접수가능 판별 로직(isAcceptable) 제거 → 설정 기반으로 전환 - all_rows 발행: { rows, subStatusColumn } envelope 구조로 메타 포함 [타임라인 강조(isCurrent) 개선] - "기준" 상태(isDerived) 기반 강조 + 공정 필터 시 매칭 공정 강조 - 폴백: active → pending 순서로 자동 결정 [접수 버튼 공정 행 특정] - cell-renderers: ActionButtonsCell에서 현재 공정의 processId를 __processId로 전달 - PopCardListV2Component: onActionButtonClick에서 __processId로 공정 행 UPDATE [상태배지 타임라인 연동] - PopCardListV2Config: StatusMappingEditor에 "타임라인 연동" 버튼 추가 같은 카드의 타임라인 statusMappings에서 값/라벨/색상/컬럼 자동 가져옴 [타임라인 설정 UI] - PopCardListV2Config: StatusMappingsEditor에 "기준" 라디오 버튼 추가 하나만 선택 가능, 재클릭 시 해제 [연결 탭 하위 테이블 필터 설정] - ConnectionEditor: isSubTable 체크박스 + targetColumn/filterMode 설정 UI - pop-layout.ts: filterConfig.isSubTable 필드 추가 [status-chip 하위 필터 자동 전환] - PopSearchComponent: 카드가 전달한 subStatusColumn 자동 감지 useSubCount 활성 시 집계/필터 컬럼 자동 전환 - PopSearchConfig: useSubCount 체크박스 설정 UI - types.ts: StatusChipConfig.useSubCount 필드 추가 [디자이너 라벨] - ComponentEditorPanel: comp.label || comp.id 패턴으로 통일
2026-03-11 12:07:11 +09:00
{isFilterConnection && selectedTargetId && subTableName && (
<div className="space-y-2 rounded bg-muted/50 p-2">
<div className="flex items-center gap-2">
<Checkbox
id={`isSubTable_${component.id}`}
checked={isSubTable}
onCheckedChange={(v) => {
setIsSubTable(v === true);
if (!v) setTargetColumn("");
}}
/>
<label htmlFor={`isSubTable_${component.id}`} className="text-[10px] text-muted-foreground cursor-pointer">
({subTableName})
</label>
</div>
{isSubTable && (
<div className="space-y-2 pl-5">
<div className="space-y-1">
<span className="text-[10px] text-muted-foreground"> </span>
{loadingColumns ? (
<div className="flex items-center gap-1 py-1">
<Loader2 className="h-3 w-3 animate-spin text-muted-foreground" />
<span className="text-[10px] text-muted-foreground"> ...</span>
</div>
) : (
<Select value={targetColumn} onValueChange={setTargetColumn}>
<SelectTrigger className="h-7 text-xs">
<SelectValue placeholder="컬럼 선택" />
</SelectTrigger>
<SelectContent>
{subColumns.filter(Boolean).map((col) => (
<SelectItem key={col} value={col} className="text-xs">
{col}
</SelectItem>
))}
</SelectContent>
</Select>
)}
</div>
<div className="space-y-1">
<span className="text-[10px] text-muted-foreground"> </span>
<Select value={filterMode} onValueChange={setFilterMode}>
<SelectTrigger className="h-7 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="equals" className="text-xs"> (equals)</SelectItem>
<SelectItem value="contains" className="text-xs"> (contains)</SelectItem>
<SelectItem value="starts_with" className="text-xs"> (starts_with)</SelectItem>
</SelectContent>
</Select>
</div>
</div>
)}
</div>
)}
<Button
size="sm"
variant="outline"
className="h-7 w-full text-xs"
disabled={!selectedTargetId}
onClick={handleSubmit}
>
{!initial && <Plus className="mr-1 h-3 w-3" />}
{submitLabel}
</Button>
</div>
);
}
// ========================================
// 받기 섹션 (읽기 전용: 연결된 소스만 표시)
// ========================================
interface ReceiveSectionProps {
component: PopComponentDefinitionV5;
allComponents: PopComponentDefinitionV5[];
incoming: PopDataConnection[];
}
function ReceiveSection({
component,
allComponents,
incoming,
}: ReceiveSectionProps) {
return (
<div className="space-y-3">
<Label className="flex items-center gap-1 text-xs font-medium">
<Unlink2 className="h-3 w-3 text-green-500" />
</Label>
{incoming.length > 0 ? (
<div className="space-y-1">
{incoming.map((conn) => {
const sourceComp = allComponents.find(
(c) => c.id === conn.sourceComponent
);
return (
<div
key={conn.id}
className="flex items-center gap-2 rounded border bg-green-50/50 px-3 py-2 text-xs"
>
<ArrowRight className="h-3 w-3 text-green-500" />
<span className="truncate">
{sourceComp?.label || conn.sourceComponent}
</span>
</div>
);
})}
</div>
) : (
<p className="text-xs text-muted-foreground">
</p>
)}
</div>
);
}