diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetTables.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetTables.test.tsx index 43e59d6a5ccf2..9c4ad15833f67 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetTables.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/AssetTables.test.tsx @@ -3,6 +3,8 @@ import {render, screen} from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import {MemoryRouter} from 'react-router'; +import {buildWorkspace} from '../../graphql/types'; +import {buildWorkspaceContextMockedResponse} from '../../runs/__fixtures__/RunsFilterInput.fixtures'; import {WorkspaceProvider} from '../../workspace/WorkspaceContext'; import {AssetsCatalogTable} from '../AssetsCatalogTable'; import { @@ -14,6 +16,8 @@ import { SingleAssetQueryTrafficDashboard, } from '../__fixtures__/AssetTables.fixtures'; +const workspaceMock = buildWorkspaceContextMockedResponse(buildWorkspace({})); + const MOCKS = [ AssetCatalogTableMock, AssetCatalogGroupTableMock, @@ -21,6 +25,7 @@ const MOCKS = [ SingleAssetQueryMaterializedWithLatestRun, SingleAssetQueryMaterializedStaleAndLate, SingleAssetQueryLastRunFailed, + workspaceMock, ]; // This file must be mocked because Jest can't handle `import.meta.url`. diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/LaunchAssetChoosePartitionsDialog.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/LaunchAssetChoosePartitionsDialog.test.tsx index 4bd3b43ba4d10..f9b68d5004012 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/LaunchAssetChoosePartitionsDialog.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/__tests__/LaunchAssetChoosePartitionsDialog.test.tsx @@ -12,12 +12,14 @@ import { buildDimensionPartitionKeys, buildMultiPartitionStatuses, buildPartitionDefinition, + buildWorkspace, } from '../../graphql/types'; import {CREATE_PARTITION_MUTATION} from '../../partitions/CreatePartitionDialog'; import { AddDynamicPartitionMutation, AddDynamicPartitionMutationVariables, } from '../../partitions/types/CreatePartitionDialog.types'; +import {buildWorkspaceContextMockedResponse} from '../../runs/__fixtures__/RunsFilterInput.fixtures'; import {buildMutationMock, buildQueryMock, getMockResultFn} from '../../testing/mocking'; import {buildRepoAddress} from '../../workspace/buildRepoAddress'; import {LaunchAssetChoosePartitionsDialog} from '../LaunchAssetChoosePartitionsDialog'; @@ -27,6 +29,8 @@ import { } from '../types/usePartitionHealthData.types'; import {PARTITION_HEALTH_QUERY} from '../usePartitionHealthData'; +const workspaceMock = buildWorkspaceContextMockedResponse(buildWorkspace({})); + describe('launchAssetChoosePartitionsDialog', () => { it('Adding a dynamic partition when multiple assets selected', async () => { const assetA = buildAsset('asset_a', ['test']); @@ -88,6 +92,7 @@ describe('launchAssetChoosePartitionsDialog', () => { assetASecondQueryMock, assetBSecondQueryMock, addPartitionMock, + workspaceMock, ]} > ({})); @@ -649,6 +653,7 @@ function renderButton({ }), buildLaunchAssetLoaderMock([MULTI_ASSET_OUT_1.assetKey, MULTI_ASSET_OUT_2.assetKey]), buildLaunchAssetLoaderMock(assetKeys), + workspaceMock, ...(launchMock ? [launchMock] : []), ]; diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/AutomaterializationTickDetailDialog.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/AutomaterializationTickDetailDialog.tsx index 06db7553ba465..5479b410c2205 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/AutomaterializationTickDetailDialog.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/AutomaterializationTickDetailDialog.tsx @@ -14,6 +14,7 @@ import {Timestamp} from '../../app/time/Timestamp'; import {tokenForAssetKey} from '../../asset-graph/Utils'; import {AssetKeyInput, InstigationTickStatus} from '../../graphql/types'; import {TickDetailSummary} from '../../instigation/TickDetailsDialog'; +import {useBlockTraceOnQueryResult} from '../../performance/TraceContext'; import {HeaderCell, HeaderRow, Inner, Row, RowCell} from '../../ui/VirtualizedTable'; import {buildRepoAddress} from '../../workspace/buildRepoAddress'; import {workspacePathFromAddress} from '../../workspace/workspacePath'; @@ -180,7 +181,7 @@ const AssetDetailRow = ({ evaluationId: number; }) => { const numMaterializations = partitionKeys?.length || 1; - const {data} = useQuery( + const queryResult = useQuery( ASSET_GROUP_QUERY, { fetchPolicy: 'cache-and-network', @@ -189,6 +190,9 @@ const AssetDetailRow = ({ }, }, ); + const {data} = queryResult; + useBlockTraceOnQueryResult(queryResult, 'AssetGroupAndLocationQuery'); + const asset = data?.assetOrError.__typename === 'Asset' ? data.assetOrError : null; const definition = asset?.definition; const repoAddress = definition diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/AutomaterializeRunHistoryTable.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/AutomaterializeRunHistoryTable.tsx index b3ffc08b80825..85faf2b03833c 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/AutomaterializeRunHistoryTable.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/AutomaterializeRunHistoryTable.tsx @@ -2,6 +2,7 @@ import {Box, ButtonGroup, CursorHistoryControls} from '@dagster-io/ui-components import styled from 'styled-components'; import {useQueryRefreshAtInterval} from '../../app/QueryRefresh'; +import {useBlockTraceOnQueryResult} from '../../performance/TraceContext'; import {RunTable} from '../../runs/RunTable'; import {RUNS_ROOT_QUERY} from '../../runs/RunsRoot'; import {RunsRootQuery, RunsRootQueryVariables} from '../../runs/types/RunsRoot.types'; @@ -40,6 +41,7 @@ export const AutomaterializeRunHistoryTable = ({ query: RUNS_ROOT_QUERY, pageSize: PAGE_SIZE, }); + useBlockTraceOnQueryResult(queryResult, 'RunsRootQuery'); useQueryRefreshAtInterval(queryResult, 15 * 1000); diff --git a/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/SensorAutomaterializationEvaluationHistoryTable.tsx b/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/SensorAutomaterializationEvaluationHistoryTable.tsx index 00477e713ef62..c5c97b0054cf3 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/SensorAutomaterializationEvaluationHistoryTable.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/assets/auto-materialization/SensorAutomaterializationEvaluationHistoryTable.tsx @@ -5,6 +5,7 @@ import {AssetDaemonTickFragment} from './types/AssetDaemonTicksQuery.types'; import {useQueryRefreshAtInterval} from '../../app/QueryRefresh'; import {InstigationTickStatus} from '../../graphql/types'; import {useQueryPersistedState} from '../../hooks/useQueryPersistedState'; +import {useBlockTraceOnQueryResult} from '../../performance/TraceContext'; import {useCursorPaginatedQuery} from '../../runs/useCursorPaginatedQuery'; import {ASSET_SENSOR_TICKS_QUERY} from '../../sensors/AssetSensorTicksQuery'; import { @@ -83,6 +84,8 @@ export const SensorAutomaterializationEvaluationHistoryTable = ({ pageSize: PAGE_SIZE, }); + useBlockTraceOnQueryResult(queryResult, 'AssetSensorTicksQuery'); + // Only refresh if we're on the first page useQueryRefreshAtInterval(queryResult, 10000, !paginationProps.hasPrevCursor); diff --git a/js_modules/dagster-ui/packages/ui-core/src/nav/__tests__/LeftNavRepositorySection.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/nav/__tests__/LeftNavRepositorySection.test.tsx index 0b4dc07e91b45..732003b7335ca 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/nav/__tests__/LeftNavRepositorySection.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/nav/__tests__/LeftNavRepositorySection.test.tsx @@ -4,6 +4,7 @@ import userEvent from '@testing-library/user-event'; import {useContext} from 'react'; import {MemoryRouter} from 'react-router-dom'; +import {__resetForJest} from '../../search/useIndexedDBCachedQuery'; import { HIDDEN_REPO_KEYS, WorkspaceContext, @@ -41,6 +42,7 @@ describe('Repository options', () => { afterEach(() => { window.localStorage.clear(); + __resetForJest(); }); it('Correctly displays the current repository state', async () => { diff --git a/js_modules/dagster-ui/packages/ui-core/src/overview/OverviewSensors.tsx b/js_modules/dagster-ui/packages/ui-core/src/overview/OverviewSensors.tsx index 22a917817d56c..0206f1c09b523 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/overview/OverviewSensors.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/overview/OverviewSensors.tsx @@ -19,6 +19,7 @@ import {useQueryPersistedState} from '../hooks/useQueryPersistedState'; import {useSelectionReducer} from '../hooks/useSelectionReducer'; import {INSTANCE_HEALTH_FRAGMENT} from '../instance/InstanceHealthFragment'; import {filterPermissionedInstigationState} from '../instigation/filterPermissionedInstigationState'; +import {useBlockTraceOnQueryResult} from '../performance/TraceContext'; import {SensorBulkActionMenu} from '../sensors/SensorBulkActionMenu'; import {SensorInfo} from '../sensors/SensorInfo'; import {makeSensorKey} from '../sensors/makeSensorKey'; @@ -33,6 +34,7 @@ import {WorkspaceContext} from '../workspace/WorkspaceContext'; import {buildRepoAddress} from '../workspace/buildRepoAddress'; import {repoAddressAsHumanString} from '../workspace/repoAddressAsString'; import {RepoAddress} from '../workspace/types'; +import {RootWorkspaceQuery} from '../workspace/types/WorkspaceContext.types'; function toSetFilterValue(type: SensorType) { const label = SENSOR_TYPE_META[type].name; @@ -54,7 +56,13 @@ const SENSOR_TYPE_TO_FILTER: Partial { - const {allRepos, visibleRepos, loading: workspaceLoading} = useContext(WorkspaceContext); + const { + allRepos, + visibleRepos, + loading: workspaceLoading, + data: cachedData, + } = useContext(WorkspaceContext); + const repoCount = allRepos.length; const [searchValue, setSearchValue] = useQueryPersistedState({ queryKey: 'search', @@ -96,7 +104,14 @@ export const OverviewSensors = () => { notifyOnNetworkStatusChange: true, }, ); - const {data, loading} = queryResultOverview; + const {data: currentData, loading} = queryResultOverview; + const data = + currentData ?? + (cachedData?.workspaceOrError.__typename === 'Workspace' + ? (cachedData as Extract) + : null); + + useBlockTraceOnQueryResult(queryResultOverview, 'OverviewSensorsQuery'); const refreshState = useQueryRefreshAtInterval(queryResultOverview, FIFTEEN_SECONDS); @@ -326,7 +341,7 @@ export const OverviewSensors = () => { ) : ( <> @@ -342,7 +357,7 @@ type RepoBucket = { sensors: {name: string; sensorType: SensorType; sensorState: BasicInstigationStateFragment}[]; }; -const buildBuckets = (data?: OverviewSensorsQuery): RepoBucket[] => { +const buildBuckets = (data?: null | OverviewSensorsQuery | RootWorkspaceQuery) => { if (data?.workspaceOrError.__typename !== 'Workspace') { return []; } diff --git a/js_modules/dagster-ui/packages/ui-core/src/performance/TraceContext.tsx b/js_modules/dagster-ui/packages/ui-core/src/performance/TraceContext.tsx index 7e9cf86d0f692..c2ee2406ca792 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/performance/TraceContext.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/performance/TraceContext.tsx @@ -53,7 +53,10 @@ export class Dependency { } /** Use this to declare a dependency on an apollo query result */ -export function useBlockTraceOnQueryResult(queryResult: QueryResult, name: string) { +export function useBlockTraceOnQueryResult( + queryResult: Pick, 'data' | 'error'>, + name: string, +) { const dep = useTraceDependency(name); const hasData = !!queryResult.data; const hasError = !!queryResult.error; diff --git a/js_modules/dagster-ui/packages/ui-core/src/pipelines/PipelineRunsRoot.tsx b/js_modules/dagster-ui/packages/ui-core/src/pipelines/PipelineRunsRoot.tsx index 346f3d30e4f32..10158620da3c5 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/pipelines/PipelineRunsRoot.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/pipelines/PipelineRunsRoot.tsx @@ -27,6 +27,7 @@ import { } from '../app/QueryRefresh'; import {useTrackPageView} from '../app/analytics'; import {usePageLoadTrace} from '../performance'; +import {useBlockTraceOnQueryResult} from '../performance/TraceContext'; import {RUN_TABLE_RUN_FRAGMENT, RunTable} from '../runs/RunTable'; import {DagsterTag} from '../runs/RunTag'; import {RunsQueryRefetchContext} from '../runs/RunUtils'; @@ -114,6 +115,8 @@ export const PipelineRunsRoot = (props: Props) => { }, }); + useBlockTraceOnQueryResult(queryResult, 'PipelineRunsRootQuery'); + const onAddTag = useCallback( (token: RunFilterToken) => { const tokenAsString = tokenToString(token); diff --git a/js_modules/dagster-ui/packages/ui-core/src/runs/__tests__/RunFilterInput.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/runs/__tests__/RunFilterInput.test.tsx index 5510bc70da016..49124ba600e2c 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/runs/__tests__/RunFilterInput.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/runs/__tests__/RunFilterInput.test.tsx @@ -30,6 +30,29 @@ import { } from '../__fixtures__/RunsFilterInput.fixtures'; import {RunTagKeysQuery} from '../types/RunsFilterInput.types'; +const workspaceMock = buildWorkspaceContextMockedResponse( + buildWorkspace({ + locationEntries: [ + buildWorkspaceLocationEntry({ + name: 'some_workspace', + locationOrLoadError: buildRepositoryLocation({ + name: 'some_location', + repositories: [ + buildRepository({ + name: 'some_repo', + pipelines: [ + buildPipeline({ + name: 'some_job', + }), + ], + }), + ], + }), + }), + ], + }), +); + const runTagKeysMock: MockedResponse = { request: { query: RUN_TAG_KEYS_QUERY, @@ -145,7 +168,7 @@ function TestRunsFilterInput({ ); } return ( - + @@ -196,30 +219,7 @@ describe('', () => { tokens={tokens} onChange={onChange} enabledFilters={['job']} - mocks={[ - buildWorkspaceContextMockedResponse( - buildWorkspace({ - locationEntries: [ - buildWorkspaceLocationEntry({ - name: 'some_workspace', - locationOrLoadError: buildRepositoryLocation({ - name: 'some_location', - repositories: [ - buildRepository({ - name: 'some_repo', - pipelines: [ - buildPipeline({ - name: 'some_job', - }), - ], - }), - ], - }), - }), - ], - }), - ), - ]} + mocks={[workspaceMock]} />, ); diff --git a/js_modules/dagster-ui/packages/ui-core/src/search/__tests__/useIndexedDBCachedQuery.test.tsx b/js_modules/dagster-ui/packages/ui-core/src/search/__tests__/useIndexedDBCachedQuery.test.tsx index 11ef6d100c02b..2529134c9ab4d 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/search/__tests__/useIndexedDBCachedQuery.test.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/search/__tests__/useIndexedDBCachedQuery.test.tsx @@ -30,6 +30,10 @@ jest.mock('idb-lru-cache', () => { }; }); +afterEach(() => { + jest.resetModules(); +}); + jest.mock('@apollo/client', () => { const actual = jest.requireActual('@apollo/client'); const query = jest.fn().mockReturnValue({ diff --git a/js_modules/dagster-ui/packages/ui-core/src/search/useIndexedDBCachedQuery.tsx b/js_modules/dagster-ui/packages/ui-core/src/search/useIndexedDBCachedQuery.tsx index 7e46a603454fa..eaab4a86bb66d 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/search/useIndexedDBCachedQuery.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/search/useIndexedDBCachedQuery.tsx @@ -7,7 +7,7 @@ type CacheData = { version: number; }; -const fetchState: Record< +let fetchState: Record< string, { onFetched: ((value: any) => void)[]; @@ -84,9 +84,25 @@ export function useIndexedDBCachedQuery cb(queryResult)); delete fetchState[key]; + const onFetched = fetchState[key]?.onFetched; + try { + setData(data); + } catch (e) { + setTimeout(() => { + throw e; + }); + } + onFetched?.forEach((cb) => { + try { + cb(queryResult); + } catch (e) { + setTimeout(() => { + throw e; + }); + } + }); + return queryResult; }, [client, key, lru, query, variables, version]); @@ -96,3 +112,7 @@ export function useIndexedDBCachedQuery { + fetchState = {}; +}; diff --git a/js_modules/dagster-ui/packages/ui-core/src/sensors/SensorPageAutomaterialize.tsx b/js_modules/dagster-ui/packages/ui-core/src/sensors/SensorPageAutomaterialize.tsx index ac1ffd93ccd6b..324e78c55bf05 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/sensors/SensorPageAutomaterialize.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/sensors/SensorPageAutomaterialize.tsx @@ -18,6 +18,7 @@ import {InstigationTickStatus} from '../graphql/types'; import {useQueryPersistedState} from '../hooks/useQueryPersistedState'; import {LiveTickTimeline} from '../instigation/LiveTickTimeline2'; import {isStuckStartedTick} from '../instigation/util'; +import {useBlockTraceOnQueryResult} from '../performance/TraceContext'; import {DagsterTag} from '../runs/RunTag'; import {repoAddressAsTag} from '../workspace/repoAddressAsString'; import {RepoAddress} from '../workspace/types'; @@ -70,6 +71,7 @@ export const SensorPageAutomaterialize = (props: Props) => { const [fetch, queryResult] = useLazyQuery( ASSET_SENSOR_TICKS_QUERY, ); + useBlockTraceOnQueryResult(queryResult, 'AssetSensorTicksQuery'); const refresh = useCallback( async () => await fetch({variables: getVariables()}), diff --git a/js_modules/dagster-ui/packages/ui-core/src/sensors/SensorRoot.tsx b/js_modules/dagster-ui/packages/ui-core/src/sensors/SensorRoot.tsx index d4c02edb4825b..6215ef0f864c7 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/sensors/SensorRoot.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/sensors/SensorRoot.tsx @@ -23,6 +23,7 @@ import {useDocumentTitle} from '../hooks/useDocumentTitle'; import {useQueryPersistedState} from '../hooks/useQueryPersistedState'; import {INSTANCE_HEALTH_FRAGMENT} from '../instance/InstanceHealthFragment'; import {TickHistoryTimeline, TicksTable} from '../instigation/TickHistory'; +import {useBlockTraceOnQueryResult} from '../performance/TraceContext'; import {repoAddressToSelector} from '../workspace/repoAddressToSelector'; import {RepoAddress} from '../workspace/types'; @@ -67,6 +68,7 @@ export const SensorRoot = ({repoAddress}: {repoAddress: RepoAddress}) => { variables: {sensorSelector}, notifyOnNetworkStatusChange: true, }); + useBlockTraceOnQueryResult(queryResult, 'SensorRootQuery'); const selectionQueryResult = useQuery< SensorAssetSelectionQuery, SensorAssetSelectionQueryVariables @@ -74,6 +76,7 @@ export const SensorRoot = ({repoAddress}: {repoAddress: RepoAddress}) => { variables: {sensorSelector}, notifyOnNetworkStatusChange: true, }); + useBlockTraceOnQueryResult(selectionQueryResult, 'SensorAssetSelectionQuery'); const refreshState1 = useQueryRefreshAtInterval(queryResult, FIFTEEN_SECONDS); const refreshState2 = useQueryRefreshAtInterval(selectionQueryResult, FIFTEEN_SECONDS); diff --git a/js_modules/dagster-ui/packages/ui-core/src/workspace/WorkspaceContext.tsx b/js_modules/dagster-ui/packages/ui-core/src/workspace/WorkspaceContext.tsx index 812c3e2a75d93..25c8ad96189d3 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/workspace/WorkspaceContext.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/workspace/WorkspaceContext.tsx @@ -1,6 +1,7 @@ -import {ApolloQueryResult, gql, useQuery} from '@apollo/client'; +import {ApolloQueryResult, gql} from '@apollo/client'; import sortBy from 'lodash/sortBy'; import * as React from 'react'; +import {useMemo} from 'react'; import {REPOSITORY_INFO_FRAGMENT} from './RepositoryInformation'; import {buildRepoAddress} from './buildRepoAddress'; @@ -20,6 +21,8 @@ import {PYTHON_ERROR_FRAGMENT} from '../app/PythonErrorFragment'; import {PythonErrorFragment} from '../app/types/PythonErrorFragment.types'; import {PipelineSelector} from '../graphql/types'; import {useStateWithStorage} from '../hooks/useStateWithStorage'; +import {BASIC_INSTIGATION_STATE_FRAGMENT} from '../overview/BasicInstigationStateFragment'; +import {useIndexedDBCachedQuery} from '../search/useIndexedDBCachedQuery'; import {SENSOR_SWITCH_FRAGMENT} from '../sensors/SensorSwitch'; type Repository = WorkspaceRepositoryFragment; @@ -42,6 +45,7 @@ type WorkspaceState = { locationEntries: WorkspaceRepositoryLocationNode[]; allRepos: DagsterRepoOption[]; visibleRepos: DagsterRepoOption[]; + data: RootWorkspaceQuery | null; refetch: () => Promise>; toggleVisible: SetVisibleOrHiddenFn; @@ -170,6 +174,7 @@ export const ROOT_WORKSPACE_QUERY = gql` id selectorId status + ...BasicInstigationStateFragment } sensorType ...SensorSwitchFragment @@ -178,6 +183,7 @@ export const ROOT_WORKSPACE_QUERY = gql` ${PYTHON_ERROR_FRAGMENT} ${REPOSITORY_INFO_FRAGMENT} ${SENSOR_SWITCH_FRAGMENT} + ${BASIC_INSTIGATION_STATE_FRAGMENT} `; /** @@ -186,9 +192,17 @@ export const ROOT_WORKSPACE_QUERY = gql` * in the workspace, and loading/error state for the relevant query. */ const useWorkspaceState = (): WorkspaceState => { - const {data, loading, refetch} = useQuery( - ROOT_WORKSPACE_QUERY, - ); + const { + data, + loading, + fetch: refetch, + } = useIndexedDBCachedQuery({ + query: ROOT_WORKSPACE_QUERY, + key: 'RootWorkspace', + version: 1, + }); + useMemo(() => refetch(), [refetch]); + const workspaceOrError = data?.workspaceOrError; const locationEntries = React.useMemo( @@ -232,6 +246,7 @@ const useWorkspaceState = (): WorkspaceState => { loading: loading && !data, // Only "loading" on initial load. error, locationEntries, + data, allRepos, visibleRepos, toggleVisible, diff --git a/js_modules/dagster-ui/packages/ui-core/src/workspace/WorkspaceRoot.tsx b/js_modules/dagster-ui/packages/ui-core/src/workspace/WorkspaceRoot.tsx index 404c36d3606ae..68cc708383044 100644 --- a/js_modules/dagster-ui/packages/ui-core/src/workspace/WorkspaceRoot.tsx +++ b/js_modules/dagster-ui/packages/ui-core/src/workspace/WorkspaceRoot.tsx @@ -25,6 +25,8 @@ const RepoRouteContainer = () => { const workspaceState = useContext(WorkspaceContext); const addressForPath = repoAddressFromPath(repoPath); + const {loading} = workspaceState; + // A RepoAddress could not be created for this path, which means it's invalid. if (!addressForPath) { return ( @@ -45,12 +47,6 @@ const RepoRouteContainer = () => { ); } - const {loading} = workspaceState; - - if (loading) { - return
; - } - const matchingRepo = workspaceState.allRepos.find( (repo) => repo.repository.name === addressForPath.name && @@ -59,7 +55,7 @@ const RepoRouteContainer = () => { // If we don't have any active code locations, or if our active repo does not match // the repo path in the URL, it means we aren't able to load this repo. - if (!matchingRepo) { + if (!matchingRepo && !loading) { return (