flowExecutionService 트랜잭션 처리 개선 및 데이터 변경 추적 로직 수정

This commit is contained in:
dohyeons
2025-12-09 11:15:18 +09:00
parent 8d07458c94
commit 0aaab45329
5 changed files with 156 additions and 123 deletions

View File

@@ -1669,53 +1669,53 @@ export function FlowWidget({
>
<Filter className="mr-1 h-3 w-3" />
</Button>
)}
</Button>
)}
</div>
{/* 필터/그룹 설정 버튼 */}
{/* 필터/그룹 설정 버튼 */}
<div className="flex items-center gap-1 border-r border-border pr-2">
<Button
<Button
variant={searchFilterColumns.size > 0 ? "default" : "ghost"}
size="sm"
onClick={() => {
size="sm"
onClick={() => {
if (!isPreviewMode) {
setIsFilterSettingOpen(true);
}
}}
disabled={isPreviewMode}
}}
disabled={isPreviewMode}
className="h-7 text-xs"
title="검색 필터 설정"
>
>
<Filter className="mr-1 h-3 w-3" />
{searchFilterColumns.size > 0 && (
{searchFilterColumns.size > 0 && (
<span className="ml-1 rounded-full bg-white/20 px-1.5 text-[10px]">
{searchFilterColumns.size}
{searchFilterColumns.size}
</span>
)}
</Button>
)}
</Button>
<Button
variant={groupByColumns.length > 0 ? "default" : "ghost"}
size="sm"
onClick={() => {
size="sm"
onClick={() => {
if (!isPreviewMode) {
setIsGroupSettingOpen(true);
}
}}
disabled={isPreviewMode}
}}
disabled={isPreviewMode}
className="h-7 text-xs"
title="그룹 설정"
>
>
<Layers className="mr-1 h-3 w-3" />
{groupByColumns.length > 0 && (
{groupByColumns.length > 0 && (
<span className="ml-1 rounded-full bg-white/20 px-1.5 text-[10px]">
{groupByColumns.length}
{groupByColumns.length}
</span>
)}
</Button>
</div>
</div>
{/* 새로고침 */}
<div className="ml-auto flex items-center gap-1">
@@ -1731,7 +1731,7 @@ export function FlowWidget({
</Button>
</div>
</div>
</div>
{/* 검색 필터 입력 영역 */}
{searchFilterColumns.size > 0 && (
@@ -1859,20 +1859,20 @@ export function FlowWidget({
{groupByColumns.length > 0 && groupedData.length > 0 ? (
// 그룹화된 렌더링 (기존 방식 유지)
<div className="overflow-x-auto">
<Table noWrapper>
<Table noWrapper>
<TableHeader className="sticky top-0 z-30 bg-background shadow-sm">
<TableRow className="hover:bg-muted/50">
{allowDataMove && (
<TableRow className="hover:bg-muted/50">
{allowDataMove && (
<TableHead className="bg-background sticky left-0 z-40 w-12 border-b px-6 py-3 text-center">
<Checkbox
checked={selectedRows.size === stepData.length && stepData.length > 0}
onCheckedChange={toggleAllRows}
/>
</TableHead>
)}
{stepDataColumns.map((col) => (
<TableHead
key={col}
<Checkbox
checked={selectedRows.size === stepData.length && stepData.length > 0}
onCheckedChange={toggleAllRows}
/>
</TableHead>
)}
{stepDataColumns.map((col) => (
<TableHead
key={col}
className="bg-background border-b px-6 py-3 text-sm font-semibold whitespace-nowrap cursor-pointer hover:bg-muted/50"
onClick={() => handleSort(col)}
>
@@ -1884,68 +1884,68 @@ export function FlowWidget({
</span>
)}
</div>
</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
</TableHead>
))}
</TableRow>
</TableHeader>
<TableBody>
{groupedData.flatMap((group) => {
const isCollapsed = collapsedGroups.has(group.groupKey);
const groupRows = [
<TableRow key={`group-${group.groupKey}`}>
<TableCell
colSpan={stepDataColumns.length + (allowDataMove ? 1 : 0)}
className="bg-muted/50 border-b"
const isCollapsed = collapsedGroups.has(group.groupKey);
const groupRows = [
<TableRow key={`group-${group.groupKey}`}>
<TableCell
colSpan={stepDataColumns.length + (allowDataMove ? 1 : 0)}
className="bg-muted/50 border-b"
>
<div
className="flex items-center gap-3 p-2 cursor-pointer hover:bg-muted"
onClick={() => toggleGroupCollapse(group.groupKey)}
>
<div
className="flex items-center gap-3 p-2 cursor-pointer hover:bg-muted"
onClick={() => toggleGroupCollapse(group.groupKey)}
>
{isCollapsed ? (
<ChevronRight className="h-4 w-4 flex-shrink-0" />
) : (
<ChevronDown className="h-4 w-4 flex-shrink-0" />
)}
<span className="font-medium text-sm flex-1">{group.groupKey}</span>
<span className="text-muted-foreground text-xs">({group.count})</span>
</div>
</TableCell>
</TableRow>,
];
{isCollapsed ? (
<ChevronRight className="h-4 w-4 flex-shrink-0" />
) : (
<ChevronDown className="h-4 w-4 flex-shrink-0" />
)}
<span className="font-medium text-sm flex-1">{group.groupKey}</span>
<span className="text-muted-foreground text-xs">({group.count})</span>
</div>
</TableCell>
</TableRow>,
];
if (!isCollapsed) {
const dataRows = group.items.map((row, itemIndex) => {
if (!isCollapsed) {
const dataRows = group.items.map((row, itemIndex) => {
const actualIndex = sortedDisplayData.indexOf(row);
return (
<TableRow
key={`${group.groupKey}-${itemIndex}`}
className={`h-16 transition-colors hover:bg-muted/50 ${selectedRows.has(actualIndex) ? "bg-primary/5" : ""}`}
>
{allowDataMove && (
<TableCell className="bg-background sticky left-0 z-10 border-b px-6 py-3 text-center">
<Checkbox
checked={selectedRows.has(actualIndex)}
onCheckedChange={() => toggleRowSelection(actualIndex)}
/>
</TableCell>
)}
{stepDataColumns.map((col) => (
<TableCell key={col} className="h-16 border-b px-6 py-3 text-sm whitespace-nowrap">
{formatValue(row[col])}
</TableCell>
))}
</TableRow>
);
});
groupRows.push(...dataRows);
}
return (
<TableRow
key={`${group.groupKey}-${itemIndex}`}
className={`h-16 transition-colors hover:bg-muted/50 ${selectedRows.has(actualIndex) ? "bg-primary/5" : ""}`}
>
{allowDataMove && (
<TableCell className="bg-background sticky left-0 z-10 border-b px-6 py-3 text-center">
<Checkbox
checked={selectedRows.has(actualIndex)}
onCheckedChange={() => toggleRowSelection(actualIndex)}
/>
</TableCell>
)}
{stepDataColumns.map((col) => (
<TableCell key={col} className="h-16 border-b px-6 py-3 text-sm whitespace-nowrap">
{formatValue(row[col])}
</TableCell>
))}
</TableRow>
);
});
groupRows.push(...dataRows);
}
return groupRows;
return groupRows;
})}
</TableBody>
</Table>
</div>
) : (
) : (
// 일반 렌더링 - SingleTableWithSticky 사용
<SingleTableWithSticky
visibleColumns={tableColumns}