feat: 출고관리 수정 모달 저장 기능 개선 및 그룹화 컬럼 설정 UI 추가
ButtonConfigPanel: 수정 액션에 그룹화 컬럼 선택 드롭다운 추가 (영문/한글 검색 지원) ScreenSplitPanel/EmbeddedScreen: groupedData prop 전달 경로 추가 buttonActions: RepeaterFieldGroup 저장 시 공통 필드 우선 적용되도록 병합 순서 변경
This commit is contained in:
@@ -60,6 +60,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
||||
editModalTitle: String(config.action?.editModalTitle || ""),
|
||||
editModalDescription: String(config.action?.editModalDescription || ""),
|
||||
targetUrl: String(config.action?.targetUrl || ""),
|
||||
groupByColumn: String(config.action?.groupByColumns?.[0] || ""),
|
||||
});
|
||||
|
||||
const [screens, setScreens] = useState<ScreenOption[]>([]);
|
||||
@@ -97,6 +98,11 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
||||
const [modalTargetColumns, setModalTargetColumns] = useState<Array<{ name: string; label: string }>>([]);
|
||||
const [modalSourcePopoverOpen, setModalSourcePopoverOpen] = useState<Record<number, boolean>>({});
|
||||
const [modalTargetPopoverOpen, setModalTargetPopoverOpen] = useState<Record<number, boolean>>({});
|
||||
|
||||
// 🆕 그룹화 컬럼 선택용 상태
|
||||
const [currentTableColumns, setCurrentTableColumns] = useState<Array<{ name: string; label: string }>>([]);
|
||||
const [groupByColumnOpen, setGroupByColumnOpen] = useState(false);
|
||||
const [groupByColumnSearch, setGroupByColumnSearch] = useState("");
|
||||
const [modalSourceSearch, setModalSourceSearch] = useState<Record<number, string>>({});
|
||||
const [modalTargetSearch, setModalTargetSearch] = useState<Record<number, string>>({});
|
||||
|
||||
@@ -130,6 +136,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
||||
editModalTitle: String(latestAction.editModalTitle || ""),
|
||||
editModalDescription: String(latestAction.editModalDescription || ""),
|
||||
targetUrl: String(latestAction.targetUrl || ""),
|
||||
groupByColumn: String(latestAction.groupByColumns?.[0] || ""),
|
||||
});
|
||||
|
||||
// 🆕 제목 블록 초기화
|
||||
@@ -327,6 +334,35 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
||||
loadColumns();
|
||||
}, [config.action?.dataTransfer?.sourceTable, config.action?.dataTransfer?.targetTable]);
|
||||
|
||||
// 🆕 현재 테이블 컬럼 로드 (그룹화 컬럼 선택용)
|
||||
useEffect(() => {
|
||||
if (!currentTableName) return;
|
||||
|
||||
const loadCurrentTableColumns = async () => {
|
||||
try {
|
||||
const response = await apiClient.get(`/table-management/tables/${currentTableName}/columns`);
|
||||
if (response.data.success) {
|
||||
let columnData = response.data.data;
|
||||
if (!Array.isArray(columnData) && columnData?.columns) columnData = columnData.columns;
|
||||
if (!Array.isArray(columnData) && columnData?.data) columnData = columnData.data;
|
||||
|
||||
if (Array.isArray(columnData)) {
|
||||
const columns = columnData.map((col: any) => ({
|
||||
name: col.name || col.columnName,
|
||||
label: col.displayName || col.label || col.columnLabel || col.name || col.columnName,
|
||||
}));
|
||||
setCurrentTableColumns(columns);
|
||||
console.log(`✅ 현재 테이블 ${currentTableName} 컬럼 로드 성공:`, columns.length, "개");
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("현재 테이블 컬럼 로드 실패:", error);
|
||||
}
|
||||
};
|
||||
|
||||
loadCurrentTableColumns();
|
||||
}, [currentTableName]);
|
||||
|
||||
// 🆕 openModalWithData 소스/타겟 테이블 컬럼 로드
|
||||
useEffect(() => {
|
||||
const actionType = config.action?.type;
|
||||
@@ -1529,6 +1565,106 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Label htmlFor="edit-group-by-column">그룹화 컬럼</Label>
|
||||
<Popover open={groupByColumnOpen} onOpenChange={setGroupByColumnOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={groupByColumnOpen}
|
||||
className="h-8 w-full justify-between text-xs"
|
||||
>
|
||||
{localInputs.groupByColumn ? (
|
||||
<span>
|
||||
{localInputs.groupByColumn}
|
||||
{currentTableColumns.find((col) => col.name === localInputs.groupByColumn)?.label &&
|
||||
currentTableColumns.find((col) => col.name === localInputs.groupByColumn)?.label !== localInputs.groupByColumn && (
|
||||
<span className="ml-1 text-muted-foreground">
|
||||
({currentTableColumns.find((col) => col.name === localInputs.groupByColumn)?.label})
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-muted-foreground">컬럼을 선택하세요</span>
|
||||
)}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="p-0" align="start" style={{ width: "var(--radix-popover-trigger-width)" }}>
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center border-b px-3 py-2">
|
||||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<Input
|
||||
placeholder="컬럼명 또는 라벨 검색..."
|
||||
value={groupByColumnSearch}
|
||||
onChange={(e) => setGroupByColumnSearch(e.target.value)}
|
||||
className="border-0 p-0 focus-visible:ring-0"
|
||||
/>
|
||||
</div>
|
||||
<div className="max-h-[200px] overflow-auto">
|
||||
{currentTableColumns.length === 0 ? (
|
||||
<div className="p-3 text-sm text-muted-foreground">
|
||||
{currentTableName ? "컬럼을 불러오는 중..." : "테이블이 설정되지 않았습니다"}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{/* 선택 해제 옵션 */}
|
||||
<div
|
||||
className="flex cursor-pointer items-center px-3 py-2 hover:bg-muted"
|
||||
onClick={() => {
|
||||
setLocalInputs((prev) => ({ ...prev, groupByColumn: "" }));
|
||||
onUpdateProperty("componentConfig.action.groupByColumns", undefined);
|
||||
setGroupByColumnOpen(false);
|
||||
setGroupByColumnSearch("");
|
||||
}}
|
||||
>
|
||||
<Check className={cn("mr-2 h-4 w-4", !localInputs.groupByColumn ? "opacity-100" : "opacity-0")} />
|
||||
<span className="text-muted-foreground">선택 안 함</span>
|
||||
</div>
|
||||
{/* 컬럼 목록 */}
|
||||
{currentTableColumns
|
||||
.filter((col) => {
|
||||
if (!groupByColumnSearch) return true;
|
||||
const search = groupByColumnSearch.toLowerCase();
|
||||
return (
|
||||
col.name.toLowerCase().includes(search) ||
|
||||
col.label.toLowerCase().includes(search)
|
||||
);
|
||||
})
|
||||
.map((col) => (
|
||||
<div
|
||||
key={col.name}
|
||||
className="flex cursor-pointer items-center px-3 py-2 hover:bg-muted"
|
||||
onClick={() => {
|
||||
setLocalInputs((prev) => ({ ...prev, groupByColumn: col.name }));
|
||||
onUpdateProperty("componentConfig.action.groupByColumns", [col.name]);
|
||||
setGroupByColumnOpen(false);
|
||||
setGroupByColumnSearch("");
|
||||
}}
|
||||
>
|
||||
<Check
|
||||
className={cn("mr-2 h-4 w-4", localInputs.groupByColumn === col.name ? "opacity-100" : "opacity-0")}
|
||||
/>
|
||||
<div className="flex flex-col">
|
||||
<span className="font-medium">{col.name}</span>
|
||||
{col.label !== col.name && (
|
||||
<span className="text-xs text-muted-foreground">{col.label}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
여러 행을 하나의 그룹으로 묶어서 수정할 때 사용합니다
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user