diff --git a/src/ElectronBackend/input/__tests__/importFromFile.test.ts b/src/ElectronBackend/input/__tests__/importFromFile.test.ts index 73c375c32..c302eacd0 100644 --- a/src/ElectronBackend/input/__tests__/importFromFile.test.ts +++ b/src/ElectronBackend/input/__tests__/importFromFile.test.ts @@ -68,8 +68,8 @@ const inputFileContent: ParsedOpossumInputFile = { }, config: { classifications: { - 0: 'UNKNOWN', - 1: 'CRITICAL', + 0: 'GOOD', + 1: 'BAD', }, }, externalAttributions: { @@ -115,8 +115,8 @@ const expectedFileContent: ParsedFileContent = { resources: { a: 1, folder: {} }, config: { classifications: { - 0: 'UNKNOWN', - 1: 'CRITICAL', + 0: 'GOOD', + 1: 'BAD', }, }, manualAttributions: { @@ -376,8 +376,8 @@ describe('Test of loading function', () => { }, config: { classifications: { - 0: 'UNKNOWN', - 1: 'CRITICAL', + 0: 'GOOD', + 1: 'BAD', }, }, externalAttributions: { @@ -438,8 +438,8 @@ describe('Test of loading function', () => { resources: { a: 1 }, config: { classifications: { - 0: 'UNKNOWN', - 1: 'CRITICAL', + 0: 'GOOD', + 1: 'BAD', }, }, manualAttributions: { diff --git a/src/ElectronBackend/input/__tests__/parseFile.test.ts b/src/ElectronBackend/input/__tests__/parseFile.test.ts index 1fa89da99..a65ea9c65 100644 --- a/src/ElectronBackend/input/__tests__/parseFile.test.ts +++ b/src/ElectronBackend/input/__tests__/parseFile.test.ts @@ -27,8 +27,8 @@ const correctInput: ParsedOpossumInputFile = { }, config: { classifications: { - 0: 'UNKNOWN', - 1: 'CRITICAL', + 0: 'GOOD', + 1: 'BAD', }, }, externalAttributions: { diff --git a/src/Frontend/Components/AccordionWithPieChart/AccordionWithPieChart.tsx b/src/Frontend/Components/AccordionWithPieChart/AccordionWithPieChart.tsx index 1fd04c90f..b367619cb 100644 --- a/src/Frontend/Components/AccordionWithPieChart/AccordionWithPieChart.tsx +++ b/src/Frontend/Components/AccordionWithPieChart/AccordionWithPieChart.tsx @@ -8,10 +8,6 @@ import MuiAccordionDetails from '@mui/material/AccordionDetails'; import MuiAccordionSummary from '@mui/material/AccordionSummary'; import MuiTypography from '@mui/material/Typography'; -import { - PieChartCriticalityNames, - ProjectStatisticsPopupTitle, -} from '../../enums/enums'; import { OpossumColors } from '../../shared-styles'; import { PieChartData } from '../../types/types'; import { PieChart } from '../PieChart/PieChart'; @@ -37,34 +33,18 @@ interface AccordionProps { data: Array; title: string; defaultExpanded?: boolean; + pieChartColorMap?: { [segmentName: string]: string }; } export function getColorsForPieChart( pieChartData: Array, - pieChartTitle: string, + pieChartColorMap?: { [segmentName: string]: string }, ): Array | undefined { - const pieChartColors: Array = []; - - if ( - pieChartTitle === ProjectStatisticsPopupTitle.CriticalSignalsCountPieChart - ) { - for (const pieChartSegment of pieChartData) { - switch (pieChartSegment.name) { - case PieChartCriticalityNames.HighCriticality: - pieChartColors.push(OpossumColors.orange); - break; - case PieChartCriticalityNames.MediumCriticality: - pieChartColors.push(OpossumColors.mediumOrange); - break; - default: - pieChartColors.push(OpossumColors.darkBlue); - break; - } - } - } else { + if (pieChartColorMap === undefined) { return; } - return pieChartColors; + + return pieChartData.map(({ name }) => pieChartColorMap[name]); } export const AccordionWithPieChart: React.FC = (props) => { @@ -87,7 +67,7 @@ export const AccordionWithPieChart: React.FC = (props) => { diff --git a/src/Frontend/Components/AccordionWithPieChart/__tests__/AccordionWithPieChart.test.tsx b/src/Frontend/Components/AccordionWithPieChart/__tests__/AccordionWithPieChart.test.tsx deleted file mode 100644 index 604781f59..000000000 --- a/src/Frontend/Components/AccordionWithPieChart/__tests__/AccordionWithPieChart.test.tsx +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates -// SPDX-FileCopyrightText: TNG Technology Consulting GmbH -// -// SPDX-License-Identifier: Apache-2.0 -import { - PieChartCriticalityNames, - ProjectStatisticsPopupTitle, -} from '../../../enums/enums'; -import { OpossumColors } from '../../../shared-styles'; -import { PieChartData } from '../../../types/types'; -import { getColorsForPieChart } from '../AccordionWithPieChart'; - -describe('getColorsForPieChart', () => { - it('obtains pie chart colors for critical signals pie chart', () => { - const expectedPieChartColors = [ - OpossumColors.orange, - OpossumColors.mediumOrange, - OpossumColors.darkBlue, - ]; - const criticalSignalsCount: Array = [ - { - name: PieChartCriticalityNames.HighCriticality, - count: 3, - }, - { - name: PieChartCriticalityNames.MediumCriticality, - count: 4, - }, - { - name: PieChartCriticalityNames.NoCriticality, - count: 2, - }, - ]; - - const pieChartColors = getColorsForPieChart( - criticalSignalsCount, - ProjectStatisticsPopupTitle.CriticalSignalsCountPieChart, - ); - - expect(pieChartColors).toEqual(expectedPieChartColors); - }); - - it('obtains undefined pie chart colors for default case', () => { - const expectedPieChartColors = undefined; - const sortedMostFrequentLicenses: Array = [ - { - name: 'Apache License Version 2.0', - count: 3, - }, - { - name: 'The MIT License (MIT)', - count: 3, - }, - ]; - - const pieChartColors = getColorsForPieChart( - sortedMostFrequentLicenses, - ProjectStatisticsPopupTitle.MostFrequentLicenseCountPieChart, - ); - - expect(pieChartColors).toEqual(expectedPieChartColors); - }); -}); diff --git a/src/Frontend/Components/ProjectStatisticsPopup/ProjectStatisticsPopup.tsx b/src/Frontend/Components/ProjectStatisticsPopup/ProjectStatisticsPopup.tsx index 9c73788eb..9478d5fe4 100644 --- a/src/Frontend/Components/ProjectStatisticsPopup/ProjectStatisticsPopup.tsx +++ b/src/Frontend/Components/ProjectStatisticsPopup/ProjectStatisticsPopup.tsx @@ -6,10 +6,12 @@ import MuiBox from '@mui/material/Box'; import MuiTypography from '@mui/material/Typography'; import { text } from '../../../shared/text'; -import { ProjectStatisticsPopupTitle } from '../../enums/enums'; +import { PieChartCriticalityNames } from '../../enums/enums'; +import { OpossumColors } from '../../shared-styles'; import { closePopup } from '../../state/actions/view-actions/view-actions'; import { useAppDispatch, useAppSelector } from '../../state/hooks'; import { + getClassifications, getExternalAttributionSources, getManualAttributions, getUnresolvedExternalAttributions, @@ -27,6 +29,7 @@ import { getCriticalSignalsCount, getIncompleteAttributionsCount, getMostFrequentLicenses, + getSignalCountByClassification, getUniqueLicenseNameToAttribution, } from './ProjectStatisticsPopup.util'; @@ -41,6 +44,7 @@ export const ProjectStatisticsPopup: React.FC = () => { const manualAttributions = useAppSelector(getManualAttributions); const attributionSources = useAppSelector(getExternalAttributionSources); + const classifications = useAppSelector(getClassifications); const unresolvedExternalAttribution = useAppSelector( getUnresolvedExternalAttributions, @@ -50,12 +54,15 @@ export const ProjectStatisticsPopup: React.FC = () => { unresolvedExternalAttribution, ); - const { licenseCounts, licenseNamesWithCriticality } = - aggregateLicensesAndSourcesFromAttributions( - unresolvedExternalAttribution, - strippedLicenseNameToAttribution, - attributionSources, - ); + const { + licenseCounts, + licenseNamesWithCriticality, + licenseNamesWithClassification, + } = aggregateLicensesAndSourcesFromAttributions( + unresolvedExternalAttribution, + strippedLicenseNameToAttribution, + attributionSources, + ); const mostFrequentLicenseCountData = getMostFrequentLicenses(licenseCounts); @@ -64,6 +71,18 @@ export const ProjectStatisticsPopup: React.FC = () => { licenseNamesWithCriticality, ); + const criticalSignalsCountColors = { + [PieChartCriticalityNames.HighCriticality]: OpossumColors.orange, + [PieChartCriticalityNames.MediumCriticality]: OpossumColors.mediumOrange, + [PieChartCriticalityNames.NoCriticality]: OpossumColors.darkBlue, + }; + + const signalCountByClassification = getSignalCountByClassification( + licenseCounts, + licenseNamesWithClassification, + classifications, + ); + const manualAttributionPropertyCounts = aggregateAttributionPropertiesFromAttributions(manualAttributions); @@ -73,6 +92,7 @@ export const ProjectStatisticsPopup: React.FC = () => { const isThereAnyPieChartData = mostFrequentLicenseCountData.length > 0 || criticalSignalsCountData.length > 0 || + signalCountByClassification.length > 0 || incompleteAttributionsData.length > 0; function close(): void { @@ -93,7 +113,8 @@ export const ProjectStatisticsPopup: React.FC = () => { manualAttributionPropertyCounts, )} title={ - ProjectStatisticsPopupTitle.AttributionPropertyCountTable + text.projectStatisticsPopup.charts + .attributionPropertyCountTable } /> { licenseCounts.totalAttributionsPerLicense } licenseNamesWithCriticality={licenseNamesWithCriticality} - title={ProjectStatisticsPopupTitle.CriticalLicensesTable} + title={text.projectStatisticsPopup.charts.criticalLicensesTable} /> {isThereAnyPieChartData - ? ProjectStatisticsPopupTitle.PieChartsSectionHeader + ? text.projectStatisticsPopup.charts.pieChartsSectionHeader : null} + } diff --git a/src/Frontend/Components/ProjectStatisticsPopup/ProjectStatisticsPopup.util.ts b/src/Frontend/Components/ProjectStatisticsPopup/ProjectStatisticsPopup.util.ts index 689077f2a..3868c9998 100644 --- a/src/Frontend/Components/ProjectStatisticsPopup/ProjectStatisticsPopup.util.ts +++ b/src/Frontend/Components/ProjectStatisticsPopup/ProjectStatisticsPopup.util.ts @@ -2,10 +2,11 @@ // SPDX-FileCopyrightText: TNG Technology Consulting GmbH // // SPDX-License-Identifier: Apache-2.0 -import { pickBy } from 'lodash'; +import { pickBy, toNumber } from 'lodash'; import { Attributions, + Classifications, Criticality, ExternalAttributionSources, PackageInfo, @@ -14,6 +15,7 @@ import { PieChartCriticalityNames } from '../../enums/enums'; import { AttributionCountPerSourcePerLicense, LicenseCounts, + LicenseNamesWithClassification, LicenseNamesWithCriticality, PieChartData, } from '../../types/types'; @@ -39,11 +41,13 @@ export function aggregateLicensesAndSourcesFromAttributions( ): { licenseCounts: LicenseCounts; licenseNamesWithCriticality: LicenseNamesWithCriticality; + licenseNamesWithClassification: LicenseNamesWithClassification; } { const { attributionCountPerSourcePerLicense, totalAttributionsPerLicense, licenseNamesWithCriticality, + licenseNamesWithClassification, } = getLicenseDataFromAttributionsAndSources( strippedLicenseNameToAttribution, attributions, @@ -67,7 +71,11 @@ export function aggregateLicensesAndSourcesFromAttributions( totalAttributionsPerSource, }; - return { licenseCounts, licenseNamesWithCriticality }; + return { + licenseCounts, + licenseNamesWithCriticality, + licenseNamesWithClassification, + }; } function getLicenseDataFromAttributionsAndSources( @@ -78,8 +86,10 @@ function getLicenseDataFromAttributionsAndSources( attributionCountPerSourcePerLicense: AttributionCountPerSourcePerLicense; totalAttributionsPerLicense: { [licenseName: string]: number }; licenseNamesWithCriticality: LicenseNamesWithCriticality; + licenseNamesWithClassification: LicenseNamesWithClassification; } { const licenseNamesWithCriticality: LicenseNamesWithCriticality = {}; + const licenseNamesWithClassification: LicenseNamesWithClassification = {}; const attributionCountPerSourcePerLicense: AttributionCountPerSourcePerLicense = {}; const totalAttributionsPerLicense: { [licenseName: string]: number } = {}; @@ -90,6 +100,7 @@ function getLicenseDataFromAttributionsAndSources( const { mostFrequentLicenseName, licenseCriticality, + licenseClassification, sourcesCountForLicense, } = getLicenseDataFromVariants( strippedLicenseNameToAttribution[strippedLicenseName], @@ -98,6 +109,8 @@ function getLicenseDataFromAttributionsAndSources( ); licenseNamesWithCriticality[mostFrequentLicenseName] = licenseCriticality; + licenseNamesWithClassification[mostFrequentLicenseName] = + licenseClassification; attributionCountPerSourcePerLicense[mostFrequentLicenseName] = sourcesCountForLicense; totalAttributionsPerLicense[mostFrequentLicenseName] = Object.values( @@ -111,6 +124,7 @@ function getLicenseDataFromAttributionsAndSources( attributionCountPerSourcePerLicense, totalAttributionsPerLicense, licenseNamesWithCriticality, + licenseNamesWithClassification, }; } @@ -121,6 +135,7 @@ function getLicenseDataFromVariants( ): { mostFrequentLicenseName: string; licenseCriticality: Criticality | undefined; + licenseClassification: number | undefined; sourcesCountForLicense: { [sourceNameOrTotal: string]: number; }; @@ -133,6 +148,8 @@ function getLicenseDataFromVariants( } = {}; const licenseCriticalityCounts = { high: 0, medium: 0, none: 0 }; + let licenseClassification: number | undefined = undefined; + for (const attributionId of attributionIds) { const licenseName = attributions[attributionId].licenseName; if (licenseName) { @@ -141,6 +158,17 @@ function getLicenseDataFromVariants( const variantCriticality = attributions[attributionId].criticality; + const variantClassification = attributions[attributionId].classification; + + if (licenseClassification === undefined) { + licenseClassification = variantClassification; + } else if (variantClassification !== undefined) { + licenseClassification = Math.max( + licenseClassification, + attributions[attributionId].classification ?? 0, + ); + } + licenseCriticalityCounts[variantCriticality || 'none']++; const sourceId = @@ -163,6 +191,7 @@ function getLicenseDataFromVariants( return { mostFrequentLicenseName, licenseCriticality, + licenseClassification, sourcesCountForLicense, }; } @@ -322,9 +351,46 @@ export function getCriticalSignalsCount( }, ]; - return criticalityData.filter( - (criticalityDataWithCount) => criticalityDataWithCount['count'] !== 0, - ); + return criticalityData.filter(({ count }) => count > 0); +} + +export function getSignalCountByClassification( + licenseCounts: LicenseCounts, + licenseNamesWithClassification: LicenseNamesWithClassification, + classifications: Classifications, +): Array { + const classificationCounts: { [classification: number]: number } = {}; + + for (const [license, attributionCount] of Object.entries( + licenseCounts.totalAttributionsPerLicense, + )) { + // count undefined classification at index -1 in classificationCounts + const classification = licenseNamesWithClassification[license] ?? -1; + classificationCounts[classification] = + (classificationCounts[classification] ?? 0) + attributionCount; + } + + const pieChartData = Object.keys(classifications) + .map((classification) => { + const classificationName = classifications[toNumber(classification)]; + const classificationCount = + classificationCounts[toNumber(classification)] ?? 0; + + return { + name: classificationName, + count: classificationCount, + }; + }) + .filter(({ count }) => count > 0); + + if (classificationCounts[-1]) { + return pieChartData.concat({ + name: 'No Classification', + count: classificationCounts[-1], + }); + } + + return pieChartData; } export function getIncompleteAttributionsCount( diff --git a/src/Frontend/Components/ProjectStatisticsPopup/__tests__/ProjectStatisticsPopup.test.tsx b/src/Frontend/Components/ProjectStatisticsPopup/__tests__/ProjectStatisticsPopup.test.tsx index 6ba6c9521..f9408d023 100644 --- a/src/Frontend/Components/ProjectStatisticsPopup/__tests__/ProjectStatisticsPopup.test.tsx +++ b/src/Frontend/Components/ProjectStatisticsPopup/__tests__/ProjectStatisticsPopup.test.tsx @@ -7,7 +7,6 @@ import userEvent from '@testing-library/user-event'; import { Attributions } from '../../../../shared/shared-types'; import { text } from '../../../../shared/text'; -import { ProjectStatisticsPopupTitle } from '../../../enums/enums'; import { loadFromFile } from '../../../state/actions/resource-actions/load-actions'; import { getParsedInputFileEnrichedWithTestData } from '../../../test-helpers/general-test-helpers'; import { renderComponent } from '../../../test-helpers/render'; @@ -49,7 +48,7 @@ describe('The ProjectStatisticsPopup', () => { expect(screen.getByText('Reuser')).toBeInTheDocument(); }); - it('renders pie charts when there are attributions', () => { + it('renders pie charts when there are signals', () => { const testManualAttributions: Attributions = { uuid_1: { source: { @@ -91,6 +90,7 @@ describe('The ProjectStatisticsPopup', () => { actions: [ loadFromFile( getParsedInputFileEnrichedWithTestData({ + config: { classifications: { 0: 'GOOD', 1: 'BAD' } }, manualAttributions: testManualAttributions, externalAttributions: testExternalAttributions, }), @@ -100,27 +100,33 @@ describe('The ProjectStatisticsPopup', () => { expect( screen.getByText( - ProjectStatisticsPopupTitle.MostFrequentLicenseCountPieChart, + text.projectStatisticsPopup.charts.mostFrequentLicenseCountPieChart, ), ).toBeInTheDocument(); expect( screen.getByText( - ProjectStatisticsPopupTitle.CriticalSignalsCountPieChart, + text.projectStatisticsPopup.charts.criticalSignalsCountPieChart, + ), + ).toBeInTheDocument(); + expect( + screen.getByText( + text.projectStatisticsPopup.charts.signalCountByClassificationPieChart, ), ).toBeInTheDocument(); expect( screen.getAllByText( - ProjectStatisticsPopupTitle.IncompleteLicensesPieChart, + text.projectStatisticsPopup.charts.incompleteAttributionsPieChart, ), ).toHaveLength(2); }); - it('does not render pie charts when there are no attributions', () => { + it('does not render pie charts when there are no signals', () => { const testExternalAttributions: Attributions = {}; renderComponent(, { actions: [ loadFromFile( getParsedInputFileEnrichedWithTestData({ + config: { classifications: { 0: 'GOOD', 1: 'BAD' } }, externalAttributions: testExternalAttributions, }), ), @@ -128,25 +134,27 @@ describe('The ProjectStatisticsPopup', () => { }); expect( screen.queryByText( - ProjectStatisticsPopupTitle.MostFrequentLicenseCountPieChart, + text.projectStatisticsPopup.charts.mostFrequentLicenseCountPieChart, ), ).not.toBeInTheDocument(); expect( screen.queryByText( - ProjectStatisticsPopupTitle.CriticalSignalsCountPieChart, + text.projectStatisticsPopup.charts.criticalSignalsCountPieChart, ), ).not.toBeInTheDocument(); expect( - screen.getByText(ProjectStatisticsPopupTitle.IncompleteLicensesPieChart), - ).toBeInTheDocument(); + screen.queryByText( + text.projectStatisticsPopup.charts.signalCountByClassificationPieChart, + ), + ).not.toBeInTheDocument(); expect( - screen.getAllByText( - ProjectStatisticsPopupTitle.IncompleteLicensesPieChart, + screen.getByText( + text.projectStatisticsPopup.charts.incompleteAttributionsPieChart, ), - ).not.toHaveLength(2); + ).toBeInTheDocument(); }); - it('renders pie charts pie charts related to signals even if there are no attributions', () => { + it('renders pie charts related to signals even if there are no attributions', () => { const testManualAttributions: Attributions = {}; const testExternalAttributions: Attributions = { uuid_1: { @@ -170,6 +178,7 @@ describe('The ProjectStatisticsPopup', () => { actions: [ loadFromFile( getParsedInputFileEnrichedWithTestData({ + config: { classifications: { 0: 'GOOD', 1: 'BAD' } }, manualAttributions: testManualAttributions, externalAttributions: testExternalAttributions, }), @@ -178,25 +187,27 @@ describe('The ProjectStatisticsPopup', () => { }); expect( screen.getByText( - ProjectStatisticsPopupTitle.MostFrequentLicenseCountPieChart, + text.projectStatisticsPopup.charts.mostFrequentLicenseCountPieChart, ), ).toBeInTheDocument(); expect( screen.getByText( - ProjectStatisticsPopupTitle.CriticalSignalsCountPieChart, + text.projectStatisticsPopup.charts.criticalSignalsCountPieChart, ), ).toBeInTheDocument(); expect( - screen.getByText(ProjectStatisticsPopupTitle.IncompleteLicensesPieChart), + screen.getByText( + text.projectStatisticsPopup.charts.signalCountByClassificationPieChart, + ), ).toBeInTheDocument(); expect( - screen.getAllByText( - ProjectStatisticsPopupTitle.IncompleteLicensesPieChart, + screen.getByText( + text.projectStatisticsPopup.charts.incompleteAttributionsPieChart, ), - ).not.toHaveLength(2); + ).toBeInTheDocument(); }); - it('renders tables when there are no attributions', () => { + it('renders tables when there are no attributions and no signals', () => { const testExternalAttributions: Attributions = {}; renderComponent(, { actions: [ diff --git a/src/Frontend/enums/enums.ts b/src/Frontend/enums/enums.ts index 6bc89a97b..6f702d2e7 100644 --- a/src/Frontend/enums/enums.ts +++ b/src/Frontend/enums/enums.ts @@ -24,16 +24,6 @@ export enum ButtonText { Delete = 'Delete', } -export enum ProjectStatisticsPopupTitle { - LicenseCountsTable = 'Signals per Sources', - AttributionPropertyCountTable = 'Attributions Overview', - CriticalLicensesTable = 'Critical Licenses', - PieChartsSectionHeader = 'Pie Charts', - MostFrequentLicenseCountPieChart = 'Most Frequent Licenses', - CriticalSignalsCountPieChart = 'Signals by Criticality', - IncompleteLicensesPieChart = 'Incomplete Attributions', -} - export enum PieChartCriticalityNames { HighCriticality = 'Highly critical signals', MediumCriticality = 'Medium critical signals', diff --git a/src/Frontend/state/actions/resource-actions/__tests__/load-actions.test.ts b/src/Frontend/state/actions/resource-actions/__tests__/load-actions.test.ts index aede447cb..be9211968 100644 --- a/src/Frontend/state/actions/resource-actions/__tests__/load-actions.test.ts +++ b/src/Frontend/state/actions/resource-actions/__tests__/load-actions.test.ts @@ -49,8 +49,8 @@ const testResources: Resources = { const testConfig: ProjectConfig = { classifications: { - 0: 'UNKNOWN', - 1: 'CRITICAL', + 0: 'GOOD', + 1: 'BAD', }, }; diff --git a/src/Frontend/test-helpers/general-test-helpers.ts b/src/Frontend/test-helpers/general-test-helpers.ts index 7191858fe..96502fa6e 100644 --- a/src/Frontend/test-helpers/general-test-helpers.ts +++ b/src/Frontend/test-helpers/general-test-helpers.ts @@ -10,6 +10,7 @@ import { AttributionsToResources, ExternalAttributionSources, ParsedFileContent, + ProjectConfig, Resources, ResourcesToAttributions, } from '../../shared/shared-types'; @@ -44,6 +45,7 @@ const EMPTY_PARSED_FILE_CONTENT: ParsedFileContent = { export function getParsedInputFileEnrichedWithTestData(testData: { resources?: Resources; + config?: ProjectConfig; manualAttributions?: Attributions; resourcesToManualAttributions?: ResourcesToAttributions; externalAttributions?: Attributions; @@ -76,6 +78,7 @@ export function getParsedInputFileEnrichedWithTestData(testData: { return { ...EMPTY_PARSED_FILE_CONTENT, resources, + ...(testData.config ? { config: testData.config } : {}), manualAttributions: { attributions: testData.manualAttributions || {}, resourcesToAttributions: testResourcesToManualAttributions, diff --git a/src/Frontend/types/types.ts b/src/Frontend/types/types.ts index e291242d0..757ec497f 100644 --- a/src/Frontend/types/types.ts +++ b/src/Frontend/types/types.ts @@ -51,3 +51,7 @@ export interface AttributionCountPerSourcePerLicense { export interface LicenseNamesWithCriticality { [licenseName: string]: Criticality | undefined; } + +export interface LicenseNamesWithClassification { + [licenseName: string]: number | undefined; +} diff --git a/src/shared/text.ts b/src/shared/text.ts index d50ca0561..984e0af91 100644 --- a/src/shared/text.ts +++ b/src/shared/text.ts @@ -167,6 +167,16 @@ export const text = { title: 'Project Statistics', toggleStartupCheckbox: 'Show project statistics on startup', criticalLicensesSignalCountColumnName: 'Signals Count', + charts: { + licenseCountsTable: 'Signals per Sources', + attributionPropertyCountTable: 'Attributions Overview', + criticalLicensesTable: 'Critical Licenses', + pieChartsSectionHeader: 'Pie Charts', + mostFrequentLicenseCountPieChart: 'Most Frequent Licenses', + criticalSignalsCountPieChart: 'Signals by Criticality', + signalCountByClassificationPieChart: 'Signals by Classification', + incompleteAttributionsPieChart: 'Incomplete Attributions', + }, }, unsavedChangesPopup: { title: 'Unsaved Changes',