diff --git a/.changeset/real-mails-add.md b/.changeset/real-mails-add.md
new file mode 100644
index 0000000000..30a9100699
--- /dev/null
+++ b/.changeset/real-mails-add.md
@@ -0,0 +1,5 @@
+---
+'@backstage/core-components': patch
+---
+
+fixed route resolving (issue #7741) when user cannot select a tab in any of the tabbed pages (like the Catalog page) if it shares the same initial letters as a preceding tab. (i.e. where tab with a path of /ci is followed by a path of /ci-2, user cannot select /ci-2 as /ci will always be selected first).
diff --git a/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx b/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx
index 9b33304a95..bbd48c127c 100644
--- a/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx
+++ b/packages/core-components/src/components/TabbedLayout/RoutedTabs.test.tsx
@@ -31,6 +31,12 @@ const testRoute2 = {
children:
tabbed-test-content-2
,
};
+const testRoute3 = {
+ title: 'tabbed-test-title-3',
+ path: '/some-other-path-similar',
+ children: tabbed-test-content-3
,
+};
+
describe('RoutedTabs', () => {
it('renders simplest case', async () => {
const rendered = await renderInTestApp(
@@ -46,7 +52,7 @@ describe('RoutedTabs', () => {
}
+ element={}
/>
,
);
@@ -61,6 +67,13 @@ describe('RoutedTabs', () => {
expect(rendered.getByText('tabbed-test-title-2')).toBeInTheDocument();
expect(rendered.queryByText('tabbed-test-content-2')).toBeInTheDocument();
+
+ const thirdTab = rendered.queryAllByRole('tab')[2];
+ act(() => {
+ fireEvent.click(thirdTab);
+ });
+ expect(rendered.getByText('tabbed-test-title-3')).toBeInTheDocument();
+ expect(rendered.queryByText('tabbed-test-content-3')).toBeInTheDocument();
});
describe('correctly delegates nested links', () => {
diff --git a/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx b/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx
index 2a65c8ffc8..5debafd3f8 100644
--- a/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx
+++ b/packages/core-components/src/components/TabbedLayout/RoutedTabs.tsx
@@ -33,9 +33,15 @@ export function useSelectedSubRoute(subRoutes: SubRoute[]): {
element: children,
}));
- const element = useRoutes(routes) ?? subRoutes[0].children;
+ // TODO: remove once react-router updated
+ const sortedRoutes = routes.sort((a, b) =>
+ // remove "/*" symbols from path end before comparing
+ b.path.replace(/\/\*$/, '').localeCompare(a.path.replace(/\/\*$/, '')),
+ );
- const [matchedRoute] = matchRoutes(routes, `/${params['*']}`) ?? [];
+ const element = useRoutes(sortedRoutes) ?? subRoutes[0].children;
+
+ const [matchedRoute] = matchRoutes(sortedRoutes, `/${params['*']}`) ?? [];
const foundIndex = matchedRoute
? subRoutes.findIndex(t => `${t.path}/*` === matchedRoute.route.path)
: 0;