diff --git a/frontend/src/components/Router.tsx b/frontend/src/components/Router.tsx index aecdb16a4cf9..2c12df73078e 100644 --- a/frontend/src/components/Router.tsx +++ b/frontend/src/components/Router.tsx @@ -46,7 +46,12 @@ import NewPipelineVersion from '../pages/NewPipelineVersion'; import { GettingStarted } from '../pages/GettingStarted'; import { KFP_FLAGS, Deployments } from '../lib/Flags'; -export type RouteConfig = { path: string; Component: React.ComponentType; view?: any }; +export type RouteConfig = { + path: string; + Component: React.ComponentType; + view?: any; + notExact?: boolean; +}; const css = stylesheet({ dialog: { @@ -154,7 +159,7 @@ const Router: React.FC = ({ configs }) => { { path: RoutePage.START, Component: GettingStarted }, { path: RoutePage.ARCHIVE, Component: Archive }, { path: RoutePage.ARTIFACTS, Component: ArtifactList }, - { path: RoutePage.ARTIFACT_DETAILS, Component: ArtifactDetails }, + { path: RoutePage.ARTIFACT_DETAILS, Component: ArtifactDetails, notExact: true }, { path: RoutePage.EXECUTIONS, Component: ExecutionList }, { path: RoutePage.EXECUTION_DETAILS, Component: ExecutionDetails }, { @@ -194,7 +199,7 @@ const Router: React.FC = ({ configs }) => { // network response handlers. } /> @@ -251,7 +256,7 @@ class RoutedPage extends React.Component<{ route?: RouteConfig }, RouteComponent const { path, Component, ...otherProps } = { ...route }; return ( ( diff --git a/frontend/src/components/__snapshots__/Router.test.tsx.snap b/frontend/src/components/__snapshots__/Router.test.tsx.snap index 24a04eed4000..ab74eababf4f 100644 --- a/frontend/src/components/__snapshots__/Router.test.tsx.snap +++ b/frontend/src/components/__snapshots__/Router.test.tsx.snap @@ -27,7 +27,7 @@ exports[`Router initial render 1`] = ` render={[Function]} /> { +class ArtifactDetails extends Page<{}, ArtifactDetailsState> { private get fullTypeName(): string { return this.props.match.params[RouteParams.ARTIFACT_TYPE] || ''; } @@ -85,9 +87,7 @@ export default class ArtifactDetails extends Page<{}, ArtifactDetailsState> { return route.replace(`:${RouteParams.ID}`, String(resource.getId())); } - public state: ArtifactDetailsState = { - selectedTab: ArtifactDetailsTab.OVERVIEW, - }; + public state: ArtifactDetailsState = {}; private api = Api.getInstance(); @@ -97,32 +97,53 @@ export default class ArtifactDetails extends Page<{}, ArtifactDetailsState> { public render(): JSX.Element { if (!this.state.artifact) { - return ; + return ( +
+ +
+ ); } return (
-
- -
- {this.state.selectedTab === ArtifactDetailsTab.OVERVIEW && ( -
- -
- )} - {this.state.selectedTab === ArtifactDetailsTab.LINEAGE_EXPLORER && ( - - )} + + {/* + ** This is react-router's nested route feature. + ** reference: https://reacttraining.com/react-router/web/example/nesting + */} + + <> +
+ +
+
+ +
+ +
+ + <> +
+ +
+ + +
+
); } @@ -176,6 +197,20 @@ export default class ArtifactDetails extends Page<{}, ArtifactDetailsState> { }; private switchTab = (selectedTab: number) => { - this.setState({ selectedTab }); + switch (selectedTab) { + case ArtifactDetailsTab.LINEAGE_EXPLORER: + return this.props.history.push(`${this.props.match.url}/${LINEAGE_PATH}`); + case ArtifactDetailsTab.OVERVIEW: + return this.props.history.push(this.props.match.url); + default: + logger.error(`Unknown selected tab ${selectedTab}.`); + } }; } + +// This guarantees that each artifact renders a different instance. +const EnhancedArtifactDetails = (props: PageProps) => { + return ; +}; + +export default EnhancedArtifactDetails;