diff --git a/.changeset/clickable-log-components.md b/.changeset/clickable-log-components.md
new file mode 100644
index 000000000..85acd64a9
--- /dev/null
+++ b/.changeset/clickable-log-components.md
@@ -0,0 +1,5 @@
+---
+'@openchoreo/backstage-plugin-openchoreo-observability': minor
+---
+
+Made component names in the project-level logging view clickable, allowing users to navigate directly to the component-scoped logging view while preserving the current time range and any relevant filters.
diff --git a/plugins/openchoreo-observability/src/components/RuntimeLogs/LogEntry.test.tsx b/plugins/openchoreo-observability/src/components/RuntimeLogs/LogEntry.test.tsx
index c71371266..5efce186d 100644
--- a/plugins/openchoreo-observability/src/components/RuntimeLogs/LogEntry.test.tsx
+++ b/plugins/openchoreo-observability/src/components/RuntimeLogs/LogEntry.test.tsx
@@ -1,4 +1,5 @@
import { useState } from 'react';
+import { MemoryRouter } from 'react-router-dom';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { LogEntry } from './LogEntry';
@@ -48,7 +49,11 @@ function renderLogEntry(
expanded,
onToggleExpand: () => setExpanded(prev => !prev),
};
- return ;
+ return (
+
+
+
+ );
};
return render();
}
@@ -97,6 +102,21 @@ describe('LogEntry', () => {
expect(screen.getByText('api-service')).toBeInTheDocument();
});
+ it('renders component name link with correct path', () => {
+ renderLogEntry({
+ selectedFields: [...allFields, LogEntryField.ComponentName],
+ entityNamespace: 'my-namespace',
+ entityKind: 'Component',
+ });
+
+ const link = screen.getByRole('link', { name: 'api-service' });
+ expect(link).toBeInTheDocument();
+ expect(link).toHaveAttribute(
+ 'href',
+ '/catalog/my-namespace/component/api-service/runtime-logs',
+ );
+ });
+
it('expands to show metadata on row click', async () => {
const user = userEvent.setup();
renderLogEntry();
diff --git a/plugins/openchoreo-observability/src/components/RuntimeLogs/LogEntry.tsx b/plugins/openchoreo-observability/src/components/RuntimeLogs/LogEntry.tsx
index aa0edcf2c..907a62fe3 100644
--- a/plugins/openchoreo-observability/src/components/RuntimeLogs/LogEntry.tsx
+++ b/plugins/openchoreo-observability/src/components/RuntimeLogs/LogEntry.tsx
@@ -9,8 +9,12 @@ import {
} from '@material-ui/core';
import FileCopyOutlined from '@material-ui/icons/FileCopyOutlined';
import { LogEntry as LogEntryType, LogEntryField } from './types';
+import { Link } from '@backstage/core-components';
+import { useLocation } from 'react-router-dom';
import { useLogEntryStyles } from './styles';
import { getColumnStyle } from './columns';
+import { Entity } from '@backstage/catalog-model';
+import { buildRuntimeLogsBasePath } from '@openchoreo/backstage-plugin-react';
/**
* Render-prop slot for a per-row action button (assistant integration,
@@ -29,6 +33,8 @@ interface LogEntryProps {
environmentName?: string;
projectName?: string;
componentName?: string;
+ entityNamespace?: string;
+ entityKind?: string;
/**
* Whether this row is currently expanded. Controlled by the parent so that
* expansion survives the virtualizer unmounting the row off-screen.
@@ -53,12 +59,15 @@ export const LogEntry: FC = ({
environmentName,
projectName,
componentName,
+ entityNamespace,
+ entityKind,
expanded,
onToggleExpand,
getLogsSnapshot,
renderRowAction,
}) => {
const classes = useLogEntryStyles();
+ const location = useLocation();
const [copySuccess, setCopySuccess] = useState(false);
const handleCopyLog = async (event: MouseEvent) => {
@@ -140,13 +149,32 @@ export const LogEntry: FC = ({
}
if (field === LogEntryField.ComponentName) {
+ const compName = log.metadata?.componentName ?? componentName ?? '';
+ const entity: Entity = {
+ apiVersion: 'backstage.io/v1alpha1',
+ kind: entityKind || 'Component',
+ metadata: {
+ name: compName,
+ namespace: entityNamespace,
+ },
+ };
+ const basePath = buildRuntimeLogsBasePath(entity);
return (
- {log.metadata?.componentName ?? componentName ?? ''}
+ {compName ? (
+ e.stopPropagation()}
+ >
+ {compName}
+
+ ) : (
+ ''
+ )}
);
}
diff --git a/plugins/openchoreo-observability/src/components/RuntimeLogs/LogsTable.tsx b/plugins/openchoreo-observability/src/components/RuntimeLogs/LogsTable.tsx
index f332a8fbf..506f4b298 100644
--- a/plugins/openchoreo-observability/src/components/RuntimeLogs/LogsTable.tsx
+++ b/plugins/openchoreo-observability/src/components/RuntimeLogs/LogsTable.tsx
@@ -21,6 +21,8 @@ interface LogsTableProps {
environmentName?: string;
projectName?: string;
componentName?: string;
+ entityNamespace?: string;
+ entityKind?: string;
renderRowAction?: RenderLogRowAction;
}
@@ -37,6 +39,8 @@ export const LogsTable: FC = ({
environmentName,
projectName,
componentName,
+ entityNamespace,
+ entityKind,
renderRowAction,
}) => {
const classes = useLogsTableStyles();
@@ -164,6 +168,8 @@ export const LogsTable: FC = ({
environmentName={environmentName}
projectName={projectName}
componentName={componentName}
+ entityNamespace={entityNamespace}
+ entityKind={entityKind}
expanded={expanded.has(key)}
onToggleExpand={() => toggle(key)}
getLogsSnapshot={getLogsSnapshot}
diff --git a/plugins/openchoreo-observability/src/components/RuntimeLogs/ObservabilityProjectRuntimeLogsPage.tsx b/plugins/openchoreo-observability/src/components/RuntimeLogs/ObservabilityProjectRuntimeLogsPage.tsx
index a02a108a9..c59856328 100644
--- a/plugins/openchoreo-observability/src/components/RuntimeLogs/ObservabilityProjectRuntimeLogsPage.tsx
+++ b/plugins/openchoreo-observability/src/components/RuntimeLogs/ObservabilityProjectRuntimeLogsPage.tsx
@@ -241,6 +241,8 @@ const ObservabilityProjectRuntimeLogsContent = ({
selectedEnvironment?.displayName || selectedEnvironment?.name
}
projectName={projectName}
+ entityNamespace={entity.metadata.namespace}
+ entityKind="component"
renderRowAction={renderRowAction}
/>
>
diff --git a/plugins/openchoreo-observability/src/components/RuntimeLogs/ObservabilityRuntimeLogsPage.tsx b/plugins/openchoreo-observability/src/components/RuntimeLogs/ObservabilityRuntimeLogsPage.tsx
index 44df01637..903a64eb6 100644
--- a/plugins/openchoreo-observability/src/components/RuntimeLogs/ObservabilityRuntimeLogsPage.tsx
+++ b/plugins/openchoreo-observability/src/components/RuntimeLogs/ObservabilityRuntimeLogsPage.tsx
@@ -257,6 +257,8 @@ const ObservabilityRuntimeLogsContent = ({
}
projectName={project}
componentName={componentName}
+ entityNamespace={entity.metadata.namespace}
+ entityKind={entity.kind}
renderRowAction={renderRowAction}
/>
>