diff --git a/ui/src/components/JobStatus/job-status-pin.jsx b/ui/src/components/JobStatus/job-status-pin.jsx index 9d3341bb..0dc72cb5 100644 --- a/ui/src/components/JobStatus/job-status-pin.jsx +++ b/ui/src/components/JobStatus/job-status-pin.jsx @@ -1,16 +1,7 @@ import { JOB_STATUS } from '@Src/constants'; -import { useGetCurrentDataQualityQueryWithPolling, useGetReferenceDataQualityQueryWithPolling } from '@Src/store/state/models/polling-hook'; import { Pin, Spinner } from '@radicalbit/radicalbit-design-system'; -function JobStatusPin({ modelUUID }) { - const { data: referenceData } = useGetReferenceDataQualityQueryWithPolling(modelUUID); - const referenceJobStatus = referenceData?.jobStatus; - - const { data: currentData } = useGetCurrentDataQualityQueryWithPolling(modelUUID); - const currentJobStatus = currentData?.jobStatus; - - const jobStatus = (referenceJobStatus === JOB_STATUS.SUCCEEDED) ? currentJobStatus : referenceJobStatus; - +function JobStatusPin({ jobStatus }) { switch (jobStatus) { case JOB_STATUS.IMPORTING: { return ( diff --git a/ui/src/container/models/Details/secondary-column/content.jsx b/ui/src/container/models/Details/secondary-column/content.jsx index e1d68310..73440b9b 100644 --- a/ui/src/container/models/Details/secondary-column/content.jsx +++ b/ui/src/container/models/Details/secondary-column/content.jsx @@ -1,19 +1,14 @@ -import { modelsApiSlice } from '@Src/store/state/models/api'; +import JobStatusPin from '@Components/JobStatus/job-status-pin'; +import { MODEL_TABS_ENUM } from '@Container/models/Details/constants'; +import { JOB_STATUS } from '@Src/constants'; +import { useGetModelQueryWithPolling } from '@Src/store/state/models/polling-hook'; +import { selectors as layoutSelectors } from '@State/layout'; import { Menu, Truncate } from '@radicalbit/radicalbit-design-system'; import { useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; import { useNavigate, useParams, useSearchParams, } from 'react-router-dom'; -import { selectors as layoutSelectors } from '@State/layout'; -import { useSelector } from 'react-redux'; -import JobStatusPin from '@Components/JobStatus/job-status-pin'; -import { selectors as contextConfigurationSelectors } from '@State/context-configuration'; -import { NamespaceEnum } from '@Src/constants'; -import { MODEL_TABS_ENUM } from '@Container/models/Details/constants'; - -const { useGetModelsQuery } = modelsApiSlice; - -const { selectQueryParamsSelector } = contextConfigurationSelectors; const commonChildrenMenu = [ { label: 'Overview', key: MODEL_TABS_ENUM.OVERVIEW }, @@ -30,23 +25,24 @@ export default function SecondaryColumnModelsContent() { const isSecondaryColumnCollapsed = useSelector(selectHasSecondaryColumnCollapsed); - const queryParams = useSelector((state) => selectQueryParamsSelector(state, NamespaceEnum.MODELS)); - - const { data } = useGetModelsQuery({ queryParams }); + const { data } = useGetModelQueryWithPolling(); const modelList = data?.items ?? []; - const modelListMenuItem = modelList.map(({ uuid: modelUUID, name }) => ( - { + const modelListMenuItem = modelList.map(({ + uuid: modelUUID, name, latestReferenceJobStatus, latestCurrentJobStatus, + }) => { + const jobStatus = latestReferenceJobStatus === JOB_STATUS.SUCCEEDED ? latestCurrentJobStatus : latestReferenceJobStatus; + return { label: (
{name} - +
), key: modelUUID, children: commonChildrenMenu, className: uuid === modelUUID ? Menu.HIDE_EXPAND_ICON : '', - } - )); + }; + }); const [openKeys, setOpenKeys] = useState([uuid]); const rootSubmenuKeys = modelListMenuItem.map(({ key }) => (key)); diff --git a/ui/src/container/models/List/columns.jsx b/ui/src/container/models/List/columns.jsx index 4e19f8fc..e38624eb 100644 --- a/ui/src/container/models/List/columns.jsx +++ b/ui/src/container/models/List/columns.jsx @@ -1,4 +1,6 @@ +import JobStatusPin from '@Components/JobStatus/job-status-pin'; import { columnFactory } from '@Src/components/smart-table/utils'; +import { JOB_STATUS } from '@Src/constants'; import { DataTypeEnumLabel, ModelTypeEnumLabel } from '@Src/store/state/models/constants'; import { RelativeDateTime } from '@radicalbit/radicalbit-design-system'; @@ -6,14 +8,25 @@ export const getColumns = ( activeFilters, activeSorter, ) => [ + columnFactory({ + title: 'S', + key: 'name', + width: '3rem', + align: 'center', + render: ({ latestCurrentJobStatus, latestReferenceJobStatus }) => { + const jobStatus = latestReferenceJobStatus === JOB_STATUS.SUCCEEDED ? latestCurrentJobStatus : latestReferenceJobStatus; + return ( + + ); + }, + }), columnFactory({ title: 'Name', - dataIndex: 'name', key: 'name', activeFilters, activeSorter, width: 250, - render: (name) => (
{name}
), + render: ({ name }) => (
{name}
), }), columnFactory({ diff --git a/ui/src/container/models/List/index.jsx b/ui/src/container/models/List/index.jsx index 75a1d497..0fffd3e9 100644 --- a/ui/src/container/models/List/index.jsx +++ b/ui/src/container/models/List/index.jsx @@ -1,26 +1,18 @@ +import SomethingWentWrong from '@Components/ErrorPage/something-went-wrong'; import SmartTable from '@Components/smart-table'; import LogoSquared from '@Img/logo-collapsed.svg'; import { ModalsEnum, NamespaceEnum } from '@Src/constants'; import useModals from '@Src/hooks/use-modals'; -import { modelsApiSlice } from '@Src/store/state/models/api'; +import { useGetModelQueryWithPolling } from '@Src/store/state/models/polling-hook'; import { Button, Spinner, Void } from '@radicalbit/radicalbit-design-system'; import { useLocation, useNavigate } from 'react-router-dom'; -import SomethingWentWrong from '@Components/ErrorPage/something-went-wrong'; -import { useSelector } from 'react-redux'; -import { selectors as contextConfigurationSelectors } from '@State/context-configuration'; import { getColumns } from './columns'; -const { useGetModelsQuery } = modelsApiSlice; - -const { selectQueryParamsSelector } = contextConfigurationSelectors; - export function ModelsList() { const navigate = useNavigate(); const { search } = useLocation(); - const queryParams = useSelector((state) => selectQueryParamsSelector(state, NamespaceEnum.MODELS)); - - const { data, isLoading, isError } = useGetModelsQuery({ queryParams }); + const { data, isLoading, isError } = useGetModelQueryWithPolling(); const models = data?.items || []; const count = data?.total || 0; diff --git a/ui/src/store/state/models/api.js b/ui/src/store/state/models/api.js index 7284c82a..4fc7846d 100644 --- a/ui/src/store/state/models/api.js +++ b/ui/src/store/state/models/api.js @@ -107,6 +107,8 @@ export const modelsApiSlice = apiService.injectEndpoints({ if (result) { return [ { type: API_TAGS.REFERENCE_IMPORT, id: modelUUID }, + { type: API_TAGS.MODEL, id: modelUUID }, + { type: API_TAGS.MODELS }, ]; } return []; @@ -178,6 +180,7 @@ export const modelsApiSlice = apiService.injectEndpoints({ return [ { type: API_TAGS.CURRENT_IMPORT, id: modelUUID }, { type: API_TAGS.MODEL, id: modelUUID }, + { type: API_TAGS.MODELS }, ]; } return []; diff --git a/ui/src/store/state/models/polling-hook.js b/ui/src/store/state/models/polling-hook.js index 3f999a0f..0f6c49f7 100644 --- a/ui/src/store/state/models/polling-hook.js +++ b/ui/src/store/state/models/polling-hook.js @@ -5,6 +5,8 @@ import { useParams } from 'react-router'; import useModals from '@Hooks/use-modals'; import { modelsApiSlice } from './api'; +const { selectQueryParamsSelector } = contextConfigurationSelectors; + const { useGetReferenceImportsQuery, useGetReferenceDataQualityQuery, @@ -16,6 +18,7 @@ const { useGetCurrentStatisticsByUUIDQuery, useGetCurrentDriftQuery, useGetModelByUUIDQuery, + useGetModelsQuery, } = modelsApiSlice; const useGetReferenceImportsQueryWithPolling = () => { @@ -153,6 +156,19 @@ const useGetCurrentDriftQueryWithPolling = () => { return result; }; +const useGetModelQueryWithPolling = () => { + const queryParams = useSelector((state) => selectQueryParamsSelector(state, NamespaceEnum.MODELS)); + const result = useGetModelsQuery({ queryParams }); + + const isReferencePending = result.data?.items.every((d) => d.latestReferenceJobStatus === JOB_STATUS.SUCCEEDED); + const isCurrentPending = result.data?.items.every((d) => d.latestCurrentJobStatus === JOB_STATUS.SUCCEEDED); + const isOperationCompleted = isReferencePending && isCurrentPending; + + useGetModelsQuery({ queryParams }, { pollingInterval: DEFAULT_POLLING_INTERVAL, skip: isOperationCompleted }); + + return result; +}; + export { useGetCurrentDataQualityQueryWithPolling, useGetCurrentDriftQueryWithPolling, @@ -163,4 +179,5 @@ export { useGetReferenceImportsQueryWithPolling, useGetReferenceModelQualityQueryWithPolling, useGetReferenceStatisticsQueryWithPolling, + useGetModelQueryWithPolling, };