Skip to content
Open

wip #3897

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components/report-viewer-tab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import { useSelector } from 'react-redux';

import { useReportFetcher } from '../hooks/use-report-fetcher';
import { COMPUTING_AND_NETWORK_MODIFICATION_TYPE } from '../utils/report/report.constant';
import { COMPUTING_AND_NETWORK_MODIFICATION_TYPE, GLOBAL_REPORT_NODE_LABEL } from '../utils/report/report.constant';
import { ROOT_NODE_LABEL } from '../constants/node.constant';
import { ReportType } from 'utils/report/report.type';
import { sortSeverityList } from 'utils/report/report-severity';
Expand Down Expand Up @@ -87,7 +87,7 @@
fetchReport(nodeOnlyReport).then((r) => {
if (r !== undefined) {
setReport(r);
fetchReportSeverities(r.id, r.parentId ? ReportType.NODE : ReportType.GLOBAL).then((severities) => {
fetchReportSeverities(r.id, r.message !== GLOBAL_REPORT_NODE_LABEL ? ReportType.NODE : ReportType.GLOBAL).then((severities) => {

Check warning on line 90 in src/components/report-viewer-tab.jsx

View workflow job for this annotation

GitHub Actions / build / build

Replace `r.id,·r.message·!==·GLOBAL_REPORT_NODE_LABEL·?·ReportType.NODE·:·ReportType.GLOBAL` with `⏎····················r.id,⏎····················r.message·!==·GLOBAL_REPORT_NODE_LABEL·?·ReportType.NODE·:·ReportType.GLOBAL⏎················`
setSeverities(sortSeverityList(severities));
});
}
Expand Down
8 changes: 4 additions & 4 deletions src/components/report-viewer/log-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ const LogTable = ({
setRowData([]);
return;
}
fetchLogs(selectedReport.id, severityFilter, messageFilter, selectedReport.type, page, rowsPerPage)?.then(
fetchLogs(selectedReport.reportId, severityFilter, messageFilter, selectedReport.type, page, rowsPerPage)?.then(
(pagedLogs) => {
const { content, totalElements, totalPages } = pagedLogs;
if (totalPages - 1 < page) {
Expand All @@ -163,7 +163,7 @@ const LogTable = ({
}, [
severityFilter,
fetchLogs,
selectedReport.id,
selectedReport.reportId,
selectedReport.type,
messageFilter,
page,
Expand Down Expand Up @@ -327,7 +327,7 @@ const LogTable = ({
setSearchTerm(searchTerm);

fetchLogMatches(
selectedReport.id,
selectedReport.reportId,
severityFilter,
messageFilter,
selectedReport.type,
Expand All @@ -348,7 +348,7 @@ const LogTable = ({
messageFilter,
resetSearch,
rowsPerPage,
selectedReport.id,
selectedReport.reportId,
selectedReport.type,
setPagination,
severityFilter,
Expand Down
17 changes: 11 additions & 6 deletions src/components/report-viewer/report-viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
SelectedReportLog,
SeverityLevel,
} from 'utils/report/report.type';
import { GLOBAL_REPORT_NODE_LABEL } from '../../utils/report/report.constant';
import { GLOBAL_REPORT_NODE_LABEL, makeNodeKey } from '../../utils/report/report.constant';
import { ImperativePanelGroupHandle, Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import DragIndicatorIcon from '@mui/icons-material/DragIndicator';
import { Box } from '@mui/material';
Expand Down Expand Up @@ -48,9 +48,13 @@
const [expandedTreeReports, setExpandedTreeReports] = useState<string[]>([]);
const [highlightedReportId, setHighlightedReportId] = useState<string>();

const isGlobal = report.message === GLOBAL_REPORT_NODE_LABEL;
const initialNodeKey = isGlobal ? GLOBAL_REPORT_NODE_LABEL : makeNodeKey(report.id, report.order);

const [selectedReport, setSelectedReport] = useState<SelectedReportLog>({
id: report.id,
type: report.message === GLOBAL_REPORT_NODE_LABEL ? ReportType.GLOBAL : ReportType.NODE,
id: initialNodeKey,
reportId: report.id,
type: isGlobal ? ReportType.GLOBAL : ReportType.NODE,
});

const reportTree = useMemo(() => mapReportsTree(report), [report]);
Expand All @@ -70,7 +74,7 @@
setSelectedReport((currentSelected) => {
if (currentSelected.id !== reportTree.id || currentSelected.type !== newType) {
setExpandedTreeReports([reportTree.id]);
return { id: reportTree.id, type: newType };
return { id: reportTree.id, reportId: reportTreeMap[reportTree.id]?.reportId ?? reportTree.id, type: newType };

Check warning on line 77 in src/components/report-viewer/report-viewer.tsx

View workflow job for this annotation

GitHub Actions / build / build

Replace `·id:·reportTree.id,·reportId:·reportTreeMap[reportTree.id]?.reportId·??·reportTree.id,·type:·newType` with `⏎····················id:·reportTree.id,⏎····················reportId:·reportTreeMap[reportTree.id]?.reportId·??·reportTree.id,⏎····················type:·newType,⏎···············`
}
return currentSelected;
});
Expand All @@ -89,7 +93,7 @@
}
return Array.from(treeReportsToExpand);
});
setHighlightedReportId(data?.parentId);
setHighlightedReportId(data?.parentId ?? undefined);
},
[reportTreeMap]
);
Expand All @@ -102,7 +106,8 @@
(report: ReportItem) => {
setSelectedReport((prevSelectedReport) => {
if (prevSelectedReport.id !== report.id) {
return { id: report.id, type: reportTreeMap[report.id].type };
const treeNode = reportTreeMap[report.id];
return { id: report.id, reportId: treeNode?.reportId ?? report.id, type: treeNode?.type ?? ReportType.NODE };

Check warning on line 110 in src/components/report-viewer/report-viewer.tsx

View workflow job for this annotation

GitHub Actions / build / build

Replace `·id:·report.id,·reportId:·treeNode?.reportId·??·report.id,·type:·treeNode?.type·??·ReportType.NODE` with `⏎························id:·report.id,⏎························reportId:·treeNode?.reportId·??·report.id,⏎························type:·treeNode?.type·??·ReportType.NODE,⏎···················`
}
return prevSelectedReport;
});
Expand Down
8 changes: 5 additions & 3 deletions src/hooks/use-report-fetcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ function makeSingleReportAndMapNames(report: Report | Report[], nodesNames: Map<
return {
message: GLOBAL_REPORT_NODE_LABEL,
id: GLOBAL_REPORT_NODE_LABEL,
order: -1,
parentOrder: null,
severity: getHighestSeverity(report),
subReports: report.map((r) => setNodeName(r, nodesNames)),
} as Report;
Expand All @@ -59,13 +61,12 @@ function setNodeName(report: Report, nodesNames: Map<string, string>) {
if (report.message !== ROOT_NODE_LABEL) {
report.message = nodesNames?.get(report.message) ?? report.message;
}
report.parentId = GLOBAL_REPORT_NODE_LABEL;
return report;
}

function prettifyReportLogMessage(reports: ReportLog[], nodesNames: Map<string, string>) {
reports.forEach((report) => {
if (report.parentId == null) {
if (report.parentOrder == null) {
if (report.message !== ROOT_NODE_LABEL) {
report.message = nodesNames?.get(report.message) ?? report.message;
}
Expand Down Expand Up @@ -200,9 +201,10 @@ export const useReportFetcher = (
page,
size
).then((r: PagedReportLogs) => {
const logReportId = reportType === ReportType.GLOBAL ? null : reportId;
return {
...r,
content: mapReportLogs(prettifyReportLogMessage(r.content, nodesNames)),
content: mapReportLogs(prettifyReportLogMessage(r.content, nodesNames), logReportId),
};
});
},
Expand Down
11 changes: 7 additions & 4 deletions src/utils/report/report-log.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,27 @@

import { REPORT_SEVERITY } from './report-severity';
import { Log, ReportLog } from './report.type';
import { makeNodeKey } from './report.constant';

export const mapReportLogs = (reportLogs: ReportLog[]) => {
export const mapReportLogs = (reportLogs: ReportLog[], reportId?: string | null) => {
const formattedLogs: Log[] = [];
const minDepth = Math.min(...reportLogs.map((log) => log.depth ?? 0));
reportLogs.forEach((reportLog) => {
formatLog(minDepth, reportLog, formattedLogs);
formatLog(minDepth, reportLog, formattedLogs, reportId);
});
return formattedLogs;
};

const formatLog = (minDepth: number, reportLog: ReportLog, formattedLogs: Log[]) => {
const formatLog = (minDepth: number, reportLog: ReportLog, formattedLogs: Log[], reportId?: string | null) => {
const severity =
Object.values(REPORT_SEVERITY).find((s) => reportLog.severity === s.name) ?? REPORT_SEVERITY.UNKNOWN;
const parentId =

Check warning on line 24 in src/utils/report/report-log.mapper.ts

View workflow job for this annotation

GitHub Actions / build / build

Delete `⏎·······`
reportLog.parentOrder != null && reportId ? makeNodeKey(reportId, reportLog.parentOrder) : null;
formattedLogs.push({
message: reportLog.message,
severity: severity.name,
backgroundColor: severity.colorName,
depth: (reportLog.depth ?? 0) - minDepth,
parentId: reportLog.parentId,
parentId,
});
Comment on lines +21 to 32
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find and read the relevant files
fd -type f -name "use-report-fetcher.tsx" | head -5

Repository: gridsuite/gridstudy-app

Length of output: 237


🏁 Script executed:

fd -type f -name "report-viewer.tsx" | head -5

Repository: gridsuite/gridstudy-app

Length of output: 237


🏁 Script executed:

fd -type f -name "report-log.mapper.ts" | head -5

Repository: gridsuite/gridstudy-app

Length of output: 237


🏁 Script executed:

fd use-report-fetcher.tsx

Repository: gridsuite/gridstudy-app

Length of output: 99


🏁 Script executed:

fd report-viewer.tsx

Repository: gridsuite/gridstudy-app

Length of output: 173


🏁 Script executed:

fd report-log.mapper.ts

Repository: gridsuite/gridstudy-app

Length of output: 104


🏁 Script executed:

cat -n src/hooks/use-report-fetcher.tsx | sed -n '195,215p'

Repository: gridsuite/gridstudy-app

Length of output: 983


🏁 Script executed:

cat -n src/utils/report/report-log.mapper.ts | sed -n '1,40p'

Repository: gridsuite/gridstudy-app

Length of output: 1639


🏁 Script executed:

cat -n src/components/report-viewer/report-viewer.tsx | sed -n '75,110p'

Repository: gridsuite/gridstudy-app

Length of output: 1960


🏁 Script executed:

fd report.type.ts

Repository: gridsuite/gridstudy-app

Length of output: 98


🏁 Script executed:

rg "ReportLog" --type ts -A 5 | head -40

Repository: gridsuite/gridstudy-app

Length of output: 2574


🏁 Script executed:

cat -n src/utils/report/report.type.ts

Repository: gridsuite/gridstudy-app

Length of output: 2646


🏁 Script executed:

cat -n src/services/study/index.ts | grep -A 20 "fetchNodeReportLogs\|fetchGlobalReportLogs"

Repository: gridsuite/gridstudy-app

Length of output: 946


🏁 Script executed:

rg "fetchGlobalReportLogs\|fetchNodeReportLogs" -A 10 src/services/study/index.ts

Repository: gridsuite/gridstudy-app

Length of output: 49


🏁 Script executed:

rg "per-log|reportId" src/utils/report/report-log.mapper.ts -B 2 -A 2

Repository: gridsuite/gridstudy-app

Length of output: 887


🏁 Script executed:

git log --oneline src/utils/report/report-log.mapper.ts | head -10

Repository: gridsuite/gridstudy-app

Length of output: 79


Global logs cannot display tree-context — highlighting and ancestor expansion will not function for global log rows.

The chain is confirmed:

  • use-report-fetcher.tsx:204 passes logReportId = null for global reports
  • report-log.mapper.ts:25 evaluates reportLog.parentOrder != null && reportId as always false when reportId is null, so every global log gets parentId: null
  • report-viewer.tsx:83-99 uses data.parentId to expand tree ancestors and highlight the originating report node — both become no-ops when parentId is null

The ReportLog type (lines 55–61 in report.type.ts) contains only message, severity, depth, parentOrder, and backgroundColor — no per-log report identifier exists. The backend endpoint (study/index.ts:111–113) confirms it does not transmit reportId when fetching global logs.

To restore tree linkage for global logs, the backend must include a per-log report UUID alongside parentOrder, the ReportLog type must be updated to accept it, and formatLog must use it to reconstruct the nodeKey when the caller-provided reportId is null.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/utils/report/report-log.mapper.ts` around lines 21 - 32, Global logs lose
tree context because formatLog (formatLog) only builds parentId using the
caller-supplied reportId and skips when that is null; fix by adding a per-log
report UUID from the backend, updating the ReportLog type to include e.g.
reportId, and changing formatLog to use reportLog.reportId (fallback to the
passed-in reportId) when constructing parentId via
makeNodeKey(reportIdOrLogReportId, reportLog.parentOrder); also update the
backend endpoint to return the per-log report UUID for global logs so
report-viewer and use-report-fetcher can expand/highlight ancestors correctly.

};
17 changes: 11 additions & 6 deletions src/utils/report/report-tree.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@
*/

import { Report, ReportTree, ReportType } from './report.type';
import { GLOBAL_REPORT_NODE_LABEL } from './report.constant';
import { GLOBAL_REPORT_NODE_LABEL, makeNodeKey } from './report.constant';
import { REPORT_SEVERITY } from './report-severity';

export function mapReportsTree(report: Report, reportType?: ReportType): ReportTree {
export function mapReportsTree(report: Report, reportType?: ReportType, parentNodeKey?: string | null): ReportTree {
const isGlobal = report.message === GLOBAL_REPORT_NODE_LABEL;
const nodeKey = isGlobal ? GLOBAL_REPORT_NODE_LABEL : makeNodeKey(report.id, report.order);

return {
type: reportType ?? (report.message === GLOBAL_REPORT_NODE_LABEL ? ReportType.GLOBAL : ReportType.NODE),
id: report.id,
type: reportType ?? (isGlobal ? ReportType.GLOBAL : ReportType.NODE),
id: nodeKey,
reportId: report.id,
order: report.order,
message: report.message,
parentId: report.parentId,
parentId: parentNodeKey ?? null,
severity: Object.values(REPORT_SEVERITY).find((s) => report.severity === s.name) ?? REPORT_SEVERITY.UNKNOWN,
subReports: report.subReports
.filter((subReport) => subReport.subReports.length > 0 || subReport.id)
.map((subReport) => mapReportsTree(subReport, ReportType.NODE)),
.map((subReport) => mapReportsTree(subReport, ReportType.NODE, nodeKey)),
} satisfies ReportTree;
}
8 changes: 8 additions & 0 deletions src/utils/report/report.constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,11 @@ export const COMPUTING_AND_NETWORK_MODIFICATION_TYPE = {
...ComputingType,
NETWORK_MODIFICATION: NETWORK_MODIFICATION,
};

/**
* Build a unique node key for the report tree from the report UUID and the node's order.
* All nodes within a single report share the same UUID; order makes them unique.
*/
export function makeNodeKey(reportId: string, order: number): string {
return `${reportId}_${order}`;
}
12 changes: 8 additions & 4 deletions src/utils/report/report.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@ export enum ReportType {
interface BaseReport<T> {
message: string;
severity: SeverityLevel;
parentId: string | null;
parentOrder: number | null;
id: string;
order: number;
subReports: T[];
}

export interface ReportTree extends Omit<BaseReport<ReportTree>, 'severity'> {
export interface ReportTree extends Omit<BaseReport<ReportTree>, 'severity' | 'parentOrder'> {
type: ReportType;
severity: ReportSeverity;
reportId: string;
parentId: string | null;
}

export interface Report extends BaseReport<Report> {}
Expand All @@ -46,19 +49,20 @@ export type Log = {
severity: string;
backgroundColor: string;
depth: number;
parentId: string;
parentId: string | null;
};

export type ReportLog = {
message: string;
severity: SeverityLevel;
depth: number;
parentId: string;
parentOrder: number | null;
backgroundColor?: string;
};

export type SelectedReportLog = {
id: string;
reportId: string;
type: ReportType;
};

Expand Down
Loading