From 3d57f85e52f4600e48aaf5b4bfb1c01306b6454c Mon Sep 17 00:00:00 2001 From: Ayoub LABIDI Date: Tue, 7 Jan 2025 09:12:33 +0100 Subject: [PATCH 1/4] LogTable : remove direct report dependency and include severity fetching logic Signed-off-by: Ayoub LABIDI --- src/components/report-viewer/log-table.tsx | 29 +++++++++++++------ .../report-viewer/report-viewer.tsx | 1 - src/hooks/use-report-fetcher.tsx | 23 +++++++++++++-- src/services/study/index.ts | 10 +++++++ src/utils/report/report-severity.ts | 16 +--------- 5 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/components/report-viewer/log-table.tsx b/src/components/report-viewer/log-table.tsx index e09cfba0e5..e5f68657e4 100644 --- a/src/components/report-viewer/log-table.tsx +++ b/src/components/report-viewer/log-table.tsx @@ -15,12 +15,12 @@ import { getColumnFilterValue, useAggridRowFilter } from 'hooks/use-aggrid-row-f import { LOGS_STORE_FIELD } from 'utils/store-sort-filter-fields'; import { useReportFetcher } from 'hooks/use-report-fetcher'; import { useDispatch } from 'react-redux'; -import { getDefaultSeverityFilter, getReportSeverities, REPORT_SEVERITY } from '../../utils/report/report-severity'; +import { getDefaultSeverityFilter, REPORT_SEVERITY } from '../../utils/report/report-severity'; import { QuickSearch } from './QuickSearch'; import { Box, Chip, Theme } from '@mui/material'; import { CellClickedEvent, GridApi, ICellRendererParams, IRowNode, RowClassParams, RowStyle } from 'ag-grid-community'; import { AgGridReact } from 'ag-grid-react'; -import { Report, ReportLog, ReportType } from 'utils/report/report.type'; +import { ReportLog, ReportType, SeverityLevel } from 'utils/report/report.type'; import { COMPUTING_AND_NETWORK_MODIFICATION_TYPE } from 'utils/report/report.constant'; import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; import VisibilityIcon from '@mui/icons-material/Visibility'; @@ -59,21 +59,22 @@ const styles = { const SEVERITY_COLUMN_FIXED_WIDTH = 115; type LogTableProps = { - report: Report; selectedReportId: string; reportType: string; reportNature: ReportType; onRowClick: (data: ReportLog) => void; }; -const LogTable = ({ report, selectedReportId, reportType, reportNature, onRowClick }: LogTableProps) => { +const LogTable = ({ selectedReportId, reportType, reportNature, onRowClick }: LogTableProps) => { const intl = useIntl(); const theme = useTheme(); const dispatch = useDispatch(); - const [, , fetchReportLogs] = useReportFetcher(reportType as keyof typeof COMPUTING_AND_NETWORK_MODIFICATION_TYPE); + const [, , fetchReportLogs, fetchNodeSeverities] = useReportFetcher( + reportType as keyof typeof COMPUTING_AND_NETWORK_MODIFICATION_TYPE + ); const { updateFilter, filterSelector } = useAggridRowFilter({ filterType: LOGS_STORE_FIELD, filterTab: reportType, @@ -89,7 +90,7 @@ const LogTable = ({ report, selectedReportId, reportType, reportNature, onRowCli const severityFilter = useMemo(() => getColumnFilterValue(filterSelector, 'severity') ?? [], [filterSelector]); const messageFilter = useMemo(() => getColumnFilterValue(filterSelector, 'message'), [filterSelector]); - const severities = useMemo(() => getReportSeverities(report), [report]); + const [severities, setSeverities] = useState(null); const resetSearch = useCallback(() => { setSearchResults([]); @@ -120,7 +121,12 @@ const LogTable = ({ report, selectedReportId, reportType, reportNature, onRowCli }, [severityFilter, fetchReportLogs, selectedReportId, reportNature, messageFilter, resetSearch]); useEffect(() => { - if (filterSelector?.length === 0 && severities?.length > 0) { + if (severities === null && selectedReportId && reportNature) { + fetchNodeSeverities(selectedReportId, reportNature)?.then((severities) => { + setSeverities(severities.toSorted((a, b) => REPORT_SEVERITY[b].level - REPORT_SEVERITY[a].level)); + }); + } + if (filterSelector?.length === 0 && severities && severities.length > 0) { dispatch( setLogsFilter(reportType, [ { @@ -132,7 +138,12 @@ const LogTable = ({ report, selectedReportId, reportType, reportNature, onRowCli ]) ); } - }, [severities, dispatch, reportType, filterSelector]); + }, [severities, dispatch, reportType, filterSelector, fetchNodeSeverities, selectedReportId, reportNature]); + + // Reset the severities when the report nature changes + useEffect(() => { + setSeverities(null); + }, [reportNature]); useEffect(() => { if (selectedReportId && reportNature) { @@ -320,7 +331,7 @@ const LogTable = ({ report, selectedReportId, reportType, reportNature, onRowCli /> - {severities.map((severity, index) => ( + {severities?.map((severity, index) => ( {selectedReportId && selectedReportType && ( Promise | undefined + ) => Promise | undefined, + (reportId: string, reportType: ReportType) => Promise | undefined ] => { const [isLoading, setIsLoading] = useState(false); const studyUuid = useSelector((state: AppState) => state.studyUuid); @@ -151,5 +152,21 @@ export const useReportFetcher = ( [currentNode, studyUuid, nodesNames] ); - return [isLoading, fetchRawParentReport, fetchReportLogs]; + const fetchReportSeverities = useCallback( + (reportId: string, reportType: ReportType) => { + if (!studyUuid) { + return; + } + let fetchPromise: (reportId: string) => Promise; + if (reportType === ReportType.GLOBAL) { + fetchPromise = () => fetchNodeSeverities(studyUuid, currentNode!.id, null, true); + } else { + fetchPromise = (reportId: string) => fetchNodeSeverities(studyUuid, currentNode!.id, reportId, false); + } + return fetchPromise(reportId); + }, + [currentNode, studyUuid] + ); + + return [isLoading, fetchRawParentReport, fetchReportLogs, fetchReportSeverities]; }; diff --git a/src/services/study/index.ts b/src/services/study/index.ts index 16a2b9c364..06bf8b943c 100644 --- a/src/services/study/index.ts +++ b/src/services/study/index.ts @@ -118,6 +118,16 @@ export function fetchNodeReportLogs( return backendFetchJson(url); } +export function fetchNodeSeverities(studyUuid: UUID, nodeUuid: UUID, reportId: string | null, isGlobalLogs: boolean) { + let url; + if (isGlobalLogs) { + url = getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/report/aggregated-severities'; + } else { + url = getStudyUrlWithNodeUuid(studyUuid, nodeUuid) + '/report/' + reportId + '/aggregated-severities'; + } + return backendFetchJson(url); +} + export function fetchSvg(svgUrl: string) { console.debug(svgUrl); return backendFetch(svgUrl).then((response) => (response.status === 204 ? null : response.json())); diff --git a/src/utils/report/report-severity.ts b/src/utils/report/report-severity.ts index 51b273d6b7..0d768968a2 100644 --- a/src/utils/report/report-severity.ts +++ b/src/utils/report/report-severity.ts @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -import { ReportSeverity, SeverityLevel, Report } from './report.type'; +import { ReportSeverity, SeverityLevel } from './report.type'; export const REPORT_SEVERITY: Record = { UNKNOWN: { @@ -80,20 +80,6 @@ export const getDefaultSeverityFilter = (severityList: string[]): string[] => { return severityFilter; }; -export const getReportSeverities = (report: Report): SeverityLevel[] => { - const severities: SeverityLevel[] = []; - if (report.severity) { - severities.push(report.severity); - } - if (report.subReports.length > 0) { - report.subReports.forEach((subreport) => { - severities.push(...getReportSeverities(subreport)); - }); - } - severities.sort((a, b) => REPORT_SEVERITY[b].level - REPORT_SEVERITY[a].level); - return [...new Set(severities)]; -}; - export function getContainerDefaultSeverityList(): string[] { // return name list like ['WARN', 'INFO'] return Object.values(REPORT_SEVERITY) From ac92120575269926ec5df2f53163c5667be3b024 Mon Sep 17 00:00:00 2001 From: Ayoub LABIDI Date: Tue, 7 Jan 2025 09:35:06 +0100 Subject: [PATCH 2/4] fix CI Signed-off-by: Ayoub LABIDI --- src/components/report-viewer/log-table.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/report-viewer/log-table.tsx b/src/components/report-viewer/log-table.tsx index e5f68657e4..163011c249 100644 --- a/src/components/report-viewer/log-table.tsx +++ b/src/components/report-viewer/log-table.tsx @@ -123,7 +123,13 @@ const LogTable = ({ selectedReportId, reportType, reportNature, onRowClick }: Lo useEffect(() => { if (severities === null && selectedReportId && reportNature) { fetchNodeSeverities(selectedReportId, reportNature)?.then((severities) => { - setSeverities(severities.toSorted((a, b) => REPORT_SEVERITY[b].level - REPORT_SEVERITY[a].level)); + setSeverities( + severities + .slice() + .sort( + (a: SeverityLevel, b: SeverityLevel) => REPORT_SEVERITY[b].level - REPORT_SEVERITY[a].level + ) + ); }); } if (filterSelector?.length === 0 && severities && severities.length > 0) { From 5ad72793782bc47e81403aee69d9c0046afbe1e2 Mon Sep 17 00:00:00 2001 From: Ayoub LABIDI Date: Tue, 7 Jan 2025 14:30:45 +0100 Subject: [PATCH 3/4] Requested changes Signed-off-by: Ayoub LABIDI --- src/components/report-viewer-tab.jsx | 12 +++++++++-- src/components/report-viewer/log-table.tsx | 20 ++----------------- .../report-viewer/report-viewer.tsx | 7 ++++--- .../common/computation-report-viewer.tsx | 18 +++++++++++++---- src/utils/report/report-severity.ts | 4 ++++ 5 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/components/report-viewer-tab.jsx b/src/components/report-viewer-tab.jsx index 4010d7284f..2cbdda0805 100644 --- a/src/components/report-viewer-tab.jsx +++ b/src/components/report-viewer-tab.jsx @@ -19,6 +19,8 @@ import { useReportFetcher } from '../hooks/use-report-fetcher'; import { COMPUTING_AND_NETWORK_MODIFICATION_TYPE } from '../utils/report/report.constant'; import { ROOT_NODE_LABEL } from '../constants/node.constant'; import { Box, Paper } from '@mui/material'; +import { ReportType } from 'utils/report/report.type'; +import { sortSeverityList } from 'utils/report/report-severity'; const styles = { div: { @@ -40,10 +42,11 @@ const styles = { */ export const ReportViewerTab = ({ visible, currentNode, disabled }) => { const [report, setReport] = useState(); + const [severities, setSeverities] = useState(); const [nodeOnlyReport, setNodeOnlyReport] = useState(true); const treeModel = useSelector((state) => state.networkModificationTreeModel); const intl = useIntl(); - const [isReportLoading, fetchReport] = useReportFetcher( + const [isReportLoading, fetchReport, , fetchReportSeverities] = useReportFetcher( COMPUTING_AND_NETWORK_MODIFICATION_TYPE.NETWORK_MODIFICATION ); @@ -64,16 +67,20 @@ export const ReportViewerTab = ({ visible, currentNode, disabled }) => { fetchReport(nodeOnlyReport).then((r) => { if (r !== undefined) { setReport(r); + fetchReportSeverities(r.id, r.parentId ? ReportType.NODE : ReportType.GLOBAL).then((severities) => { + setSeverities(sortSeverityList(severities)); + }); } }); } else { // if the user unbuilds a node, the report needs to be reset. // otherwise, the report will be kept in the state and useless report fetches with previous id will be made when the user rebuilds the node. setReport(); + setSeverities(); } // It is important to keep the notifications in the useEffect's dependencies (even if it is not // apparent that they are used) to trigger the update of reports when a notification happens. - }, [visible, currentNode, disabled, fetchReport, nodeOnlyReport]); + }, [visible, currentNode, disabled, fetchReport, nodeOnlyReport, fetchReportSeverities]); return ( @@ -101,6 +108,7 @@ export const ReportViewerTab = ({ visible, currentNode, disabled }) => { )} diff --git a/src/components/report-viewer/log-table.tsx b/src/components/report-viewer/log-table.tsx index 163011c249..5f8efc5e17 100644 --- a/src/components/report-viewer/log-table.tsx +++ b/src/components/report-viewer/log-table.tsx @@ -62,10 +62,11 @@ type LogTableProps = { selectedReportId: string; reportType: string; reportNature: ReportType; + severities: SeverityLevel[] | undefined; onRowClick: (data: ReportLog) => void; }; -const LogTable = ({ selectedReportId, reportType, reportNature, onRowClick }: LogTableProps) => { +const LogTable = ({ selectedReportId, reportType, reportNature, severities, onRowClick }: LogTableProps) => { const intl = useIntl(); const theme = useTheme(); @@ -90,7 +91,6 @@ const LogTable = ({ selectedReportId, reportType, reportNature, onRowClick }: Lo const severityFilter = useMemo(() => getColumnFilterValue(filterSelector, 'severity') ?? [], [filterSelector]); const messageFilter = useMemo(() => getColumnFilterValue(filterSelector, 'message'), [filterSelector]); - const [severities, setSeverities] = useState(null); const resetSearch = useCallback(() => { setSearchResults([]); @@ -121,17 +121,6 @@ const LogTable = ({ selectedReportId, reportType, reportNature, onRowClick }: Lo }, [severityFilter, fetchReportLogs, selectedReportId, reportNature, messageFilter, resetSearch]); useEffect(() => { - if (severities === null && selectedReportId && reportNature) { - fetchNodeSeverities(selectedReportId, reportNature)?.then((severities) => { - setSeverities( - severities - .slice() - .sort( - (a: SeverityLevel, b: SeverityLevel) => REPORT_SEVERITY[b].level - REPORT_SEVERITY[a].level - ) - ); - }); - } if (filterSelector?.length === 0 && severities && severities.length > 0) { dispatch( setLogsFilter(reportType, [ @@ -146,11 +135,6 @@ const LogTable = ({ selectedReportId, reportType, reportNature, onRowClick }: Lo } }, [severities, dispatch, reportType, filterSelector, fetchNodeSeverities, selectedReportId, reportNature]); - // Reset the severities when the report nature changes - useEffect(() => { - setSeverities(null); - }, [reportNature]); - useEffect(() => { if (selectedReportId && reportNature) { refreshLogsOnSelectedReport(); diff --git a/src/components/report-viewer/report-viewer.tsx b/src/components/report-viewer/report-viewer.tsx index 4482f2d8d8..e7223b0a21 100644 --- a/src/components/report-viewer/report-viewer.tsx +++ b/src/components/report-viewer/report-viewer.tsx @@ -11,11 +11,11 @@ import { mapReportsTree } from '../../utils/report/report-tree.mapper'; import { useDispatch } from 'react-redux'; import { VirtualizedTreeview } from './virtualized-treeview'; import { ReportItem } from './treeview-item'; -import { Report, ReportLog, ReportTree, ReportType } from 'utils/report/report.type'; +import { Report, ReportLog, ReportTree, ReportType, SeverityLevel } from 'utils/report/report.type'; -type ReportViewerProps = { report: Report; reportType: string }; +type ReportViewerProps = { report: Report; reportType: string; severities: SeverityLevel[] | undefined }; -export default function ReportViewer({ report, reportType }: ReportViewerProps) { +export default function ReportViewer({ report, reportType, severities }: ReportViewerProps) { const dispatch = useDispatch(); const [expandedTreeReports, setExpandedTreeReports] = useState([]); @@ -100,6 +100,7 @@ export default function ReportViewer({ report, reportType }: ReportViewerProps) selectedReportId={selectedReportId} reportType={reportType} reportNature={selectedReportType} // GlobalReport or NodeReport + severities={severities} onRowClick={onLogRowClick} /> )} diff --git a/src/components/results/common/computation-report-viewer.tsx b/src/components/results/common/computation-report-viewer.tsx index 084a1dc5af..ab83137683 100644 --- a/src/components/results/common/computation-report-viewer.tsx +++ b/src/components/results/common/computation-report-viewer.tsx @@ -12,9 +12,10 @@ import { AppState } from '../../../redux/reducer'; import { ComputingType } from '../../computing-status/computing-type'; import WaitingLoader from '../../utils/waiting-loader'; import { useReportFetcher } from '../../../hooks/use-report-fetcher'; -import { Report } from '../../../utils/report/report.type'; +import { Report, ReportType, SeverityLevel } from '../../../utils/report/report.type'; import { BUILD_STATUS } from 'components/network/constants'; import { Box } from '@mui/material'; +import { sortSeverityList } from 'utils/report/report-severity'; interface ComputationReportViewerProps { reportType: ComputingType; @@ -22,9 +23,10 @@ interface ComputationReportViewerProps { export const ComputationReportViewer: FunctionComponent = ({ reportType }) => { const [report, setReport] = useState(); + const [severities, setSeverities] = useState(); const studyUuid = useSelector((state: AppState) => state.studyUuid); const currentNode = useSelector((state: AppState) => state.currentTreeNode); - const [isReportLoading, fetchReport] = useReportFetcher(reportType); + const [isReportLoading, fetchReport, , fetchReportSeverities] = useReportFetcher(reportType); const shouldFetchReport = useMemo( () => studyUuid && currentNode?.id && currentNode?.data?.globalBuildStatus !== BUILD_STATUS.NOT_BUILT, [studyUuid, currentNode] @@ -35,19 +37,27 @@ export const ComputationReportViewer: FunctionComponent { if (report !== undefined) { setReport(report); + fetchReportSeverities?.(report?.id, report?.parentId ? ReportType.NODE : ReportType.GLOBAL)?.then( + (severities) => { + setSeverities(sortSeverityList(severities)); + } + ); } }); } else { // if the user unbuilds a node, the report needs to be reset. // otherwise, the report will be kept in the state and useless report fetches with previous id will be made when the user rebuilds the node. setReport(undefined); + setSeverities(undefined); } - }, [reportType, fetchReport, shouldFetchReport]); + }, [reportType, fetchReport, shouldFetchReport, fetchReportSeverities]); return ( - {shouldFetchReport && report && } + {shouldFetchReport && report && ( + + )} ); diff --git a/src/utils/report/report-severity.ts b/src/utils/report/report-severity.ts index 0d768968a2..2d95cf5bc4 100644 --- a/src/utils/report/report-severity.ts +++ b/src/utils/report/report-severity.ts @@ -80,6 +80,10 @@ export const getDefaultSeverityFilter = (severityList: string[]): string[] => { return severityFilter; }; +export function sortSeverityList(severityList: SeverityLevel[]): SeverityLevel[] { + return severityList.sort((a, b) => REPORT_SEVERITY[b].level - REPORT_SEVERITY[a].level); +} + export function getContainerDefaultSeverityList(): string[] { // return name list like ['WARN', 'INFO'] return Object.values(REPORT_SEVERITY) From 6631a4e351e0b24444ea870cbd61de64103b4920 Mon Sep 17 00:00:00 2001 From: Ayoub LABIDI Date: Tue, 7 Jan 2025 16:12:53 +0100 Subject: [PATCH 4/4] Requested change Signed-off-by: Ayoub LABIDI --- .../results/common/computation-report-viewer.tsx | 10 ++++------ src/hooks/use-report-fetcher.tsx | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/components/results/common/computation-report-viewer.tsx b/src/components/results/common/computation-report-viewer.tsx index ab83137683..4c1e4cf8ea 100644 --- a/src/components/results/common/computation-report-viewer.tsx +++ b/src/components/results/common/computation-report-viewer.tsx @@ -12,7 +12,7 @@ import { AppState } from '../../../redux/reducer'; import { ComputingType } from '../../computing-status/computing-type'; import WaitingLoader from '../../utils/waiting-loader'; import { useReportFetcher } from '../../../hooks/use-report-fetcher'; -import { Report, ReportType, SeverityLevel } from '../../../utils/report/report.type'; +import { Report, SeverityLevel } from '../../../utils/report/report.type'; import { BUILD_STATUS } from 'components/network/constants'; import { Box } from '@mui/material'; import { sortSeverityList } from 'utils/report/report-severity'; @@ -37,11 +37,9 @@ export const ComputationReportViewer: FunctionComponent { if (report !== undefined) { setReport(report); - fetchReportSeverities?.(report?.id, report?.parentId ? ReportType.NODE : ReportType.GLOBAL)?.then( - (severities) => { - setSeverities(sortSeverityList(severities)); - } - ); + fetchReportSeverities?.(report?.id)?.then((severities) => { + setSeverities(sortSeverityList(severities)); + }); } }); } else { diff --git a/src/hooks/use-report-fetcher.tsx b/src/hooks/use-report-fetcher.tsx index 2d9c2fcd53..0c48ef6c70 100644 --- a/src/hooks/use-report-fetcher.tsx +++ b/src/hooks/use-report-fetcher.tsx @@ -76,7 +76,7 @@ export const useReportFetcher = ( reportType: ReportType, filterMessage: string ) => Promise | undefined, - (reportId: string, reportType: ReportType) => Promise | undefined + (reportId: string, reportType?: ReportType) => Promise | undefined ] => { const [isLoading, setIsLoading] = useState(false); const studyUuid = useSelector((state: AppState) => state.studyUuid); @@ -153,7 +153,7 @@ export const useReportFetcher = ( ); const fetchReportSeverities = useCallback( - (reportId: string, reportType: ReportType) => { + (reportId: string, reportType?: ReportType) => { if (!studyUuid) { return; }