Skip to content

Commit 0a66b9c

Browse files
feat: introduce hardware listing versioning and update routing (#1743)
* feat(hardware): introduce hardware listing versioning and update routing * feat(hardware): add /hardware/v2 route
1 parent 54eab00 commit 0a66b9c

16 files changed

Lines changed: 204 additions & 33 deletions

File tree

dashboard/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ VITE_API_BASE_URL=http://localhost:8000
55
# Feature Flags
66
VITE_FEATURE_FLAG_SHOW_DEV=false
77
VITE_FEATURE_FLAG_TREE_LISTING_VERSION=v1
8+
VITE_FEATURE_FLAG_HARDWARE_LISTING_VERSION=v1
89

910
PLAYWRIGHT_TEST_BASE_URL=https://staging.dashboard.kernelci.org:9000

dashboard/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,4 @@ Available feature flags:
7575

7676
- `VITE_FEATURE_FLAG_SHOW_DEV` - Controls visibility of dev-only features (boolean, default: `false`)
7777
- `VITE_FEATURE_FLAG_TREE_LISTING_VERSION` - Controls which tree listing version to display. Set to `"v1"` for the old version or `"v2"` for the new version (string, default: `"v1"`)
78+
- `VITE_FEATURE_FLAG_HARDWARE_LISTING_VERSION` - Controls which hardware listing version to display. Set to `"v1"` for the old version or `"v2"` for the new version (string, default: `"v1"`)

dashboard/src/api/hardware.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import type {
88
HardwareListingResponseV2,
99
} from '@/types/hardware';
1010

11+
import type { HardwareListingRoutesMap } from '@/utils/constants/hardwareListing';
12+
1113
import { RequestData } from './commonRequest';
1214

1315
const fetchHardwareListing = async (
@@ -32,8 +34,9 @@ const fetchHardwareListing = async (
3234
export const useHardwareListing = (
3335
startTimestampInSeconds: number,
3436
endTimestampInSeconds: number,
37+
searchFrom: HardwareListingRoutesMap['v1']['search'],
3538
): UseQueryResult<HardwareListingResponse> => {
36-
const { origin } = useSearch({ from: '/_main/hardware/v1' });
39+
const { origin } = useSearch({ from: searchFrom });
3740

3841
const queryKey = [
3942
'hardwareListing',
@@ -76,8 +79,9 @@ const fetchHardwareListingV2 = async (
7679
export const useHardwareListingV2 = (
7780
startTimestampInSeconds: number,
7881
endTimestampInSeconds: number,
82+
searchFrom: HardwareListingRoutesMap['v2']['search'],
7983
): UseQueryResult<HardwareListingResponseV2> => {
80-
const { origin } = useSearch({ from: '/_main/hardware' });
84+
const { origin } = useSearch({ from: searchFrom });
8185

8286
const queryKey = [
8387
'hardwareListingV2',
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
type FeatureFlags = {
22
showDev: boolean;
33
treeListingVersion: string;
4+
hardwareListingVersion: string;
45
};
56

67
export const useFeatureFlag = (): FeatureFlags => {
78
return {
89
showDev: import.meta.env.VITE_FEATURE_FLAG_SHOW_DEV ?? false,
910
treeListingVersion:
1011
import.meta.env.VITE_FEATURE_FLAG_TREE_LISTING_VERSION ?? 'v1',
12+
hardwareListingVersion:
13+
import.meta.env.VITE_FEATURE_FLAG_HARDWARE_LISTING_VERSION ?? 'v1',
1114
};
1215
};

dashboard/src/pages/Hardware/Hardware.tsx

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,24 @@ import HardwareListingPage from '@/pages/Hardware/HardwareListingPage';
1010
import DebounceInput from '@/components/DebounceInput/DebounceInput';
1111
import { MemoizedListingOGTags } from '@/components/OpenGraphTags/ListingOGTags';
1212
import { OldPageBanner } from '@/components/Banner/PageBanner';
13+
import { useFeatureFlag } from '@/hooks/useFeatureFlag';
14+
import type { HardwareListingRoutesMap } from '@/utils/constants/hardwareListing';
1315

14-
const Hardware = (): JSX.Element => {
16+
const Hardware = ({
17+
urlFromMap,
18+
}: {
19+
urlFromMap: HardwareListingRoutesMap['v1'];
20+
}): JSX.Element => {
21+
const { hardwareListingVersion } = useFeatureFlag();
1522
const { hardwareSearch } = useSearch({
16-
from: '/_main/hardware/v1',
23+
from: urlFromMap.search,
1724
});
1825

19-
const navigate = useNavigate({ from: '/hardware/v1' });
26+
const navigate = useNavigate({ from: urlFromMap.navigate });
2027

2128
const onInputSearchTextChange = useCallback(
2229
(e: ChangeEvent<HTMLInputElement>) => {
2330
navigate({
24-
from: '/hardware/v1',
2531
search: previousSearch => ({
2632
...previousSearch,
2733
hardwareSearch: e.target.value,
@@ -49,12 +55,17 @@ const Hardware = (): JSX.Element => {
4955
/>
5056
</div>
5157
</div>
52-
<OldPageBanner
53-
pageNameId="hardwareListing.bannerTitle"
54-
pageRoute="/hardware"
55-
/>
58+
{hardwareListingVersion !== 'v1' && (
59+
<OldPageBanner
60+
pageNameId="hardwareListing.bannerTitle"
61+
pageRoute="/hardware"
62+
/>
63+
)}
5664
<div className="bg-light-gray w-full py-10">
57-
<HardwareListingPage inputFilter={hardwareSearch ?? ''} />
65+
<HardwareListingPage
66+
inputFilter={hardwareSearch ?? ''}
67+
urlFromMap={urlFromMap}
68+
/>
5869
</div>
5970
</>
6071
);

dashboard/src/pages/Hardware/HardwareListingPage.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ import {
2020

2121
import { MemoizedKcidevFooter } from '@/components/Footer/KcidevFooter';
2222

23+
import type { HardwareListingRoutesMap } from '@/utils/constants/hardwareListing';
24+
2325
import { HardwareTable } from './HardwareTable';
2426

2527
interface HardwareListingPageProps {
2628
inputFilter: string;
29+
urlFromMap: HardwareListingRoutesMap['v1'];
2730
}
2831

2932
const calculateTimeStamp = (
@@ -43,11 +46,13 @@ const calculateTimeStamp = (
4346
return { startTimestampInSeconds, endTimestampInSeconds };
4447
};
4548

46-
const useHardwareListingTime = (): {
49+
const useHardwareListingTime = (
50+
searchFrom: HardwareListingPageProps['urlFromMap']['search'],
51+
): {
4752
startTimestampInSeconds: number;
4853
endTimestampInSeconds: number;
4954
} => {
50-
const { intervalInDays } = useSearch({ from: '/_main/hardware/v1' });
55+
const { intervalInDays } = useSearch({ from: searchFrom });
5156
const [timestamps, setTimeStamps] = useState(() => {
5257
return calculateTimeStamp(intervalInDays);
5358
});
@@ -63,14 +68,16 @@ const useHardwareListingTime = (): {
6368

6469
const HardwareListingPage = ({
6570
inputFilter,
71+
urlFromMap,
6672
}: HardwareListingPageProps): JSX.Element => {
6773
const { startTimestampInSeconds, endTimestampInSeconds } =
68-
useHardwareListingTime();
69-
const { origin } = useSearch({ from: '/_main/hardware/v1' });
74+
useHardwareListingTime(urlFromMap.search);
75+
const { origin } = useSearch({ from: urlFromMap.search });
7076

7177
const { data, error, status, isLoading } = useHardwareListing(
7278
startTimestampInSeconds,
7379
endTimestampInSeconds,
80+
urlFromMap.search,
7481
);
7582

7683
const listItems: HardwareItem[] = useMemo(() => {
@@ -151,7 +158,7 @@ const HardwareListingPage = ({
151158
queryData={data}
152159
error={error}
153160
isLoading={isLoading}
154-
navigateFrom="/hardware/v1"
161+
navigateFrom={urlFromMap.navigate}
155162
/>
156163
</div>
157164
{kcidevComponent}

dashboard/src/pages/Hardware/HardwareListingPageV2.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ import {
2020

2121
import { MemoizedKcidevFooter } from '@/components/Footer/KcidevFooter';
2222

23+
import type { HardwareListingRoutesMap } from '@/utils/constants/hardwareListing';
24+
2325
import { HardwareTable } from './HardwareTable';
2426

2527
interface HardwareListingPageV2Props {
2628
inputFilter: string;
29+
urlFromMap: HardwareListingRoutesMap['v2'];
2730
}
2831

2932
const calculateTimeStamp = (
@@ -43,11 +46,13 @@ const calculateTimeStamp = (
4346
return { startTimestampInSeconds, endTimestampInSeconds };
4447
};
4548

46-
const useHardwareListingTime = (): {
49+
const useHardwareListingTime = (
50+
searchFrom: HardwareListingPageV2Props['urlFromMap']['search'],
51+
): {
4752
startTimestampInSeconds: number;
4853
endTimestampInSeconds: number;
4954
} => {
50-
const { intervalInDays } = useSearch({ from: '/_main/hardware' });
55+
const { intervalInDays } = useSearch({ from: searchFrom });
5156
const [timestamps, setTimeStamps] = useState(() => {
5257
return calculateTimeStamp(intervalInDays);
5358
});
@@ -63,14 +68,16 @@ const useHardwareListingTime = (): {
6368

6469
const HardwareListingPageV2 = ({
6570
inputFilter,
71+
urlFromMap,
6672
}: HardwareListingPageV2Props): JSX.Element => {
6773
const { startTimestampInSeconds, endTimestampInSeconds } =
68-
useHardwareListingTime();
69-
const { origin } = useSearch({ from: '/_main/hardware' });
74+
useHardwareListingTime(urlFromMap.search);
75+
const { origin } = useSearch({ from: urlFromMap.search });
7076

7177
const { data, error, status, isLoading } = useHardwareListingV2(
7278
startTimestampInSeconds,
7379
endTimestampInSeconds,
80+
urlFromMap.search,
7481
);
7582

7683
const listItems: HardwareItem[] = useMemo(() => {
@@ -151,7 +158,7 @@ const HardwareListingPageV2 = ({
151158
queryData={data}
152159
error={error}
153160
isLoading={isLoading}
154-
navigateFrom="/hardware"
161+
navigateFrom={urlFromMap.navigate}
155162
/>
156163
</div>
157164
{kcidevComponent}

dashboard/src/pages/Hardware/HardwareTable.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ interface IHardwareTable {
6969
navigateFrom: HardwareListingRoutes;
7070
}
7171

72-
type HardwareListingRoutes = '/hardware' | '/hardware/v1';
72+
type HardwareListingRoutes = '/hardware' | '/hardware/v1' | '/hardware/v2';
7373

7474
const getLinkProps = (
7575
row: Row<HardwareItem>,

dashboard/src/pages/Hardware/HardwareV2.tsx

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,24 @@ import HardwareListingPageV2 from '@/pages/Hardware/HardwareListingPageV2';
1010
import DebounceInput from '@/components/DebounceInput/DebounceInput';
1111
import { MemoizedListingOGTags } from '@/components/OpenGraphTags/ListingOGTags';
1212
import { NewPageBanner } from '@/components/Banner/PageBanner';
13+
import { useFeatureFlag } from '@/hooks/useFeatureFlag';
14+
import type { HardwareListingRoutesMap } from '@/utils/constants/hardwareListing';
1315

14-
export const HardwareV2 = (): JSX.Element => {
16+
export const HardwareV2 = ({
17+
urlFromMap,
18+
}: {
19+
urlFromMap: HardwareListingRoutesMap['v2'];
20+
}): JSX.Element => {
21+
const { hardwareListingVersion } = useFeatureFlag();
1522
const { hardwareSearch } = useSearch({
16-
from: '/_main/hardware',
23+
from: urlFromMap.search,
1724
});
1825

19-
const navigate = useNavigate({ from: '/hardware' });
26+
const navigate = useNavigate({ from: urlFromMap.navigate });
2027

2128
const onInputSearchTextChange = useCallback(
2229
(e: ChangeEvent<HTMLInputElement>) => {
2330
navigate({
24-
from: '/hardware',
2531
search: previousSearch => ({
2632
...previousSearch,
2733
hardwareSearch: e.target.value,
@@ -50,12 +56,17 @@ export const HardwareV2 = (): JSX.Element => {
5056
/>
5157
</div>
5258
</div>
53-
<NewPageBanner
54-
pageNameId="hardwareListing.bannerTitle"
55-
pageRoute="/hardware/v1"
56-
/>
59+
{hardwareListingVersion !== 'v2' && (
60+
<NewPageBanner
61+
pageNameId="hardwareListing.bannerTitle"
62+
pageRoute="/hardware/v1"
63+
/>
64+
)}
5765
<div className="bg-light-gray w-full py-10">
58-
<HardwareListingPageV2 inputFilter={hardwareSearch ?? ''} />
66+
<HardwareListingPageV2
67+
inputFilter={hardwareSearch ?? ''}
68+
urlFromMap={urlFromMap}
69+
/>
5970
</div>
6071
</>
6172
);

0 commit comments

Comments
 (0)