Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] RHOAI.next IA Study #3215

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const blankDashboardCR: DashboardConfig = {
disablePipelineExperiments: false,
disableDistributedWorkloads: false,
disableModelRegistry: true,
disableConnectionTypes: true,
disableConnectionTypes: false,
disableStorageClasses: true,
},
notebookController: {
Expand Down
50 changes: 25 additions & 25 deletions frontend/src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,36 +107,36 @@ const App: React.FC = () => {
</Bullseye>
) : (
<AppContext.Provider value={contextValue}>
<Page
className="odh-dashboard"
isManagedSidebar
header={
<Header onNotificationsClick={() => setNotificationsOpen(!notificationsOpen)} />
}
sidebar={isAllowed ? <NavSidebar /> : undefined}
notificationDrawer={
<AppNotificationDrawer onClose={() => setNotificationsOpen(false)} />
}
isNotificationDrawerExpanded={notificationsOpen}
mainContainerId={DASHBOARD_MAIN_CONTAINER_ID}
data-testid={DASHBOARD_MAIN_CONTAINER_ID}
>
<ErrorBoundary>
<DevFeatureFlagsBanner
dashboardConfig={dashboardConfig.spec.dashboardConfig}
{...devFeatureFlagsProps}
/>
<ProjectsContextProvider>
<ProjectsContextProvider>
<Page
className="odh-dashboard"
isManagedSidebar
header={
<Header onNotificationsClick={() => setNotificationsOpen(!notificationsOpen)} />
}
sidebar={isAllowed ? <NavSidebar /> : undefined}
notificationDrawer={
<AppNotificationDrawer onClose={() => setNotificationsOpen(false)} />
}
isNotificationDrawerExpanded={notificationsOpen}
mainContainerId={DASHBOARD_MAIN_CONTAINER_ID}
data-testid={DASHBOARD_MAIN_CONTAINER_ID}
>
<ErrorBoundary>
<DevFeatureFlagsBanner
dashboardConfig={dashboardConfig.spec.dashboardConfig}
{...devFeatureFlagsProps}
/>
<ModelRegistrySelectorContextProvider>
<QuickStarts>
<AppRoutes />
</QuickStarts>
</ModelRegistrySelectorContextProvider>
</ProjectsContextProvider>
<ToastNotifications />
<TelemetrySetup />
</ErrorBoundary>
</Page>
<ToastNotifications />
<TelemetrySetup />
</ErrorBoundary>
</Page>
</ProjectsContextProvider>
</AppContext.Provider>
)}
</AreaContextProvider>
Expand Down
10 changes: 4 additions & 6 deletions frontend/src/app/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { SupportedArea } from '~/concepts/areas';
import useIsAreaAvailable from '~/concepts/areas/useIsAreaAvailable';
import ModelRegistrySettingsRoutes from '~/pages/modelRegistrySettings/ModelRegistrySettingsRoutes';
import ConnectionTypeRoutes from '~/pages/connectionTypes/ConnectionTypeRoutes';
import ComingSoonPage from '~/pages/ComingSoonPage';

const HomePage = React.lazy(() => import('../pages/home/Home'));

Expand Down Expand Up @@ -43,10 +44,6 @@ const GlobalPipelineExecutionsRoutes = React.lazy(

const GlobalArtifactsRoutes = React.lazy(() => import('../pages/pipelines/GlobalArtifactsRoutes'));

const GlobalDistributedWorkloadsRoutes = React.lazy(
() => import('../pages/distributedWorkloads/GlobalDistributedWorkloadsRoutes'),
);

const ClusterSettingsPage = React.lazy(() => import('../pages/clusterSettings/ClusterSettings'));
const CustomServingRuntimeRoutes = React.lazy(
() => import('../pages/modelServing/customServingRuntimes/CustomServingRuntimeRoutes'),
Expand Down Expand Up @@ -94,7 +91,10 @@ const AppRoutes: React.FC = () => {
) : (
<Route path="/" element={<InstalledApplications />} />
)}
<Route path="/models" element={<ComingSoonPage title="All models" />} />
<Route path="/monitorModels" element={<ComingSoonPage title="Monitor" />} />
<Route path="/explore" element={<ExploreApplications />} />
<Route path="/features" element={<ComingSoonPage title="Features" />} />
<Route path="/resources" element={<LearningCenterPage />} />

<Route path="/projects/*" element={<ProjectViewRoutes />} />
Expand All @@ -117,8 +117,6 @@ const AppRoutes: React.FC = () => {
<Route path={globArtifactsAll} element={<GlobalArtifactsRoutes />} />
<Route path={globExecutionsAll} element={<GlobalPipelineExecutionsRoutes />} />

<Route path="/distributedWorkloads/*" element={<GlobalDistributedWorkloadsRoutes />} />

<Route path="/dependency-missing/:area" element={<DependencyMissingPage />} />

{isAdmin && (
Expand Down
79 changes: 64 additions & 15 deletions frontend/src/app/NavSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,58 @@ import {
Nav,
NavExpandable,
NavItem,
NavGroup as PfNavGroup,
NavList,
PageSidebar,
PageSidebarBody,
} from '@patternfly/react-core';
import { isNavDataGroup, NavDataGroup, NavDataHref, useBuildNavData } from '~/utilities/NavData';
import {
isNavDataGroup,
isNavDataSection,
NavDataGroup,
NavDataHref,
NavDataSection,
useBuildNavData,
} from '~/utilities/NavData';
import { ProjectsContext } from '~/concepts/projects/ProjectsContext';

const checkLinkActiveStatus = (pathname: string, href: string) =>
href.split('/')[1] === pathname.split('/')[1];
const checkLinkActiveStatus = (pathname: string, href: string, namespace?: string) => {
if (!namespace) {
return href.split('/')[1] === pathname.split('/')[1];
}

const NavHref: React.FC<{ item: NavDataHref; pathname: string }> = ({ item, pathname }) => (
<NavItem
key={item.id}
data-id={item.id}
itemId={item.id}
isActive={checkLinkActiveStatus(pathname, item.href)}
>
<Link to={item.href}>{item.label}</Link>
</NavItem>
);
const splits = href.split('/');
const itemIdentifier = splits[splits.length - 1];

let pathSplits = pathname.split('/');
if (pathSplits[pathSplits.length - 2] === 'projects') {
pathSplits = pathSplits.slice(0, -1);
}
const pathIdentifier = pathSplits[pathSplits.length - 1];

return itemIdentifier ? (pathIdentifier || '/').includes(itemIdentifier) : !pathIdentifier;
};

const NavHref: React.FC<{ item: NavDataHref; pathname: string }> = ({ item, pathname }) => {
const { preferredProject } = React.useContext(ProjectsContext);
return (
<NavItem
key={item.id}
data-id={item.id}
itemId={item.id}
isActive={checkLinkActiveStatus(pathname, item.href, preferredProject?.metadata.name)}
>
<Link to={item.href}>{item.label}</Link>
</NavItem>
);
};

const NavGroup: React.FC<{ item: NavDataGroup; pathname: string }> = ({ item, pathname }) => {
const { group, children } = item;
const isActive = !!children.find((c) => checkLinkActiveStatus(pathname, c.href));
const { preferredProject } = React.useContext(ProjectsContext);
const isActive = !!children.find((c) =>
checkLinkActiveStatus(pathname, c.href, preferredProject?.metadata.name),
);
const [expanded, setExpanded] = React.useState(isActive);

// Whenever the group becomes active, it should also be expanded
Expand Down Expand Up @@ -55,6 +84,24 @@ const NavGroup: React.FC<{ item: NavDataGroup; pathname: string }> = ({ item, pa
);
};

const NavSection: React.FC<{ item: NavDataSection; pathname: string }> = ({ item, pathname }) => (
<PfNavGroup
data-id={item.section.id}
key={item.section.id}
id={item.section.id}
title={item.section.title}
aria-label={item.section.title}
>
{item.children.map((childItem) =>
isNavDataGroup(childItem) ? (
<NavGroup key={childItem.id} item={childItem} pathname={pathname} />
) : (
<NavHref key={childItem.id} data-id={childItem.id} item={childItem} pathname={pathname} />
),
)}
</PfNavGroup>
);

const NavSidebar: React.FC = () => {
const routerLocation = useLocation();
const userNavData = useBuildNavData();
Expand All @@ -65,7 +112,9 @@ const NavSidebar: React.FC = () => {
<Nav theme="dark" aria-label="Nav">
<NavList>
{userNavData.map((item) =>
isNavDataGroup(item) ? (
isNavDataSection(item) ? (
<NavSection key={item.id} item={item} pathname={routerLocation.pathname} />
) : isNavDataGroup(item) ? (
<NavGroup key={item.id} item={item} pathname={routerLocation.pathname} />
) : (
<NavHref key={item.id} item={item} pathname={routerLocation.pathname} />
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/searchSelector/SearchSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ const SearchSelector: React.FC<SearchSelectorProps> = ({
isFullWidth={isFullWidth}
data-testid={`${dataTestId}-toggle`}
variant={toggleVariant}
className={toggleVariant === 'plainText' ? 'pf-v5-u-px-0 pf-v5-u-py-sm' : undefined}
>
<Truncate content={toggleText} />
</MenuToggle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { RunTypeOption } from './types';

type CloneRecurringRunPageProps = {
detailsRedirect: (recurringRunId: string) => string;
getProjectRedirectPath: (namespace: string) => string;
contextExperiment?: ExperimentKFv2 | null;
contextPipeline?: PipelineKFv2 | null;
contextPipelineVersion?: PipelineVersionKFv2 | null;
Expand All @@ -20,6 +21,7 @@ const CloneRecurringRunPage: React.FC<PathProps & CloneRecurringRunPageProps> =
breadcrumbPath,
contextPath,
detailsRedirect,
getProjectRedirectPath,
...props
}) => {
const { recurringRunId } = useParams();
Expand Down Expand Up @@ -47,6 +49,7 @@ const CloneRecurringRunPage: React.FC<PathProps & CloneRecurringRunPageProps> =
loaded={loaded}
loadError={error}
empty={false}
getRedirectPath={getProjectRedirectPath}
>
<RunPage
cloneRun={recurringRun}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { RunTypeOption } from './types';

type CloneRunPageProps = {
detailsRedirect: (runId: string) => string;
getProjectRedirectPath: (namespace: string) => string;
contextExperiment?: ExperimentKFv2 | null;
contextPipeline?: PipelineKFv2 | null;
contextPipelineVersion?: PipelineVersionKFv2 | null;
Expand All @@ -20,6 +21,7 @@ const CloneRunPage: React.FC<PathProps & CloneRunPageProps> = ({
breadcrumbPath,
contextPath,
detailsRedirect,
getProjectRedirectPath,
...props
}) => {
const { runId } = useParams();
Expand Down Expand Up @@ -47,6 +49,7 @@ const CloneRunPage: React.FC<PathProps & CloneRunPageProps> = ({
loaded={loaded}
loadError={error}
empty={false}
getRedirectPath={getProjectRedirectPath}
>
<RunPage
cloneRun={run}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ const PipelineDetails: PipelineCoreDetailsPageComponent = ({ breadcrumbPath }) =
})}
empty={false}
loaded={isLoaded}
getRedirectPath={(ns) => `${ns}/pipelines`}
headerAction={
isPipelineVersionLoaded && (
<Flex
Expand Down
29 changes: 8 additions & 21 deletions frontend/src/concepts/projects/ProjectSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from 'react';
import { Bullseye, Divider, Flex, FlexItem, MenuItem, Truncate } from '@patternfly/react-core';
import { Divider, MenuItem, MenuToggle, Truncate } from '@patternfly/react-core';
import { byName, ProjectsContext } from '~/concepts/projects/ProjectsContext';
import { ProjectObjectType, typedObjectImage } from '~/concepts/design/utils';
import { getDisplayNameFromK8sResource } from '~/concepts/k8s/utils';
import SearchSelector from '~/components/searchSelector/SearchSelector';
import { ProjectKind } from '~/k8sTypes';
Expand All @@ -12,6 +11,7 @@ type ProjectSelectorProps = {
invalidDropdownPlaceholder?: string;
selectAllProjects?: boolean;
primary?: boolean;
variant?: React.ComponentProps<typeof MenuToggle>['variant'];
filterLabel?: string;
showTitle?: boolean;
selectorLabel?: string;
Expand All @@ -24,6 +24,7 @@ const ProjectSelector: React.FC<ProjectSelectorProps> = ({
invalidDropdownPlaceholder,
selectAllProjects,
primary,
variant = 'plainText',
filterLabel,
showTitle = false,
selectorLabel = 'Project',
Expand All @@ -48,7 +49,10 @@ const ProjectSelector: React.FC<ProjectSelectorProps> = ({
: projects;
const visibleProjects = filteredProjects.filter(bySearchText);

const toggleLabel = projects.length === 0 ? 'No projects' : selectionDisplayName;
const toggleLabel =
projects.length === 0
? 'No projects'
: `${showTitle ? `${selectorLabel}: ` : ''}${selectionDisplayName}`;
const selector = (
<SearchSelector
dataTestId="project-selector"
Expand All @@ -60,7 +64,7 @@ const ProjectSelector: React.FC<ProjectSelectorProps> = ({
searchPlaceholder="Project name"
searchValue={searchText}
toggleText={toggleLabel}
toggleVariant={primary ? 'primary' : undefined}
toggleVariant={primary ? 'primary' : variant}
>
<>
{selectAllProjects && (
Expand Down Expand Up @@ -96,23 +100,6 @@ const ProjectSelector: React.FC<ProjectSelectorProps> = ({
</SearchSelector>
);

if (showTitle) {
return (
<Flex spaceItems={{ default: 'spaceItemsXs' }} alignItems={{ default: 'alignItemsCenter' }}>
<img
src={typedObjectImage(ProjectObjectType.project)}
alt=""
style={{ height: 'var(--pf-v5-global--icon--FontSize--lg)' }}
/>
<Flex spaceItems={{ default: 'spaceItemsSm' }} alignItems={{ default: 'alignItemsCenter' }}>
<FlexItem>
<Bullseye>{selectorLabel}</Bullseye>
</FlexItem>
<FlexItem>{selector}</FlexItem>
</Flex>
</Flex>
);
}
return selector;
};

Expand Down
Loading
Loading