From 21d720a9b46d033efa9f2f48597c66852f43faf0 Mon Sep 17 00:00:00 2001 From: Fizer Khan Date: Fri, 5 Dec 2025 21:35:38 +0530 Subject: [PATCH] update metrics layout. add support for layout change in dashboard. --- apps/web/app/(dashboard)/alerts/page.tsx | 2 +- .../[clusterId]/[stream]/[name]/page.tsx | 72 +++---- .../app/(dashboard)/dashboards/[id]/page.tsx | 187 +++++++++++++----- .../app/(dashboard)/saved-queries/page.tsx | 8 +- 4 files changed, 176 insertions(+), 93 deletions(-) diff --git a/apps/web/app/(dashboard)/alerts/page.tsx b/apps/web/app/(dashboard)/alerts/page.tsx index 481e664..8cb87dc 100644 --- a/apps/web/app/(dashboard)/alerts/page.tsx +++ b/apps/web/app/(dashboard)/alerts/page.tsx @@ -964,7 +964,7 @@ function AlertsPageContent() { setIsEditChannelOpen(false); } }}> - { + { setIsCreateChannelOpen(false); setIsEditChannelOpen(false); }}> diff --git a/apps/web/app/(dashboard)/consumers/[clusterId]/[stream]/[name]/page.tsx b/apps/web/app/(dashboard)/consumers/[clusterId]/[stream]/[name]/page.tsx index 03b653d..920d141 100644 --- a/apps/web/app/(dashboard)/consumers/[clusterId]/[stream]/[name]/page.tsx +++ b/apps/web/app/(dashboard)/consumers/[clusterId]/[stream]/[name]/page.tsx @@ -477,6 +477,42 @@ function ConsumerDetailContent() { + {/* Stats Cards - Moved to top */} +
+ + + Pending + + +
{formatNumber(consumer.num_pending || 0)}
+
+
+ + + Ack Pending + + +
{formatNumber(consumer.num_ack_pending || 0)}
+
+
+ + + Redelivered + + +
{formatNumber(consumer.num_redelivered || 0)}
+
+
+ + + Waiting + + +
{formatNumber(consumer.num_waiting || 0)}
+
+
+
+ {/* Consumer Lag Chart */} @@ -569,42 +605,6 @@ function ConsumerDetailContent() { )} - - {/* Quick Stats */} -
- - - Pending - - -
{formatNumber(consumer.num_pending || 0)}
-
-
- - - Ack Pending - - -
{formatNumber(consumer.num_ack_pending || 0)}
-
-
- - - Redelivered - - -
{formatNumber(consumer.num_redelivered || 0)}
-
-
- - - Waiting - - -
{formatNumber(consumer.num_waiting || 0)}
-
-
-
)} diff --git a/apps/web/app/(dashboard)/dashboards/[id]/page.tsx b/apps/web/app/(dashboard)/dashboards/[id]/page.tsx index de1cac5..67508e7 100644 --- a/apps/web/app/(dashboard)/dashboards/[id]/page.tsx +++ b/apps/web/app/(dashboard)/dashboards/[id]/page.tsx @@ -20,6 +20,8 @@ import { PieChart, X, CheckCircle2, + Edit, + MoreVertical, } from 'lucide-react'; import Link from 'next/link'; import { api } from '@/lib/api'; @@ -41,6 +43,13 @@ import { SelectTrigger, SelectValue, } from '@/components/ui/select'; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu'; import { DashboardWidget } from '@/components/dashboard/dashboard-widget'; // Widget types @@ -77,6 +86,7 @@ export default function DashboardBuilderPage() { const [newWidgetCluster, setNewWidgetCluster] = useState(''); const [newWidgetMetric, setNewWidgetMetric] = useState(''); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); + const [isEditingLayout, setIsEditingLayout] = useState(false); const { data: dashboardData, isLoading } = useQuery({ queryKey: ['dashboard', dashboardId], @@ -101,16 +111,30 @@ export default function DashboardBuilderPage() { const [saveSuccess, setSaveSuccess] = useState(false); const saveMutation = useMutation({ - mutationFn: () => - api.dashboards.update(dashboardId, { + mutationFn: async (updatedWidgets?: Widget[]) => { + const widgetsToSave = updatedWidgets ?? widgets; + if (dashboardId === 'new') { + return api.dashboards.create({ + name: dashboardName || 'New Dashboard', + description: dashboardDescription, + widgets: widgetsToSave, + }); + } + return api.dashboards.update(dashboardId, { name: dashboardName, description: dashboardDescription, - widgets, - }), - onSuccess: () => { + widgets: widgetsToSave, + }); + }, + onSuccess: (data) => { setHasUnsavedChanges(false); + setIsEditingLayout(false); setSaveSuccess(true); setTimeout(() => setSaveSuccess(false), 2000); + // If new dashboard was created, redirect to its page + if (dashboardId === 'new' && data?.dashboard?.id) { + router.replace(`/dashboards/${data.dashboard.id}`); + } queryClient.invalidateQueries({ queryKey: ['dashboard', dashboardId] }); queryClient.invalidateQueries({ queryKey: ['dashboards'] }); }, @@ -135,13 +159,16 @@ export default function DashboardBuilderPage() { }, }; - setWidgets([...widgets, newWidget]); - setHasUnsavedChanges(true); + const updatedWidgets = [...widgets, newWidget]; + setWidgets(updatedWidgets); setShowAddWidget(false); setSelectedWidgetType(''); setNewWidgetTitle(''); setNewWidgetCluster(''); setNewWidgetMetric(''); + + // Auto-save after adding widget + saveMutation.mutate(updatedWidgets); }; const removeWidget = (widgetId: string) => { @@ -175,24 +202,35 @@ export default function DashboardBuilderPage() {
- { - setDashboardName(e.target.value); - setHasUnsavedChanges(true); - }} - className="text-2xl font-bold border-none shadow-none px-0 h-auto focus-visible:ring-0" - placeholder="Dashboard Name" - /> - { - setDashboardDescription(e.target.value); - setHasUnsavedChanges(true); - }} - className="text-sm text-muted-foreground border-none shadow-none px-0 h-auto focus-visible:ring-0" - placeholder="Add a description..." - /> + {isEditingLayout ? ( + <> + { + setDashboardName(e.target.value); + setHasUnsavedChanges(true); + }} + className="text-2xl font-bold border-none shadow-none px-0 h-auto focus-visible:ring-0" + placeholder="Dashboard Name" + /> + { + setDashboardDescription(e.target.value); + setHasUnsavedChanges(true); + }} + className="text-sm text-muted-foreground border-none shadow-none px-0 h-auto focus-visible:ring-0" + placeholder="Add a description..." + /> + + ) : ( + <> +

{dashboardName || 'Untitled Dashboard'}

+ {dashboardDescription && ( +

{dashboardDescription}

+ )} + + )}
@@ -200,21 +238,44 @@ export default function DashboardBuilderPage() { Add Widget - + {isEditingLayout ? ( + <> + + + + ) : ( + + )}
@@ -243,28 +304,50 @@ export default function DashboardBuilderPage() { gridColumn: `span ${widget.position.w}`, }} > - -
+ + {/* Widget controls - always visible, disabled during edit layout */} +
+ {isEditingLayout && ( + + )} - + + + + + + setShowWidgetConfig(widget)}> + + Configure + + + removeWidget(widget.id)} + > + + Delete + + +
- {widget.title}
diff --git a/apps/web/app/(dashboard)/saved-queries/page.tsx b/apps/web/app/(dashboard)/saved-queries/page.tsx index 0c08d85..0c3949b 100644 --- a/apps/web/app/(dashboard)/saved-queries/page.tsx +++ b/apps/web/app/(dashboard)/saved-queries/page.tsx @@ -294,7 +294,7 @@ export default function SavedQueriesPage() { {/* Create Query Dialog */} - + Create New Query @@ -314,7 +314,7 @@ export default function SavedQueriesPage() {