From c9371d085d40211a613384bfff06cdbe624466ea Mon Sep 17 00:00:00 2001 From: Dawid Rusnak Date: Fri, 18 Aug 2023 14:02:02 +0200 Subject: [PATCH] tech: migrate Tests and Test Suites slices to Zustand (#837) * tech: migrate Tests to Zustand store - replace Redux slice with Zustand store * tech: migrate Test Suites to Zustand store - replace Redux slice with Zustand store --- src/AppRoot.tsx | 8 +++ .../EntityListContent/EntityListContent.tsx | 11 ++-- .../LabelsFilter/LabelsFilter.tsx | 10 +-- .../StatusFilter/StatusFilter.tsx | 26 +++----- .../TextSearchFilter/TextSearchFilter.tsx | 8 +-- .../TestSuitesList/TestSuiteCard.tsx | 10 +-- .../TestSuitesList/TestSuitesList.tsx | 39 +++++------- .../pages/Tests/TestsList/TestCard.tsx | 10 +-- .../pages/Tests/TestsList/TestsList.tsx | 34 +++++----- src/models/entity.ts | 8 ++- src/models/test.ts | 16 ----- src/models/testSuite.ts | 16 ----- src/redux/initialState.ts | 62 ------------------- src/redux/reducers/testSuitesSlice.ts | 29 --------- src/redux/reducers/testsSlice.ts | 28 --------- src/redux/store.ts | 4 -- src/store/testSuites.ts | 37 +++++++++++ src/store/tests.ts | 37 +++++++++++ 18 files changed, 152 insertions(+), 241 deletions(-) delete mode 100644 src/redux/reducers/testSuitesSlice.ts delete mode 100644 src/redux/reducers/testsSlice.ts create mode 100644 src/store/testSuites.ts create mode 100644 src/store/tests.ts diff --git a/src/AppRoot.tsx b/src/AppRoot.tsx index 16c95c06f..d66c52d88 100644 --- a/src/AppRoot.tsx +++ b/src/AppRoot.tsx @@ -28,6 +28,9 @@ import {useAppDispatch} from '@redux/hooks'; import {useApiEndpoint} from '@services/apiEndpoint'; import {useGetClusterConfigQuery} from '@services/config'; +import {initializeTestSuitesStore} from '@store/testSuites'; +import {initializeTestsStore} from '@store/tests'; + import {useTelemetry, useTelemetryValue} from '@telemetry/hooks'; import anonymizeQueryString from '@utils/anonymizeQueryString'; @@ -47,6 +50,9 @@ const AppRoot: React.FC = () => { const telemetry = useTelemetry(); const apiEndpoint = useApiEndpoint(); + const [TestsProvider] = initializeTestsStore(); + const [TestSuitesProvider] = initializeTestSuitesStore(); + const {currentData: clusterConfig, refetch: refetchClusterConfig} = useGetClusterConfigQuery(); // Pause/resume telemetry based on the cluster settings @@ -116,6 +122,8 @@ const AppRoot: React.FC = () => { .append(DashboardContext.Provider, {value: dashboardValue}) .append(PermissionsProvider, {scope: permissionsScope, resolver: permissionsResolver}) .append(MainContext.Provider, {value: mainContextValue}) + .append(TestsProvider, {}) + .append(TestSuitesProvider, {}) .append(ModalHandler, {}) .append(ModalOutletProvider, {}) .render( diff --git a/src/components/organisms/EntityList/EntityListContent/EntityListContent.tsx b/src/components/organisms/EntityList/EntityListContent/EntityListContent.tsx index 21c201340..1272d3f16 100644 --- a/src/components/organisms/EntityList/EntityListContent/EntityListContent.tsx +++ b/src/components/organisms/EntityList/EntityListContent/EntityListContent.tsx @@ -30,6 +30,7 @@ import {StyledFiltersSection} from './EntityListContent.styled'; const EntityListContent: React.FC = props => { const { + itemKey, pageTitle, pageTitleAddon, pageDescription: PageDescription, @@ -53,7 +54,7 @@ const EntityListContent: React.FC = props => { const [isApplyingFilters, setIsApplyingFilters] = useState(false); const [isLoadingNext, setIsLoadingNext] = useState(false); - const {dispatch, isClusterAvailable} = useContext(MainContext); + const {isClusterAvailable} = useContext(MainContext); const {setModalConfig, setModalOpen} = useContext(ModalContext); const apiEndpoint = useApiEndpoint(); const mayCreate = usePermission(Permissions.createEntity); @@ -67,7 +68,7 @@ const EntityListContent: React.FC = props => { selector: searchParams.get('selector')?.split(',').filter(Boolean) ?? undefined, }); if (!isEqual(filters, queryFilters)) { - dispatch(setQueryFilters(filters)); + setQueryFilters(filters); } }, []); @@ -92,12 +93,12 @@ const EntityListContent: React.FC = props => { }, [queryFilters]); const resetFilters = () => { - dispatch(setQueryFilters(initialFiltersState)); + setQueryFilters(initialFiltersState); }; const onScrollBottom = () => { setIsLoadingNext(true); - dispatch(setQueryFilters({...queryFilters, pageSize: queryFilters.pageSize + initialPageSize})); + setQueryFilters({...queryFilters, pageSize: queryFilters.pageSize + initialPageSize}); }; useEffect(() => { @@ -159,7 +160,7 @@ const EntityListContent: React.FC = props => { = props => { const {setFilters, filters, isFiltersDisabled, width} = props; - const {dispatch} = useContext(MainContext); - const [isVisible, setVisibilityState] = useState(false); const [labelsMapping, setLabelsMapping] = useState([]); @@ -133,14 +129,14 @@ const LabelsFilter: React.FC = props => { return; } - dispatch(setFilters({...filters, selector: resultedFilters, pageSize: initialPageSize})); + setFilters({...filters, selector: resultedFilters, pageSize: initialPageSize}); onOpenChange(false); }; const resetFilters = () => { setLabelsMapping([defaultKeyValuePair]); onOpenChange(false); - dispatch(setFilters({...filters, selector: [], pageSize: initialPageSize})); + setFilters({...filters, selector: [], pageSize: initialPageSize}); }; const menu = ( diff --git a/src/components/organisms/EntityList/EntityListFilters/StatusFilter/StatusFilter.tsx b/src/components/organisms/EntityList/EntityListFilters/StatusFilter/StatusFilter.tsx index 73ac360d3..2507807dd 100644 --- a/src/components/organisms/EntityList/EntityListFilters/StatusFilter/StatusFilter.tsx +++ b/src/components/organisms/EntityList/EntityListFilters/StatusFilter/StatusFilter.tsx @@ -1,11 +1,9 @@ -import {useCallback, useContext, useMemo, useState} from 'react'; +import {useCallback, useMemo, useState} from 'react'; import {FilterFilled} from '@ant-design/icons'; import {capitalize} from 'lodash'; -import {MainContext} from '@contexts'; - import {FilterProps} from '@models/filters'; import { @@ -26,8 +24,6 @@ const statusList = ['queued', 'running', 'passed', 'failed', 'aborted']; const StatusFilter: React.FC = props => { const {filters, setFilters, isFiltersDisabled} = props; - const {dispatch} = useContext(MainContext); - const [isVisible, setVisibilityState] = useState(false); const onOpenChange = (flag: boolean) => { @@ -37,19 +33,17 @@ const StatusFilter: React.FC = props => { const handleClick = useCallback( (status: string) => { if (filters.status.includes(status)) { - dispatch( - setFilters({ - ...filters, - status: filters.status.filter((currentStatus: string) => { - return status !== currentStatus; - }), - }) - ); + setFilters({ + ...filters, + status: filters.status.filter((currentStatus: string) => { + return status !== currentStatus; + }), + }); } else { - dispatch(setFilters({...filters, status: [...filters.status, status], pageSize: initialPageSize})); + setFilters({...filters, status: [...filters.status, status], pageSize: initialPageSize}); } }, - [dispatch, setFilters, filters] + [setFilters, filters] ); const renderedStatuses = useMemo(() => { @@ -69,7 +63,7 @@ const StatusFilter: React.FC = props => { }, [filters.status, handleClick]); const resetFilter = () => { - dispatch(setFilters({...filters, status: [], pageSize: initialPageSize})); + setFilters({...filters, status: [], pageSize: initialPageSize}); onOpenChange(false); }; diff --git a/src/components/organisms/EntityList/EntityListFilters/TextSearchFilter/TextSearchFilter.tsx b/src/components/organisms/EntityList/EntityListFilters/TextSearchFilter/TextSearchFilter.tsx index 9d6e6ab95..c721801c5 100644 --- a/src/components/organisms/EntityList/EntityListFilters/TextSearchFilter/TextSearchFilter.tsx +++ b/src/components/organisms/EntityList/EntityListFilters/TextSearchFilter/TextSearchFilter.tsx @@ -1,11 +1,9 @@ -import {useContext, useEffect, useState} from 'react'; +import {useEffect, useState} from 'react'; import {useDebounce} from 'react-use'; import {SearchOutlined} from '@ant-design/icons'; import {Input} from 'antd'; -import {MainContext} from '@contexts'; - import {FilterProps} from '@models/filters'; import {initialPageSize} from '@redux/initialState'; @@ -15,8 +13,6 @@ import Colors from '@styles/Colors'; const TextSearchFilter: React.FC = props => { const {filters, setFilters, isFiltersDisabled} = props; - const {dispatch} = useContext(MainContext); - const [inputValue, setInputValue] = useState(filters.textSearch); const onChange = (e: React.ChangeEvent) => { @@ -25,7 +21,7 @@ const TextSearchFilter: React.FC = props => { const [, cancel] = useDebounce( () => { - dispatch(setFilters({...filters, textSearch: inputValue, pageSize: initialPageSize})); + setFilters({...filters, textSearch: inputValue, pageSize: initialPageSize}); }, 300, [inputValue] diff --git a/src/components/pages/TestSuites/TestSuitesList/TestSuiteCard.tsx b/src/components/pages/TestSuites/TestSuitesList/TestSuiteCard.tsx index dc84f925b..0d91a08a8 100644 --- a/src/components/pages/TestSuites/TestSuitesList/TestSuiteCard.tsx +++ b/src/components/pages/TestSuites/TestSuitesList/TestSuiteCard.tsx @@ -4,7 +4,7 @@ import {MainContext} from '@contexts'; import useInViewport from '@hooks/useInViewport'; -import {TestSuiteWithExecutionRedux} from '@models/testSuite'; +import {TestSuiteWithExecution} from '@models/testSuite'; import EntityGridItemPure, {Item} from '@molecules/EntityGrid/EntityGridItemPure'; @@ -13,26 +13,26 @@ import {useGetTestSuiteExecutionMetricsQuery} from '@services/testSuiteExecution import {PollingIntervals} from '@utils/numbers'; export interface TestSuiteCardProps { - item: TestSuiteWithExecutionRedux; + item: TestSuiteWithExecution; onClick: (item: Item) => void; onAbort: (item: Item) => void; } -const TestSuiteCard: FC = ({item: {dataItem, latestExecution}, onClick, onAbort}) => { +const TestSuiteCard: FC = ({item: {testSuite, latestExecution}, onClick, onAbort}) => { const {isClusterAvailable} = useContext(MainContext); const ref = useRef(null); const isInViewport = useInViewport(ref); const {data: metrics} = useGetTestSuiteExecutionMetricsQuery( - {id: dataItem.name, last: 7, limit: 13}, + {id: testSuite.name, last: 7, limit: 13}, {skip: !isInViewport || !isClusterAvailable, pollingInterval: PollingIntervals.halfMin} ); return ( { - const {dispatch, isClusterAvailable} = useContext(MainContext); - const queryFilters = useAppSelector(selectTestSuitesFilters); - - const {data, isLoading, isFetching} = useGetTestSuitesQuery(queryFilters || null, { + const {isClusterAvailable} = useContext(MainContext); + const [filters, setFilters] = useTestSuitesField('filters'); + + const { + data: testSuites, + isLoading, + isFetching, + } = useGetTestSuitesQuery(filters || null, { pollingInterval: PollingIntervals.everySecond, skip: !isClusterAvailable, }); - - useEffect(() => { - dispatch(setTestSuites(data || [])); - }, [data]); + useTestSuitesSync({testSuites}); const [abortAll] = useAbortAllTestSuiteExecutionsMutation(); const onItemClick = useDashboardNavigate((item: TestSuite) => `/test-suites/${item.name}`); @@ -65,6 +59,7 @@ const TestSuitesList: FC = () => { return ( { addEntityButtonText="Add a new test suite" pageDescription={PageDescription} emptyDataComponent={EmptyTestSuites} - initialFiltersState={initialTestSuitesFiltersState} + initialFiltersState={initialFilters} dataTest="add-a-new-test-suite-btn" - queryFilters={queryFilters} - setQueryFilters={setTestSuitesFilters} - data={useAppSelector(selectTestSuites)} + queryFilters={filters} + setQueryFilters={setFilters} + data={testSuites} isLoading={isLoading} isFetching={isFetching} createModalConfig={createModal} diff --git a/src/components/pages/Tests/TestsList/TestCard.tsx b/src/components/pages/Tests/TestsList/TestCard.tsx index e87ba6cfa..58a1a2b88 100644 --- a/src/components/pages/Tests/TestsList/TestCard.tsx +++ b/src/components/pages/Tests/TestsList/TestCard.tsx @@ -4,7 +4,7 @@ import {MainContext} from '@contexts'; import useInViewport from '@hooks/useInViewport'; -import {TestWithExecutionRedux} from '@models/test'; +import {TestWithExecution} from '@models/test'; import EntityGridItemPure, {Item} from '@molecules/EntityGrid/EntityGridItemPure'; @@ -13,26 +13,26 @@ import {useGetTestExecutionMetricsQuery} from '@services/tests'; import {PollingIntervals} from '@utils/numbers'; export interface TestCardProps { - item: TestWithExecutionRedux; + item: TestWithExecution; onClick: (item: Item) => void; onAbort: (item: Item) => void; } -const TestCard: FC = ({item: {dataItem, latestExecution}, onClick, onAbort}) => { +const TestCard: FC = ({item: {test, latestExecution}, onClick, onAbort}) => { const {isClusterAvailable} = useContext(MainContext); const ref = useRef(null); const isInViewport = useInViewport(ref); const {data: metrics} = useGetTestExecutionMetricsQuery( - {id: dataItem.name, last: 7, limit: 13}, + {id: test.name, last: 7, limit: 13}, {skip: !isInViewport || !isClusterAvailable, pollingInterval: PollingIntervals.halfMin} ); return ( { - const {dispatch, isClusterAvailable} = useContext(MainContext); - const queryFilters = useAppSelector(selectTestsFilters); - - const {data, isLoading, isFetching} = useGetTestsQuery(queryFilters || null, { + const {isClusterAvailable} = useContext(MainContext); + const [filters, setFilters] = useTestsField('filters'); + + const { + data: tests, + isLoading, + isFetching, + } = useGetTestsQuery(filters, { pollingInterval: PollingIntervals.everySecond, skip: !isClusterAvailable, }); - - useEffect(() => { - dispatch(setTests(data || [])); - }, [data]); + useTestsSync({tests}); const [abortAll] = useAbortAllTestExecutionsMutation(); const onItemClick = useDashboardNavigate((item: Test) => `/tests/${item.name}`); @@ -66,6 +65,7 @@ const TestsList: FC = () => { return ( { addEntityButtonText="Add a new test" pageDescription={PageDescription} emptyDataComponent={EmptyTests} - initialFiltersState={initialTestsFiltersState} + initialFiltersState={initialFilters} dataTest="add-a-new-test-btn" - queryFilters={queryFilters} - setQueryFilters={setTestsFilters} - data={useAppSelector(selectTests)} + queryFilters={filters} + setQueryFilters={setFilters} + data={tests} isLoading={isLoading} isFetching={isFetching} createModalConfig={createModal} diff --git a/src/models/entity.ts b/src/models/entity.ts index ac069672b..54b2c4c65 100644 --- a/src/models/entity.ts +++ b/src/models/entity.ts @@ -2,8 +2,8 @@ import {FC, ReactNode} from 'react'; import {ModalConfig} from '@contexts/ModalContext'; -import {TestWithExecutionRedux} from '@models/test'; -import {TestSuiteWithExecutionRedux} from '@models/testSuite'; +import {TestWithExecution} from '@models/test'; +import {TestSuiteWithExecution} from '@models/testSuite'; import {Item} from '@molecules/EntityGrid/EntityGridItemPure'; @@ -22,6 +22,8 @@ export type EntityListBlueprint = { initialFiltersState: any; + itemKey: string; + // TODO: Fix types CardComponent: FC<{item: any; onClick: (item: Item) => void; onAbort: (item: Item) => void}>; @@ -42,7 +44,7 @@ export type EntityListBlueprint = { dataTest?: string; queryFilters: any; - data?: TestSuiteWithExecutionRedux[] | TestWithExecutionRedux[]; + data?: TestSuiteWithExecution[] | TestWithExecution[]; createModalConfig: ModalConfig; diff --git a/src/models/test.ts b/src/models/test.ts index e5a04056c..7e71e32bf 100644 --- a/src/models/test.ts +++ b/src/models/test.ts @@ -43,11 +43,6 @@ export type TestWithExecution = { latestExecution?: Execution; }; -export type TestWithExecutionRedux = { - dataItem: Test; - latestExecution?: Execution; -}; - export type TestFilters = { textSearch: string; type: string; @@ -69,14 +64,3 @@ export type TestSuiteStepTest = { namespace: Test['namespace']; type?: Test['type']; }; - -interface TestsState { - isLoading?: boolean; - dataList: TestWithExecutionRedux[]; - latestExecution?: Execution; - filters: TestFilters; - totals: {}; - filtered: {}; -} - -export type {TestsState}; diff --git a/src/models/testSuite.ts b/src/models/testSuite.ts index 9d49fb72f..c42b11dff 100644 --- a/src/models/testSuite.ts +++ b/src/models/testSuite.ts @@ -47,11 +47,6 @@ export type TestSuiteWithExecution = { latestExecution?: TestSuiteExecution; }; -export type TestSuiteWithExecutionRedux = { - dataItem: TestSuite; - latestExecution?: TestSuiteExecution; -}; - export type TestSuiteFilters = { textSearch: string; pageSize: number; @@ -61,14 +56,3 @@ export type TestSuiteFilters = { endDate: null; status: Array; }; - -interface TestSuitesState { - isLoading?: boolean; - dataList: TestSuiteWithExecutionRedux[]; - latestExecution?: Execution; - filters: TestSuiteFilters; - totals: {}; - filtered: {}; -} - -export type {TestSuitesState}; diff --git a/src/redux/initialState.ts b/src/redux/initialState.ts index 26b7099ad..da8c2b332 100644 --- a/src/redux/initialState.ts +++ b/src/redux/initialState.ts @@ -1,68 +1,8 @@ import {ExecutorsState} from '@models/executors'; import {SourcesState} from '@models/sources'; -import {TestFilters, TestsState} from '@models/test'; -import {TestSuiteFilters, TestSuitesState} from '@models/testSuite'; export const initialPageSize = 20; -export const initialTestSuitesFiltersState: TestSuiteFilters = { - textSearch: '', - pageSize: initialPageSize, - page: 0, - selector: [], - startDate: null, - endDate: null, - status: [], -}; - -export const initialTestSuitesState: TestSuitesState = { - isLoading: false, - dataList: [], - latestExecution: undefined, - filters: initialTestSuitesFiltersState, - totals: { - results: 0, - passed: 0, - failed: 0, - pending: 0, - }, - filtered: { - results: 0, - passed: 0, - failed: 0, - pending: 0, - }, -}; - -export const initialTestsFiltersState: TestFilters = { - textSearch: '', - type: '', - pageSize: initialPageSize, - page: 0, - selector: [], - createdAt: null, - status: [], -}; - -const initialTestsState: TestsState = { - isLoading: false, - dataList: [], - latestExecution: undefined, - filters: initialTestsFiltersState, - totals: { - results: 0, - passed: 0, - failed: 0, - pending: 0, - }, - filtered: { - results: 0, - passed: 0, - failed: 0, - pending: 0, - }, -}; - const initialExecutorsState: ExecutorsState = { executorsList: [], executorsFeaturesMap: {}, @@ -75,8 +15,6 @@ const initialSourcesState: SourcesState = { }; const initialReduxState = { - testSuites: initialTestSuitesState, - tests: initialTestsState, executors: initialExecutorsState, sources: initialSourcesState, }; diff --git a/src/redux/reducers/testSuitesSlice.ts b/src/redux/reducers/testSuitesSlice.ts deleted file mode 100644 index 1a27b64fa..000000000 --- a/src/redux/reducers/testSuitesSlice.ts +++ /dev/null @@ -1,29 +0,0 @@ -import {Draft, PayloadAction, createSlice} from '@reduxjs/toolkit'; - -import type {TestSuiteWithExecution, TestSuitesState} from '@models/testSuite'; - -import initialState from '@redux/initialState'; - -import type {RootState} from '../store'; - -export const testSuitesSlice = createSlice({ - name: 'testSuitesSlice', - initialState: initialState.testSuites, - reducers: { - setTestSuites: (state: Draft, action: PayloadAction) => { - const adjustedPayload = action.payload.map(testItem => { - return {dataItem: testItem.testSuite, latestExecution: testItem.latestExecution}; - }); - - state.dataList = adjustedPayload; - }, - setTestSuitesFilters: (state: Draft, action: PayloadAction) => { - state.filters = action.payload; - }, - }, -}); - -export const selectTestSuites = (state: RootState) => state.testSuites.dataList; -export const selectTestSuitesFilters = (state: RootState) => state.testSuites.filters; - -export const {setTestSuites, setTestSuitesFilters} = testSuitesSlice.actions; diff --git a/src/redux/reducers/testsSlice.ts b/src/redux/reducers/testsSlice.ts deleted file mode 100644 index 131bdb440..000000000 --- a/src/redux/reducers/testsSlice.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {Draft, PayloadAction, createSlice} from '@reduxjs/toolkit'; - -import type {TestWithExecution, TestsState} from '@models/test'; - -import initialState from '@redux/initialState'; - -import type {RootState} from '../store'; - -export const testsSlice = createSlice({ - name: 'testsSlice', - initialState: initialState.tests, - reducers: { - setTests: (state: Draft, action: PayloadAction) => { - const adjustedPayload = action.payload.map(testItem => { - return {dataItem: testItem.test, latestExecution: testItem.latestExecution}; - }); - - state.dataList = adjustedPayload; - }, - setTestsFilters: (state: Draft, action: PayloadAction) => { - state.filters = action.payload; - }, - }, -}); - -export const selectTests = (state: RootState) => state.tests.dataList; -export const selectTestsFilters = (state: RootState) => state.tests.filters; -export const {setTests, setTestsFilters} = testsSlice.actions; diff --git a/src/redux/store.ts b/src/redux/store.ts index 2c39191b4..74e1755b8 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -2,8 +2,6 @@ import {Action, Middleware, ThunkAction, configureStore} from '@reduxjs/toolkit' import {executorsSlice} from '@redux/reducers/executorsSlice'; import {sourcesSlice} from '@redux/reducers/sourcesSlice'; -import {testSuitesSlice} from '@redux/reducers/testSuitesSlice'; -import {testsSlice} from '@redux/reducers/testsSlice'; import {configApi} from '@services/config'; import {executionsApi} from '@services/executions'; @@ -30,8 +28,6 @@ export const middlewares: Middleware[] = [ ]; export const reducers = { - testSuites: testSuitesSlice.reducer, - tests: testsSlice.reducer, executors: executorsSlice.reducer, sources: sourcesSlice.reducer, diff --git a/src/store/testSuites.ts b/src/store/testSuites.ts new file mode 100644 index 000000000..81dace442 --- /dev/null +++ b/src/store/testSuites.ts @@ -0,0 +1,37 @@ +import {StateCreator} from 'zustand'; + +import {TestSuiteFilters, TestSuiteWithExecution} from '@models/testSuite'; + +import {initialPageSize} from '@redux/initialState'; + +import {connectStore, createStoreFactory} from '@store/utils'; + +interface TestSuitesSlice { + testSuites?: TestSuiteWithExecution[]; + filters: TestSuiteFilters; +} + +export const initialFilters: TestSuiteFilters = { + textSearch: '', + pageSize: initialPageSize, + page: 0, + selector: [], + startDate: null, + endDate: null, + status: [], +}; + +const createTestSuitesSlice: StateCreator = set => ({ + testSuites: undefined, + filters: initialFilters, +}); + +const createTestSuitesStore = createStoreFactory('TestSuites', createTestSuitesSlice); + +export const { + use: useTestSuites, + useField: useTestSuitesField, + pick: useTestSuitesPick, + sync: useTestSuitesSync, + init: initializeTestSuitesStore, +} = connectStore(createTestSuitesStore); diff --git a/src/store/tests.ts b/src/store/tests.ts new file mode 100644 index 000000000..0396ceac4 --- /dev/null +++ b/src/store/tests.ts @@ -0,0 +1,37 @@ +import {StateCreator} from 'zustand'; + +import {TestFilters, TestWithExecution} from '@models/test'; + +import {initialPageSize} from '@redux/initialState'; + +import {connectStore, createStoreFactory} from '@store/utils'; + +interface TestsSlice { + tests?: TestWithExecution[]; + filters: TestFilters; +} + +export const initialFilters: TestFilters = { + textSearch: '', + type: '', + pageSize: initialPageSize, + page: 0, + selector: [], + createdAt: null, + status: [], +}; + +const createTestsSlice: StateCreator = set => ({ + tests: undefined, + filters: initialFilters, +}); + +const createTestsStore = createStoreFactory('Tests', createTestsSlice); + +export const { + use: useTests, + useField: useTestsField, + pick: useTestsPick, + sync: useTestsSync, + init: initializeTestsStore, +} = connectStore(createTestsStore);