Skip to content

Commit 674cfd6

Browse files
authored
Merge pull request #69 from nassery318/add-tooltips-to-accordion-heads
Add tooltips to accordion heads
2 parents c31ae86 + 8686a34 commit 674cfd6

File tree

4 files changed

+283
-25
lines changed

4 files changed

+283
-25
lines changed

apps/frontend/src/components/Dashboard.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { LayoutDashboard, Search } from "lucide-react"
44
import { useParams } from "react-router"
55
import { formatBytes } from "@common/src/bytes-conversion"
66
import { Database } from "lucide-react"
7+
import { accordionDescriptions } from "@common/src/dashboard-metrics"
8+
import { singleMetricDescriptions } from "@common/src/dashboard-metrics"
79
import { AppHeader } from "./ui/app-header"
810
import Accordion from "./ui/accordion"
911
import DonutChart from "./ui/donut-chart"
@@ -43,6 +45,7 @@ export function Dashboard() {
4345
const clientConnectivityMetrics = {
4446
blocked_clients: infoData.blocked_clients,
4547
clients_in_timeout_table: infoData.clients_in_timeout_table,
48+
connected_clients : infoData.connected_clients,
4649
connected_slaves: infoData.connected_slaves,
4750
total_connections_received: infoData.total_connections_received,
4851
evicted_clients: infoData.evicted_clients,
@@ -115,39 +118,53 @@ export function Dashboard() {
115118
/>
116119
</div>
117120
<Accordion
121+
accordionDescription={accordionDescriptions.memoryUsageMetrics}
118122
accordionItems={memoryUsageMetrics}
119123
accordionName="Memory Usage Metrics"
120124
searchQuery={searchQuery}
125+
singleMetricDescriptions={singleMetricDescriptions}
121126
valueType="bytes" />
122127
<Accordion
128+
accordionDescription={accordionDescriptions.uptimeMetrics}
123129
accordionItems={upTimeMetrics}
124130
accordionName="Uptime Metrics"
125131
searchQuery={searchQuery}
132+
singleMetricDescriptions={singleMetricDescriptions}
126133
valueType="mixed" />
127134
<Accordion
135+
accordionDescription={accordionDescriptions.replicationPersistenceMetrics}
128136
accordionItems={replicationPersistenceMetrics}
129137
accordionName="Replication & Persistence Metrics"
130138
searchQuery={searchQuery}
139+
singleMetricDescriptions={singleMetricDescriptions}
131140
valueType="number" />
132141
<Accordion
142+
accordionDescription={accordionDescriptions.clientConnectivityMetrics}
133143
accordionItems={clientConnectivityMetrics}
134144
accordionName="Client Connectivity Metrics"
135145
searchQuery={searchQuery}
146+
singleMetricDescriptions={singleMetricDescriptions}
136147
valueType="number" />
137148
<Accordion
149+
accordionDescription={accordionDescriptions.commandExecutionMetrics}
138150
accordionItems={commandExecutionMetrics}
139151
accordionName="Command Execution Metrics"
140152
searchQuery={searchQuery}
153+
singleMetricDescriptions={singleMetricDescriptions}
141154
valueType="number" />
142155
<Accordion
156+
accordionDescription={accordionDescriptions.dataEffectivenessEvictionMetrics}
143157
accordionItems={dataEffectivenessAndEvictionMetrics}
144158
accordionName="Data Effectiveness & Eviction Metrics"
145-
searchQuery={searchQuery}
159+
searchQuery={searchQuery}
160+
singleMetricDescriptions={singleMetricDescriptions}
146161
valueType="number" />
147162
<Accordion
163+
accordionDescription={accordionDescriptions.messagingMetrics}
148164
accordionItems={messagingMetrics}
149165
accordionName="Messaging Metrics"
150-
searchQuery={searchQuery}
166+
searchQuery={searchQuery}
167+
singleMetricDescriptions={singleMetricDescriptions}
151168
valueType="number" />
152169
</div>
153170
{/* Chart Area */}

apps/frontend/src/components/ui/accordion.tsx

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
import { useState, useMemo, useEffect } from "react"
2-
import { CircleChevronDown, CircleChevronUp, Dot } from "lucide-react"
2+
import { CircleChevronDown, CircleChevronUp, Dot, CircleQuestionMark } from "lucide-react"
33
import { formatMetricValue, type ValueType } from "@common/src/format-metric-value"
4+
import { TooltipProvider } from "@radix-ui/react-tooltip"
5+
import { CustomTooltip } from "./custom-tooltip"
46

57
interface AccordionProps {
68
accordionName?: string;
79
accordionItems?: Record<string, number | null>;
810
valueType?: ValueType;
911
searchQuery?: string;
12+
accordionDescription?: string;
13+
singleMetricDescriptions?: Record<string, { description: string; unit: string }>;
1014
}
1115

12-
export default function Accordion({ accordionName, accordionItems, valueType = "number", searchQuery = "" }: AccordionProps) {
16+
export default function Accordion({ accordionName, accordionItems, valueType = "number", searchQuery = "",
17+
accordionDescription = "", singleMetricDescriptions = {} }: AccordionProps) {
1318
const [isOpen, setIsOpen] = useState(false)
1419

1520
const ToggleIcon = isOpen ? CircleChevronUp : CircleChevronDown
@@ -55,25 +60,38 @@ export default function Accordion({ accordionName, accordionItems, valueType = "
5560

5661
return (
5762
<div className="w-full mt-2">
58-
<div className="h-14 px-2 py-4 dark:border-tw-dark-border border rounded flex items-center gap-2 justify-between">
59-
<div className="flex flex-col gap-1">
60-
<span className="font-semibold text-sm">{accordionName}</span>
61-
<span className="text-xs font-light text-tw-dark-border">
62-
{searchQuery.trim() && filteredItemCount !== itemCount ? (
63-
<>{filteredItemCount} of {itemCount} {itemCount === 1 ? "metric" : "metrics"}</>
64-
) : (
65-
<>{itemCount} {itemCount === 1 ? "metric" : "metrics"}</>
66-
)}</span>
63+
<TooltipProvider>
64+
<div className="h-14 px-2 py-4 dark:border-tw-dark-border border rounded flex items-center gap-2 justify-between">
65+
<div className="flex flex-col gap-1">
66+
<span className="font-semibold text-sm flex items-center gap-1">{accordionName}
67+
<CustomTooltip description={accordionDescription}>
68+
<CircleQuestionMark className="bg-tw-primary/10 rounded-full text-tw-primary" size={16} />
69+
</CustomTooltip>
70+
</span>
71+
<span className="text-xs font-light text-tw-dark-border">
72+
{searchQuery.trim() && filteredItemCount !== itemCount ? (
73+
<>{filteredItemCount} of {itemCount} {itemCount === 1 ? "metric" : "metrics"}</>
74+
) : (
75+
<>{itemCount} {itemCount === 1 ? "metric" : "metrics"}</>
76+
)}</span>
77+
</div>
78+
<button onClick={() => setIsOpen(!isOpen)}><ToggleIcon className="text-tw-primary cursor-pointer hover:text-tw-primary/80" /></button>
6779
</div>
68-
<button onClick={() => setIsOpen(!isOpen)}><ToggleIcon className="text-tw-primary cursor-pointer hover:text-tw-primary/80" /></button>
69-
</div>
80+
</TooltipProvider>
7081

7182
{isOpen && (
7283
<div className="px-2 py-3 border bg-gray-50 dark:bg-gray-800 text-sm dark:border-tw-dark-border rounded-b">
7384
<ul className="space-y-2">
7485
{Object.entries(filteredItems).map(([key, value]) => (
7586
<li className="flex justify-between items-center hover:bg-tw-primary/20" key={key}>
76-
<span className="font-normal flex items-center"><Dot className="text-tw-primary" size={30} />{formatKey(key)}</span>
87+
<div className="flex items-center gap-1">
88+
<span className="font-normal flex items-center"><Dot className="text-tw-primary" size={30} />{formatKey(key)}</span>
89+
{singleMetricDescriptions[key] && (
90+
<CustomTooltip description={singleMetricDescriptions[key].description} unit={singleMetricDescriptions[key].unit}>
91+
<CircleQuestionMark className="bg-tw-primary/10 rounded-full text-tw-primary" size={13} />
92+
</CustomTooltip>
93+
)}
94+
</div>
7795
<span className="font-light">{formatMetricValue(key, value, valueType)}</span>
7896
</li>
7997
))}

apps/frontend/src/components/ui/custom-tooltip.tsx

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,36 @@ import {
77

88
interface CustomTooltipProps {
99
children: React.ReactNode;
10-
content: string;
10+
content?: string;
11+
description?: string;
12+
unit?: string;
1113
}
1214

13-
export function CustomTooltip({ children, content }: CustomTooltipProps) {
15+
export function CustomTooltip({ children, content, description, unit }: CustomTooltipProps) {
1416
return (
1517
<Tooltip delayDuration={200}>
1618
<TooltipTrigger asChild>{children}</TooltipTrigger>
17-
<TooltipContent
18-
align="center"
19-
className={"bg-tw-primary text-white px-2 py-1 mt-1 rounded text-xs font-light z-10"}
20-
side="bottom"
21-
>
22-
<p>{content}</p>
23-
</TooltipContent>
19+
{content &&
20+
<TooltipContent
21+
align="center"
22+
className={"bg-tw-primary text-white px-2 py-1 mt-1 rounded text-xs font-light z-10"}
23+
side="bottom"
24+
>
25+
<p>{content}</p>
26+
</TooltipContent>
27+
}
28+
{description &&
29+
<TooltipContent
30+
align="center"
31+
className={"bg-tw-primary text-white px-2 py-1 mt-1 rounded text-xs font-light z-10 w-1/2"}
32+
side="right"
33+
>
34+
<p>{description}</p>
35+
{unit && (
36+
<p className="bg-white/20 rounded-full px-1 py-0.5 text-xs mt-1 font-medium text-white inline-block w-fit">{unit}</p>
37+
)}
38+
</TooltipContent>
39+
}
2440
</Tooltip>
2541
)
2642
}

0 commit comments

Comments
 (0)