Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
83c5a0d
feat: database storage
astandrik Apr 14, 2026
b0067b0
fix: some fixes
astandrik Apr 15, 2026
9e038f9
fix: review fixes
astandrik Apr 21, 2026
25e2668
fix: review fixes
astandrik Apr 22, 2026
ff1fad1
fix: data space usage
astandrik Apr 24, 2026
d4432e2
fix: design fixes 1
astandrik Apr 29, 2026
985fa47
fix: design review 2
astandrik Apr 29, 2026
2c72d94
fix: tooltip
astandrik Apr 29, 2026
06ddbdb
fix: refactor
astandrik May 4, 2026
b42b6ad
fix: design fixes
astandrik May 4, 2026
aa9d615
fix: design fixes
astandrik May 4, 2026
1798637
fix: refine new storage layout and tooltips
astandrik May 5, 2026
6fe846a
test: update new storage snapshots
astandrik May 5, 2026
ac47f66
test: update tenant storage screenshots
astandrik May 5, 2026
99e79cc
test: add full tenant storage screenshots
astandrik May 5, 2026
e14c455
test: update tenant storage table screenshots
astandrik May 5, 2026
2f78929
test: update tenant storage table snapshots
astandrik May 5, 2026
ddb1238
fix: address storage review feedback
astandrik May 6, 2026
223531b
fix: handle unknown storage top row data
astandrik May 6, 2026
5a7afc5
fix: handle tablet type storage fallbacks
astandrik May 6, 2026
46077d7
Merge branch 'main' into astandrik.3779-2
astandrik May 6, 2026
b7f9087
fix: preserve aggregate storage breakdown
astandrik May 6, 2026
94cfe86
fix: handle unknown tenant storage media
astandrik May 6, 2026
41654b4
fix: classify old system tablet storage
astandrik May 6, 2026
48b4528
Merge branch 'main' into astandrik.3779-2
astandrik May 6, 2026
66f40d1
fix: handle aggregate tenant storage media
astandrik May 6, 2026
7472fdd
fix: some formatting fixes
astandrik May 6, 2026
25cb600
fix: display refactoring
astandrik May 6, 2026
fc4077c
fix: legacy storage
astandrik May 7, 2026
fa65b4e
fix: handle partial tenant storage breakdown
astandrik May 7, 2026
cc2acb2
fix: review fixes
astandrik May 7, 2026
e41d4c5
fix: review fix
astandrik May 8, 2026
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
24 changes: 21 additions & 3 deletions src/containers/Cluster/ClusterOverview/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@ import {calculateProgressStatus} from '../../../utils/progress';

import type {ClusterMetricsBaseProps, ClusterMetricsCommonProps} from './shared';

function parseDiagramValue(value: number | string) {
if (typeof value === 'string' && value.trim() === '') {
return NaN;
}

const parsedValue = Number(value);

return Number.isFinite(parsedValue) ? parsedValue : NaN;
}

function calculateFillWidth(value: number, capacity: number) {
if (!Number.isFinite(value) || !Number.isFinite(capacity) || capacity <= 0) {
return 0;
}

return (value / capacity) * 100;
}

export function calculateBaseDiagramValues({
colorizeProgress = true,
warningThreshold,
Expand Down Expand Up @@ -33,9 +51,9 @@ export function getDiagramValues({
}: ClusterMetricsCommonProps & {
legendFormatter: (params: {value: number; capacity: number}) => string;
}) {
const parsedValue = parseFloat(String(value));
const parsedCapacity = parseFloat(String(capacity));
const fillWidth = (parsedValue / parsedCapacity) * 100 || 0;
const parsedValue = parseDiagramValue(value);
const parsedCapacity = parseDiagramValue(capacity);
const fillWidth = calculateFillWidth(parsedValue, parsedCapacity);

const legend = legendFormatter({
value: parsedValue,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,39 @@ import './MetricsTabs.scss';

const b = cn('tenant-metrics-tabs');

interface SelectStorageStatsForMetricCardParams {
blobStorageStats?: TenantStorageStats[];
tabletStorageStats?: TenantStorageStats[];
isServerless: boolean;
}

export function selectStorageStatsForMetricCard({
blobStorageStats,
tabletStorageStats,
isServerless,
}: SelectStorageStatsForMetricCardParams) {
if (isServerless) {
return tabletStorageStats || blobStorageStats || [];
}

const hasLimit = (stats?: TenantStorageStats[]) =>
Boolean(stats?.some((item) => Number(item.limit) > 0));

if (hasLimit(tabletStorageStats)) {
return tabletStorageStats || [];
}

if (hasLimit(blobStorageStats)) {
return blobStorageStats || [];
}

return blobStorageStats || tabletStorageStats || [];
}

interface MetricsTabsProps {
poolsCpuStats?: TenantPoolsStats[];
memoryStats?: TenantMetricStats[];
storageMetricStats?: TenantStorageStats[];
blobStorageStats?: TenantStorageStats[];
tabletStorageStats?: TenantStorageStats[];
networkUtilization?: number;
Expand All @@ -46,6 +76,7 @@ interface MetricsTabsProps {
export function MetricsTabs({
poolsCpuStats,
memoryStats,
storageMetricStats,
blobStorageStats,
tabletStorageStats,
networkUtilization,
Expand Down Expand Up @@ -84,11 +115,18 @@ export function MetricsTabs({
[poolsCpuStats],
);
const cpuMetrics = React.useMemo(() => calculateMetricAggregates(cpuPools), [cpuPools]);
const isServerless = databaseType === 'Serverless';

// Calculate storage metrics using utility
const storageStats = React.useMemo(
() => tabletStorageStats || blobStorageStats || [],
[tabletStorageStats, blobStorageStats],
() =>
storageMetricStats ??
selectStorageStatsForMetricCard({
blobStorageStats,
tabletStorageStats,
isServerless,
}),
[blobStorageStats, isServerless, storageMetricStats, tabletStorageStats],
);
const storageMetrics = React.useMemo(
() => calculateMetricAggregates(storageStats),
Expand All @@ -106,8 +144,6 @@ export function MetricsTabs({

// card variant is handled within subcomponents

const isServerless = databaseType === 'Serverless';

const renderNetworkTab = () => {
if (!showNetworkUtilization) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {EType} from '../../../../../../types/api/tenant';
import {selectStorageStatsForMetricCard} from '../MetricsTabs';

describe('selectStorageStatsForMetricCard', () => {
test('keeps prod legacy fallback to database storage when tablet storage has no limit', () => {
const blobStorageStats = [
{
name: EType.SSD,
used: 492_778_291_200,
limit: 6_399_113_297_920,
usage: 7.7,
},
];
const tabletStorageStats = [
{
name: EType.SSD,
used: 35_915_303_563,
limit: undefined,
usage: undefined,
},
];

expect(
selectStorageStatsForMetricCard({
blobStorageStats,
tabletStorageStats,
isServerless: false,
}),
).toBe(blobStorageStats);
});

test('keeps quota-based tablet storage priority from main', () => {
const blobStorageStats = [
{
name: EType.SSD,
used: 492_778_291_200,
limit: 6_399_113_297_920,
usage: 7.7,
},
];
const tabletStorageStats = [
{
name: EType.SSD,
used: 289_166_965_049,
limit: 612_032_839_680,
usage: 47.2,
},
];

expect(
selectStorageStatsForMetricCard({
blobStorageStats,
tabletStorageStats,
isServerless: false,
}),
).toBe(tabletStorageStats);
});

test('keeps serverless legacy priority for tablet storage', () => {
const blobStorageStats = [
{
name: EType.SSD,
used: 500,
limit: 1_000,
usage: 50,
},
];
const tabletStorageStats = [
{
name: EType.SSD,
used: 100,
limit: undefined,
usage: undefined,
},
];

expect(
selectStorageStatsForMetricCard({
blobStorageStats,
tabletStorageStats,
isServerless: true,
}),
).toBe(tabletStorageStats);
});
});
Loading
Loading