diff --git a/frontend/components/admin/dashboard/CanvasElement.tsx b/frontend/components/admin/dashboard/CanvasElement.tsx
index 599718b9..90eec9ca 100644
--- a/frontend/components/admin/dashboard/CanvasElement.tsx
+++ b/frontend/components/admin/dashboard/CanvasElement.tsx
@@ -903,11 +903,6 @@ export function CanvasElement({
- ) : element.type === "widget" && element.subtype === "list-v2" ? (
- // 리스트 위젯 (다중 데이터 소스) - 승격 완료
-
-
-
) : element.type === "widget" && element.subtype === "custom-metric-v2" ? (
// 통계 카드 위젯 (다중 데이터 소스) - 승격 완료
@@ -1014,8 +1009,8 @@ export function CanvasElement({
}}
/>
- ) : element.type === "widget" && element.subtype === "list" ? (
- // 리스트 위젯 렌더링 (구버전)
+ ) : element.type === "widget" && (element.subtype === "list" || element.subtype === "list-v2") ? (
+ // 리스트 위젯 렌더링 (v1 & v2)
diff --git a/frontend/components/admin/dashboard/DashboardDesigner.tsx b/frontend/components/admin/dashboard/DashboardDesigner.tsx
index cdd080b6..3df5abdd 100644
--- a/frontend/components/admin/dashboard/DashboardDesigner.tsx
+++ b/frontend/components/admin/dashboard/DashboardDesigner.tsx
@@ -270,7 +270,14 @@ export default function DashboardDesigner({ dashboardId: initialDashboardId }: D
// 요소 업데이트
const updateElement = useCallback((id: string, updates: Partial) => {
- setElements((prev) => prev.map((el) => (el.id === id ? { ...el, ...updates } : el)));
+ setElements((prev) =>
+ prev.map((el) => {
+ if (el.id === id) {
+ return { ...el, ...updates };
+ }
+ return el;
+ }),
+ );
}, []);
// 요소 삭제
@@ -359,14 +366,17 @@ export default function DashboardDesigner({ dashboardId: initialDashboardId }: D
(updatedElement: DashboardElement) => {
// 현재 요소의 최신 상태를 가져와서 position과 size는 유지
const currentElement = elements.find((el) => el.id === updatedElement.id);
+
if (currentElement) {
- // position과 size는 현재 상태 유지, 나머지만 업데이트
+ // id, position, size 제거 후 나머지만 업데이트
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ const { id, position, size, ...updates } = updatedElement;
const finalElement = {
- ...updatedElement,
- position: currentElement.position,
- size: currentElement.size,
+ ...currentElement,
+ ...updates,
};
- updateElement(finalElement.id, finalElement);
+
+ updateElement(id, updates);
// 사이드바도 최신 상태로 업데이트
setSidebarElement(finalElement);
}
diff --git a/frontend/components/admin/dashboard/WidgetConfigSidebar.tsx b/frontend/components/admin/dashboard/WidgetConfigSidebar.tsx
index f4104e73..4f2b14a5 100644
--- a/frontend/components/admin/dashboard/WidgetConfigSidebar.tsx
+++ b/frontend/components/admin/dashboard/WidgetConfigSidebar.tsx
@@ -270,14 +270,28 @@ export function WidgetConfigSidebar({ element, isOpen, onClose, onApply }: Widge
const handleApply = useCallback(() => {
if (!element) return;
+ // 다중 데이터 소스를 사용하는 위젯 체크
+ const isMultiDataSourceWidget =
+ element.subtype === "map-summary-v2" ||
+ element.subtype === "chart" ||
+ element.subtype === "list-v2" ||
+ element.subtype === "custom-metric-v2" ||
+ element.subtype === "risk-alert-v2";
+
const updatedElement: DashboardElement = {
...element,
customTitle: customTitle.trim() || undefined,
showHeader,
- // 데이터 소스가 필요한 위젯만 dataSource 포함
+ // 데이터 소스 처리
...(needsDataSource(element.subtype)
? {
dataSource,
+ // 다중 데이터 소스 위젯은 dataSources도 포함
+ ...(isMultiDataSourceWidget
+ ? {
+ dataSources: element.dataSources || [],
+ }
+ : {}),
}
: {}),
// 리스트 위젯 설정
@@ -291,7 +305,16 @@ export function WidgetConfigSidebar({ element, isOpen, onClose, onApply }: Widge
element.subtype === "chart" ||
["bar", "horizontal-bar", "pie", "line", "area", "stacked-bar", "donut", "combo"].includes(element.subtype)
? {
- chartConfig,
+ // 다중 데이터 소스 위젯은 chartConfig에 dataSources 포함
+ chartConfig: isMultiDataSourceWidget
+ ? { ...chartConfig, dataSources: element.dataSources || [] }
+ : chartConfig,
+ // 프론트엔드 호환성을 위해 dataSources도 element에 직접 포함
+ ...(isMultiDataSourceWidget
+ ? {
+ dataSources: element.dataSources || [],
+ }
+ : {}),
}
: {}),
// 커스텀 메트릭 설정
diff --git a/frontend/components/admin/dashboard/widgets/ListWidget.tsx b/frontend/components/admin/dashboard/widgets/ListWidget.tsx
index 54237d26..8193aea4 100644
--- a/frontend/components/admin/dashboard/widgets/ListWidget.tsx
+++ b/frontend/components/admin/dashboard/widgets/ListWidget.tsx
@@ -39,7 +39,9 @@ export function ListWidget({ element, onConfigUpdate }: ListWidgetProps) {
// 데이터 로드
useEffect(() => {
const loadData = async () => {
- if (!element.dataSource || (!element.dataSource.query && !element.dataSource.endpoint)) return;
+ if (!element.dataSource || (!element.dataSource.query && !element.dataSource.endpoint)) {
+ return;
+ }
setIsLoading(true);
setError(null);
@@ -168,8 +170,8 @@ export function ListWidget({ element, onConfigUpdate }: ListWidgetProps) {
return (
-
-
데이터 로딩 중...
+
+
데이터 로딩 중...
);
@@ -181,8 +183,8 @@ export function ListWidget({ element, onConfigUpdate }: ListWidgetProps) {
⚠️
-
오류 발생
-
{error}
+
오류 발생
+
{error}
);
@@ -194,8 +196,8 @@ export function ListWidget({ element, onConfigUpdate }: ListWidgetProps) {
📋
-
리스트를 설정하세요
-
⚙️ 버튼을 클릭하여 데이터 소스와 컬럼을 설정해주세요
+
리스트를 설정하세요
+
⚙️ 버튼을 클릭하여 데이터 소스와 컬럼을 설정해주세요
);
@@ -222,7 +224,7 @@ export function ListWidget({ element, onConfigUpdate }: ListWidgetProps) {
{/* 제목 - 항상 표시 */}
-
{element.customTitle || element.title}
+ {element.customTitle || element.title}
{/* 테이블 뷰 */}
@@ -251,7 +253,7 @@ export function ListWidget({ element, onConfigUpdate }: ListWidgetProps) {
col.visible).length}
- className="text-center text-muted-foreground"
+ className="text-muted-foreground text-center"
>
데이터가 없습니다
@@ -281,7 +283,7 @@ export function ListWidget({ element, onConfigUpdate }: ListWidgetProps) {
{config.viewMode === "card" && (
{paginatedRows.length === 0 ? (
-
데이터가 없습니다
+
데이터가 없습니다
) : (
col.visible)
.map((col) => (
-
{col.label || col.name}
+
{col.label || col.name}
{String(row[col.dataKey || col.field] ?? "")}