Skip to content

Commit

Permalink
feat(listing-details): add and implements query inconsistency invalid…
Browse files Browse the repository at this point in the history
…ator hook

add hook to cache bust in case of inconsistency between listing and
details

closes #833

```
  • Loading branch information
WilsonNet committed Jan 29, 2025
1 parent 22b496a commit 2a0a40c
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 16 deletions.
13 changes: 8 additions & 5 deletions dashboard/src/components/TreeListingPage/TreeListingPage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useMemo } from 'react';

import type {
TableTestStatus,
Tree,
TreeFastPathResponse,
TreeTableBody,
Expand Down Expand Up @@ -67,25 +68,27 @@ const TreeListingPage = ({ inputFilter }: ITreeListingPage): JSX.Element => {
: undefined;

const testStatus = isCompleteTree(tree)
? {
done: tree.test_status.done,
? ({
error: tree.test_status.error,
fail: tree.test_status.fail,
miss: tree.test_status.miss,
pass: tree.test_status.pass,
skip: tree.test_status.skip,
}
done: tree.test_status.done,
null: tree.test_status.null,
} satisfies TableTestStatus)
: undefined;

const bootStatus = isCompleteTree(tree)
? {
? ({
done: tree.boot_status.done,
error: tree.boot_status.error,
fail: tree.boot_status.fail,
miss: tree.boot_status.miss,
pass: tree.boot_status.pass,
skip: tree.boot_status.skip,
}
null: tree.boot_status.null,
} satisfies TableTestStatus)
: undefined;

return {
Expand Down
8 changes: 8 additions & 0 deletions dashboard/src/components/TreeListingPage/TreeTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ const getLinkProps = (
},
intervalInDays: previousSearch.intervalInDays,
}),
state: s => ({
...s,
treeStatusCount: {
buildsStatus: row.original.buildStatus,
testStatus: row.original.bootStatus,
bootStatus: row.original.testStatus,
},
}),
};
};

Expand Down
46 changes: 46 additions & 0 deletions dashboard/src/hooks/useQueryInconsistencyInvalidator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useQueryClient } from '@tanstack/react-query';
import type { UseNavigateResult } from '@tanstack/react-router';
import { useEffect } from 'react';

import { deepCompare } from '@/utils/records';

type ReferenceTable =
| Record<string, Record<string, number> | undefined>
| undefined;

type QueryInconsistencyInvalidatorArgs<T extends ReferenceTable> = {
referenceData?: T;
comparedData?: T;
enabled?: boolean;
navigate: UseNavigateResult<'/tree/$treeId' | '/hardware/$hardwareId'>;
};

export const useQueryInconsistencyInvalidator = <T extends ReferenceTable>({
referenceData: referenceData,
comparedData: comparedData,
navigate,
enabled = true,
}: QueryInconsistencyInvalidatorArgs<T>): void => {
const queryClient = useQueryClient();
useEffect(() => {
if (!enabled || !referenceData || !comparedData) {
return;
}

const shouldInvalidate = !deepCompare(referenceData, comparedData);

if (shouldInvalidate) {
queryClient.invalidateQueries().then(() => {
navigate({
search: s => s,
state: s => {
return {
...s,
treeStatusCount: undefined,
};
},
});
});
}
}, [referenceData, comparedData, queryClient, navigate, enabled]);
};
14 changes: 13 additions & 1 deletion dashboard/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import { routeTree } from './routeTree.gen';
import './index.css';
import { isDev } from './lib/utils/vite';
import { ToastProvider } from './components/ui/toast';
import type { RedirectFrom } from './types/general';
import type { BuildStatus, RedirectFrom, StatusCount } from './types/general';
import { parseSearch, stringifySearch } from './utils/search';
import type { TableTestStatus } from './types/tree/Tree';
import type { BuildCount } from './types/hardware';

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
Expand All @@ -40,6 +42,16 @@ declare module '@tanstack/react-router' {
interface HistoryState {
id?: string;
from?: RedirectFrom;
treeStatusCount?: {
buildsStatus?: BuildStatus;
bootStatus?: TableTestStatus;
testStatus?: TableTestStatus;
};
hardwareStatusCount?: {
buildsStatus: BuildCount;
bootStatus: StatusCount;
testStatus: StatusCount;
};
}
}

Expand Down
10 changes: 6 additions & 4 deletions dashboard/src/pages/Hardware/HardwareListingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ import QuerySwitcher from '@/components/QuerySwitcher/QuerySwitcher';

import { Toaster } from '@/components/ui/toaster';

import type { HardwareTableItem } from '@/types/hardware';
import type { BuildCount, HardwareTableItem } from '@/types/hardware';

import { useHardwareListing } from '@/api/hardware';

import { dateObjectToTimestampInSeconds, daysToSeconds } from '@/utils/date';

import { MemoizedSectionError } from '@/components/DetailsPages/SectionError';

import type { StatusCount } from '@/types/general';

import { HardwareTable } from './HardwareTable';

interface HardwareListingPageProps {
Expand Down Expand Up @@ -77,13 +79,13 @@ const HardwareListingPage = ({
return hardware.hardware_name?.includes(inputFilter);
})
.map((hardware): HardwareTableItem => {
const buildCount = {
const buildCount: BuildCount = {
valid: hardware.build_status_summary?.valid,
invalid: hardware.build_status_summary?.invalid,
null: hardware.build_status_summary?.null,
};

const testStatusCount = {
const testStatusCount: StatusCount = {
DONE: hardware.test_status_summary.DONE,
ERROR: hardware.test_status_summary.ERROR,
FAIL: hardware.test_status_summary.FAIL,
Expand All @@ -93,7 +95,7 @@ const HardwareListingPage = ({
NULL: hardware.test_status_summary.NULL,
};

const bootStatusCount = {
const bootStatusCount: StatusCount = {
DONE: hardware.boot_status_summary.DONE,
ERROR: hardware.boot_status_summary.ERROR,
FAIL: hardware.boot_status_summary.FAIL,
Expand Down
8 changes: 8 additions & 0 deletions dashboard/src/pages/Hardware/HardwareTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,14 @@ const getLinkProps = (
endTimestampInSeconds,
diffFilter: { ...previousSearch.diffFilter, ...newDiffFilter },
}),
state: s => ({
...s,
hardwareStatusCount: {
buildsStatus: row.original.build_status_summary,
testStatus: row.original.test_status_summary,
bootStatus: row.original.boot_status_summary,
},
}),
};
};

Expand Down
52 changes: 51 additions & 1 deletion dashboard/src/pages/TreeDetails/TreeDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { useNavigate, useParams, useSearch } from '@tanstack/react-router';
import {
useNavigate,
useParams,
useRouterState,
useSearch,
} from '@tanstack/react-router';
import { useCallback, useMemo } from 'react';

import { FormattedMessage } from 'react-intl';
Expand Down Expand Up @@ -48,6 +53,8 @@ import { useTreeDetailsLazyLoadQuery } from '@/hooks/useTreeDetailsLazyLoadQuery

import { LoadingCircle } from '@/components/ui/loading-circle';

import { useQueryInconsistencyInvalidator } from '@/hooks/useQueryInconsistencyInvalidator';

import TreeDetailsFilter from './TreeDetailsFilter';
import type { TreeDetailsTabRightElement } from './Tabs/TreeDetailsTab';
import TreeDetailsTab from './Tabs/TreeDetailsTab';
Expand Down Expand Up @@ -139,6 +146,49 @@ function TreeDetails(): JSX.Element {
status: summaryQueryStatus,
} = treeDetailsLazyLoaded.summary;

const treeRouterStatus = useRouterState({
select: s => s.location.state.treeStatusCount,
});

type TreeRouterStatus = typeof treeRouterStatus;

const comparedData: TreeRouterStatus = useMemo(() => {
if (!data) return {} satisfies TreeRouterStatus;

const { builds, tests, boots } = data.summary;

return {
buildsStatus: {
valid: builds.status.valid ?? 0,
invalid: builds.status.invalid ?? 0,
null: builds.status.null ?? 0,
},
testStatus: {
done: tests.status.DONE ?? 0,
fail: tests.status.FAIL ?? 0,
error: tests.status.ERROR ?? 0,
pass: tests.status.PASS ?? 0,
miss: tests.status.MISS ?? 0,
skip: tests.status.SKIP ?? 0,
null: tests.status.NULL ?? 0,
},
bootStatus: {
done: boots.status.DONE ?? 0,
error: boots.status.ERROR ?? 0,
fail: boots.status.FAIL ?? 0,
pass: boots.status.PASS ?? 0,
miss: boots.status.MISS ?? 0,
skip: boots.status.SKIP ?? 0,
null: boots.status.NULL ?? 0,
},
} satisfies TreeRouterStatus;
}, [data]);

useQueryInconsistencyInvalidator<TreeRouterStatus>({
referenceData: treeRouterStatus,
comparedData: comparedData,
navigate: navigate,
});
const onFilterChange = useCallback(
(newFilter: TFilter) => {
navigate({
Expand Down
55 changes: 54 additions & 1 deletion dashboard/src/pages/hardwareDetails/HardwareDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { useNavigate, useParams, useSearch } from '@tanstack/react-router';
import {
useNavigate,
useParams,
useRouterState,
useSearch,
} from '@tanstack/react-router';

import { FormattedMessage } from 'react-intl';

Expand Down Expand Up @@ -45,6 +50,8 @@ import { MemoizedSectionError } from '@/components/DetailsPages/SectionError';

import { useHardwareDetailsLazyLoadQuery } from '@/hooks/useHardwareDetailsLazyLoadQuery';

import { useQueryInconsistencyInvalidator } from '@/hooks/useQueryInconsistencyInvalidator';

import { HardwareHeader } from './HardwareDetailsHeaderTable';
import type { TreeDetailsTabRightElement } from './Tabs/HardwareDetailsTabs';
import HardwareDetailsTabs from './Tabs/HardwareDetailsTabs';
Expand Down Expand Up @@ -148,6 +155,52 @@ function HardwareDetails(): JSX.Element {
treeCommits: treeCommits,
});

const hardwareStatusHistoryState = useRouterState({
select: s => s.location.state.hardwareStatusCount,
});

type HardwareStatusComparedState = typeof hardwareStatusHistoryState;

const hardwareDataPreparedForInconsistencyValidation: HardwareStatusComparedState =
useMemo(() => {
const { data } = summaryResponse;
if (!data) return;

const { boots, builds, tests } = data;

return {
bootStatus: {
DONE: boots.status.DONE,
FAIL: boots.status.FAIL,
ERROR: boots.status.ERROR,
NULL: boots.status.NULL,
PASS: boots.status.PASS,
MISS: boots.status.MISS,
SKIP: boots.status.SKIP,
},
testStatus: {
DONE: tests.status.DONE,
FAIL: tests.status.FAIL,
ERROR: tests.status.ERROR,
NULL: tests.status.NULL,
PASS: tests.status.PASS,
MISS: tests.status.MISS,
SKIP: tests.status.SKIP,
},
buildsStatus: {
valid: builds.status.valid,
invalid: builds.status.invalid,
null: builds.status.null,
},
} satisfies HardwareStatusComparedState;
}, [summaryResponse]);

useQueryInconsistencyInvalidator<HardwareStatusComparedState>({
referenceData: hardwareStatusHistoryState,
comparedData: hardwareDataPreparedForInconsistencyValidation,
navigate: navigate,
});

const hardwareTableForCommitHistory = useMemo(() => {
const result: CommitHead[] = [];
if (!summaryResponse.isLoading && summaryResponse.data) {
Expand Down
4 changes: 2 additions & 2 deletions dashboard/src/types/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ export type BuildStatus = {
null: number;
};

export interface StatusCount {
export type StatusCount = {
PASS?: number;
FAIL?: number;
MISS?: number;
SKIP?: number;
ERROR?: number;
NULL?: number;
DONE?: number;
}
};

export type Architecture = Record<
string,
Expand Down
4 changes: 2 additions & 2 deletions dashboard/src/types/hardware.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { StatusCount } from './general';

interface BuildCount {
export type BuildCount = {
valid: number;
invalid: number;
null: number;
}
};

export interface HardwareItem {
hardware_name: string;
Expand Down
24 changes: 24 additions & 0 deletions dashboard/src/utils/records.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const isRecord = (obj: unknown): obj is Record<string, unknown> => {
return typeof obj === 'object' && !Array.isArray(obj);
};

export const deepCompare = (
obj1: Record<string, unknown>,
obj2: Record<string, unknown>,
): boolean => {
if (Object.keys(obj1).length !== Object.keys(obj2).length) {
return false;
}

for (const key in obj1) {
if (isRecord(obj1[key]) && isRecord(obj2[key])) {
if (!deepCompare(obj1[key], obj2[key])) {
return false;
}
} else if (obj1[key] !== obj2[key]) {
return false;
}
}

return true;
};

0 comments on commit 2a0a40c

Please sign in to comment.