mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-04-28 03:20:11 +00:00
Refine storage summary and table interactions
This commit is contained in:
parent
386099aeee
commit
46ba8c6ef8
12 changed files with 141 additions and 70 deletions
|
|
@ -287,9 +287,21 @@ export const DiskList: Component<DiskListProps> = (props) => {
|
|||
</TableCell>
|
||||
|
||||
<TableCell class={PHYSICAL_DISK_CELL_SIZE_CLASS}>
|
||||
<span class={PHYSICAL_DISK_SIZE_VALUE_CLASS}>
|
||||
{formatBytes(data.size)}
|
||||
</span>
|
||||
<Show
|
||||
when={data.size > 0}
|
||||
fallback={
|
||||
<span
|
||||
class={PHYSICAL_DISK_MUTED_PLACEHOLDER_CLASS}
|
||||
title="Disk size not reported by SMART/agent"
|
||||
>
|
||||
—
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<span class={PHYSICAL_DISK_SIZE_VALUE_CLASS}>
|
||||
{formatBytes(data.size)}
|
||||
</span>
|
||||
</Show>
|
||||
</TableCell>
|
||||
|
||||
</TableRow>
|
||||
|
|
|
|||
|
|
@ -105,6 +105,13 @@ const Storage: Component = () => {
|
|||
onChartHoverSyncChange={setChartHoverSync}
|
||||
showJumpToActiveRow={shouldShowJumpToActiveStorageRow}
|
||||
onJumpToActiveRow={jumpToActiveStorageRow}
|
||||
onScopeToDegradedPools={() => {
|
||||
setView('pools');
|
||||
setStorageFilterStatus('warning');
|
||||
}}
|
||||
onScopeToFailingDisks={() => {
|
||||
setView('disks');
|
||||
}}
|
||||
/>
|
||||
</StickySummarySection>
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ type StoragePageSummaryProps = {
|
|||
onChartHoverSyncChange: (value: SummaryChartHoverSync | null) => void;
|
||||
showJumpToActiveRow: () => boolean;
|
||||
onJumpToActiveRow: () => void;
|
||||
onScopeToDegradedPools?: () => void;
|
||||
onScopeToFailingDisks?: () => void;
|
||||
};
|
||||
|
||||
export const StoragePageSummary: Component<StoragePageSummaryProps> = (props) => {
|
||||
|
|
@ -61,6 +63,8 @@ export const StoragePageSummary: Component<StoragePageSummaryProps> = (props) =>
|
|||
onChartHoverSyncChange={props.onChartHoverSyncChange}
|
||||
showJumpToActiveRow={props.showJumpToActiveRow()}
|
||||
onJumpToActiveRow={props.onJumpToActiveRow}
|
||||
onScopeToDegradedPools={props.onScopeToDegradedPools}
|
||||
onScopeToFailingDisks={props.onScopeToFailingDisks}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,13 +8,11 @@ import {
|
|||
buildStoragePoolRowModel,
|
||||
STORAGE_POOL_ROW_GROWTH_CELL_CLASS,
|
||||
STORAGE_POOL_ROW_GROWTH_TEXT_CLASS,
|
||||
getStoragePoolImpactTextClass,
|
||||
STORAGE_POOL_ROW_CLASS,
|
||||
STORAGE_POOL_ROW_EXPANDED_CLASS,
|
||||
STORAGE_POOL_ROW_HEIGHT_CLASS,
|
||||
STORAGE_POOL_ROW_PLACEHOLDER_CLASS,
|
||||
STORAGE_POOL_ROW_HOST_CELL_CLASS,
|
||||
STORAGE_POOL_ROW_IMPACT_CELL_CLASS,
|
||||
STORAGE_POOL_ROW_ISSUE_CELL_CLASS,
|
||||
STORAGE_POOL_ROW_ISSUE_TEXT_CLASS,
|
||||
STORAGE_POOL_ROW_NAME_CELL_CLASS,
|
||||
|
|
@ -101,6 +99,20 @@ export const StoragePoolRow: Component<StoragePoolRowProps> = (props) => {
|
|||
</div>
|
||||
</td>
|
||||
|
||||
<td class={STORAGE_POOL_ROW_ISSUE_CELL_CLASS}>
|
||||
<Show
|
||||
when={row().compactIssue !== '—'}
|
||||
fallback={<span class={STORAGE_POOL_ROW_PLACEHOLDER_CLASS}>—</span>}
|
||||
>
|
||||
<span
|
||||
class={`${STORAGE_POOL_ROW_ISSUE_TEXT_CLASS} ${getStoragePoolIssueTextClass(props.record)}`}
|
||||
title={row().compactIssueSummary || row().compactIssue}
|
||||
>
|
||||
{row().compactIssue}
|
||||
</span>
|
||||
</Show>
|
||||
</td>
|
||||
|
||||
<td class={STORAGE_POOL_ROW_SOURCE_CELL_CLASS}>
|
||||
<span class={`${row().platformToneClass} ${STORAGE_POOL_ROW_SOURCE_BADGE_CLASS}`}>
|
||||
{row().platformLabel}
|
||||
|
|
@ -160,28 +172,6 @@ export const StoragePoolRow: Component<StoragePoolRowProps> = (props) => {
|
|||
</span>
|
||||
</td>
|
||||
|
||||
<td class={STORAGE_POOL_ROW_IMPACT_CELL_CLASS}>
|
||||
<span
|
||||
class={getStoragePoolImpactTextClass(row().compactImpact)}
|
||||
title={row().compactImpact}
|
||||
>
|
||||
{row().compactImpact}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class={STORAGE_POOL_ROW_ISSUE_CELL_CLASS}>
|
||||
<Show
|
||||
when={row().compactIssue !== '—'}
|
||||
fallback={<span class={STORAGE_POOL_ROW_PLACEHOLDER_CLASS}>—</span>}
|
||||
>
|
||||
<span
|
||||
class={`${STORAGE_POOL_ROW_ISSUE_TEXT_CLASS} ${getStoragePoolIssueTextClass(props.record)}`}
|
||||
title={row().compactIssueSummary || row().compactIssue}
|
||||
>
|
||||
{row().compactIssue}
|
||||
</span>
|
||||
</Show>
|
||||
</td>
|
||||
</tr>
|
||||
<Show when={props.expanded}>
|
||||
<StoragePoolDetail
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ interface StorageSummaryProps {
|
|||
onChartHoverSyncChange?: (value: SummaryChartHoverSync | null) => void;
|
||||
showJumpToActiveRow?: boolean;
|
||||
onJumpToActiveRow?: () => void;
|
||||
onScopeToDegradedPools?: () => void;
|
||||
onScopeToFailingDisks?: () => void;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -158,6 +160,44 @@ const StorageSummary: Component<StorageSummaryProps> = (props) => {
|
|||
summaryFocus.filterSeriesForActiveScope(allDiskTempSeries()),
|
||||
);
|
||||
|
||||
// Symmetric cross-card scoping: a pool-row hover scopes the three pool
|
||||
// charts; a disk-row hover scopes the disk chart. The "foreign" cards
|
||||
// fall back to default state instead of dimming, because the hovered
|
||||
// entity has no representation in their dataset.
|
||||
const poolSeriesIdSet = createMemo(() => {
|
||||
const ids = new Set<string>();
|
||||
for (const s of allPoolUsageSeries()) if (s.id) ids.add(s.id);
|
||||
for (const s of allPoolUsedSeries()) if (s.id) ids.add(s.id);
|
||||
for (const s of allPoolAvailSeries()) if (s.id) ids.add(s.id);
|
||||
return ids;
|
||||
});
|
||||
const diskSeriesIdSet = createMemo(() => {
|
||||
const ids = new Set<string>();
|
||||
for (const s of allDiskTempSeries()) if (s.id) ids.add(s.id);
|
||||
return ids;
|
||||
});
|
||||
type SeriesFamily = 'pool' | 'disk';
|
||||
const activeFamily = (): SeriesFamily | null => {
|
||||
const id = summaryFocus.activeSeriesId();
|
||||
if (!id) return null;
|
||||
if (poolSeriesIdSet().has(id)) return 'pool';
|
||||
if (diskSeriesIdSet().has(id)) return 'disk';
|
||||
return null;
|
||||
};
|
||||
const interactionStateForFamily = (
|
||||
family: SeriesFamily,
|
||||
series: InteractiveSparklineSeries[],
|
||||
) => {
|
||||
const af = activeFamily();
|
||||
if (af && af !== family) return 'default' as const;
|
||||
return summaryFocus.interactionStateFor(series);
|
||||
};
|
||||
const highlightIdForFamily = (family: SeriesFamily) => {
|
||||
const af = activeFamily();
|
||||
if (af && af !== family) return null;
|
||||
return summaryFocus.activeSeriesId();
|
||||
};
|
||||
|
||||
const hasPoolUsage = () => poolUsageSeries().length > 0;
|
||||
const hasDiskTemp = () => diskTempSeries().length > 0;
|
||||
const hasPoolUsed = () => poolUsedSeries().length > 0;
|
||||
|
|
@ -249,14 +289,42 @@ const StorageSummary: Component<StorageSummaryProps> = (props) => {
|
|||
}
|
||||
>
|
||||
<Show when={(props.poolsDegraded ?? 0) > 0}>
|
||||
<span class="text-amber-600 dark:text-amber-400">
|
||||
{props.poolsDegraded} degraded
|
||||
</span>
|
||||
<Show
|
||||
when={props.onScopeToDegradedPools}
|
||||
fallback={
|
||||
<span class="text-amber-600 dark:text-amber-400">
|
||||
{props.poolsDegraded} degraded
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => props.onScopeToDegradedPools?.()}
|
||||
title="Show degraded pools"
|
||||
class="text-amber-600 hover:text-amber-700 hover:underline focus:underline focus:outline-none dark:text-amber-400 dark:hover:text-amber-300"
|
||||
>
|
||||
{props.poolsDegraded} degraded
|
||||
</button>
|
||||
</Show>
|
||||
</Show>
|
||||
<Show when={(props.disksFailing ?? 0) > 0}>
|
||||
<span class="text-amber-600 dark:text-amber-400">
|
||||
{props.disksFailing} {props.disksFailing === 1 ? 'disk failing' : 'disks failing'}
|
||||
</span>
|
||||
<Show
|
||||
when={props.onScopeToFailingDisks}
|
||||
fallback={
|
||||
<span class="text-amber-600 dark:text-amber-400">
|
||||
{props.disksFailing} {props.disksFailing === 1 ? 'disk failing' : 'disks failing'}
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => props.onScopeToFailingDisks?.()}
|
||||
title="Show physical disks"
|
||||
class="text-amber-600 hover:text-amber-700 hover:underline focus:underline focus:outline-none dark:text-amber-400 dark:hover:text-amber-300"
|
||||
>
|
||||
{props.disksFailing} {props.disksFailing === 1 ? 'disk failing' : 'disks failing'}
|
||||
</button>
|
||||
</Show>
|
||||
</Show>
|
||||
</Show>
|
||||
<Show when={props.showJumpToActiveRow && props.onJumpToActiveRow}>
|
||||
|
|
@ -274,7 +342,7 @@ const StorageSummary: Component<StorageSummaryProps> = (props) => {
|
|||
loaded={props.loaded}
|
||||
hasData={hasPoolUsage()}
|
||||
emptyMessage={emptyLabel()}
|
||||
interactionState={summaryFocus.interactionStateFor(poolUsageSeries())}
|
||||
interactionState={interactionStateForFamily('pool', poolUsageSeries())}
|
||||
>
|
||||
<InteractiveSparkline
|
||||
series={poolUsageSeries()}
|
||||
|
|
@ -285,8 +353,8 @@ const StorageSummary: Component<StorageSummaryProps> = (props) => {
|
|||
highlightNearestSeriesOnHover
|
||||
hoverSourceKey="pool-usage"
|
||||
hoverSync={chartHoverSync()}
|
||||
highlightSeriesId={summaryFocus.activeSeriesId()}
|
||||
interactionState={summaryFocus.interactionStateFor(poolUsageSeries())}
|
||||
highlightSeriesId={highlightIdForFamily('pool')}
|
||||
interactionState={interactionStateForFamily('pool', poolUsageSeries())}
|
||||
onHoverSyncChange={setChartHoverSync}
|
||||
/>
|
||||
</SummaryMetricCard>
|
||||
|
|
@ -298,7 +366,7 @@ const StorageSummary: Component<StorageSummaryProps> = (props) => {
|
|||
loaded={props.loaded}
|
||||
hasData={hasDiskTemp()}
|
||||
emptyMessage={emptyLabel()}
|
||||
interactionState={summaryFocus.interactionStateFor(diskTempSeries())}
|
||||
interactionState={interactionStateForFamily('disk', diskTempSeries())}
|
||||
>
|
||||
<InteractiveSparkline
|
||||
series={diskTempSeries()}
|
||||
|
|
@ -311,8 +379,8 @@ const StorageSummary: Component<StorageSummaryProps> = (props) => {
|
|||
highlightNearestSeriesOnHover
|
||||
hoverSourceKey="disk-temperature"
|
||||
hoverSync={chartHoverSync()}
|
||||
highlightSeriesId={summaryFocus.activeSeriesId()}
|
||||
interactionState={summaryFocus.interactionStateFor(diskTempSeries())}
|
||||
highlightSeriesId={highlightIdForFamily('disk')}
|
||||
interactionState={interactionStateForFamily('disk', diskTempSeries())}
|
||||
onHoverSyncChange={setChartHoverSync}
|
||||
/>
|
||||
</SummaryMetricCard>
|
||||
|
|
@ -324,7 +392,7 @@ const StorageSummary: Component<StorageSummaryProps> = (props) => {
|
|||
loaded={props.loaded}
|
||||
hasData={hasPoolUsed()}
|
||||
emptyMessage={emptyLabel()}
|
||||
interactionState={summaryFocus.interactionStateFor(poolUsedSeries())}
|
||||
interactionState={interactionStateForFamily('pool', poolUsedSeries())}
|
||||
>
|
||||
<InteractiveSparkline
|
||||
series={poolUsedSeries()}
|
||||
|
|
@ -337,8 +405,8 @@ const StorageSummary: Component<StorageSummaryProps> = (props) => {
|
|||
highlightNearestSeriesOnHover
|
||||
hoverSourceKey="used-capacity"
|
||||
hoverSync={chartHoverSync()}
|
||||
highlightSeriesId={summaryFocus.activeSeriesId()}
|
||||
interactionState={summaryFocus.interactionStateFor(poolUsedSeries())}
|
||||
highlightSeriesId={highlightIdForFamily('pool')}
|
||||
interactionState={interactionStateForFamily('pool', poolUsedSeries())}
|
||||
onHoverSyncChange={setChartHoverSync}
|
||||
/>
|
||||
</SummaryMetricCard>
|
||||
|
|
@ -350,7 +418,7 @@ const StorageSummary: Component<StorageSummaryProps> = (props) => {
|
|||
loaded={props.loaded}
|
||||
hasData={hasPoolAvail()}
|
||||
emptyMessage={emptyLabel()}
|
||||
interactionState={summaryFocus.interactionStateFor(poolAvailSeries())}
|
||||
interactionState={interactionStateForFamily('pool', poolAvailSeries())}
|
||||
>
|
||||
<InteractiveSparkline
|
||||
series={poolAvailSeries()}
|
||||
|
|
@ -363,8 +431,8 @@ const StorageSummary: Component<StorageSummaryProps> = (props) => {
|
|||
highlightNearestSeriesOnHover
|
||||
hoverSourceKey="available-space"
|
||||
hoverSync={chartHoverSync()}
|
||||
highlightSeriesId={summaryFocus.activeSeriesId()}
|
||||
interactionState={summaryFocus.interactionStateFor(poolAvailSeries())}
|
||||
highlightSeriesId={highlightIdForFamily('pool')}
|
||||
interactionState={interactionStateForFamily('pool', poolAvailSeries())}
|
||||
onHoverSyncChange={setChartHoverSync}
|
||||
/>
|
||||
</SummaryMetricCard>
|
||||
|
|
|
|||
|
|
@ -542,7 +542,7 @@ describe('Storage', () => {
|
|||
'[data-highlight-series-active="true"][data-highlight-series-id="pool:alpha"][data-active-series-display="isolate"][data-rendered-series-count="1"]',
|
||||
).length,
|
||||
).toBe(3);
|
||||
expect(summary.querySelectorAll('[data-summary-card-state="inactive"]').length).toBe(1);
|
||||
expect(summary.querySelectorAll('[data-summary-card-state="inactive"]').length).toBe(0);
|
||||
});
|
||||
|
||||
fireEvent.pointerLeave(alphaRow, { pointerType: 'mouse' });
|
||||
|
|
@ -588,7 +588,7 @@ describe('Storage', () => {
|
|||
'[data-highlight-series-active="true"][data-highlight-series-id="pool:alpha"]',
|
||||
).length,
|
||||
).toBe(3);
|
||||
expect(summary.querySelectorAll('[data-summary-card-state="inactive"]').length).toBe(1);
|
||||
expect(summary.querySelectorAll('[data-summary-card-state="inactive"]').length).toBe(0);
|
||||
});
|
||||
|
||||
fireEvent.mouseLeave(poolUsageChart);
|
||||
|
|
@ -1175,7 +1175,7 @@ describe('Storage', () => {
|
|||
'[data-highlight-series-active="true"][data-highlight-series-id="pool:alpha"]',
|
||||
).length,
|
||||
).toBe(1);
|
||||
expect(summary.querySelectorAll('[data-summary-card-state="inactive"]').length).toBe(3);
|
||||
expect(summary.querySelectorAll('[data-summary-card-state="inactive"]').length).toBe(2);
|
||||
expect(
|
||||
screen
|
||||
.getByText('Used Capacity')
|
||||
|
|
|
|||
|
|
@ -192,13 +192,14 @@ describe('StorageSummary', () => {
|
|||
|
||||
expect(poolCards).toHaveLength(3);
|
||||
for (const sparkline of sparklines) {
|
||||
expect(sparkline.getAttribute('data-highlight-series-id')).toBe('pool:alpha');
|
||||
expect(sparkline.getAttribute('data-hover-sync-series-id')).toBe('pool:alpha');
|
||||
}
|
||||
for (const sparkline of poolCards) {
|
||||
expect(sparkline.getAttribute('data-highlight-series-id')).toBe('pool:alpha');
|
||||
expect(sparkline.getAttribute('data-interaction-state')).toBe('active');
|
||||
}
|
||||
expect(diskTempCard?.getAttribute('data-interaction-state')).toBe('inactive');
|
||||
expect(diskTempCard?.getAttribute('data-highlight-series-id') ?? '').toBe('');
|
||||
expect(diskTempCard?.getAttribute('data-interaction-state')).toBe('default');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -91,14 +91,13 @@ describe('storagePagePresentation', () => {
|
|||
]);
|
||||
expect(getStoragePoolTableColumns('Growth (24h)').map((column) => column.label)).toEqual([
|
||||
'Storage',
|
||||
'Primary Issue',
|
||||
'Source',
|
||||
'Type',
|
||||
'Host',
|
||||
'Protection',
|
||||
'Usage',
|
||||
'Growth (24h)',
|
||||
'Impact',
|
||||
'Primary Issue',
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import type { StorageRecord } from '@/features/storageBackups/models';
|
|||
import {
|
||||
buildStoragePoolRowModel,
|
||||
STORAGE_POOL_ROW_GROWTH_TEXT_CLASS,
|
||||
getStoragePoolImpactTextClass,
|
||||
STORAGE_POOL_ROW_CLASS,
|
||||
STORAGE_POOL_ROW_EXPANDED_CLASS,
|
||||
STORAGE_POOL_ROW_HEIGHT_CLASS,
|
||||
|
|
@ -68,6 +67,5 @@ describe('storage pool row presentation', () => {
|
|||
expect(model.compactIssue).toBe('Capacity Pressure');
|
||||
expect(model.compactImpact).toBe('—');
|
||||
expect(model.freeBytes).toBe(200);
|
||||
expect(getStoragePoolImpactTextClass('—')).toContain('text-muted');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ export const getStoragePoolTableColumns = (
|
|||
label: 'Storage',
|
||||
className: 'px-1.5 sm:px-2 py-0.5 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider',
|
||||
},
|
||||
{
|
||||
label: 'Primary Issue',
|
||||
className: 'px-1.5 sm:px-2 py-0.5 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider',
|
||||
},
|
||||
{
|
||||
label: 'Source',
|
||||
className: 'px-1.5 sm:px-2 py-0.5 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider',
|
||||
|
|
@ -58,15 +62,6 @@ export const getStoragePoolTableColumns = (
|
|||
className:
|
||||
'hidden lg:table-cell px-1.5 sm:px-2 py-0.5 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider',
|
||||
},
|
||||
{
|
||||
label: 'Impact',
|
||||
className:
|
||||
'hidden xl:table-cell px-1.5 sm:px-2 py-0.5 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider',
|
||||
},
|
||||
{
|
||||
label: 'Primary Issue',
|
||||
className: 'px-1.5 sm:px-2 py-0.5 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider',
|
||||
},
|
||||
];
|
||||
|
||||
export const STORAGE_BANNER_ACTION_BUTTON_CLASS =
|
||||
|
|
|
|||
|
|
@ -54,9 +54,7 @@ export const STORAGE_POOL_ROW_USAGE_BAR_WRAP_CLASS = 'min-w-[120px] flex-1';
|
|||
export const STORAGE_POOL_ROW_GROWTH_CELL_CLASS =
|
||||
'hidden lg:table-cell px-2 py-1 align-middle text-[11px]';
|
||||
export const STORAGE_POOL_ROW_GROWTH_TEXT_CLASS = 'block truncate font-mono font-semibold';
|
||||
export const STORAGE_POOL_ROW_IMPACT_CELL_CLASS =
|
||||
'hidden lg:table-cell px-2 py-1 align-middle text-[11px] text-base-content';
|
||||
export const STORAGE_POOL_ROW_ISSUE_CELL_CLASS = 'px-2 py-1 align-middle text-[11px]';
|
||||
export const STORAGE_POOL_ROW_ISSUE_CELL_CLASS = 'px-2 py-1 align-middle text-[11px] max-w-[14rem]';
|
||||
export const STORAGE_POOL_ROW_ISSUE_TEXT_CLASS = 'block truncate text-[11px] font-semibold';
|
||||
export const STORAGE_POOL_ROW_PLACEHOLDER_CLASS = 'text-muted';
|
||||
export const STORAGE_POOL_ROW_USAGE_FALLBACK_CLASS = 'text-[11px] text-muted';
|
||||
|
|
@ -91,5 +89,3 @@ export const buildStoragePoolRowModel = (
|
|||
};
|
||||
};
|
||||
|
||||
export const getStoragePoolImpactTextClass = (impact: string): string =>
|
||||
`${STORAGE_POOL_ROW_TEXT_TRUNCATE_CLASS} ${impact === '—' ? STORAGE_POOL_ROW_PLACEHOLDER_CLASS : ''}`.trim();
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ type StorageChartsResponse = {
|
|||
};
|
||||
|
||||
const ARTIFACTS_DIR = path.resolve(__dirname, '..', '..', 'tmp', 'storage-growth-column');
|
||||
const STORAGE_POOL_GROWTH_CELL_SELECTOR = 'td:nth-child(8)';
|
||||
|
||||
const test = base.extend<{}, WorkerFixtures>({
|
||||
storageState: async ({ authStorageStatePath }, use) => {
|
||||
|
|
@ -165,7 +166,7 @@ test.describe.serial('Storage growth column', () => {
|
|||
const defaultPayload = (await defaultResponse.json()) as StorageChartsResponse;
|
||||
const defaultGrowth = await firstVisibleGrowthExpectation(page, defaultPayload);
|
||||
const defaultGrowthCell = page.locator(
|
||||
`tr[data-summary-series-id="${defaultGrowth.seriesId}"] td:nth-child(7)`,
|
||||
`tr[data-summary-series-id="${defaultGrowth.seriesId}"] ${STORAGE_POOL_GROWTH_CELL_SELECTOR}`,
|
||||
);
|
||||
await expect(defaultGrowthCell).toHaveText(defaultGrowth.label);
|
||||
|
||||
|
|
@ -189,7 +190,7 @@ test.describe.serial('Storage growth column', () => {
|
|||
|
||||
await expect(poolsTable.getByText('Growth (7d)', { exact: true })).toBeVisible();
|
||||
const sevenDayGrowthCell = page.locator(
|
||||
`tr[data-summary-series-id="${defaultGrowth.seriesId}"] td:nth-child(7)`,
|
||||
`tr[data-summary-series-id="${defaultGrowth.seriesId}"] ${STORAGE_POOL_GROWTH_CELL_SELECTOR}`,
|
||||
);
|
||||
await expect(sevenDayGrowthCell).toHaveText(
|
||||
growthLabelForPool(sevenDayPayload.pools?.[defaultGrowth.seriesId]),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue