diff --git a/frontend/src/app/App.tsx b/frontend/src/app/App.tsx index a8cf9cb390..e9976970d7 100644 --- a/frontend/src/app/App.tsx +++ b/frontend/src/app/App.tsx @@ -42,17 +42,20 @@ import './App.scss'; type PocConfigType = { altNav?: boolean; + altPreferredProject?: boolean; }; const FAVORITE_PROJECTS_KEY = 'odh-favorite-projects'; const POC_SESSION_KEY = 'odh-poc-flags'; const ALT_NAV_PARAM = 'altNav'; +const ALT_PROJECTS_PARAM = 'altProjects'; const App: React.FC = () => { const [notificationsOpen, setNotificationsOpen] = React.useState(false); const { username, userError, isAllowed } = useUser(); const [searchParams, setSearchParams] = useSearchParams(); const [altNav, setAltNav] = React.useState(false); + const [altPreferredProject, setAltPreferredProject] = React.useState(false); const firstLoad = React.useRef(true); const [pocConfig, setPocConfig] = useBrowserStorage( POC_SESSION_KEY, @@ -96,6 +99,15 @@ const App: React.FC = () => { searchParams.delete(ALT_NAV_PARAM); setSearchParams(searchParams, { replace: true }); } + if (searchParams.has(ALT_PROJECTS_PARAM)) { + const updated = searchParams.get(ALT_PROJECTS_PARAM) === 'true'; + setAltPreferredProject(updated); + setPocConfig({ altNav: updated }); + + // clean up query string + searchParams.delete(ALT_NAV_PARAM); + setSearchParams(searchParams, { replace: true }); + } // do not react to changes to setters // eslint-disable-next-line react-hooks/exhaustive-deps }, [searchParams]); @@ -109,11 +121,20 @@ const App: React.FC = () => { storageClasses, isRHOAI: dashboardConfig.metadata?.namespace === 'redhat-ods-applications', altNav, + altPreferredProject, favoriteProjects, setFavoriteProjects, } : null, - [dashboardConfig, buildStatuses, storageClasses, altNav, favoriteProjects, setFavoriteProjects], + [ + dashboardConfig, + buildStatuses, + storageClasses, + altNav, + altPreferredProject, + favoriteProjects, + setFavoriteProjects, + ], ); const isUnauthorized = fetchConfigError?.request?.status === 403; diff --git a/frontend/src/app/AppContext.ts b/frontend/src/app/AppContext.ts index f2568a650f..a53dc3a0b3 100644 --- a/frontend/src/app/AppContext.ts +++ b/frontend/src/app/AppContext.ts @@ -8,6 +8,7 @@ type AppContextProps = { storageClasses: StorageClassKind[]; isRHOAI: boolean; altNav?: boolean; + altPreferredProject?: boolean; favoriteProjects: string[]; setFavoriteProjects: (projects: string[]) => void; }; diff --git a/frontend/src/concepts/distributedWorkloads/DistributedWorkloadsContext.tsx b/frontend/src/concepts/distributedWorkloads/DistributedWorkloadsContext.tsx index 15cc6575a5..67f1d2bdbd 100644 --- a/frontend/src/concepts/distributedWorkloads/DistributedWorkloadsContext.tsx +++ b/frontend/src/concepts/distributedWorkloads/DistributedWorkloadsContext.tsx @@ -53,7 +53,7 @@ export const DistributedWorkloadsContextProvider = )(({ children, namespace }) => { const { projects } = React.useContext(ProjectsContext); const project = projects.find(byName(namespace)) ?? null; - useSyncPreferredProject(project); + useSyncPreferredProject('distributed-workloads', project); const { currentRefreshInterval } = React.useContext(MetricsCommonContext); diff --git a/frontend/src/concepts/pipelines/context/PipelinesContext.tsx b/frontend/src/concepts/pipelines/context/PipelinesContext.tsx index fc12134303..2f2095ec22 100644 --- a/frontend/src/concepts/pipelines/context/PipelinesContext.tsx +++ b/frontend/src/concepts/pipelines/context/PipelinesContext.tsx @@ -79,7 +79,7 @@ export const PipelineContextProvider = conditionalArea { const { projects } = React.useContext(ProjectsContext); const project = projects.find(byName(namespace)) ?? null; - useSyncPreferredProject(project); + useSyncPreferredProject('pipelines', project); const state = usePipelineNamespaceCR(namespace); const [pipelineNamespaceCR, crLoaded, crLoadError, refreshCR] = state; diff --git a/frontend/src/concepts/projects/InvalidProject.tsx b/frontend/src/concepts/projects/InvalidProject.tsx index 83f532c89c..82522b8d32 100644 --- a/frontend/src/concepts/projects/InvalidProject.tsx +++ b/frontend/src/concepts/projects/InvalidProject.tsx @@ -3,17 +3,24 @@ import EmptyStateErrorMessage from '~/components/EmptyStateErrorMessage'; import ProjectSelectorNavigator from '~/concepts/projects/ProjectSelectorNavigator'; type InvalidProjectProps = { + page: string; title?: string; namespace?: string; getRedirectPath: (namespace: string) => string; }; -const InvalidProject: React.FC = ({ namespace, title, getRedirectPath }) => ( +const InvalidProject: React.FC = ({ + page, + namespace, + title, + getRedirectPath, +}) => ( string; } & Omit, 'onSelection' | 'namespace'>; const ProjectSelectorNavigator: React.FC = ({ + page, getRedirectPath, ...projectSelectorProps }) => { @@ -19,9 +21,7 @@ const ProjectSelectorNavigator: React.FC = ({ { - if (!projectName) { - updatePreferredProject(null); - } + updatePreferredProject(page, projectName || null); navigate(getRedirectPath(projectName)); }} namespace={namespace ?? ''} diff --git a/frontend/src/concepts/projects/ProjectsContext.tsx b/frontend/src/concepts/projects/ProjectsContext.tsx index 6f9a12ab71..59ec09e8d5 100644 --- a/frontend/src/concepts/projects/ProjectsContext.tsx +++ b/frontend/src/concepts/projects/ProjectsContext.tsx @@ -4,6 +4,7 @@ import { FetchState } from '~/utilities/useFetchState'; import { KnownLabels, ProjectKind } from '~/k8sTypes'; import { useDashboardNamespace } from '~/redux/selectors'; import { getDisplayNameFromK8sResource } from '~/concepts/k8s/utils'; +import { AppContext } from '~/app/AppContext'; import { isAvailableProject } from './utils'; const projectSorter = (projectA: ProjectKind, projectB: ProjectKind) => @@ -16,13 +17,13 @@ type ProjectsContextType = { /** eg. Terminating state, etc */ nonActiveProjects: ProjectKind[]; - /** Some component set this value, you should use this instead of projects[0] */ - preferredProject: ProjectKind | null; + /** Get the project last used for the given page] */ + getPreferredProject: (page: string) => ProjectKind | null; /** * Allows for navigation to be unimpeded by project selection * @see useSyncPreferredProject */ - updatePreferredProject: (project: ProjectKind | null) => void; + updatePreferredProject: (page: string, projectName: string | null) => void; waitForProject: (projectName: string) => Promise; // ...the rest of the state variables @@ -34,8 +35,9 @@ export const ProjectsContext = React.createContext({ projects: [], modelServingProjects: [], nonActiveProjects: [], - preferredProject: null, - updatePreferredProject: () => undefined, + getPreferredProject: () => null, + // eslint-disable-next-line @typescript-eslint/no-empty-function + updatePreferredProject: () => {}, loaded: false, loadError: new Error('Not in project provider'), waitForProject: () => Promise.resolve(), @@ -50,10 +52,26 @@ type ProjectsProviderProps = { }; const ProjectsContextProvider: React.FC = ({ children }) => { - const [preferredProject, setPreferredProject] = - React.useState(null); const [projectData, loaded, loadError] = useProjects(); const { dashboardNamespace } = useDashboardNamespace(); + const { altPreferredProject } = React.useContext(AppContext); + const [pageProjects, setPageProjects] = React.useState<{ [key: string]: ProjectKind | null }>({}); + + const getPreferredProject = React.useCallback( + (page: string) => pageProjects[!altPreferredProject ? page : '__preferredProject'] ?? null, + [altPreferredProject, pageProjects], + ); + const updatePreferredProject = React.useCallback( + (page: string, projectName: string | null) => { + const project = projectData.find((p) => p.metadata.name === projectName); + setPageProjects((prev) => { + const projects = { ...prev }; + projects[!altPreferredProject ? page : '__preferredProject'] = project || null; + return projects; + }); + }, + [altPreferredProject, projectData], + ); const { projects, modelServingProjects, nonActiveProjects } = React.useMemo( () => @@ -121,8 +139,8 @@ const ProjectsContextProvider: React.FC = ({ children }) projects: projects.toSorted(projectSorter), modelServingProjects: modelServingProjects.toSorted(projectSorter), nonActiveProjects: nonActiveProjects.toSorted(projectSorter), - preferredProject, - updatePreferredProject: setPreferredProject, + getPreferredProject, + updatePreferredProject, loaded, loadError, waitForProject, @@ -131,8 +149,8 @@ const ProjectsContextProvider: React.FC = ({ children }) projects, modelServingProjects, nonActiveProjects, - preferredProject, - setPreferredProject, + getPreferredProject, + updatePreferredProject, loaded, loadError, waitForProject, diff --git a/frontend/src/concepts/projects/useSyncPreferredProject.tsx b/frontend/src/concepts/projects/useSyncPreferredProject.tsx index e357c78d81..47cab7e3fb 100644 --- a/frontend/src/concepts/projects/useSyncPreferredProject.tsx +++ b/frontend/src/concepts/projects/useSyncPreferredProject.tsx @@ -2,14 +2,15 @@ import * as React from 'react'; import { ProjectsContext } from '~/concepts/projects/ProjectsContext'; import { ProjectKind } from '~/k8sTypes'; -const useSyncPreferredProject = (newPreferredProject: ProjectKind | null): void => { - const { preferredProject, updatePreferredProject } = React.useContext(ProjectsContext); +const useSyncPreferredProject = (page: string, newPreferredProject: ProjectKind | null): void => { + const { getPreferredProject, updatePreferredProject } = React.useContext(ProjectsContext); + const preferredProject = getPreferredProject(page); React.useEffect(() => { if (newPreferredProject?.metadata.name !== preferredProject?.metadata.name) { - updatePreferredProject(newPreferredProject); + updatePreferredProject(page, newPreferredProject?.metadata.name || null); } - }, [newPreferredProject, preferredProject, updatePreferredProject]); + }, [page, newPreferredProject, preferredProject, updatePreferredProject]); }; export default useSyncPreferredProject; diff --git a/frontend/src/pages/clusterStorage/GlobalClusterStoragePage.tsx b/frontend/src/pages/clusterStorage/GlobalClusterStoragePage.tsx index 9919a022e7..8872433243 100644 --- a/frontend/src/pages/clusterStorage/GlobalClusterStoragePage.tsx +++ b/frontend/src/pages/clusterStorage/GlobalClusterStoragePage.tsx @@ -6,7 +6,8 @@ import { ProjectsContext } from '~/concepts/projects/ProjectsContext'; import StorageList from '~/pages/projects/screens/detail/storage/StorageList'; const GlobalClusterStoragePage: React.FC = () => { - const { projects, preferredProject, updatePreferredProject } = React.useContext(ProjectsContext); + const { getPreferredProject, updatePreferredProject } = React.useContext(ProjectsContext); + const preferredProject = getPreferredProject('cluster-storage'); const navigate = useNavigate(); return ( @@ -17,8 +18,7 @@ const GlobalClusterStoragePage: React.FC = () => { selectAllProjects invalidDropdownPlaceholder="All projects" onSelection={(projectName) => { - const project = projects.find((p) => p.metadata.name === projectName); - updatePreferredProject(project || null); + updatePreferredProject('cluster-storage', projectName); navigate('/clusterStorage'); }} namespace={preferredProject?.metadata.name ?? 'all-projects'} diff --git a/frontend/src/pages/connections/GlobalConnectionsPage.tsx b/frontend/src/pages/connections/GlobalConnectionsPage.tsx index 6806842a8f..81c1441970 100644 --- a/frontend/src/pages/connections/GlobalConnectionsPage.tsx +++ b/frontend/src/pages/connections/GlobalConnectionsPage.tsx @@ -6,7 +6,8 @@ import { ProjectsContext } from '~/concepts/projects/ProjectsContext'; import ConnectionsList from '~/pages/projects/screens/detail/connections/ConnectionsList'; const GlobalConnectionsPage: React.FC = () => { - const { projects, preferredProject, updatePreferredProject } = React.useContext(ProjectsContext); + const { getPreferredProject, updatePreferredProject } = React.useContext(ProjectsContext); + const preferredProject = getPreferredProject('connections'); const navigate = useNavigate(); return ( @@ -17,8 +18,7 @@ const GlobalConnectionsPage: React.FC = () => { selectAllProjects invalidDropdownPlaceholder="All projects" onSelection={(projectName) => { - const project = projects.find((p) => p.metadata.name === projectName); - updatePreferredProject(project || null); + updatePreferredProject('connections', projectName); navigate('/connections'); }} namespace={preferredProject?.metadata.name ?? 'all-projects'} diff --git a/frontend/src/pages/distributedWorkloads/global/GlobalDistributedWorkloads.tsx b/frontend/src/pages/distributedWorkloads/global/GlobalDistributedWorkloads.tsx index 4f9a03e134..df8b133f29 100644 --- a/frontend/src/pages/distributedWorkloads/global/GlobalDistributedWorkloads.tsx +++ b/frontend/src/pages/distributedWorkloads/global/GlobalDistributedWorkloads.tsx @@ -26,7 +26,8 @@ const GlobalDistributedWorkloads: React.FC = ({ getInvalidRedirectPath, }) => { const { namespace } = useParams<{ namespace: string }>(); - const { projects, preferredProject } = React.useContext(ProjectsContext); + const { projects, getPreferredProject } = React.useContext(ProjectsContext); + const preferredProject = getPreferredProject('distributed-workloads'); if (projects.length === 0) { return ( @@ -52,7 +53,11 @@ const GlobalDistributedWorkloads: React.FC = ({ loaded empty emptyStatePage={ - + } /> ); @@ -67,6 +72,7 @@ const GlobalDistributedWorkloads: React.FC = ({ empty={false} headerContent={ `/distributedWorkloads/${activeTab.path}/${ns}`} showTitle /> diff --git a/frontend/src/pages/modelServing/ModelServingContext.tsx b/frontend/src/pages/modelServing/ModelServingContext.tsx index 4d9fc75bf7..e76cb9e7b5 100644 --- a/frontend/src/pages/modelServing/ModelServingContext.tsx +++ b/frontend/src/pages/modelServing/ModelServingContext.tsx @@ -75,9 +75,10 @@ const ModelServingContextProvider = conditionalArea { const { dashboardNamespace } = useDashboardNamespace(); const navigate = useNavigate(); - const { projects, preferredProject } = React.useContext(ProjectsContext); + const { projects, getPreferredProject } = React.useContext(ProjectsContext); + const preferredProject = getPreferredProject('model-serving'); const project = projects.find(byName(namespace)) ?? null; - useSyncPreferredProject(project); + useSyncPreferredProject('model-serving', project); const servingRuntimeTemplates = useTemplates(dashboardNamespace); const servingRuntimeTemplateOrder = useContextResourceData( diff --git a/frontend/src/pages/modelServing/screens/global/GlobalModelServingCoreLoader.tsx b/frontend/src/pages/modelServing/screens/global/GlobalModelServingCoreLoader.tsx index 07c8541863..7661865828 100644 --- a/frontend/src/pages/modelServing/screens/global/GlobalModelServingCoreLoader.tsx +++ b/frontend/src/pages/modelServing/screens/global/GlobalModelServingCoreLoader.tsx @@ -20,7 +20,8 @@ const GlobalModelServingCoreLoader: React.FC getInvalidRedirectPath, }) => { const { namespace } = useParams<{ namespace: string }>(); - const { projects, preferredProject } = React.useContext(ProjectsContext); + const { projects, getPreferredProject } = React.useContext(ProjectsContext); + const preferredProject = getPreferredProject('model-serving'); let renderStateProps: ApplicationPageRenderState & { children?: React.ReactNode }; if (projects.length === 0) { @@ -43,7 +44,11 @@ const GlobalModelServingCoreLoader: React.FC renderStateProps = { empty: true, emptyStatePage: ( - + ), }; } else { diff --git a/frontend/src/pages/modelServing/screens/global/ModelServingProjectSelection.tsx b/frontend/src/pages/modelServing/screens/global/ModelServingProjectSelection.tsx index 19cd3b4dcc..c65b906fd6 100644 --- a/frontend/src/pages/modelServing/screens/global/ModelServingProjectSelection.tsx +++ b/frontend/src/pages/modelServing/screens/global/ModelServingProjectSelection.tsx @@ -9,6 +9,7 @@ const ModelServingProjectSelection: React.FC getRedirectPath, }) => ( { - const { projects, preferredProject, updatePreferredProject } = React.useContext(ProjectsContext); + const { getPreferredProject, updatePreferredProject } = React.useContext(ProjectsContext); + const preferredProject = getPreferredProject('notebooks'); const navigate = useNavigate(); return ( @@ -18,8 +19,7 @@ const GlobalNotebooksPage: React.FC = () => { selectAllProjects invalidDropdownPlaceholder="All projects" onSelection={(projectName) => { - const project = projects.find((p) => p.metadata.name === projectName); - updatePreferredProject(project || null); + updatePreferredProject('notebooks', projectName); navigate('/workbenches'); }} namespace={preferredProject?.metadata.name ?? 'all-projects'} diff --git a/frontend/src/pages/pipelines/GlobalArtifactsRoutes.tsx b/frontend/src/pages/pipelines/GlobalArtifactsRoutes.tsx index cedbd549ad..caf5893ae9 100644 --- a/frontend/src/pages/pipelines/GlobalArtifactsRoutes.tsx +++ b/frontend/src/pages/pipelines/GlobalArtifactsRoutes.tsx @@ -3,7 +3,7 @@ import { Navigate, Route } from 'react-router-dom'; import ProjectsRoutes from '~/concepts/projects/ProjectsRoutes'; import GlobalPipelineCoreLoader from '~/pages/pipelines/global/GlobalPipelineCoreLoader'; -import { artifactsBaseRoute } from '~/routes'; +import { artifactsBaseRoute, artifactsRootPath } from '~/routes'; import { GlobalArtifactsPage } from './global/experiments/artifacts'; import GlobalPipelineCoreDetails from './global/GlobalPipelineCoreDetails'; import { ArtifactDetails } from './global/experiments/artifacts/ArtifactDetails'; @@ -12,7 +12,12 @@ const GlobalArtifactsRoutes: React.FC = () => ( } + element={ + + } > } /> ( path="/:namespace?/*" element={ ( path="/:namespace?/*" element={ ( path={globNamespaceAll} element={ ( path={globNamespaceAll} element={ ; type EmptyStateProps = 'emptyStatePage' | 'empty'; type GlobalPipelineCoreLoaderProps = { + page: string; getInvalidRedirectPath: (namespace: string) => string; } & Omit< ApplicationPageProps, @@ -20,11 +21,13 @@ type GlobalPipelineCoreLoaderProps = { type ApplicationPageRenderState = Pick; const GlobalPipelineCoreLoader: React.FC = ({ + page, getInvalidRedirectPath, ...applicationPageProps }) => { const { namespace } = useParams<{ namespace: string }>(); - const { projects, preferredProject } = React.useContext(ProjectsContext); + const { projects, getPreferredProject } = React.useContext(ProjectsContext); + const preferredProject = getPreferredProject(page); let renderStateProps: ApplicationPageRenderState & { children?: React.ReactNode }; if (projects.length === 0) { @@ -47,7 +50,11 @@ const GlobalPipelineCoreLoader: React.FC = ({ renderStateProps = { empty: true, emptyStatePage: ( - + ), }; } else { @@ -61,7 +68,9 @@ const GlobalPipelineCoreLoader: React.FC = ({ {...applicationPageProps} {...renderStateProps} loaded - headerContent={} + headerContent={ + + } provideChildrenPadding /> ); diff --git a/frontend/src/pages/pipelines/global/PipelineCoreApplicationPage.tsx b/frontend/src/pages/pipelines/global/PipelineCoreApplicationPage.tsx index cc56beb718..95f3d6efcd 100644 --- a/frontend/src/pages/pipelines/global/PipelineCoreApplicationPage.tsx +++ b/frontend/src/pages/pipelines/global/PipelineCoreApplicationPage.tsx @@ -13,6 +13,7 @@ import ProjectLink from '~/concepts/projects/ProjectLink'; export type PipelineCoreApplicationPageProps = { children: React.ReactNode; + page: string; getRedirectPath: (namespace: string) => string; showProjectSelector?: boolean; overrideChildPadding?: boolean; @@ -23,6 +24,7 @@ export type PipelineCoreApplicationPageProps = { const PipelineCoreApplicationPage: React.FC = ({ children, + page, getRedirectPath, overrideChildPadding, showProjectSelector = true, @@ -54,7 +56,7 @@ const PipelineCoreApplicationPage: React.FC = emptyStatePage={} headerContent={ showProjectSelector ? ( - + ) : null } provideChildrenPadding={!overrideChildPadding} diff --git a/frontend/src/pages/pipelines/global/PipelineCoreProjectSelector.tsx b/frontend/src/pages/pipelines/global/PipelineCoreProjectSelector.tsx index c0302e7d14..7af736b564 100644 --- a/frontend/src/pages/pipelines/global/PipelineCoreProjectSelector.tsx +++ b/frontend/src/pages/pipelines/global/PipelineCoreProjectSelector.tsx @@ -2,11 +2,13 @@ import * as React from 'react'; import ProjectSelectorNavigator from '~/concepts/projects/ProjectSelectorNavigator'; type PipelineCoreProjectSelectorProps = { + page: string; getRedirectPath: (namespace: string) => string; }; const PipelineCoreProjectSelector: React.FC = ({ + page, getRedirectPath, -}) => ; +}) => ; export default PipelineCoreProjectSelector; diff --git a/frontend/src/pages/pipelines/global/experiments/ExperimentPipelineRuns.tsx b/frontend/src/pages/pipelines/global/experiments/ExperimentPipelineRuns.tsx index 04656f655a..8936384932 100644 --- a/frontend/src/pages/pipelines/global/experiments/ExperimentPipelineRuns.tsx +++ b/frontend/src/pages/pipelines/global/experiments/ExperimentPipelineRuns.tsx @@ -14,7 +14,7 @@ import { ExperimentContext, useContextExperimentArchivedOrDeleted, } from '~/pages/pipelines/global/experiments/ExperimentContext'; -import { experimentsBaseRoute } from '~/routes'; +import { experimentsBaseRoute, experimentsRootPath } from '~/routes'; const ExperimentPipelineRuns: PipelineCoreDetailsPageComponent = ({ breadcrumbPath }) => { const { experiment } = React.useContext(ExperimentContext); @@ -22,6 +22,7 @@ const ExperimentPipelineRuns: PipelineCoreDetailsPageComponent = ({ breadcrumbPa return ( } diff --git a/frontend/src/pages/pipelines/global/experiments/GlobalExperiments.tsx b/frontend/src/pages/pipelines/global/experiments/GlobalExperiments.tsx index e53bf51975..4ad7c8b67d 100644 --- a/frontend/src/pages/pipelines/global/experiments/GlobalExperiments.tsx +++ b/frontend/src/pages/pipelines/global/experiments/GlobalExperiments.tsx @@ -5,7 +5,7 @@ import PipelineCoreApplicationPage from '~/pages/pipelines/global/PipelineCoreAp import EnsureAPIAvailability from '~/concepts/pipelines/EnsureAPIAvailability'; import PipelineAndVersionContextProvider from '~/concepts/pipelines/content/PipelineAndVersionContext'; import EnsureCompatiblePipelineServer from '~/concepts/pipelines/EnsureCompatiblePipelineServer'; -import { experimentsBaseRoute } from '~/routes'; +import { experimentsBaseRoute, experimentsRootPath } from '~/routes'; import { ProjectObjectType } from '~/concepts/design/utils'; import TitleWithIcon from '~/concepts/design/TitleWithIcon'; import { ExperimentListTabs, experimentsPageDescription, experimentsPageTitle } from './const'; @@ -20,6 +20,7 @@ const GlobalExperiments: React.FC = ({ tab }) => { return ( { return ( } description="View your artifacts and their metadata." headerAction={} diff --git a/frontend/src/pages/pipelines/global/experiments/executions/GlobalExecutions.tsx b/frontend/src/pages/pipelines/global/experiments/executions/GlobalExecutions.tsx index d7e41f2dbc..35933ce890 100644 --- a/frontend/src/pages/pipelines/global/experiments/executions/GlobalExecutions.tsx +++ b/frontend/src/pages/pipelines/global/experiments/executions/GlobalExecutions.tsx @@ -5,7 +5,7 @@ import PipelineServerActions from '~/concepts/pipelines/content/PipelineServerAc import PipelineCoreApplicationPage from '~/pages/pipelines/global/PipelineCoreApplicationPage'; import EnsureAPIAvailability from '~/concepts/pipelines/EnsureAPIAvailability'; import EnsureCompatiblePipelineServer from '~/concepts/pipelines/EnsureCompatiblePipelineServer'; -import { executionsBaseRoute } from '~/routes'; +import { executionsBaseRoute, executionsRootPath } from '~/routes'; import { executionsPageDescription, executionsPageTitle, @@ -19,6 +19,7 @@ const GlobalExecutions: React.FC = () => { return ( { return ( } description={pipelinesPageDescription} headerAction={} diff --git a/frontend/src/pages/pipelines/global/runs/GlobalPipelineRuns.tsx b/frontend/src/pages/pipelines/global/runs/GlobalPipelineRuns.tsx index 5677869f3b..738fe91daf 100644 --- a/frontend/src/pages/pipelines/global/runs/GlobalPipelineRuns.tsx +++ b/frontend/src/pages/pipelines/global/runs/GlobalPipelineRuns.tsx @@ -4,7 +4,7 @@ import PipelineServerActions from '~/concepts/pipelines/content/PipelineServerAc import PipelineCoreApplicationPage from '~/pages/pipelines/global/PipelineCoreApplicationPage'; import EnsureAPIAvailability from '~/concepts/pipelines/EnsureAPIAvailability'; import EnsureCompatiblePipelineServer from '~/concepts/pipelines/EnsureCompatiblePipelineServer'; -import { pipelineRunsBaseRoute } from '~/routes'; +import { pipelineRunsBaseRoute, pipelineRunsRootPath } from '~/routes'; import { ProjectObjectType } from '~/concepts/design/utils'; import TitleWithIcon from '~/concepts/design/TitleWithIcon'; import { @@ -26,6 +26,7 @@ const GlobalPipelineRuns: React.FC = ({ tab }) => { return ( } diff --git a/frontend/src/pages/projects/ProjectDetailsContext.tsx b/frontend/src/pages/projects/ProjectDetailsContext.tsx index b8b66299a4..7aa00f4f00 100644 --- a/frontend/src/pages/projects/ProjectDetailsContext.tsx +++ b/frontend/src/pages/projects/ProjectDetailsContext.tsx @@ -80,9 +80,10 @@ const ProjectDetailsContextProvider: React.FC { const { dashboardNamespace } = useDashboardNamespace(); const { namespace } = useParams(); - const { projects, loaded, preferredProject } = React.useContext(ProjectsContext); + const { projects, loaded, getPreferredProject } = React.useContext(ProjectsContext); + const preferredProject = getPreferredProject('project-details'); const project = projects.find(byName(namespace)) ?? null; - useSyncPreferredProject(project); + useSyncPreferredProject('project-details', project); const notebooks = useContextResourceData( useProjectNotebookStates(namespace, true), ); @@ -174,6 +175,7 @@ const ProjectDetailsContextProvider: React.FC `/projects/${ns}`}