diff --git a/dashboard/src/components/Breadcrumb/IssueBreadcrumb.tsx b/dashboard/src/components/Breadcrumb/IssueBreadcrumb.tsx
new file mode 100644
index 00000000..17ad038b
--- /dev/null
+++ b/dashboard/src/components/Breadcrumb/IssueBreadcrumb.tsx
@@ -0,0 +1,42 @@
+import type { MessageDescriptor } from 'react-intl';
+import { FormattedMessage } from 'react-intl';
+
+import { memo, type JSX } from 'react';
+
+import type { LinkProps } from '@tanstack/react-router';
+
+import {
+ Breadcrumb,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbList,
+ BreadcrumbPage,
+ BreadcrumbSeparator,
+} from './Breadcrumb';
+
+const IssueBreadcrumb = ({
+ searchParams,
+ locationMessage,
+}: {
+ searchParams: LinkProps['search'];
+ locationMessage: MessageDescriptor['id'];
+}): JSX.Element => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+export const MemoizedIssueBreadcrumb = memo(IssueBreadcrumb);
diff --git a/dashboard/src/components/IssueTable/IssueTable.tsx b/dashboard/src/components/IssueTable/IssueTable.tsx
index 7c902774..5a7c26a4 100644
--- a/dashboard/src/components/IssueTable/IssueTable.tsx
+++ b/dashboard/src/components/IssueTable/IssueTable.tsx
@@ -41,6 +41,7 @@ import { valueOrEmpty } from '@/lib/string';
import { TooltipDateTime } from '@/components/TooltipDateTime';
import { shouldShowRelativeDate } from '@/lib/date';
+import { RedirectFrom } from '@/types/general';
const getLinkProps = (
row: Row,
@@ -74,6 +75,8 @@ const getLinkProps = (
params: { issueId: row.original.id },
state: s => ({
...s,
+ id: row.original.id,
+ from: RedirectFrom.Issue,
}),
};
};
diff --git a/dashboard/src/locales/messages/index.ts b/dashboard/src/locales/messages/index.ts
index 53929b81..e3fabc65 100644
--- a/dashboard/src/locales/messages/index.ts
+++ b/dashboard/src/locales/messages/index.ts
@@ -204,9 +204,11 @@ export const messages = {
'hardwareListing.description': 'List of hardware from kernel tests',
'hardwareListing.title': 'Hardware Listing ― KCI Dashboard',
'issue.alsoPresentTooltip': 'Issue also present in {tree}',
+ 'issue.details': 'Issue Details',
'issue.firstSeen': 'First seen',
'issue.newIssue': 'New issue: This is the first time this issue was seen',
'issue.noIssueFound': 'No issue found.',
+ 'issue.path': 'Issues',
'issue.searchPlaceholder': 'Search by issue comment with a regex',
'issue.tooltip':
'Issues groups several builds or tests by matching result status and logs.{br}They may also be linked to an external issue tracker or mailing list discussion.',
diff --git a/dashboard/src/pages/IssueDetails/IssueDetails.tsx b/dashboard/src/pages/IssueDetails/IssueDetails.tsx
index 4df46573..142945c6 100644
--- a/dashboard/src/pages/IssueDetails/IssueDetails.tsx
+++ b/dashboard/src/pages/IssueDetails/IssueDetails.tsx
@@ -10,6 +10,7 @@ import { RedirectFrom } from '@/types/general';
import { MemoizedTreeBreadcrumb } from '@/components/Breadcrumb/TreeBreadcrumb';
import { MemoizedHardwareBreadcrumb } from '@/components/Breadcrumb/HardwareBreadcrumb';
import { useSearchStore } from '@/hooks/store/useSearchStore';
+import { MemoizedIssueBreadcrumb } from '@/components/Breadcrumb/IssueBreadcrumb';
const getBuildTableRowLink = (buildId: string): LinkProps => ({
to: '/build/$buildId',
@@ -54,6 +55,15 @@ const IssueDetailsPage = (): JSX.Element => {
/>
);
}
+
+ if (historyState.from === RedirectFrom.Issue) {
+ return (
+
+ );
+ }
}
}, [historyState.from, historyState.id, previousSearch]);
diff --git a/dashboard/src/types/general.ts b/dashboard/src/types/general.ts
index 3e2560a0..5f4eece9 100644
--- a/dashboard/src/types/general.ts
+++ b/dashboard/src/types/general.ts
@@ -361,6 +361,7 @@ export const getTargetFilter = (
export enum RedirectFrom {
Tree = 'tree',
Hardware = 'hardware',
+ Issue = 'issues',
}
export type PossibleMonitorPath = '/tree' | '/hardware' | '/issues';