From 79f6ba3016b4dace6e0f3029c278bf864546f4a9 Mon Sep 17 00:00:00 2001 From: Juntao Wang Date: Wed, 15 Nov 2023 14:26:01 -0500 Subject: [PATCH] Use sync preferred project when switching to global model serving page --- .../ModelServingGlobal.stories.tsx | 1 - .../src/concepts/projects/ProjectSelector.tsx | 12 +++---- .../projects/ProjectSelectorNavigator.tsx | 4 +-- .../src/concepts/projects/ProjectsContext.tsx | 2 +- frontend/src/k8sTypes.ts | 1 - .../modelServing/ModelServingContext.tsx | 5 +++ .../screens/global/ModelServingGlobal.tsx | 36 ++++++++++--------- .../global/ModelServingProjectSelection.tsx | 5 +-- .../screens/detail/DetailsSection.tsx | 4 +-- 9 files changed, 36 insertions(+), 34 deletions(-) diff --git a/frontend/src/__tests__/integration/pages/modelServing/ModelServingGlobal.stories.tsx b/frontend/src/__tests__/integration/pages/modelServing/ModelServingGlobal.stories.tsx index a0598e3e0e..ad72d908c6 100644 --- a/frontend/src/__tests__/integration/pages/modelServing/ModelServingGlobal.stories.tsx +++ b/frontend/src/__tests__/integration/pages/modelServing/ModelServingGlobal.stories.tsx @@ -3,7 +3,6 @@ import React from 'react'; import { StoryFn, Meta, StoryObj } from '@storybook/react'; import { rest } from 'msw'; import { within, userEvent } from '@storybook/testing-library'; -// import { expect } from '@storybook/jest'; import { Route, Routes } from 'react-router-dom'; import { Spinner } from '@patternfly/react-core'; import { mockK8sResourceList } from '~/__mocks__/mockK8sResourceList'; diff --git a/frontend/src/concepts/projects/ProjectSelector.tsx b/frontend/src/concepts/projects/ProjectSelector.tsx index b30511a807..2145b6a4c6 100644 --- a/frontend/src/concepts/projects/ProjectSelector.tsx +++ b/frontend/src/concepts/projects/ProjectSelector.tsx @@ -3,10 +3,9 @@ import { Dropdown, DropdownItem, DropdownToggle } from '@patternfly/react-core'; import { getProjectDisplayName } from '~/pages/projects/utils'; import { byName, ProjectsContext } from '~/concepts/projects/ProjectsContext'; import useMountProjectRefresh from '~/concepts/projects/useMountProjectRefresh'; -import { ProjectKind } from '~/k8sTypes'; type ProjectSelectorProps = { - onSelection: (project: ProjectKind) => void; + onSelection: (projectName: string) => void; namespace: string; invalidDropdownPlaceholder?: string; selectAllProjects?: boolean; @@ -22,7 +21,7 @@ const ProjectSelector: React.FC = ({ primary, filterLabel, }) => { - const { projects } = React.useContext(ProjectsContext); + const { projects, updatePreferredProject } = React.useContext(ProjectsContext); useMountProjectRefresh(); const selection = projects.find(byName(namespace)); const [dropdownOpen, setDropdownOpen] = React.useState(false); @@ -54,10 +53,11 @@ const ProjectSelector: React.FC = ({ key={'all-projects'} onClick={() => { setDropdownOpen(false); - onSelection({ metadata: { name: '' } } as ProjectKind); + onSelection(''); + updatePreferredProject(null); }} > - {'All projects'} + All projects , ] : []), @@ -66,7 +66,7 @@ const ProjectSelector: React.FC = ({ key={project.metadata.name} onClick={() => { setDropdownOpen(false); - onSelection(project); + onSelection(project.metadata.name); }} > {getProjectDisplayName(project)} diff --git a/frontend/src/concepts/projects/ProjectSelectorNavigator.tsx b/frontend/src/concepts/projects/ProjectSelectorNavigator.tsx index e485fc2ca2..a682863959 100644 --- a/frontend/src/concepts/projects/ProjectSelectorNavigator.tsx +++ b/frontend/src/concepts/projects/ProjectSelectorNavigator.tsx @@ -16,8 +16,8 @@ const ProjectSelectorNavigator: React.FC = ({ return ( { - navigate(getRedirectPath(project.metadata.name)); + onSelection={(projectName) => { + navigate(getRedirectPath(projectName)); }} namespace={namespace ?? ''} /> diff --git a/frontend/src/concepts/projects/ProjectsContext.tsx b/frontend/src/concepts/projects/ProjectsContext.tsx index 94202b1cc6..91212af5a6 100644 --- a/frontend/src/concepts/projects/ProjectsContext.tsx +++ b/frontend/src/concepts/projects/ProjectsContext.tsx @@ -19,7 +19,7 @@ type ProjectsContext = { * Allows for navigation to be unimpeded by project selection * @see useSyncPreferredProject */ - updatePreferredProject: (project: ProjectKind) => void; + updatePreferredProject: (project: ProjectKind | null) => void; refresh: (waitForName?: string) => Promise; // ...the rest of the state variables diff --git a/frontend/src/k8sTypes.ts b/frontend/src/k8sTypes.ts index ef343aacbd..adb3cd4a46 100644 --- a/frontend/src/k8sTypes.ts +++ b/frontend/src/k8sTypes.ts @@ -294,7 +294,6 @@ export type PodKind = K8sResourceCommon & { }; }; -/** Assumed Dashboard Project -- if we need more beyond that we should break this type up */ export type ProjectKind = K8sResourceCommon & { metadata: { annotations?: DisplayNameAnnotations & diff --git a/frontend/src/pages/modelServing/ModelServingContext.tsx b/frontend/src/pages/modelServing/ModelServingContext.tsx index 1d8f38f34b..4ee5ac953d 100644 --- a/frontend/src/pages/modelServing/ModelServingContext.tsx +++ b/frontend/src/pages/modelServing/ModelServingContext.tsx @@ -18,6 +18,8 @@ import { useContextResourceData } from '~/utilities/useContextResourceData'; import { useDashboardNamespace } from '~/redux/selectors'; import { DataConnection } from '~/pages/projects/types'; import useDataConnections from '~/pages/projects/screens/detail/data-connections/useDataConnections'; +import useSyncPreferredProject from '~/concepts/projects/useSyncPreferredProject'; +import { ProjectsContext, byName } from '~/concepts/projects/ProjectsContext'; import useInferenceServices from './useInferenceServices'; import useServingRuntimes from './useServingRuntimes'; import useTemplates from './customServingRuntimes/useTemplates'; @@ -48,6 +50,9 @@ const ModelServingContextProvider: React.FC = () => { const { dashboardNamespace } = useDashboardNamespace(); const navigate = useNavigate(); const { namespace } = useParams<{ namespace: string }>(); + const { projects } = React.useContext(ProjectsContext); + const project = projects.find(byName(namespace)) ?? null; + useSyncPreferredProject(project); const servingRuntimeTemplates = useContextResourceData( useTemplates(dashboardNamespace), ); diff --git a/frontend/src/pages/modelServing/screens/global/ModelServingGlobal.tsx b/frontend/src/pages/modelServing/screens/global/ModelServingGlobal.tsx index 10add0b155..79dc66d2f7 100644 --- a/frontend/src/pages/modelServing/screens/global/ModelServingGlobal.tsx +++ b/frontend/src/pages/modelServing/screens/global/ModelServingGlobal.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useParams } from 'react-router-dom'; +import { Navigate, useParams } from 'react-router-dom'; import ApplicationsPage from '~/pages/ApplicationsPage'; import { ModelServingContext } from '~/pages/modelServing/ModelServingContext'; import useServingPlatformStatuses from '~/pages/modelServing/useServingPlatformStatuses'; @@ -21,7 +21,9 @@ const ModelServingGlobal: React.FC = () => { servingRuntimes: { data: servingRuntimes }, inferenceServices: { data: inferenceServices }, } = React.useContext(ModelServingContext); - const { dataScienceProjects: projects } = React.useContext(ProjectsContext); + const { projects, preferredProject } = React.useContext(ProjectsContext); + + const getRedirectPath = (projectName: string) => `/modelServing/${projectName}`; const { namespace } = useParams<{ namespace: string }>(); const currentProject = projects.find(byName(namespace)); @@ -58,16 +60,20 @@ const ModelServingGlobal: React.FC = () => { emptyStatePage: , }; } - if (namespace && !currentProject) { - renderStateProps = { - empty: true, - emptyStatePage: ( - `/modelServing/${namespace}`} - /> - ), - }; + if (namespace) { + if (!currentProject) { + renderStateProps = { + empty: true, + emptyStatePage: ( + + ), + }; + } + } else { + // Redirect the namespace suffix into the URL + if (preferredProject) { + return ; + } } } @@ -78,11 +84,7 @@ const ModelServingGlobal: React.FC = () => { description="Manage and view the health and performance of your deployed models." loadError={loadError} loaded - headerContent={ - `/modelServing/${namespace}`} - /> - } + headerContent={} provideChildrenPadding > string; @@ -15,12 +14,10 @@ const ModelServingProjectSelection: React.FC Project - {/* Maybe we want to filter the projects with no deployed models that's why I added the filterLable prop */} diff --git a/frontend/src/pages/projects/screens/detail/DetailsSection.tsx b/frontend/src/pages/projects/screens/detail/DetailsSection.tsx index 7119d18320..7307aeb60a 100644 --- a/frontend/src/pages/projects/screens/detail/DetailsSection.tsx +++ b/frontend/src/pages/projects/screens/detail/DetailsSection.tsx @@ -18,8 +18,8 @@ type DetailsSectionProps = { title: string; isLoading: boolean; loadError?: Error; - isEmpty?: boolean; - emptyState?: React.ReactNode; + isEmpty: boolean; + emptyState: React.ReactNode; children: React.ReactNode; labels?: React.ReactNode[]; showDivider?: boolean;