Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Resource Browser Visualizations #2164

Merged
merged 30 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8a234d5
feat: ResourceBrowser - Cluster Data Visualizations - TreeMap, Filter…
RohitRaj011 Oct 29, 2024
9e49420
refactor: ClusterMap - scss update
RohitRaj011 Oct 29, 2024
ef58eb4
refactor: ClusterMap, ClusterSelectionList - UAT changes
RohitRaj011 Oct 29, 2024
8e74fd7
feat: ClusterMap - add loading state
RohitRaj011 Oct 29, 2024
b371169
fix: ClusterMap - bar padding
RohitRaj011 Oct 29, 2024
55eff4a
refactor: ClusterMap - Tooltip design update, code refactor
RohitRaj011 Oct 30, 2024
d775fd1
refactor: ClusterSelectionList, ResourceBrowser - code refactor, scro…
RohitRaj011 Oct 30, 2024
8dcdd6a
refactor: ClusterSelectionList - Remove table header in empty state
RohitRaj011 Oct 30, 2024
13e4b28
feat: Cluster - add Production/Non-Production tag
RohitRaj011 Oct 30, 2024
fb87aa8
fix: ClusterMap - tooltip padding
RohitRaj011 Oct 30, 2024
fb6a51e
fix: ClusterSelector - null check missing
RohitRaj011 Oct 30, 2024
150cc46
refactor - ClusterSelectionList, ClusterMap - UAT changes
RohitRaj011 Oct 30, 2024
47dba14
feat: ClusterSelectionList - clusterFilter move from state to url
RohitRaj011 Oct 30, 2024
98177d7
refactor: ClusterForm, ClusterSelectionList, ClusterMap - types refactor
RohitRaj011 Nov 4, 2024
d80971f
fix: ClusterForm - types fix
RohitRaj011 Nov 5, 2024
d330ae1
feat: add monitoring tab
AbhishekA1509 Oct 29, 2024
cf6854c
feat: add MonitoringDashboard
AbhishekA1509 Oct 30, 2024
65526aa
Update devtron-fe-common-lib to version 0.6.0-beta-1
AbhishekA1509 Oct 30, 2024
0e5b3b9
fix: self review
AbhishekA1509 Nov 4, 2024
1a7864c
fix: move fixedTabIndices to util
AbhishekA1509 Nov 4, 2024
75821e9
Merge pull request #2162 from devtron-labs/feat/rb-monitoring
AbhishekA1509 Nov 6, 2024
4d7f81c
feat: ResourceBrowser - hide virtual clusters from page header cluste…
RohitRaj011 Nov 6, 2024
a4dec04
refactor: css update
RohitRaj011 Nov 6, 2024
c208194
Merge branch 'kubecon-2024' of github.com:devtron-labs/dashboard into…
RohitRaj011 Nov 6, 2024
319d0b3
chore: common-lib version bump
RohitRaj011 Nov 6, 2024
f3c752c
fix: ClusterSelectionList - clearFilters not working fix
RohitRaj011 Nov 7, 2024
f09f7e3
Merge branch 'kubecon-2024' of github.com:devtron-labs/dashboard into…
RohitRaj011 Nov 7, 2024
6b51b39
chore: common-lib version bump
RohitRaj011 Nov 7, 2024
3f38460
fix: ClusterMap - css update
RohitRaj011 Nov 7, 2024
caa16e8
refactor: DynamicTabs - css update
RohitRaj011 Nov 7, 2024
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"homepage": "/dashboard",
"dependencies": {
"@devtron-labs/devtron-fe-common-lib": "0.6.0-patch-1-beta-7",
"@devtron-labs/devtron-fe-common-lib": "0.6.0-patch-1-beta-10",
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@rjsf/core": "^5.13.3",
"@rjsf/utils": "^5.13.3",
Expand Down
96 changes: 96 additions & 0 deletions src/Pages/ResourceBrowser/ClusterList/ClusterMap/ClusterMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Link } from 'react-router-dom'
import { ResponsiveContainer, Treemap, TreemapProps } from 'recharts'
import { followCursor } from 'tippy.js'

import { ClusterStatusType, ConditionalWrap, Tooltip } from '@devtron-labs/devtron-fe-common-lib'

import { getVisibleSvgTextWithEllipsis } from './utils'
import { ClusterMapProps } from './types'

import './clustermap.scss'

const renderWithLink = (href: string) => (children: JSX.Element) => (
<Link className="anchor" to={href}>
{children}
</Link>
)

const ClusterTreeMapContent = ({
x,
y,
width,
height,
status,
name,
value,
href,
}: TreemapProps['content']['props']) => (
<ConditionalWrap condition={!!href} wrap={renderWithLink(href)}>
<Tooltip
alwaysShowTippyOnHover
content={
<div className="flexbox-col dc__gap-8 fs-12 lh-18">
<div className="flexbox-col dc__gap-2">
<span className="fw-6 cn-0">{name}</span>
<span className="cn-50">{`${value} Nodes`}</span>
</div>
<span className={`dc__capitalize ${status === ClusterStatusType.HEALTHY ? 'cg-3' : 'cr-3'}`}>
{status}
</span>
</div>
}
followCursor
plugins={[followCursor]}
>
<g className="cluster-map__bar">
<rect
x={x}
y={y}
width={width}
height={height}
className={`cluster-map__rect ${status === 'unhealthy' ? 'cluster-map__rect--unhealthy' : ''}`}
/>
<text x={x + 8} y={y + 22} className="cluster-map__text fcn-9 fs-13 fw-6">
{getVisibleSvgTextWithEllipsis({ text: name, maxWidth: width, fontSize: 13, fontWeight: 600 })}
</text>
<text x={x + 8} y={y + 38} className="cluster-map__text fcn-9 fs-12 fw-4">
{value}
</text>
</g>
</Tooltip>
</ConditionalWrap>
)

export const ClusterMap = ({ treeMapData = [], isLoading = false }: ClusterMapProps) =>
treeMapData.length ? (
<div className="cluster-map pb-16 px-20">
<div className="w-100 p-12 dc__border-n1 br-8 flexbox dc__align-items-center dc__gap-6">
{isLoading ? (
<div className="w-100 flexbox-col dc__gap-4">
<div className="shimmer-loading h-16" />
<div className="shimmer-loading cluster-map__container" />
</div>
eshankvaish marked this conversation as resolved.
Show resolved Hide resolved
) : (
treeMapData.map(({ id, label, data }) => (
<div key={id} className="flexbox-col dc__gap-4" style={{ flex: data.length, minWidth: '0' }}>
{label && (
<Tooltip content={label}>
<p className="m-0 fs-12 lh-16 fw-6 cn-9 dc__truncate">{label}</p>
</Tooltip>
)}
<div className="cluster-map__container">
<ResponsiveContainer width="100%" height="100%">
<Treemap
data={data}
stroke="var(--N0)"
content={<ClusterTreeMapContent />}
isAnimationActive={false}
/>
</ResponsiveContainer>
</div>
</div>
))
)}
</div>
</div>
) : null
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.cluster-map {
$parent-selector: &;

&__container {
height: 165px;
}

&__bar:hover {
#{$parent-selector}__rect {
fill: var(--G400);

&--unhealthy {
fill: var(--R400);
}
}

#{$parent-selector}__text {
fill: var(--N0);
}
}

&__rect {
stroke: var(--N0);
stroke-width: 2;
fill: var(--G200);

&--unhealthy {
fill: var(--R200);
}
}

&__text {
stroke-width: 0;
}
}
2 changes: 2 additions & 0 deletions src/Pages/ResourceBrowser/ClusterList/ClusterMap/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './ClusterMap'
export * from './types'
19 changes: 19 additions & 0 deletions src/Pages/ResourceBrowser/ClusterList/ClusterMap/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ClusterStatusType } from '@devtron-labs/devtron-fe-common-lib'

interface MapData {
name: string
value: number
status: Extract<ClusterStatusType, ClusterStatusType.HEALTHY | ClusterStatusType.UNHEALTHY>
href?: string
}

export interface ClusterTreeMapData {
id: number
label?: string
data: MapData[]
}

export interface ClusterMapProps {
isLoading?: boolean
treeMapData: ClusterTreeMapData[]
}
58 changes: 58 additions & 0 deletions src/Pages/ResourceBrowser/ClusterList/ClusterMap/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const createMeasurementSvg = (fontSize: number, fontWeight: number) => {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.setAttribute('width', '0')
svg.setAttribute('height', '0')
// Hide it from view
svg.style.position = 'absolute'

const textElement = document.createElementNS('http://www.w3.org/2000/svg', 'text')
textElement.setAttribute('x', '0')
textElement.setAttribute('y', '0')
textElement.setAttribute('font-size', `${fontSize}px`)
textElement.setAttribute('font-weight', `${fontWeight}`)
textElement.setAttribute(
'font-family',
"'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif",
)

svg.appendChild(textElement)
document.body.appendChild(svg)

return { svg, textElement }
}

export const getVisibleSvgTextWithEllipsis = (() => {
let svgInstance: SVGSVGElement | null = null
let textElementInstance: SVGTextElement | null = null

return ({ text = '', maxWidth = 0, fontSize = 16, fontWeight = 400 }) => {
if (!svgInstance || !textElementInstance) {
const { svg, textElement } = createMeasurementSvg(fontSize, fontWeight)
svgInstance = svg
textElementInstance = textElement
}

const textElement = textElementInstance
textElement.textContent = '...'
const ellipsisWidth = textElement.getBBox().width

let start = 0
let end = text.length

while (start < end) {
const mid = Math.floor((start + end) / 2)
textElement.textContent = text.slice(0, mid + 1)

const currentWidth = textElement.getBBox().width
if (currentWidth + ellipsisWidth > maxWidth - 8) {
end = mid
} else {
start = mid + 1
}
}

const visibleText = text.slice(0, start) + (start < text.length ? '...' : '')

return visibleText
}
})()
1 change: 1 addition & 0 deletions src/Pages/ResourceBrowser/ClusterList/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ClusterMap'
1 change: 1 addition & 0 deletions src/Pages/ResourceBrowser/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ClusterList'
Loading
Loading