Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
086edb4
style: Apply textcolor
yeoniii20 Mar 14, 2025
67940b2
feat: Create dashboard detail copy
yeoniii20 Mar 14, 2025
6ff59a0
feat: Apply responsive grid layout
yeoniii20 Mar 14, 2025
1c12d0b
feat: Update react grid layout version
yeoniii20 Mar 14, 2025
4fa6553
feat: Update react grid layout version
yeoniii20 Mar 14, 2025
1c69eca
feat: Export interface
yeoniii20 Mar 14, 2025
7c10ad6
feat: Export widget interface
yeoniii20 Mar 14, 2025
a0ac327
feat: Apply widget and chart
yeoniii20 Mar 14, 2025
435b227
feat: Update detailDashboard.tsx
yeoniii20 Mar 14, 2025
9f5c6c7
feat: Update detailDashboard.tsx
yeoniii20 Mar 14, 2025
a5b2d5f
style: Delete duplicate title
yeoniii20 Mar 14, 2025
3df7a8f
feat: Update useChartStore.ts
yeoniii20 Mar 17, 2025
2a61297
feat: Add gridLayout
yeoniii20 Mar 17, 2025
a4f1c42
feat: Update useWidgetStore.ts
yeoniii20 Mar 17, 2025
37fc899
design: Add edit button
yeoniii20 Mar 17, 2025
1cdc7e9
fix: Update detailDashboard.tsx
yeoniii20 Mar 17, 2025
860b6da
feat: Apply gridLayout
yeoniii20 Mar 17, 2025
e0f59dd
feat: Save chart and widget with gridLayout
yeoniii20 Mar 17, 2025
f049dc9
feat: Update page.tsx
yeoniii20 Mar 17, 2025
0d1a8a6
feat: Update detailDashboard.tsx
yeoniii20 Mar 17, 2025
ebb205e
feat: Apply middleware
yeoniii20 Mar 17, 2025
5e66147
feat: Apply middleware
yeoniii20 Mar 17, 2025
c6e6756
feat: Create converToTable utils
yeoniii20 Mar 19, 2025
ac188ab
feat: Add chart data
yeoniii20 Mar 19, 2025
db0d346
feat: Add react-grid-layout css
yeoniii20 Mar 19, 2025
9dcb230
feat: Update detailDashboard.tsx
yeoniii20 Mar 19, 2025
6f88fc3
feat: Backup detailDashboard
yeoniii20 Mar 19, 2025
a073fc9
feat: Add pannel position info
yeoniii20 Mar 19, 2025
6710187
fix: Build error
yeoniii20 Mar 19, 2025
bb16d1d
feat: Update useDashboardStore.ts
yeoniii20 Mar 19, 2025
052f1ae
feat: Update page.tsx
yeoniii20 Mar 19, 2025
704457f
feat: Update detailDashboard.tsx
yeoniii20 Mar 19, 2025
956bc3f
feat: Update page.tsx
yeoniii20 Mar 19, 2025
0107a47
feat: Add gridPosition
yeoniii20 Mar 20, 2025
9c3d60a
feat: Add gridPosition
yeoniii20 Mar 20, 2025
2f57bc6
feat: Add gridPosition
yeoniii20 Mar 20, 2025
6ca81b4
feat: Update chartDetail.ts
yeoniii20 Mar 20, 2025
00e6ee7
feat: Apply grid position
yeoniii20 Mar 20, 2025
254a830
fix: Modify stroe
yeoniii20 Mar 20, 2025
98273a9
fix: Modify gridLayout type
yeoniii20 Mar 20, 2025
da7416f
feat: Apply grid position
yeoniii20 Mar 20, 2025
5688072
fix: Update detailDashboard.tsx
yeoniii20 Mar 20, 2025
0841f4d
fix: Build error
yeoniii20 Mar 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"react-dnd": "^16.0.1",
"react-dom": "^19.0.0",
"react-draggable": "^4.4.6",
"react-grid-layout": "^1.5.0",
"react-grid-layout": "^1.5.1",
"react-icons": "^5.4.0",
"react-pdf": "^9.2.1",
"react-plotly.js": "^2.6.0",
Expand Down
70 changes: 40 additions & 30 deletions src/app/(monitoring)/d/content/chartSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import CommonWidget from "@/app/components/dashboard/commonWidget";
import { useWidgetOptions } from "@/app/context/widgetOptionContext";
import { useWidgetStore } from "@/app/store/useWidgetStore";
import { ChartOptions, WidgetOptions } from "@/app/types/options";
import { useDashboardStore } from "@/app/store/useDashboardStore";

Chart.register(zoomPlugin);

Expand Down Expand Up @@ -76,6 +77,7 @@ const ChartSection = () => {

const { charts, addChart, updateChart, removeChart } = useChartStore();
const { widgets, addWidget, updateWidget, removeWidget } = useWidgetStore();
const { addPanelToDashboard } = useDashboardStore();

const existingChart = chartId
? charts[dashboardId]?.find((chart) => chart.chartId === chartId)
Expand Down Expand Up @@ -169,50 +171,58 @@ const ChartSection = () => {
};

const handleCreateClick = () => {
const newChartId = uuidv4();
const newWidgetId = uuidv4();
const defaultGridPos = { x: 0, y: 0, w: 4, h: 4 }; // ✅ 기본 위치값

if (chartId) {
// 기존 차트가 있는 경우
if (existingChart) {
// 선택된 섹션이 "chartOption"이면 업데이트
if (selectedSection === "chartOption") {
updateChart(dashboardId, chartId, newChartOptions, datasets);
}
// 선택된 섹션이 "widgetOption"이면 변환 (차트 → 위젯)
else {
updateChart(
dashboardId,
chartId,
newChartOptions,
datasets,
existingChart.gridPos
);
} else {
removeChart(dashboardId, chartId);
addWidget(dashboardId, newWidgetOptions);
addWidget(
dashboardId,
newWidgetOptions,
existingChart.gridPos || defaultGridPos
);
addPanelToDashboard(dashboardId, newWidgetId, "widget");
}
}
// 기존 위젯이 있는 경우
else if (existingWidget) {
// 선택된 섹션이 "widgetOption"이면 업데이트
} else if (existingWidget) {
if (selectedSection === "widgetOption") {
updateWidget(dashboardId, chartId, newWidgetOptions);
}
// 선택된 섹션이 "chartOption"이면 변환 (위젯 → 차트)
else {
updateWidget(
dashboardId,
chartId,
newWidgetOptions,
existingWidget.gridPos
);
} else {
removeWidget(dashboardId, chartId);
addChart(dashboardId, newChartOptions, datasets);
addChart(
dashboardId,
newChartOptions,
datasets,
existingWidget.gridPos || defaultGridPos
);
addPanelToDashboard(dashboardId, newChartId, "chart");
}
}
// 기존 차트/위젯이 없으면 새로 추가
else {
if (selectedSection === "chartOption") {
addChart(dashboardId, newChartOptions, datasets);
} else if (selectedSection === "widgetOption") {
addWidget(dashboardId, newWidgetOptions);
}
}
}
// 차트 ID가 없으면 새로운 차트/위젯 추가
else {
} else {
if (selectedSection === "chartOption") {
addChart(dashboardId, newChartOptions, datasets);
addChart(dashboardId, newChartOptions, datasets, defaultGridPos);
addPanelToDashboard(dashboardId, newChartId, "chart");
} else if (selectedSection === "widgetOption") {
addWidget(dashboardId, newWidgetOptions);
addWidget(dashboardId, newWidgetOptions, defaultGridPos);
addPanelToDashboard(dashboardId, newWidgetId, "widget");
}
}

// 저장 후 대시보드 상세 페이지로 이동
router.push(`/detail?id=${dashboardId}`);
};

Expand Down
128 changes: 79 additions & 49 deletions src/app/(monitoring)/dashboard2/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import SearchInput from "@/app/components/search/searchInput";
import Alert from "@/app/components/alert/alert";
import { useRouter } from "next/navigation";
import TabMenu from "@/app/components/menu/tabMenu";
import { useDashboardStore } from "@/app/store/useDashboardStore";
import { PanelLayout, useDashboardStore } from "@/app/store/useDashboardStore";
import { useChartStore } from "@/app/store/useChartStore";
import { useWidgetStore } from "@/app/store/useWidgetStore";

Expand All @@ -18,15 +18,17 @@ const Dashboard2Page = () => {
dashboardList,
addDashboard,
removeDashboard,
dashboardChartMap,
addChartToDashboard,
dashboardPanels,
addPanelToDashboard,
updateDashboard,
} = useDashboardStore();
const { charts, addChart } = useChartStore();
const { widgets, cloneWidget } = useWidgetStore();
const { widgets, addWidget } = useWidgetStore();
const { saveDashboard } = useDashboardStore();

const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const [editingTabIndex, setEditingTabIndex] = useState<string | null>(null);
const [menuOpenIndex, setMenuOpenIndex] = useState<number | null>(null);
const [menuOpenIndex, setMenuOpenIndex] = useState<string | null>(null);
const [searchQuery, setSearchQuery] = useState<string>("");
const [alertMessage, setAlertMessage] = useState<string>("");

Expand All @@ -40,7 +42,7 @@ const Dashboard2Page = () => {
tab.label.toLowerCase().includes(searchQuery.toLowerCase())
);

// 대시보드 추가
// 대시보드 추가
const handleTabAdd = (newTabName: string, newTabDescription: string) => {
addDashboard({
id: uuidv4(),
Expand All @@ -51,7 +53,7 @@ const Dashboard2Page = () => {
setAlertMessage("새로운 탭이 추가되었습니다!");
};

// 대시보드 수정
// 대시보드 수정
const handleTabEdit = (
id: string,
newName: string,
Expand All @@ -62,15 +64,15 @@ const Dashboard2Page = () => {
setAlertMessage("탭이 수정되었습니다!");
};

// 대시보드 삭제
// 대시보드 삭제
const handleTabDelete = (dashboardId: string) => {
removeDashboard(dashboardId);
setMenuOpenIndex(null);
setIsModalOpen(false);
setAlertMessage("대시보드가 삭제되었습니다!");
};

// 대시보드 복제 (차트 포함)
// 대시보드 복제 (차트 & 위젯 포함)
const handleTabClone = (
dashboardId: string,
label: string,
Expand All @@ -79,50 +81,78 @@ const Dashboard2Page = () => {
const newDashboardId = uuidv4();
const newLabel = `${label}_copy`;

// 새 대시보드 추가
addDashboard({ id: newDashboardId, label: newLabel, description });

// ✅ 기존 차트 복제
const chartsToClone = dashboardChartMap[dashboardId] || [];
const newChartIds: string[] = [];

chartsToClone.forEach((chartId) => {
const existingChart = Object.values(charts)
.flat()
.find((chart) => chart.chartId === chartId);

if (existingChart) {
const newChartId = uuidv4();
const clonedChartOptions = { ...existingChart.chartOptions };
const clonedDatasets = existingChart.datasets.map((dataset) => ({
...dataset,
}));

addChart(newDashboardId, clonedChartOptions, clonedDatasets);
addChartToDashboard(newDashboardId, newChartId);
newChartIds.push(newChartId);
// 대시보드가 추가된 후 패널을 복제
const panelsToClone = dashboardPanels[dashboardId] || [];
const newDashboardPanels: PanelLayout[] = [];

panelsToClone.forEach((panel) => {
const { panelId, type, gridPos } = panel;

if (type === "chart") {
const existingChart = Object.values(charts)
.flat()
.find((chart) => chart.chartId === panelId);

if (existingChart) {
const newChartId = uuidv4();
const clonedChartOptions = { ...existingChart.chartOptions };
const clonedDatasets = existingChart.datasets.map((dataset) => ({
...dataset,
}));

const clonedGridPos = { ...gridPos };

addChart(
newDashboardId,
clonedChartOptions,
clonedDatasets,
clonedGridPos
);
addPanelToDashboard(newDashboardId, newChartId, "chart");

newDashboardPanels.push({
panelId: newChartId,
type: "chart",
gridPos: clonedGridPos,
});
}
}
});

// ✅ 기존 대시보드의 위젯 복제
const widgetsToClone = widgets[dashboardId] || [];
const newWidgetIds: string[] = [];

widgetsToClone.forEach((widget) => {
const newWidgetId = uuidv4();
const clonedWidgetOptions = {
...widget.widgetOptions,
widgetId: newWidgetId,
};

useWidgetStore.getState().addWidget(newDashboardId, clonedWidgetOptions);
newWidgetIds.push(newWidgetId);
if (type === "widget") {
const existingWidget = Object.values(widgets)
.flat()
.find((widget) => widget.widgetId === panelId);

if (existingWidget) {
const newWidgetId = uuidv4();
const clonedWidgetOptions = {
...existingWidget.widgetOptions,
widgetId: newWidgetId,
};

const clonedGridPos = { ...gridPos };

addWidget(newDashboardId, clonedWidgetOptions, clonedGridPos);
addPanelToDashboard(newDashboardId, newWidgetId, "widget");

newDashboardPanels.push({
panelId: newWidgetId,
type: "widget",
gridPos: clonedGridPos,
});
}
}
});

console.log("📌 새로운 대시보드 ID:", newDashboardId);
console.log("📌 복제된 차트 ID 리스트:", newChartIds);
console.log("📌 복제된 위젯 ID 리스트:", newWidgetIds);
// 복제된 패널을 저장할 때 `dashboardPanels` 업데이트
console.log("복제된 패널 리스트:", newDashboardPanels);
saveDashboard(newDashboardId, newDashboardPanels);

setAlertMessage("대시보드가 복제되었습니다!");
router.push(`/detail?id=${newDashboardId}`);
};

const handleTabClick = (tab: any) => {
Expand Down Expand Up @@ -156,7 +186,7 @@ const Dashboard2Page = () => {
onClick={() => setIsModalOpen(true)}
className="flex bg-navy-btn py-1.5 px-2 rounded-lg text-white text-sm hover:bg-navy-btn_hover mb-4 justify-self-end"
>
+ 항목 추가
+ 대시보드 추가
</button>
{alertMessage && <Alert message={alertMessage} />}
<div className="w-full mb-2 border-b border-0.5 border-navy-border" />
Expand All @@ -176,11 +206,11 @@ const Dashboard2Page = () => {
<MoreVertical
className="text-text3 cursor-pointer hover:text-text2"
onClick={(e) => {
e.stopPropagation();
setMenuOpenIndex(menuOpenIndex === index ? null : index);
e.stopPropagation(); // 메뉴 클릭 유지
setMenuOpenIndex(menuOpenIndex === tab.id ? null : tab.id);
}}
/>
{menuOpenIndex === index && (
{menuOpenIndex === tab.id && (
<TabMenu
index={tab.id}
setEditingTabIndex={() => setEditingTabIndex(tab.id)}
Expand Down
Loading