Move sub-page tab href resolution to PageLayout
Move the logic for resolving relative sub-page tab hrefs from PageBlueprint into the app PageLayout component, where it belongs as an app-level rendering concern. Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> Made-with: Cursor
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { JSX } from 'react';
|
||||
import { Routes, Route, Navigate, useResolvedPath } from 'react-router-dom';
|
||||
import { Routes, Route, Navigate } from 'react-router-dom';
|
||||
import { IconElement } from '../icons/types';
|
||||
import { RouteRef } from '../routing';
|
||||
import {
|
||||
@@ -72,7 +72,6 @@ export const PageBlueprint = createExtensionBlueprint({
|
||||
{ config, node, inputs },
|
||||
) {
|
||||
const title = config.title ?? params.title;
|
||||
const routePath = config.path ?? params.path;
|
||||
const icon = params.icon;
|
||||
const pluginId = node.spec.plugin.pluginId;
|
||||
const noHeader = params.noHeader ?? false;
|
||||
@@ -80,7 +79,7 @@ export const PageBlueprint = createExtensionBlueprint({
|
||||
title ?? node.spec.plugin.title ?? node.spec.plugin.pluginId;
|
||||
const resolvedIcon = icon ?? node.spec.plugin.icon;
|
||||
|
||||
yield coreExtensionData.routePath(routePath);
|
||||
yield coreExtensionData.routePath(config.path ?? params.path);
|
||||
if (params.loader) {
|
||||
const loader = params.loader;
|
||||
const PageContent = () => {
|
||||
@@ -100,34 +99,24 @@ export const PageBlueprint = createExtensionBlueprint({
|
||||
};
|
||||
yield coreExtensionData.reactElement(<PageContent />);
|
||||
} else if (inputs.pages.length > 0) {
|
||||
// Parent page with sub-pages - render header with tabs
|
||||
const tabs: PageLayoutTab[] = inputs.pages.map(page => {
|
||||
const path = page.get(coreExtensionData.routePath);
|
||||
const tabTitle = page.get(coreExtensionData.title);
|
||||
const tabIcon = page.get(coreExtensionData.icon);
|
||||
return {
|
||||
id: path,
|
||||
label: tabTitle || path,
|
||||
icon: tabIcon,
|
||||
href: path,
|
||||
};
|
||||
});
|
||||
|
||||
const PageContent = () => {
|
||||
const firstPagePath = inputs.pages[0]?.get(coreExtensionData.routePath);
|
||||
|
||||
const headerActionsApi = useApi(pluginHeaderActionsApiRef);
|
||||
const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);
|
||||
const parentPath = useResolvedPath('.').pathname.replace(/\/$/, '');
|
||||
const staticParentPath =
|
||||
routePath.startsWith('/') &&
|
||||
!routePath.includes('/:') &&
|
||||
!routePath.includes('*')
|
||||
? routePath.replace(/\/$/, '')
|
||||
: undefined;
|
||||
const tabs: PageLayoutTab[] = inputs.pages.map(page => {
|
||||
const path = page.get(coreExtensionData.routePath);
|
||||
const tabTitle = page.get(coreExtensionData.title);
|
||||
const tabIcon = page.get(coreExtensionData.icon);
|
||||
const tabPath = path.replace(/^\/+/, '');
|
||||
const basePath = staticParentPath ?? parentPath ?? '';
|
||||
const href = path.startsWith('/')
|
||||
? path
|
||||
: `${basePath}/${tabPath}`.replace(/\/{2,}/g, '/');
|
||||
|
||||
return {
|
||||
id: path,
|
||||
label: tabTitle || path,
|
||||
icon: tabIcon,
|
||||
href,
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<PageLayout
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
import { PluginHeader } from '@backstage/ui';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import { useMemo } from 'react';
|
||||
import { useResolvedPath } from 'react-router-dom';
|
||||
|
||||
export const Progress = SwappableComponentBlueprint.make({
|
||||
name: 'core-progress',
|
||||
@@ -75,13 +76,18 @@ export const PageLayout = SwappableComponentBlueprint.make({
|
||||
component: SwappablePageLayout,
|
||||
loader: () => (props: PageLayoutProps) => {
|
||||
const { title, icon, noHeader, headerActions, tabs, children } = props;
|
||||
const tabsWithMatchStrategy = useMemo(
|
||||
// TODO(Rugvip): Different solution to this path handling would be good
|
||||
const parentPath = useResolvedPath('.').pathname.replace(/\/$/, '');
|
||||
const resolvedTabs = useMemo(
|
||||
() =>
|
||||
tabs?.map(tab => ({
|
||||
...tab,
|
||||
href: tab.href.startsWith('/')
|
||||
? tab.href
|
||||
: `${parentPath}/${tab.href}`.replace(/\/{2,}/g, '/'),
|
||||
matchStrategy: 'prefix' as const,
|
||||
})),
|
||||
[tabs],
|
||||
[tabs, parentPath],
|
||||
);
|
||||
|
||||
if (noHeader) {
|
||||
@@ -93,7 +99,7 @@ export const PageLayout = SwappableComponentBlueprint.make({
|
||||
<PluginHeader
|
||||
title={title}
|
||||
icon={icon}
|
||||
tabs={tabsWithMatchStrategy}
|
||||
tabs={resolvedTabs}
|
||||
customActions={headerActions}
|
||||
/>
|
||||
{children}
|
||||
|
||||
Reference in New Issue
Block a user