diff --git a/client/src/Pages/Dashboard/components/DashboardCard.tsx b/client/src/Pages/Dashboard/components/DashboardCard.tsx
index 49f7f4395..f638e110b 100644
--- a/client/src/Pages/Dashboard/components/DashboardCard.tsx
+++ b/client/src/Pages/Dashboard/components/DashboardCard.tsx
@@ -3,9 +3,7 @@ import Skeleton from "@mui/material/Skeleton";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { useTheme } from "@mui/material/styles";
-import { GripVertical } from "lucide-react";
import { useTranslation } from "react-i18next";
-import type { DraggableSyntheticListeners } from "@dnd-kit/core";
import { LAYOUT } from "@/Utils/Theme/constants";
import { typographyLevels } from "@/Utils/Theme/Palette";
@@ -14,7 +12,6 @@ interface DashboardCardProps {
topRight?: React.ReactNode;
isLoading?: boolean;
error?: unknown;
- dragHandleProps?: DraggableSyntheticListeners;
children: React.ReactNode;
}
@@ -23,7 +20,6 @@ export const DashboardCard = ({
topRight,
isLoading,
error,
- dragHandleProps,
children,
}: DashboardCardProps) => {
const theme = useTheme();
@@ -82,33 +78,14 @@ export const DashboardCard = ({
>
{title}
-
- {topRight && (
-
- {topRight}
-
- )}
-
-
-
-
+ {topRight}
+
+ )}
{renderContent()}
diff --git a/client/src/Pages/Dashboard/components/EditCardsModal.tsx b/client/src/Pages/Dashboard/components/EditCardsModal.tsx
deleted file mode 100644
index a2487bf6d..000000000
--- a/client/src/Pages/Dashboard/components/EditCardsModal.tsx
+++ /dev/null
@@ -1,181 +0,0 @@
-import Dialog from "@mui/material/Dialog";
-import DialogTitle from "@mui/material/DialogTitle";
-import DialogContent from "@mui/material/DialogContent";
-import DialogActions from "@mui/material/DialogActions";
-import Stack from "@mui/material/Stack";
-import Box from "@mui/material/Box";
-import Typography from "@mui/material/Typography";
-import FormControlLabel from "@mui/material/FormControlLabel";
-import { useTheme } from "@mui/material/styles";
-import { useDispatch, useSelector } from "react-redux";
-import { useTranslation } from "react-i18next";
-import { Button, Checkbox } from "@/Components/inputs";
-import { setDashboardCardsVisibility, resetDashboardCards } from "@/Features/UI/uiSlice";
-import {
- cardCategories,
- defaultVisibleCards,
- DASHBOARD_CARD_IDS,
-} from "@/Pages/Dashboard/dashboardCards";
-import type { DashboardCardId } from "@/Pages/Dashboard/dashboardCards";
-import type { RootState } from "@/Types/state";
-import { LAYOUT } from "@/Utils/Theme/constants";
-import { typographyLevels } from "@/Utils/Theme/Palette";
-
-interface EditCardsModalProps {
- open: boolean;
- onClose: () => void;
-}
-
-const leftCategories = cardCategories.slice(0, Math.ceil(cardCategories.length / 2));
-const rightCategories = cardCategories.slice(Math.ceil(cardCategories.length / 2));
-
-export const EditCardsModal = ({ open, onClose }: EditCardsModalProps) => {
- const theme = useTheme();
- const dispatch = useDispatch();
- const { t } = useTranslation();
-
- const visibility = useSelector(
- (state: RootState) => state.ui.dashboardCards ?? defaultVisibleCards
- );
-
- const allVisible = DASHBOARD_CARD_IDS.every((id) => visibility[id]);
- const someVisible = DASHBOARD_CARD_IDS.some((id) => visibility[id]);
- const selectAllIndeterminate = someVisible && !allVisible;
-
- const handleToggleCard = (id: DashboardCardId, visible: boolean) => {
- dispatch(setDashboardCardsVisibility({ id, visible }));
- };
-
- const handleSelectAll = () => {
- const next = !allVisible;
- DASHBOARD_CARD_IDS.forEach((id) => {
- dispatch(setDashboardCardsVisibility({ id, visible: next }));
- });
- };
-
- const handleReset = () => {
- dispatch(resetDashboardCards());
- };
-
- const renderCategory = (category: (typeof cardCategories)[number]) => (
-
-
- {t(category.labelKey)}
-
- {category.cards.map((id) => (
-
- {t(`pages.dashboard.cards.${id}`)}
-
- }
- control={
- handleToggleCard(id, e.target.checked)}
- />
- }
- sx={{ m: 0, gap: theme.spacing(LAYOUT.SM) }}
- />
- ))}
-
- );
-
- return (
-
- );
-};
diff --git a/client/src/Pages/Dashboard/components/SortableCard.tsx b/client/src/Pages/Dashboard/components/SortableCard.tsx
deleted file mode 100644
index 5e8848117..000000000
--- a/client/src/Pages/Dashboard/components/SortableCard.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import Box from "@mui/material/Box";
-import { useSortable } from "@dnd-kit/sortable";
-import { CSS } from "@dnd-kit/utilities";
-import type { DraggableSyntheticListeners } from "@dnd-kit/core";
-
-interface SortableCardProps {
- id: string;
- isDragging?: boolean;
- children: (listeners: DraggableSyntheticListeners) => React.ReactNode;
-}
-
-export const SortableCard = ({ id, isDragging, children }: SortableCardProps) => {
- const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
- id,
- });
-
- return (
-
- {children(listeners)}
-
- );
-};
diff --git a/client/src/Pages/Dashboard/components/cards/CurrentlyDownCard.tsx b/client/src/Pages/Dashboard/components/cards/CurrentlyDownCard.tsx
deleted file mode 100644
index 4f7b9a672..000000000
--- a/client/src/Pages/Dashboard/components/cards/CurrentlyDownCard.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import Stack from "@mui/material/Stack";
-import Typography from "@mui/material/Typography";
-import { useTheme } from "@mui/material/styles";
-import { DashboardCard } from "@/Pages/Dashboard/components/DashboardCard";
-import { typographyLevels } from "@/Utils/Theme/Palette";
-import { useTranslation } from "react-i18next";
-import type { DashboardMonitorRow } from "@/Pages/Dashboard/types";
-import type { DraggableSyntheticListeners } from "@dnd-kit/core";
-
-interface CurrentlyDownCardProps {
- downMonitors: DashboardMonitorRow[];
- isLoading?: boolean;
- error?: unknown;
- dragHandleProps?: DraggableSyntheticListeners;
-}
-
-export const CurrentlyDownCard = ({
- downMonitors,
- isLoading,
- error,
- dragHandleProps,
-}: CurrentlyDownCardProps) => {
- const theme = useTheme();
- const { t } = useTranslation();
-
- return (
-
- {downMonitors.length === 0 ? (
-
- {t("pages.dashboard.emptyStates.allMonitorsUp")}
-
- ) : (
-
- {downMonitors.map((m) => (
-
- {m.name}
-
- ))}
-
- )}
-
- );
-};
diff --git a/client/src/Pages/Dashboard/components/cards/LowestUptimeCard.tsx b/client/src/Pages/Dashboard/components/cards/LowestUptimeCard.tsx
deleted file mode 100644
index fb3658dee..000000000
--- a/client/src/Pages/Dashboard/components/cards/LowestUptimeCard.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import Stack from "@mui/material/Stack";
-import { DashboardCard } from "@/Pages/Dashboard/components/DashboardCard";
-import { BarRow } from "@/Pages/Dashboard/components/cards/BarRow";
-import { useTranslation } from "react-i18next";
-import { formatPercentageFromWhole } from "@/Utils/FormatUtils";
-import type { DashboardMonitorRow } from "@/Pages/Dashboard/types";
-import type { DraggableSyntheticListeners } from "@dnd-kit/core";
-import { LAYOUT } from "@/Utils/Theme/constants";
-
-const TOP_N = 5;
-
-interface LowestUptimeCardProps {
- lowestUptimeMonitors: DashboardMonitorRow[];
- isLoading?: boolean;
- error?: unknown;
- dragHandleProps?: DraggableSyntheticListeners;
-}
-
-export const LowestUptimeCard = ({
- lowestUptimeMonitors,
- isLoading,
- error,
- dragHandleProps,
-}: LowestUptimeCardProps) => {
- const { t } = useTranslation();
-
- const top = lowestUptimeMonitors.slice(0, TOP_N);
- const total = lowestUptimeMonitors.length;
-
- return (
- 0
- ? t("pages.dashboard.emptyStates.topOf", {
- count: Math.min(TOP_N, total),
- total,
- })
- : undefined
- }
- isLoading={isLoading}
- error={error}
- >
-
- {top.map((monitor) => {
- const uptime = monitor.uptimePercentage;
- const downtime = 100 - uptime;
- return (
-
- );
- })}
-
-
- );
-};
diff --git a/client/src/Pages/Dashboard/components/cards/MonitorStatusCard.tsx b/client/src/Pages/Dashboard/components/cards/MonitorStatusCard.tsx
index 451f7d948..16eb9bceb 100644
--- a/client/src/Pages/Dashboard/components/cards/MonitorStatusCard.tsx
+++ b/client/src/Pages/Dashboard/components/cards/MonitorStatusCard.tsx
@@ -7,20 +7,16 @@ import { typographyLevels } from "@/Utils/Theme/Palette";
import { SPACING } from "@/Utils/Theme/constants";
import { useTranslation } from "react-i18next";
import type { MonitorsSummary } from "@/Types/Monitor";
-import type { DraggableSyntheticListeners } from "@dnd-kit/core";
-
interface MonitorStatusCardProps {
summary: MonitorsSummary;
isLoading?: boolean;
error?: unknown;
- dragHandleProps?: DraggableSyntheticListeners;
}
export const MonitorStatusCard = ({
summary,
isLoading,
error,
- dragHandleProps,
}: MonitorStatusCardProps) => {
const theme = useTheme();
const { t } = useTranslation();
@@ -34,7 +30,6 @@ export const MonitorStatusCard = ({
title={t("pages.dashboard.cards.monitorStatus")}
isLoading={isLoading}
error={error}
- dragHandleProps={dragHandleProps}
>
{
- const theme = useTheme();
- const { t } = useTranslation();
-
- const maxCount = monitorsByGroup[0]?.count ?? 1;
-
- return (
-
- {monitorsByGroup.length === 0 ? (
-
- {t("pages.dashboard.emptyStates.noGroups")}
-
- ) : (
-
- {monitorsByGroup.map(({ group, count }) => (
-
- ))}
-
- )}
-
- );
-};
diff --git a/client/src/Pages/Dashboard/components/cards/MonitorsByTypeCard.tsx b/client/src/Pages/Dashboard/components/cards/MonitorsByTypeCard.tsx
index 70430f96e..46709aa50 100644
--- a/client/src/Pages/Dashboard/components/cards/MonitorsByTypeCard.tsx
+++ b/client/src/Pages/Dashboard/components/cards/MonitorsByTypeCard.tsx
@@ -4,21 +4,18 @@ import { BarRow } from "@/Pages/Dashboard/components/cards/BarRow";
import { useTranslation } from "react-i18next";
import { useTheme } from "@mui/material/styles";
import type { DashboardTypeCount } from "@/Pages/Dashboard/types";
-import type { DraggableSyntheticListeners } from "@dnd-kit/core";
import { LAYOUT } from "@/Utils/Theme/constants";
interface MonitorsByTypeCardProps {
monitorsByType: DashboardTypeCount[];
isLoading?: boolean;
error?: unknown;
- dragHandleProps?: DraggableSyntheticListeners;
}
export const MonitorsByTypeCard = ({
monitorsByType,
isLoading,
error,
- dragHandleProps,
}: MonitorsByTypeCardProps) => {
const { t } = useTranslation();
const theme = useTheme();
@@ -30,7 +27,6 @@ export const MonitorsByTypeCard = ({
title={t("pages.dashboard.cards.monitorsByType")}
isLoading={isLoading}
error={error}
- dragHandleProps={dragHandleProps}
>
{monitorsByType.map(({ type, count }) => (
diff --git a/client/src/Pages/Dashboard/components/cards/SlowestMonitorsCard.tsx b/client/src/Pages/Dashboard/components/cards/SlowestMonitorsCard.tsx
deleted file mode 100644
index a149189be..000000000
--- a/client/src/Pages/Dashboard/components/cards/SlowestMonitorsCard.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import Stack from "@mui/material/Stack";
-import { DashboardCard } from "@/Pages/Dashboard/components/DashboardCard";
-import { BarRow } from "@/Pages/Dashboard/components/cards/BarRow";
-import { useTranslation } from "react-i18next";
-import { formatMs } from "@/Utils/TimeUtils";
-import type { DashboardMonitorRow } from "@/Pages/Dashboard/types";
-import type { DraggableSyntheticListeners } from "@dnd-kit/core";
-import { LAYOUT } from "@/Utils/Theme/constants";
-
-const TOP_N = 5;
-
-interface SlowestMonitorsCardProps {
- slowestMonitors: DashboardMonitorRow[];
- isLoading?: boolean;
- error?: unknown;
- dragHandleProps?: DraggableSyntheticListeners;
-}
-
-export const SlowestMonitorsCard = ({
- slowestMonitors,
- isLoading,
- error,
- dragHandleProps,
-}: SlowestMonitorsCardProps) => {
- const { t } = useTranslation();
-
- const top = slowestMonitors.slice(0, TOP_N);
- const maxAvg = top[0]?.avgResponseTime ?? 1;
- const total = slowestMonitors.length;
-
- return (
- 0
- ? t("pages.dashboard.emptyStates.topOf", {
- count: Math.min(TOP_N, total),
- total,
- })
- : undefined
- }
- isLoading={isLoading}
- error={error}
- >
-
- {top.map((m) => (
-
- ))}
-
-
- );
-};
diff --git a/client/src/Pages/Dashboard/components/cards/StubCard.tsx b/client/src/Pages/Dashboard/components/cards/StubCard.tsx
deleted file mode 100644
index c853bb853..000000000
--- a/client/src/Pages/Dashboard/components/cards/StubCard.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import Typography from "@mui/material/Typography";
-import { useTheme } from "@mui/material/styles";
-import { DashboardCard } from "@/Pages/Dashboard/components/DashboardCard";
-import { typographyLevels } from "@/Utils/Theme/Palette";
-import { useTranslation } from "react-i18next";
-import type { DashboardCardId } from "@/Pages/Dashboard/dashboardCards";
-import type { DraggableSyntheticListeners } from "@dnd-kit/core";
-
-interface StubCardProps {
- cardId: DashboardCardId;
- isLoading?: boolean;
- error?: unknown;
- dragHandleProps?: DraggableSyntheticListeners;
-}
-
-export const StubCard = ({
- cardId,
- isLoading,
- error,
- dragHandleProps,
-}: StubCardProps) => {
- const theme = useTheme();
- const { t } = useTranslation();
-
- return (
-
-
- {t("pages.dashboard.comingSoon")}
-
-
- );
-};
diff --git a/client/src/Pages/Dashboard/index.tsx b/client/src/Pages/Dashboard/index.tsx
index c68ca9fae..4cb9045ab 100644
--- a/client/src/Pages/Dashboard/index.tsx
+++ b/client/src/Pages/Dashboard/index.tsx
@@ -1,232 +1,38 @@
-import { useState } from "react";
import Box from "@mui/material/Box";
-import Stack from "@mui/material/Stack";
import { useTheme } from "@mui/material/styles";
import useMediaQuery from "@mui/material/useMediaQuery";
-import { LayoutGrid } from "lucide-react";
-import { useDispatch, useSelector } from "react-redux";
-import { useTranslation } from "react-i18next";
-import {
- DndContext,
- DragOverlay,
- PointerSensor,
- useSensor,
- useSensors,
- closestCenter,
-} from "@dnd-kit/core";
-import type {
- DragStartEvent,
- DragEndEvent,
- DraggableSyntheticListeners,
-} from "@dnd-kit/core";
-import { SortableContext, arrayMove } from "@dnd-kit/sortable";
-import type { SortingStrategy } from "@dnd-kit/sortable";
import { BasePage } from "@/Components/design-elements/BasePage";
-import { Button } from "@/Components/inputs";
import { LAYOUT } from "@/Utils/Theme/constants";
-import type { RootState } from "@/Types/state";
-import { setDashboardCardOrder } from "@/Features/UI/uiSlice";
-import {
- DASHBOARD_CARD_IDS,
- defaultVisibleCards,
- type DashboardCardId,
-} from "@/Pages/Dashboard/dashboardCards";
-import { EditCardsModal } from "@/Pages/Dashboard/components/EditCardsModal";
import { useDashboardData } from "@/Pages/Dashboard/hooks/useDashboardData";
-import { SortableCard } from "@/Pages/Dashboard/components/SortableCard";
-
import { MonitorStatusCard } from "@/Pages/Dashboard/components/cards/MonitorStatusCard";
-import { CurrentlyDownCard } from "@/Pages/Dashboard/components/cards/CurrentlyDownCard";
-import { SlowestMonitorsCard } from "@/Pages/Dashboard/components/cards/SlowestMonitorsCard";
-import { LowestUptimeCard } from "@/Pages/Dashboard/components/cards/LowestUptimeCard";
import { MonitorsByTypeCard } from "@/Pages/Dashboard/components/cards/MonitorsByTypeCard";
-import { MonitorsByGroupCard } from "@/Pages/Dashboard/components/cards/MonitorsByGroupCard";
-import { StubCard } from "@/Pages/Dashboard/components/cards/StubCard";
-
-// No displacement transforms during drag — only the DragOverlay moves
-const noAnimationStrategy: SortingStrategy = () => null;
const Dashboard = () => {
const theme = useTheme();
- const { t } = useTranslation();
- const dispatch = useDispatch();
const isSmall = useMediaQuery(theme.breakpoints.down("md"));
- const [modalOpen, setModalOpen] = useState(false);
- const [activeId, setActiveId] = useState(null);
- const visibility = useSelector(
- (state: RootState) => state.ui.dashboardCards ?? defaultVisibleCards
- );
- const cardOrder = useSelector(
- (state: RootState) => state.ui.dashboardCardOrder ?? [...DASHBOARD_CARD_IDS]
- );
-
- const {
- isLoading,
- error,
- summary,
- downMonitors,
- slowestMonitors,
- lowestUptimeMonitors,
- monitorsByType,
- monitorsByGroup,
- } = useDashboardData();
-
- const visibleCards = cardOrder.filter((id) => visibility[id]);
-
- const sensors = useSensors(
- useSensor(PointerSensor, {
- activationConstraint: { distance: 8 },
- })
- );
-
- const handleDragStart = (event: DragStartEvent) => {
- setActiveId(event.active.id as DashboardCardId);
- };
-
- const handleDragEnd = (event: DragEndEvent) => {
- setActiveId(null);
- const { active, over } = event;
- if (!over || active.id === over.id) return;
-
- const oldIndex = visibleCards.indexOf(active.id as DashboardCardId);
- const newIndex = visibleCards.indexOf(over.id as DashboardCardId);
- if (oldIndex === -1 || newIndex === -1) return;
-
- const newVisible = arrayMove(visibleCards, oldIndex, newIndex);
- let vi = 0;
- const newFullOrder = cardOrder.map((id) => (visibility[id] ? newVisible[vi++] : id));
- dispatch(setDashboardCardOrder(newFullOrder));
- };
-
- const renderCardContent = (
- id: DashboardCardId,
- dragHandleProps?: DraggableSyntheticListeners
- ) => {
- switch (id) {
- case "monitorStatus":
- return (
-
- );
- case "currentlyDown":
- return (
-
- );
- case "slowestMonitors":
- return (
-
- );
- case "lowestUptime":
- return (
-
- );
- case "monitorsByType":
- return (
-
- );
- case "monitorsByGroup":
- return (
-
- );
- default:
- return (
-
- );
- }
- };
+ const { isLoading, error, summary, monitorsByType } = useDashboardData();
return (
-
- }
- onClick={() => setModalOpen(true)}
- >
- {t("pages.dashboard.editCards")}
-
-
-
-
-
-
- {visibleCards.map((id) => (
-
- {(listeners) => renderCardContent(id, listeners)}
-
- ))}
-
-
-
-
- {activeId ? (
-
- {renderCardContent(activeId)}
-
- ) : null}
-
-
-
- setModalOpen(false)}
- />
+
+
+
);
};