diff --git a/frontend/.storybook/preview.tsx b/frontend/.storybook/preview.tsx index 058b0448374..94674037bb9 100644 --- a/frontend/.storybook/preview.tsx +++ b/frontend/.storybook/preview.tsx @@ -2,6 +2,7 @@ import React from 'react'; import themesConf from '../src/lib/themes'; import { ThemeProvider, StyledEngineProvider } from '@mui/material/styles'; import { initialize, mswDecorator } from 'msw-storybook-addon'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { rest } from 'msw'; // https://github.com/mswjs/msw-storybook-addon @@ -10,16 +11,27 @@ initialize(); const darkTheme = themesConf['dark']; const lightTheme = themesConf['light']; +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 3 * 60_000, + refetchOnWindowFocus: false, + }, + }, +}); + const withThemeProvider = (Story, context) => { const backgroundColor = context.globals.backgrounds ? context.globals.backgrounds.value : 'light'; const theme = backgroundColor !== 'dark' ? lightTheme : darkTheme; const ourThemeProvider = ( - - - - - + + + + + + + ); return ourThemeProvider; }; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 2c6477337b9..42a8001ec57 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -22,6 +22,8 @@ "@mui/system": "^5.15.14", "@mui/x-tree-view": "^6.17.0", "@reduxjs/toolkit": "^1.9.3", + "@tanstack/react-query": "^4.36.1", + "@tanstack/react-query-devtools": "^4.36.1", "@testing-library/react": "^12.1.2", "@types/glob": "^8.1.0", "@types/humanize-duration": "^3.27.1", @@ -9367,6 +9369,63 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tanstack/query-core": { + "version": "4.36.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.36.1.tgz", + "integrity": "sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "4.36.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.36.1.tgz", + "integrity": "sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "4.36.1", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-native": "*" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "4.36.1", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.36.1.tgz", + "integrity": "sha512-WYku83CKP3OevnYSG8Y/QO9g0rT75v1om5IvcWUwiUZJ4LanYGLVCZ8TdFG5jfsq4Ej/lu2wwDAULEUnRIMBSw==", + "license": "MIT", + "dependencies": { + "@tanstack/match-sorter-utils": "^8.7.0", + "superjson": "^1.10.0", + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^4.36.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@tanstack/react-table": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.16.0.tgz", @@ -12806,6 +12865,21 @@ "dev": true, "license": "MIT" }, + "node_modules/copy-anything": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", + "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", + "license": "MIT", + "dependencies": { + "is-what": "^4.1.8" + }, + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/core-js": { "version": "3.37.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.1.tgz", @@ -18285,6 +18359,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", @@ -25531,6 +25617,18 @@ "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", "license": "MIT" }, + "node_modules/superjson": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-1.13.3.tgz", + "integrity": "sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==", + "license": "MIT", + "dependencies": { + "copy-anything": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -26909,6 +27007,15 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util": { "version": "0.12.5", "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", diff --git a/frontend/package.json b/frontend/package.json index 35ce4809922..ce86ac827c1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,6 +23,8 @@ "@mui/system": "^5.15.14", "@mui/x-tree-view": "^6.17.0", "@reduxjs/toolkit": "^1.9.3", + "@tanstack/react-query": "^4.36.1", + "@tanstack/react-query-devtools": "^4.36.1", "@testing-library/react": "^12.1.2", "@types/glob": "^8.1.0", "@types/humanize-duration": "^3.27.1", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 1482dbf49d1..8b5c688efe5 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,5 +1,7 @@ import './i18n/config'; import './components/App/icons'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import React from 'react'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; @@ -29,13 +31,27 @@ function AppWithRedux(props: React.PropsWithChildren<{}>) { ); } +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 3 * 60_000, + refetchOnWindowFocus: false, + }, + }, +}); +const queryDevtoolsEnabled = false; + function App() { return ( }> - - - + + {queryDevtoolsEnabled && } + + + + + ); diff --git a/frontend/src/components/Sidebar/VersionButton.tsx b/frontend/src/components/Sidebar/VersionButton.tsx index f9fe8126d78..746dacfa760 100644 --- a/frontend/src/components/Sidebar/VersionButton.tsx +++ b/frontend/src/components/Sidebar/VersionButton.tsx @@ -6,6 +6,7 @@ import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; import DialogTitle from '@mui/material/DialogTitle'; import { styled, useTheme } from '@mui/system'; +import { useQuery } from '@tanstack/react-query'; import { useSnackbar } from 'notistack'; import React from 'react'; import { useTranslation } from 'react-i18next'; @@ -27,7 +28,6 @@ const VersionIcon = styled(Icon)({ export default function VersionButton() { const isSidebarOpen = useTypedSelector(state => state.sidebar.isSidebarOpen); const { enqueueSnackbar } = useSnackbar(); - const [clusterVersion, setClusterVersion] = React.useState(null); const cluster = useCluster(); const theme = useTheme(); const [open, setOpen] = React.useState(false); @@ -62,68 +62,43 @@ export default function VersionButton() { ]; } - React.useEffect( - () => { - let stillAlive = true; - function fetchVersion() { - getVersion() - .then((results: StringDict) => { - if (!stillAlive) { - return; - } - - setClusterVersion(results); - let versionChange = 0; - if (clusterVersion && results && results.gitVersion) { - versionChange = semver.compare(results.gitVersion, clusterVersion.gitVersion); + const { data: clusterVersion } = useQuery({ + placeholderData: null, + queryKey: ['version', cluster ?? ''], + queryFn: () => { + return getVersion() + .then((results: StringDict) => { + let versionChange = 0; + if (clusterVersion && results && results.gitVersion) { + versionChange = semver.compare(results.gitVersion, clusterVersion.gitVersion); - let msg = ''; - if (versionChange > 0) { - msg = t('translation|Cluster version upgraded to {{ gitVersion }}', { - gitVersion: results.gitVersion, - }); - } else if (versionChange < 0) { - msg = t('translation|Cluster version downgraded to {{ gitVersion }}', { - gitVersion: results.gitVersion, - }); - } - - if (msg) { - enqueueSnackbar(msg, { - key: 'version', - preventDuplicate: true, - autoHideDuration: versionSnackbarHideTimeout, - variant: 'info', - }); - } + let msg = ''; + if (versionChange > 0) { + msg = t('translation|Cluster version upgraded to {{ gitVersion }}', { + gitVersion: results.gitVersion, + }); + } else if (versionChange < 0) { + msg = t('translation|Cluster version downgraded to {{ gitVersion }}', { + gitVersion: results.gitVersion, + }); } - }) - .catch((error: Error) => console.error('Getting the cluster version:', error)); - } - - if (!clusterVersion) { - fetchVersion(); - } - const intervalHandler = setInterval(() => { - fetchVersion(); - }, versionFetchInterval); + if (msg) { + enqueueSnackbar(msg, { + key: 'version', + preventDuplicate: true, + autoHideDuration: versionSnackbarHideTimeout, + variant: 'info', + }); + } + } - return function cleanup() { - stillAlive = false; - clearInterval(intervalHandler); - }; + return results; + }) + .catch((error: Error) => console.error('Getting the cluster version:', error)); }, - // eslint-disable-next-line - [clusterVersion] - ); - - // Use the location to make sure the version is changed, as it depends on the cluster - // (defined in the URL ATM). - // @todo: Update this if the active cluster management is changed. - React.useEffect(() => { - setClusterVersion(null); - }, [cluster]); + refetchInterval: versionFetchInterval, + }); function handleClose() { setOpen(false); diff --git a/frontend/src/components/cluster/Overview.stories.tsx b/frontend/src/components/cluster/Overview.stories.tsx index b62d6265ece..65a1a42b2cf 100644 --- a/frontend/src/components/cluster/Overview.stories.tsx +++ b/frontend/src/components/cluster/Overview.stories.tsx @@ -1,11 +1,12 @@ import Container from '@mui/material/Container'; import { Meta, StoryFn } from '@storybook/react'; +import { useMockListQuery } from '../../helpers/testHelpers'; import Event from '../../lib/k8s/event'; import { TestContext } from '../../test'; import Overview from './Overview'; -Event.useList = () => { - const objList = [ +Event.useListQuery = useMockListQuery.data( + [ { apiVersion: 'v1', count: 1, @@ -130,9 +131,8 @@ Event.useList = () => { reportingComponent: '', reportingInstance: '', }, - ].map((data: any) => new Event(data)); - return [objList, null, () => {}, () => {}] as any; -}; + ].map((data: any) => new Event(data)) +); export default { title: 'cluster/Overview', diff --git a/frontend/src/components/cluster/Overview.tsx b/frontend/src/components/cluster/Overview.tsx index 33325725f59..eec8416939f 100644 --- a/frontend/src/components/cluster/Overview.tsx +++ b/frontend/src/components/cluster/Overview.tsx @@ -23,8 +23,8 @@ import { export default function Overview() { const { t } = useTranslation(['translation']); - const [pods] = Pod.useList(); - const [nodes] = Node.useList(); + const { items: pods } = Pod.useListQuery(); + const { items: nodes } = Node.useListQuery(); const [nodeMetrics, metricsError] = Node.useMetrics(); @@ -74,7 +74,9 @@ function EventsSection() { ) ) ); - const [events, eventsError] = Event.useList({ limit: Event.maxLimit }); + const { items: events, error: eventsError } = Event.useListQuery({ + queryParams: { limit: Event.maxLimit }, + }); const warningActionFilterFunc = (event: Event, search?: string) => { if (!filterFunc(event, search)) { @@ -138,7 +140,7 @@ function EventsSection() { }} defaultGlobalFilter={eventsFilter ?? undefined} data={events} - errorMessage={Event.getErrorMessage(eventsError)} + errorMessage={Event.getErrorMessage(eventsError as any)} columns={[ { label: t('Type'), diff --git a/frontend/src/components/cluster/__snapshots__/Overview.Events.stories.storyshot b/frontend/src/components/cluster/__snapshots__/Overview.Events.stories.storyshot index 6180ccaf9e5..17d00a20f90 100644 --- a/frontend/src/components/cluster/__snapshots__/Overview.Events.stories.storyshot +++ b/frontend/src/components/cluster/__snapshots__/Overview.Events.stories.storyshot @@ -58,87 +58,21 @@

- CPU Usage + CPU

+

- 0.00 / 36 units + 36 units

-
-
- - - - - - - - - - - - - - - - 0.0 % - - - - -
-
-
+ /> @@ -160,87 +94,21 @@

- Memory Usage + Memory

+

- 0.00 / 143.63 GB + 143.63 GB

-
-
- - - - - - - - - - - - - - - - 0.0 % - - - - -
-
-
+ /> @@ -311,21 +179,55 @@ tabindex="0" > - - - + + + - - - + + diff --git a/frontend/src/components/daemonset/List.stories.tsx b/frontend/src/components/daemonset/List.stories.tsx index 720fd406e62..58e6943293d 100644 --- a/frontend/src/components/daemonset/List.stories.tsx +++ b/frontend/src/components/daemonset/List.stories.tsx @@ -1,11 +1,12 @@ import Container from '@mui/material/Container'; import { Meta, Story } from '@storybook/react'; +import { useMockListQuery } from '../../helpers/testHelpers'; import DaemonSet from '../../lib/k8s/daemonSet'; import { TestContext } from '../../test'; import List from './List'; -DaemonSet.useList = () => { - const objList = [ +DaemonSet.useListQuery = useMockListQuery.data( + [ { apiVersion: 'apps/v1', kind: 'DaemonSet', @@ -280,9 +281,8 @@ DaemonSet.useList = () => { updatedNumberScheduled: 2, }, }, - ].map((data: any) => new DaemonSet(data)); - return [objList, null, () => {}, () => {}] as any; -}; + ].map((data: any) => new DaemonSet(data)) +); export default { title: 'DaemonSet/List', diff --git a/frontend/src/components/endpoints/EndpointDetails.stories.tsx b/frontend/src/components/endpoints/EndpointDetails.stories.tsx index 67f99d429f3..a5bca66c1be 100644 --- a/frontend/src/components/endpoints/EndpointDetails.stories.tsx +++ b/frontend/src/components/endpoints/EndpointDetails.stories.tsx @@ -1,12 +1,13 @@ import { Meta, Story } from '@storybook/react'; +import { useMockQuery } from '../../helpers/testHelpers'; import { KubeObjectClass } from '../../lib/k8s/cluster'; import Endpoints, { KubeEndpoint } from '../../lib/k8s/endpoints'; import { TestContext } from '../../test'; import EndpointDetails from './Details'; -const usePhonyGet: KubeObjectClass['useGet'] = (name, namespace) => { - return [ - new Endpoints({ +const usePhonyQuery: KubeObjectClass['useQuery'] = ({ name, namespace }: any): any => { + return { + data: new Endpoints({ kind: 'Endpoints', apiVersion: 'v1', metadata: { @@ -55,10 +56,8 @@ const usePhonyGet: KubeObjectClass['useGet'] = (name, namespace) => { }, ], } as KubeEndpoint), - null, - () => {}, - () => {}, - ] as any; + error: null, + }; }; export default { @@ -77,16 +76,12 @@ export default { } as Meta; interface MockerStory { - useGet?: KubeObjectClass['useGet']; - useList?: KubeObjectClass['useList']; + usePhonyQuery?: KubeObjectClass['usePhonyQuery']; } const Template: Story = (args: MockerStory) => { - if (!!args.useGet) { - Endpoints.useGet = args.useGet; - } - if (!!args.useList) { - Endpoints.useList = args.useList; + if (!!args.usePhonyQuery) { + Endpoints.useQuery = args.usePhonyQuery; } return ( @@ -98,15 +93,15 @@ const Template: Story = (args: MockerStory) => { export const Default = Template.bind({}); Default.args = { - useGet: usePhonyGet, + usePhonyQuery: usePhonyQuery, }; export const NoItemYet = Template.bind({}); NoItemYet.args = { - useGet: () => [null, null, () => {}, () => {}] as any, + usePhonyQuery: useMockQuery.noData, }; export const Error = Template.bind({}); Error.args = { - useGet: () => [null, 'Phony error is phony!', () => {}, () => {}] as any, + usePhonyQuery: useMockQuery.error, }; diff --git a/frontend/src/components/endpoints/EndpointList.stories.tsx b/frontend/src/components/endpoints/EndpointList.stories.tsx index e85d606775c..4c7094176e6 100644 --- a/frontend/src/components/endpoints/EndpointList.stories.tsx +++ b/frontend/src/components/endpoints/EndpointList.stories.tsx @@ -1,11 +1,12 @@ import { Meta, Story } from '@storybook/react'; +import { useMockListQuery } from '../../helpers/testHelpers'; import Endpoints, { KubeEndpoint } from '../../lib/k8s/endpoints'; import { TestContext } from '../../test'; import { generateK8sResourceList } from '../../test/mocker'; import EndpointList from './List'; -Endpoints.useList = () => { - const objList = generateK8sResourceList( +Endpoints.useListQuery = useMockListQuery.data( + generateK8sResourceList( { kind: 'Endpoints', apiVersion: 'v1', @@ -39,10 +40,8 @@ Endpoints.useList = () => { ], }, { instantiateAs: Endpoints } - ); - - return [objList, null, () => {}, () => {}] as any; -}; + ) +); export default { title: 'endpoints/EndpointsListView', diff --git a/frontend/src/components/horizontalPodAutoscaler/HPADetails.stories.tsx b/frontend/src/components/horizontalPodAutoscaler/HPADetails.stories.tsx index ae42e4ecd85..23d9ac647af 100644 --- a/frontend/src/components/horizontalPodAutoscaler/HPADetails.stories.tsx +++ b/frontend/src/components/horizontalPodAutoscaler/HPADetails.stories.tsx @@ -6,9 +6,13 @@ import HPA, { KubeHPA } from '../../lib/k8s/hpa'; import { TestContext } from '../../test'; import HPADetails from './Details'; -const usePhonyGet: KubeObjectClass['useGet'] = () => { - return [ - new HPA({ +HPA.getAuthorization = () => { + return { status: { allowed: true, reason: '', code: 200 } }; +}; + +const usePhonyQuery: KubeObjectClass['useQuery'] = (): any => { + return { + data: new HPA({ apiVersion: 'autoscaling/v2', kind: 'HorizontalPodAutoscaler', metadata: { @@ -105,7 +109,8 @@ const usePhonyGet: KubeObjectClass['useGet'] = () => { lastScaleTime: '2022-10-21T11:15:12Z', }, } as KubeHPA), - ] as any; + error: null, + }; }; export default { @@ -124,36 +129,32 @@ export default { } as Meta; interface MockerStory { - useGet?: KubeObjectClass['useGet']; - useList?: KubeObjectClass['useList']; + usePhonyQuery?: KubeObjectClass['usePhonyQuery']; } const Template: Story = (args: MockerStory) => { - if (!!args.useGet) { - HPA.useGet = args.useGet; + if (!!args.usePhonyQuery) { + HPA.useQuery = args.usePhonyQuery; Event.objectEvents = async (obj: KubeObject) => { console.log('object:', obj); return []; }; } - if (!!args.useList) { - HPA.useList = args.useList; - } return ; }; export const Default = Template.bind({}); Default.args = { - useGet: usePhonyGet, + usePhonyQuery: usePhonyQuery, }; export const NoItemYet = Template.bind({}); NoItemYet.args = { - useGet: () => [null, null, () => {}, () => {}] as any, + usePhonyQuery: () => ({ data: null, error: null } as any), }; export const Error = Template.bind({}); Error.args = { - useGet: () => [null, 'Phony error is phony!', () => {}, () => {}] as any, + usePhonyQuery: () => ({ data: null, error: 'Phony error is phony!' } as any), }; diff --git a/frontend/src/components/horizontalPodAutoscaler/HPAList.stories.tsx b/frontend/src/components/horizontalPodAutoscaler/HPAList.stories.tsx index 8ac233be68d..21682eda5c1 100644 --- a/frontend/src/components/horizontalPodAutoscaler/HPAList.stories.tsx +++ b/frontend/src/components/horizontalPodAutoscaler/HPAList.stories.tsx @@ -1,17 +1,16 @@ import { Meta, Story } from '@storybook/react'; +import { useMockListQuery } from '../../helpers/testHelpers'; import HPA, { KubeHPA } from '../../lib/k8s/hpa'; import { TestContext } from '../../test'; import { generateK8sResourceList } from '../../test/mocker'; import HpaList from './List'; -HPA.getAuthorization = (): Promise<{ status: any }> => { - return new Promise(resolve => { - resolve({ status: { allowed: true, reason: '', code: 200 } }); - }); +HPA.getAuthorization = () => { + return { status: { allowed: true, reason: '', code: 200 } }; }; -HPA.useList = () => { - const objList = generateK8sResourceList( +HPA.useListQuery = useMockListQuery.data( + generateK8sResourceList( { apiVersion: 'autoscaling/v2', kind: 'HorizontalPodAutoscaler', @@ -109,9 +108,8 @@ HPA.useList = () => { }, }, { instantiateAs: HPA } - ); - return [objList, null, () => {}, () => {}] as any; -}; + ) +); export default { title: 'hpa/HpaListView', diff --git a/frontend/src/components/ingress/ClassDetails.stories.tsx b/frontend/src/components/ingress/ClassDetails.stories.tsx index 142a534bbe7..c88a95801aa 100644 --- a/frontend/src/components/ingress/ClassDetails.stories.tsx +++ b/frontend/src/components/ingress/ClassDetails.stories.tsx @@ -26,7 +26,7 @@ interface MockerStory { const Template: Story = (args: MockerStory) => { const { ingressJson } = args; if (!!ingressJson) { - IngressClass.useGet = () => [new IngressClass(ingressJson), null, () => {}, () => {}] as any; + IngressClass.useQuery = () => ({ data: new IngressClass(ingressJson), error: null } as any); } return
; }; diff --git a/frontend/src/components/ingress/ClassList.stories.tsx b/frontend/src/components/ingress/ClassList.stories.tsx index 28e963f3e5f..d2897949c9c 100644 --- a/frontend/src/components/ingress/ClassList.stories.tsx +++ b/frontend/src/components/ingress/ClassList.stories.tsx @@ -1,17 +1,16 @@ import { Meta, Story } from '@storybook/react'; +import { useMockListQuery } from '../../helpers/testHelpers'; import { KubeObject } from '../../lib/k8s/cluster'; import IngressClass from '../../lib/k8s/ingressClass'; import { TestContext } from '../../test'; import ListView from './ClassList'; import { RESOURCE_DEFAULT_INGRESS_CLASS, RESOURCE_INGRESS_CLASS } from './storyHelper'; -IngressClass.useList = () => { - const objList = [RESOURCE_INGRESS_CLASS, RESOURCE_DEFAULT_INGRESS_CLASS].map( +IngressClass.useListQuery = useMockListQuery.data( + [RESOURCE_INGRESS_CLASS, RESOURCE_DEFAULT_INGRESS_CLASS].map( (data: KubeObject) => new IngressClass(data) - ); - - return [objList, null, () => {}, () => {}] as any; -}; + ) +); export default { title: 'IngressClass/ListView', diff --git a/frontend/src/components/ingress/Details.stories.tsx b/frontend/src/components/ingress/Details.stories.tsx index bb85776a309..432474585b0 100644 --- a/frontend/src/components/ingress/Details.stories.tsx +++ b/frontend/src/components/ingress/Details.stories.tsx @@ -26,7 +26,7 @@ interface MockerStory { const Template: Story = (args: MockerStory) => { const { ingressJson } = args; if (!!ingressJson) { - Ingress.useGet = () => [new Ingress(ingressJson), null, () => {}, () => {}] as any; + Ingress.useQuery = () => ({ data: new Ingress(ingressJson), error: null } as any); } return
; }; diff --git a/frontend/src/components/ingress/List.stories.tsx b/frontend/src/components/ingress/List.stories.tsx index 0d0e13bbf4c..3742fafe443 100644 --- a/frontend/src/components/ingress/List.stories.tsx +++ b/frontend/src/components/ingress/List.stories.tsx @@ -1,15 +1,14 @@ import { Meta, Story } from '@storybook/react'; +import { useMockListQuery } from '../../helpers/testHelpers'; import { KubeObject } from '../../lib/k8s/cluster'; import Ingress from '../../lib/k8s/ingress'; import { TestContext } from '../../test'; import ListView from './List'; import { PORT_INGRESS, RESOURCE_INGRESS } from './storyHelper'; -Ingress.useList = () => { - const objList = [PORT_INGRESS, RESOURCE_INGRESS].map((data: KubeObject) => new Ingress(data)); - - return [objList, null, () => {}, () => {}] as any; -}; +Ingress.useListQuery = useMockListQuery.data( + [PORT_INGRESS, RESOURCE_INGRESS].map((data: KubeObject) => new Ingress(data)) +); export default { title: 'Ingress/ListView', diff --git a/frontend/src/components/job/JobList.stories.tsx b/frontend/src/components/job/JobList.stories.tsx index 7f39fcad381..09e0dd9c126 100644 --- a/frontend/src/components/job/JobList.stories.tsx +++ b/frontend/src/components/job/JobList.stories.tsx @@ -1,44 +1,41 @@ import { Meta, Story } from '@storybook/react'; +import { useMockListQuery } from '../../helpers/testHelpers'; import Job from '../../lib/k8s/job'; import { TestContext } from '../../test'; import { generateK8sResourceList } from '../../test/mocker'; import List from './List'; import { jobs } from './storyHelper'; -Job.useList = () => { - const jobList = generateK8sResourceList(jobs[0], { numResults: 3 }); - - const failedJob = jobList[1]; - failedJob.status = { - ...failedJob.status, - conditions: [ - { - type: 'Failed', - status: 'True', - lastProbeTime: '2023-07-28T08:01:00Z', - lastTransitionTime: '2023-07-28T08:01:00Z', - }, - ], - }; - - const suspendedJob = jobList[2]; - suspendedJob.status = { - ...suspendedJob.status, - conditions: [ - { - type: 'Suspended', - status: 'True', - lastProbeTime: '2023-07-28T08:01:00Z', - lastTransitionTime: '2023-07-28T08:01:00Z', - }, - ], - }; - - const objList = jobList.map(data => new Job(data)); +const jobList = generateK8sResourceList(jobs[0], { numResults: 3 }); +const failedJob = jobList[1]; +failedJob.status = { + ...failedJob.status, + conditions: [ + { + type: 'Failed', + status: 'True', + lastProbeTime: '2023-07-28T08:01:00Z', + lastTransitionTime: '2023-07-28T08:01:00Z', + }, + ], +}; - return [objList, null, () => {}, () => {}] as any; +const suspendedJob = jobList[2]; +suspendedJob.status = { + ...suspendedJob.status, + conditions: [ + { + type: 'Suspended', + status: 'True', + lastProbeTime: '2023-07-28T08:01:00Z', + lastTransitionTime: '2023-07-28T08:01:00Z', + }, + ], }; +const objList = jobList.map(data => new Job(data)); +Job.useListQuery = useMockListQuery.data(objList); + export default { title: 'Job/List', component: List, diff --git a/frontend/src/components/job/List.tsx b/frontend/src/components/job/List.tsx index a3fd0026edd..34c6532e3fe 100644 --- a/frontend/src/components/job/List.tsx +++ b/frontend/src/components/job/List.tsx @@ -56,7 +56,7 @@ export function makePodStatusLabel(job: Job) { } export default function JobsList() { - const [jobs, error] = Job.useList(); + const { items: jobs, error } = Job.useListQuery(); return ; } diff --git a/frontend/src/components/lease/Details.stories.tsx b/frontend/src/components/lease/Details.stories.tsx index 27cee54405e..68fc092488c 100644 --- a/frontend/src/components/lease/Details.stories.tsx +++ b/frontend/src/components/lease/Details.stories.tsx @@ -4,7 +4,7 @@ import { TestContext } from '../../test'; import { LeaseDetails } from './Details'; import { LEASE_DUMMY_DATA } from './storyHelper'; -Lease.useGet = () => [new Lease(LEASE_DUMMY_DATA[0]), null, () => {}, () => {}] as any; +Lease.useQuery = () => ({ data: new Lease(LEASE_DUMMY_DATA[0]), error: null } as any); export default { title: 'Lease/LeaseDetailsView', diff --git a/frontend/src/components/lease/List.stories.tsx b/frontend/src/components/lease/List.stories.tsx index f2c4d9a5e9e..3b36ce920bb 100644 --- a/frontend/src/components/lease/List.stories.tsx +++ b/frontend/src/components/lease/List.stories.tsx @@ -1,15 +1,14 @@ import { Meta, StoryFn } from '@storybook/react'; +import { useMockListQuery } from '../../helpers/testHelpers'; import { KubeObject } from '../../lib/k8s/cluster'; import { Lease } from '../../lib/k8s/lease'; import { TestContext } from '../../test'; import { LeaseList } from './List'; import { LEASE_DUMMY_DATA } from './storyHelper'; -Lease.useList = () => { - const objList = LEASE_DUMMY_DATA.map((data: KubeObject) => new Lease(data)); - - return [objList, null, () => {}, () => {}] as any; -}; +Lease.useListQuery = useMockListQuery.data( + LEASE_DUMMY_DATA.map((data: KubeObject) => new Lease(data)) +); export default { title: 'Lease/ListView', diff --git a/frontend/src/components/limitRange/Details.stories.tsx b/frontend/src/components/limitRange/Details.stories.tsx index fec02437312..fd34bf65e0a 100644 --- a/frontend/src/components/limitRange/Details.stories.tsx +++ b/frontend/src/components/limitRange/Details.stories.tsx @@ -1,11 +1,11 @@ import { Meta, Story } from '@storybook/react'; +import { useMockQuery } from '../../helpers/testHelpers'; import { LimitRange } from '../../lib/k8s/limitRange'; import { TestContext } from '../../test'; import { LimitRangeDetails } from './Details'; import { LIMIT_RANGE_DUMMY_DATA } from './storyHelper'; -LimitRange.useGet = () => - [new LimitRange(LIMIT_RANGE_DUMMY_DATA[0]), null, () => {}, () => {}] as any; +LimitRange.useQuery = useMockQuery.data(new LimitRange(LIMIT_RANGE_DUMMY_DATA[0])); export default { title: 'LimitRange/DetailsView', diff --git a/frontend/src/components/limitRange/List.stories.tsx b/frontend/src/components/limitRange/List.stories.tsx index fbad7388b25..90643768f15 100644 --- a/frontend/src/components/limitRange/List.stories.tsx +++ b/frontend/src/components/limitRange/List.stories.tsx @@ -1,15 +1,14 @@ import { Meta, Story } from '@storybook/react'; +import { useMockListQuery } from '../../helpers/testHelpers'; import { KubeObject } from '../../lib/k8s/cluster'; import { LimitRange } from '../../lib/k8s/limitRange'; import { TestContext } from '../../test'; import { LimitRangeList } from './List'; import { LIMIT_RANGE_DUMMY_DATA } from './storyHelper'; -LimitRange.useList = () => { - const objList = LIMIT_RANGE_DUMMY_DATA.map((data: KubeObject) => new LimitRange(data)); - - return [objList, null, () => {}, () => {}] as any; -}; +LimitRange.useListQuery = useMockListQuery.data( + LIMIT_RANGE_DUMMY_DATA.map((data: KubeObject) => new LimitRange(data)) +); export default { title: 'LimitRange/ListView', diff --git a/frontend/src/components/limitRange/List.tsx b/frontend/src/components/limitRange/List.tsx index 894ec6fe4d6..9a4300743bd 100644 --- a/frontend/src/components/limitRange/List.tsx +++ b/frontend/src/components/limitRange/List.tsx @@ -39,7 +39,7 @@ export function LimitRangeRenderer(props: LimitRangeProps) { } export function LimitRangeList() { - const [limitRanges, error] = LimitRange.useList(); + const { items: limitRanges, error } = LimitRange.useListQuery(); return ; } diff --git a/frontend/src/components/namespace/Details.tsx b/frontend/src/components/namespace/Details.tsx index e4460de9d9e..cc2e4d22851 100644 --- a/frontend/src/components/namespace/Details.tsx +++ b/frontend/src/components/namespace/Details.tsx @@ -68,7 +68,7 @@ export interface NamespacedLimitRangesSectionProps { export function NamespacedLimitRangesSection(props: NamespacedLimitRangesSectionProps) { const { resource } = props; - const [limitRanges, error] = LimitRange.useList({ + const { items: limitRanges, error } = LimitRange.useListQuery({ namespace: resource.metadata.name, }); @@ -89,14 +89,14 @@ export interface NamespacedResourceQuotasSectionProps { export function NamespacedResourceQuotasSection(props: NamespacedResourceQuotasSectionProps) { const { resource } = props; - const [resourceQuotas, error] = ResourceQuota.useList({ + const { items: resourceQuotasList, error } = ResourceQuota.useListQuery({ namespace: resource.metadata.name, }); return ( diff --git a/frontend/src/components/namespace/NamespaceDetails.stories.tsx b/frontend/src/components/namespace/NamespaceDetails.stories.tsx index fdfe402c83e..aaaa11335ac 100644 --- a/frontend/src/components/namespace/NamespaceDetails.stories.tsx +++ b/frontend/src/components/namespace/NamespaceDetails.stories.tsx @@ -20,8 +20,8 @@ const createObj = (name: string) => }, } as KubeNamespace); -Namespace.useGet = name => { - return [new Namespace(createObj(name)), null, () => {}, () => {}] as any; +Namespace.useQuery = ({ name }: any) => { + return { data: new Namespace(createObj(name)), error: null } as any; }; export default { diff --git a/frontend/src/components/namespace/NamespaceList.stories.tsx b/frontend/src/components/namespace/NamespaceList.stories.tsx index 93cda719134..918a96c0731 100644 --- a/frontend/src/components/namespace/NamespaceList.stories.tsx +++ b/frontend/src/components/namespace/NamespaceList.stories.tsx @@ -4,7 +4,7 @@ import { TestContext } from '../../test'; import { generateK8sResourceList } from '../../test/mocker'; import NamespacesList from './List'; -Namespace.useList = () => { +Namespace.useListQuery = () => { const objList = generateK8sResourceList( { kind: 'Namespace', @@ -19,7 +19,7 @@ Namespace.useList = () => { }, { instantiateAs: Namespace } ); - return [objList, null, () => {}, () => {}] as any; + return { items: objList, error: null } as any; }; export default { diff --git a/frontend/src/components/node/Details.tsx b/frontend/src/components/node/Details.tsx index 053110f9ec5..950a0791528 100644 --- a/frontend/src/components/node/Details.tsx +++ b/frontend/src/components/node/Details.tsx @@ -43,7 +43,7 @@ export default function NodeDetails() { const [nodeMetrics, metricsError] = Node.useMetrics(); const [isupdatingNodeScheduleProperty, setisUpdatingNodeScheduleProperty] = React.useState(false); const [isNodeDrainInProgress, setisNodeDrainInProgress] = React.useState(false); - const [nodeFromAPI, nodeError] = Node.useGet(name); + const { data: nodeFromAPI, error: nodeError } = Node.useQuery({ name }); const [node, setNode] = useState(nodeFromAPI); const noMetrics = metricsError?.status === 404; const [drainDialogOpen, setDrainDialogOpen] = useState(false); diff --git a/frontend/src/components/node/List.stories.tsx b/frontend/src/components/node/List.stories.tsx index 9963a73524d..b5cfe94ddcb 100644 --- a/frontend/src/components/node/List.stories.tsx +++ b/frontend/src/components/node/List.stories.tsx @@ -4,7 +4,7 @@ import Node from '../../lib/k8s/node'; import { TestContext } from '../../test'; import List from './List'; -Node.useList = () => { +Node.useListQuery = () => { const objList = [ { apiVersion: 'v1', @@ -144,7 +144,7 @@ Node.useList = () => { }, }, ].map((data: any) => new Node(data)); - return [objList, null, () => {}, () => {}] as any; + return { items: objList, error: null } as any; }; export default { diff --git a/frontend/src/components/node/__snapshots__/List.Nodes.stories.storyshot b/frontend/src/components/node/__snapshots__/List.Nodes.stories.storyshot index 6a4033c0399..25ba5aac10e 100644 --- a/frontend/src/components/node/__snapshots__/List.Nodes.stories.storyshot +++ b/frontend/src/components/node/__snapshots__/List.Nodes.stories.storyshot @@ -45,7 +45,7 @@ class="MuiCollapse-wrapperInner MuiCollapse-vertical css-9l5vo-MuiCollapse-wrapperInner" >