├── .env.sample ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── pull_request_template.md └── workflows │ ├── build-and-e2e-test.yml │ ├── check-code-quality.yml │ ├── check-license-compliance.yml │ └── publish-release.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .lintstagedrc.js ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .reuse └── dep5 ├── .yarn ├── plugins │ └── @yarnpkg │ │ ├── plugin-engines.cjs │ │ ├── plugin-licenses.cjs │ │ └── plugin-spdx.cjs └── releases │ └── yarn-4.9.2.cjs ├── .yarnrc.yml ├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── DCO.md ├── LICENSE ├── LICENSES ├── Apache-2.0.txt ├── CC0-1.0.txt └── MIT.txt ├── README.md ├── USER_GUIDE.md ├── babel.config.json ├── commitlint.config.ts ├── docs ├── FileFormats.md ├── integration.png ├── integration.puml ├── intellij_playwright_plugin_test_config.png ├── logo.png ├── opossum_youtube.png ├── run_plantuml.sh ├── screenshots_of_the_ui.gif └── user_guide_screenshots │ ├── audit_view.png │ ├── breakpoint_icon.png │ ├── classification_icon.png │ ├── criticality_icon.png │ ├── directory_icon.png │ ├── disabled_qa_mode.png │ ├── enabled_qa_mode.png │ ├── exclude_from_notice_icon.png │ ├── file_icon.png │ ├── first_party_icon.png │ ├── has_signals_icon.png │ ├── incomplete_information_icon.png │ ├── needs_follow_up_icon.png │ ├── preferred_icon.png │ ├── previously_preferred_icon.png │ ├── report_view.png │ └── top_bar.png ├── eslint.config.mjs ├── example-files ├── input_from_ort.json.gz ├── large_opossum_input.json.gz ├── opossum_input.json └── opossum_ui_scan_input.json.gz ├── index.html ├── jest.config.mjs ├── knip.json ├── package.json ├── public ├── assets │ └── icons │ │ ├── about-black.png │ │ ├── about-white.png │ │ ├── check-box-black.png │ │ ├── check-box-blank-black.png │ │ ├── check-box-blank-white.png │ │ ├── check-box-white.png │ │ ├── chromium-black.png │ │ ├── chromium-white.png │ │ ├── com-list-black.png │ │ ├── com-list-white.png │ │ ├── copy-black.png │ │ ├── copy-white.png │ │ ├── cut-black.png │ │ ├── cut-white.png │ │ ├── det-list-black.png │ │ ├── det-list-white.png │ │ ├── developer-tool-black.png │ │ ├── developer-tool-white.png │ │ ├── export-black.png │ │ ├── export-white.png │ │ ├── follow-up-black.png │ │ ├── follow-up-white.png │ │ ├── full-screen-black.png │ │ ├── full-screen-white.png │ │ ├── github-black.png │ │ ├── github-white.png │ │ ├── import-black.png │ │ ├── import-white.png │ │ ├── json-black.png │ │ ├── json-white.png │ │ ├── location-searching-black.png │ │ ├── location-searching-white.png │ │ ├── log-black.png │ │ ├── log-white.png │ │ ├── magnifying-glass-black.png │ │ ├── magnifying-glass-white.png │ │ ├── merge-black.png │ │ ├── merge-white.png │ │ ├── notice-black.png │ │ ├── notice-white.png │ │ ├── open-black.png │ │ ├── open-white.png │ │ ├── paste-black.png │ │ ├── paste-white.png │ │ ├── quit-black.png │ │ ├── quit-white.png │ │ ├── redo-black.png │ │ ├── redo-white.png │ │ ├── restore-black.png │ │ ├── restore-white.png │ │ ├── save-black.png │ │ ├── save-white.png │ │ ├── search-black.png │ │ ├── search-white.png │ │ ├── select-all-black.png │ │ ├── select-all-white.png │ │ ├── statictics-black.png │ │ ├── statictics-white.png │ │ ├── undo-black.png │ │ ├── undo-white.png │ │ ├── update-black.png │ │ ├── update-white.png │ │ ├── user-guide-black.png │ │ ├── user-guide-white.png │ │ ├── yaml-black.png │ │ ├── yaml-white.png │ │ ├── zoom-in-black.png │ │ ├── zoom-in-white.png │ │ ├── zoom-out-black.png │ │ └── zoom-out-white.png └── icons │ ├── icon_512x512.png │ └── wave.svg ├── renovate.json ├── src ├── ElectronBackend │ ├── app.ts │ ├── enums │ │ └── enums.ts │ ├── errorHandling │ │ ├── __tests__ │ │ │ └── errorHandling.test.ts │ │ └── errorHandling.ts │ ├── input │ │ ├── OpossumInputFileSchema.json │ │ ├── OpossumOutputFileSchema.json │ │ ├── __tests__ │ │ │ ├── importFromFile.test.ts │ │ │ ├── parseFile.test.ts │ │ │ ├── parseInputData.test.ts │ │ │ └── refineConfiguration.test.ts │ │ ├── importFromFile.ts │ │ ├── parseFile.ts │ │ ├── parseInputData.ts │ │ └── refineConfiguration.ts │ ├── main │ │ ├── ProcessingStatusUpdater.ts │ │ ├── __tests__ │ │ │ ├── createWindowDev.test.ts │ │ │ ├── createWindowProd.test.ts │ │ │ ├── get-save-file-listener.test.ts │ │ │ ├── globalBackendState.test.ts │ │ │ ├── listeners.test.ts │ │ │ ├── mainErrorCase.test.ts │ │ │ ├── menu.test.ts │ │ │ ├── openFileFromCliOrEnvVariableIfProvided.test.ts │ │ │ └── user-settings-service.test.ts │ │ ├── createWindow.ts │ │ ├── dialogs.ts │ │ ├── getPath.ts │ │ ├── globalBackendState.ts │ │ ├── iconHelpers.ts │ │ ├── listeners.ts │ │ ├── logger.ts │ │ ├── main.ts │ │ ├── menu.ts │ │ ├── menu │ │ │ ├── aboutMenu.ts │ │ │ ├── editMenu.ts │ │ │ ├── fileMenu.ts │ │ │ ├── helpMenu.ts │ │ │ ├── switchableMenuItem.ts │ │ │ └── viewMenu.ts │ │ ├── notice-document-helpers.ts │ │ ├── openFileFromCliOrEnvVariableIfProvided.ts │ │ └── user-settings-service.ts │ ├── opossum-file │ │ ├── ExternalFileConverter.ts │ │ ├── FileConverter.ts │ │ ├── LegacyFileConverter.ts │ │ ├── __tests__ │ │ │ ├── legacy.json │ │ │ ├── merge_base.opossum │ │ │ ├── opossum-file.test.ts │ │ │ ├── owasp-dependency-check-report.json │ │ │ └── scancode.json │ │ └── opossum-file.ts │ ├── output │ │ ├── __tests__ │ │ │ ├── writeCsvToFile.test.ts │ │ │ └── writeSpdxFile.test.ts │ │ ├── writeCsvToFile.ts │ │ └── writeSpdxFile.ts │ ├── preload.ts │ ├── spdxTools │ │ ├── __tests__ │ │ │ └── spdxTools.test.ts │ │ ├── spdxTools.ts │ │ └── types.ts │ ├── tsconfig.json │ ├── types │ │ └── types.ts │ └── utils │ │ ├── __tests__ │ │ └── getLoadedFile.test.ts │ │ ├── getFilePathWithAppendix.ts │ │ ├── getLoadedFile.ts │ │ └── isOpossumFileFormat.ts ├── Frontend │ ├── Components │ │ ├── App │ │ │ ├── App.style.ts │ │ │ └── App.tsx │ │ ├── AppContainer │ │ │ └── AppContainer.tsx │ │ ├── AttributionCountPerSourcePerLicenseTable │ │ │ ├── AttributionCountPerSourcePerLicenseTable.tsx │ │ │ ├── AttributionCountPerSourcePerLicenseTable.util.ts │ │ │ ├── AttributionCountPerSourcePerLicenseTableFooter │ │ │ │ └── AttributionCountPerSourcePerLicenseTableFooter.tsx │ │ │ ├── AttributionCountPerSourcePerLicenseTableHead │ │ │ │ └── AttributionCountPerSourcePerLicenseTableHead.tsx │ │ │ ├── AttributionCountPerSourcePerLicenseTableRow │ │ │ │ └── AttributionCountPerSourcePerLicenseTableRow.tsx │ │ │ └── __tests__ │ │ │ │ ├── AttributionCountPerSourcePerLicenseTable.test.tsx │ │ │ │ └── AttributionCountPerSourcePerLicenseTable.util.test.ts │ │ ├── AttributionDetails │ │ │ ├── AttributionDetails.tsx │ │ │ ├── ButtonRow │ │ │ │ ├── ButtonRow.style.ts │ │ │ │ └── ButtonRow.tsx │ │ │ └── __tests__ │ │ │ │ └── AttributionDetails.test.tsx │ │ ├── AttributionForm │ │ │ ├── AttributionForm.style.ts │ │ │ ├── AttributionForm.tsx │ │ │ ├── AuditingOptions │ │ │ │ ├── AuditingOptions.tsx │ │ │ │ └── AuditingOptions.util.tsx │ │ │ ├── Comment │ │ │ │ └── Comment.tsx │ │ │ ├── CopyrightSubPanel │ │ │ │ └── CopyrightSubPanel.tsx │ │ │ ├── LicenseSubPanel │ │ │ │ └── LicenseSubPanel.tsx │ │ │ ├── PackageAutocomplete │ │ │ │ └── PackageAutocomplete.tsx │ │ │ ├── PackageSubPanel │ │ │ │ └── PackageSubPanel.tsx │ │ │ └── __tests__ │ │ │ │ └── AttributionForm.test.tsx │ │ ├── AttributionPanels │ │ │ ├── AttributionPanels.style.ts │ │ │ ├── AttributionPanels.tsx │ │ │ ├── AttributionsPanel │ │ │ │ ├── AttributionsList │ │ │ │ │ └── AttributionsList.tsx │ │ │ │ ├── AttributionsPanel.tsx │ │ │ │ ├── ConfirmButton │ │ │ │ │ └── ConfirmButton.tsx │ │ │ │ ├── CreateButton │ │ │ │ │ └── CreateButton.tsx │ │ │ │ ├── DeleteButton │ │ │ │ │ └── DeleteButton.tsx │ │ │ │ ├── LinkButton │ │ │ │ │ └── LinkButton.tsx │ │ │ │ ├── ReplaceButton │ │ │ │ │ └── ReplaceButton.tsx │ │ │ │ └── __tests__ │ │ │ │ │ └── AttributionsPanel.test.tsx │ │ │ ├── PackagesPanel │ │ │ │ ├── PackagesPanel.style.ts │ │ │ │ ├── PackagesPanel.tsx │ │ │ │ └── __tests__ │ │ │ │ │ └── PackagesPanel.test.tsx │ │ │ └── SignalsPanel │ │ │ │ ├── DeleteButton │ │ │ │ └── DeleteButton.tsx │ │ │ │ ├── IncludeExcludeButton │ │ │ │ └── IncludeExcludeButton.tsx │ │ │ │ ├── LinkButton │ │ │ │ └── LinkButton.tsx │ │ │ │ ├── RestoreButton │ │ │ │ └── RestoreButton.tsx │ │ │ │ ├── SignalsList │ │ │ │ ├── SignalsList.style.ts │ │ │ │ └── SignalsList.tsx │ │ │ │ ├── SignalsPanel.tsx │ │ │ │ └── __tests__ │ │ │ │ └── SignalsPanel.test.tsx │ │ ├── AuditView │ │ │ ├── AuditView.style.ts │ │ │ ├── AuditView.tsx │ │ │ └── __tests__ │ │ │ │ └── AuditView.test.tsx │ │ ├── Autocomplete │ │ │ ├── Autocomplete.style.tsx │ │ │ ├── Autocomplete.tsx │ │ │ ├── Listbox │ │ │ │ ├── Listbox.style.ts │ │ │ │ └── Listbox.tsx │ │ │ └── __tests__ │ │ │ │ └── Autocomplete.test.tsx │ │ ├── BackendCommunication │ │ │ └── BackendCommunication.tsx │ │ ├── BarChart │ │ │ └── BarChart.tsx │ │ ├── CardList │ │ │ └── CardList.tsx │ │ ├── Checkbox │ │ │ └── Checkbox.tsx │ │ ├── ConfirmDeletePopup │ │ │ ├── ConfirmDeletePopup.style.ts │ │ │ ├── ConfirmDeletePopup.tsx │ │ │ └── __tests__ │ │ │ │ └── ConfirmDeletePopup.test.tsx │ │ ├── ConfirmReplacePopup │ │ │ ├── ConfirmReplacePopup.style.ts │ │ │ ├── ConfirmReplacePopup.tsx │ │ │ └── __tests__ │ │ │ │ └── ConfirmReplacePopup.test.tsx │ │ ├── ConfirmSavePopup │ │ │ ├── ConfirmSavePopup.style.ts │ │ │ ├── ConfirmSavePopup.tsx │ │ │ └── __tests__ │ │ │ │ └── ConfirmSavePopup.test.tsx │ │ ├── ConfirmationDialog │ │ │ ├── ConfirmationDialog.tsx │ │ │ └── __test__ │ │ │ │ └── ConfirmationDialog.test.tsx │ │ ├── DialogLogDisplay │ │ │ └── DialogLogDisplay.style.ts │ │ ├── DiffEndIcon │ │ │ └── DiffEndIcon.tsx │ │ ├── DiffPopup │ │ │ ├── DiffPopup.style.tsx │ │ │ ├── DiffPopup.tsx │ │ │ ├── DiffPopup.util.tsx │ │ │ └── __test__ │ │ │ │ └── DiffPopup.util.test.tsx │ │ ├── EmptyPlaceholder │ │ │ ├── EmptyPlaceholder.style.ts │ │ │ └── EmptyPlaceholder.tsx │ │ ├── ErrorFallback │ │ │ ├── ErrorFallback.style.ts │ │ │ └── ErrorFallback.tsx │ │ ├── ErrorPopup │ │ │ ├── ErrorPopup.tsx │ │ │ └── __tests__ │ │ │ │ └── ErrorPopup.test.tsx │ │ ├── FilePathInput │ │ │ └── FilePathInput.tsx │ │ ├── FilterButton │ │ │ ├── FilterButton.style.ts │ │ │ ├── FilterButton.tsx │ │ │ ├── LicenseAutocomplete │ │ │ │ └── LicenseAutocomplete.tsx │ │ │ └── __tests__ │ │ │ │ └── FilterButton.test.tsx │ │ ├── GlobalPopup │ │ │ ├── GlobalPopup.tsx │ │ │ └── __tests__ │ │ │ │ └── GlobalPopup.test.tsx │ │ ├── GoToLinkButton │ │ │ ├── GoToLinkButton.tsx │ │ │ └── __tests__ │ │ │ │ └── GoToLinkButton.test.tsx │ │ ├── GroupedList │ │ │ ├── GroupedList.style.ts │ │ │ ├── GroupedList.tsx │ │ │ └── __tests__ │ │ │ │ └── GroupedList.test.tsx │ │ ├── IconButton │ │ │ ├── IconButton.tsx │ │ │ └── __tests__ │ │ │ │ └── IconButton.test.tsx │ │ ├── Icons │ │ │ ├── Icons.tsx │ │ │ └── __tests__ │ │ │ │ └── Icons.test.tsx │ │ ├── ImportDialog │ │ │ └── ImportDialog.tsx │ │ ├── List │ │ │ ├── List.style.ts │ │ │ ├── List.tsx │ │ │ └── __tests__ │ │ │ │ └── List.test.tsx │ │ ├── LoadingMask │ │ │ ├── LoadingMask.style.ts │ │ │ └── LoadingMask.tsx │ │ ├── LogDisplay │ │ │ ├── LogDisplay.style.ts │ │ │ └── LogDisplay.tsx │ │ ├── MergeDialog │ │ │ └── MergeDialog.tsx │ │ ├── NotSavedPopup │ │ │ ├── NotSavedPopup.tsx │ │ │ └── __tests__ │ │ │ │ └── NotSavedPopup.test.tsx │ │ ├── NotificationPopup │ │ │ ├── NotificationPopup.tsx │ │ │ └── __tests__ │ │ │ │ └── NotificationPopup.test.tsx │ │ ├── PackageCard │ │ │ ├── PackageCard.tsx │ │ │ ├── PackageCard.util.tsx │ │ │ └── __tests__ │ │ │ │ └── PackageCard.test.tsx │ │ ├── PathBar │ │ │ ├── PathBar.tsx │ │ │ └── __tests__ │ │ │ │ └── PathBar.test.tsx │ │ ├── PieChart │ │ │ └── PieChart.tsx │ │ ├── ProcessPopup │ │ │ ├── ProcessPopup.style.ts │ │ │ ├── ProcessPopup.tsx │ │ │ └── __tests__ │ │ │ │ └── ProcessPopup.test.tsx │ │ ├── ProgressBar │ │ │ ├── ProgressBar.tsx │ │ │ ├── ProgressBar.util.tsx │ │ │ └── __tests__ │ │ │ │ ├── ProgressBar.test.tsx │ │ │ │ └── ProgressBar.util.test.ts │ │ ├── ProjectMetadataPopup │ │ │ ├── ProjectMetadataPopup.tsx │ │ │ └── __tests__ │ │ │ │ └── ProjectMetadataPopup.test.tsx │ │ ├── ProjectMetadataTable │ │ │ └── ProjectMetadataTable.tsx │ │ ├── ProjectStatisticsPopup │ │ │ ├── ProjectStatisticsPopup.style.ts │ │ │ ├── ProjectStatisticsPopup.tsx │ │ │ ├── ProjectStatisticsPopup.util.ts │ │ │ └── __tests__ │ │ │ │ ├── ProjectStatisticsPopup.test.tsx │ │ │ │ └── ProjectStatisticsPopup.util.test.tsx │ │ ├── ReportTableHeader │ │ │ ├── ReportTableHeader.tsx │ │ │ └── __tests__ │ │ │ │ └── ReportTableHeader.test.tsx │ │ ├── ReportTableItem │ │ │ ├── ReportTableItem.tsx │ │ │ ├── ReportTableItem.util.ts │ │ │ └── __tests__ │ │ │ │ ├── ReportTableItem.test.tsx │ │ │ │ └── ReportTableItem.util.test.tsx │ │ ├── ReportView │ │ │ ├── ReportView.tsx │ │ │ ├── TableConfig.tsx │ │ │ └── __tests__ │ │ │ │ └── ReportView.test.tsx │ │ ├── ResizableBox │ │ │ └── ResizableBox.tsx │ │ ├── ResizePanels │ │ │ ├── ResizeButton │ │ │ │ └── ResizeButton.tsx │ │ │ ├── ResizePanels.style.ts │ │ │ └── ResizePanels.tsx │ │ ├── ResourceBrowser │ │ │ ├── LinkedResourcesTree │ │ │ │ ├── LinkedResourcesTree.tsx │ │ │ │ ├── LinkedResourcesTreeNode │ │ │ │ │ ├── LinkedResourcesTreeNode.tsx │ │ │ │ │ └── __tests__ │ │ │ │ │ │ └── LinkedResourcesTreeNode.test.tsx │ │ │ │ └── __tests__ │ │ │ │ │ └── LinkedResourcesTree.test.tsx │ │ │ ├── ResourceBrowser.tsx │ │ │ └── ResourcesTree │ │ │ │ ├── ResourcesTree.tsx │ │ │ │ ├── ResourcesTreeNode │ │ │ │ ├── ResourcesTreeNode.tsx │ │ │ │ ├── ResourcesTreeNode.util.ts │ │ │ │ ├── ResourcesTreeNodeLabel │ │ │ │ │ ├── ResourcesTreeNodeLabel.tsx │ │ │ │ │ └── __tests__ │ │ │ │ │ │ └── ResourcesTreeNodeLabel.test.tsx │ │ │ │ └── __tests__ │ │ │ │ │ └── ResourcesTreeNode.util.test.ts │ │ │ │ └── __tests__ │ │ │ │ └── ResourcesTree.test.tsx │ │ ├── SearchList │ │ │ └── SearchList.tsx │ │ ├── SearchRefContext │ │ │ └── SearchRefContext.tsx │ │ ├── SelectMenu │ │ │ ├── SelectMenu.style.tsx │ │ │ ├── SelectMenu.tsx │ │ │ └── __tests__ │ │ │ │ └── SelectMenu.test.tsx │ │ ├── SortButton │ │ │ ├── SortButton.tsx │ │ │ ├── __tests__ │ │ │ │ └── SortButton.test.tsx │ │ │ └── useSortingOptions.tsx │ │ ├── Spinner │ │ │ └── Spinner.tsx │ │ ├── SwitchableProgressBar │ │ │ ├── SwitchableProgressBar.tsx │ │ │ └── __tests__ │ │ │ │ └── SwitchableProcessBar.test.tsx │ │ ├── TableCellWithSorting │ │ │ └── TableCellWithSorting.tsx │ │ ├── TextBox │ │ │ ├── TextBox.tsx │ │ │ └── __tests__ │ │ │ │ └── TextBox.test.tsx │ │ ├── Toaster │ │ │ ├── Toaster.tsx │ │ │ ├── Toaster.util.ts │ │ │ └── index.ts │ │ ├── TopBar │ │ │ ├── TopBar.tsx │ │ │ └── __tests__ │ │ │ │ └── TopBar.test.tsx │ │ ├── UpdateAppPopup │ │ │ ├── UpdateAppPopup.tsx │ │ │ ├── UpdateAppPopup.util.ts │ │ │ └── __tests__ │ │ │ │ └── UpdateAppPopup.test.tsx │ │ ├── VirtualizedTree │ │ │ ├── VirtualizedTree.tsx │ │ │ ├── VirtualizedTree.util.ts │ │ │ ├── VirtualizedTreeNode │ │ │ │ ├── VirtualizedTreeNode.tsx │ │ │ │ └── VirtualizedTreeNode.util.ts │ │ │ └── __tests__ │ │ │ │ └── VirtualizedTree.test.tsx │ │ └── VirtuosoComponentContext │ │ │ └── VirtuosoComponentContext.tsx │ ├── enums │ │ └── enums.ts │ ├── shared-constants.ts │ ├── shared-styles.ts │ ├── state │ │ ├── actions │ │ │ ├── popup-actions │ │ │ │ ├── __tests__ │ │ │ │ │ └── popup-actions.test.ts │ │ │ │ └── popup-actions.ts │ │ │ ├── resource-actions │ │ │ │ ├── __tests__ │ │ │ │ │ ├── all-views-simple-actions.test.ts │ │ │ │ │ ├── audit-view-simple-actions.test.ts │ │ │ │ │ ├── load-actions.test.ts │ │ │ │ │ ├── navigation-actions.test.ts │ │ │ │ │ ├── preference-actions.test.ts │ │ │ │ │ └── save-actions.test.ts │ │ │ │ ├── all-views-simple-actions.ts │ │ │ │ ├── audit-view-simple-actions.ts │ │ │ │ ├── export-actions.ts │ │ │ │ ├── load-actions.ts │ │ │ │ ├── navigation-actions.ts │ │ │ │ ├── preference-actions.ts │ │ │ │ ├── save-actions.ts │ │ │ │ └── types.ts │ │ │ ├── user-settings-actions │ │ │ │ ├── __tests__ │ │ │ │ │ └── user-settings-actions.test.ts │ │ │ │ ├── types.ts │ │ │ │ └── user-settings-actions.ts │ │ │ ├── variables-actions │ │ │ │ ├── types.ts │ │ │ │ └── variables-actions.ts │ │ │ └── view-actions │ │ │ │ ├── __tests__ │ │ │ │ └── view-actions.test.ts │ │ │ │ ├── types.ts │ │ │ │ └── view-actions.ts │ │ ├── configure-store.ts │ │ ├── helpers │ │ │ ├── __tests__ │ │ │ │ ├── get-parents.test.ts │ │ │ │ ├── progress-bar-data-helpers.test.ts │ │ │ │ ├── resource-helpers.test.ts │ │ │ │ └── save-action-helpers.test.ts │ │ │ ├── get-parents.ts │ │ │ ├── progress-bar-data-helpers.ts │ │ │ ├── resources-helpers.ts │ │ │ └── save-action-helpers.ts │ │ ├── hooks.ts │ │ ├── reducer.ts │ │ ├── reducers │ │ │ ├── resource-reducer.ts │ │ │ ├── user-settings-reducer.ts │ │ │ ├── variables-reducer.ts │ │ │ └── view-reducer.ts │ │ ├── selectors │ │ │ ├── __tests__ │ │ │ │ ├── all-views-resource-selectors.test.ts │ │ │ │ ├── audit-view-resource-selectors.test.ts │ │ │ │ └── resource-selectors.test.ts │ │ │ ├── resource-selectors.ts │ │ │ ├── user-settings-selector.ts │ │ │ └── view-selector.ts │ │ ├── types.ts │ │ └── variables │ │ │ ├── __tests__ │ │ │ └── use-variable.test.ts │ │ │ ├── use-attribution-ids-for-replacement.ts │ │ │ ├── use-filtered-data.ts │ │ │ ├── use-panel-sizes.ts │ │ │ ├── use-progress-data.ts │ │ │ ├── use-user-setting.ts │ │ │ └── use-variable.ts │ ├── test-helpers │ │ ├── general-test-helpers.ts │ │ └── render.tsx │ ├── types │ │ └── types.ts │ ├── util │ │ ├── __tests__ │ │ │ ├── attribution-utils.test.ts │ │ │ ├── can-have-children.test.ts │ │ │ ├── get-card-labels.test.ts │ │ │ ├── get-closest-parent-attribution.test.ts │ │ │ ├── get-contained-attribution-count.test.ts │ │ │ ├── get-stripped-package-info.test.ts │ │ │ ├── handle-purl.test.ts │ │ │ ├── input-validation.test.ts │ │ │ ├── lodash-extension-utils.test.ts │ │ │ ├── maybe-pluralize.test.ts │ │ │ ├── open-url.test.ts │ │ │ ├── package-search-api.test.ts │ │ │ ├── prettify-source.test.ts │ │ │ ├── search-package-info.test.ts │ │ │ ├── sort-attributions.test.tsx │ │ │ └── tryit.test.ts │ │ ├── attribution-utils.ts │ │ ├── can-resource-have-children.ts │ │ ├── ensure-array.ts │ │ ├── get-card-labels.ts │ │ ├── get-closest-parent-attributions.ts │ │ ├── get-comparable-attributes.ts │ │ ├── get-contained-attribution-count.ts │ │ ├── get-stripped-package-info.ts │ │ ├── handle-purl.ts │ │ ├── http-client.ts │ │ ├── input-validation.ts │ │ ├── lodash-extension-utils.ts │ │ ├── maybe-pluralize.ts │ │ ├── open-url.ts │ │ ├── package-search-api.ts │ │ ├── package-search-hooks.ts │ │ ├── prettify-source.ts │ │ ├── search-package-info.ts │ │ ├── sort-attributions.ts │ │ ├── tryit.ts │ │ ├── use-debounced-input.ts │ │ ├── use-ipc-renderer.ts │ │ ├── use-previous.ts │ │ ├── use-processing-status-updated.ts │ │ └── use-virtuoso-refs.ts │ └── web-workers │ │ ├── __tests__ │ │ ├── signals-worker.test.ts │ │ └── use-signals-worker.test.ts │ │ ├── scripts │ │ ├── __tests__ │ │ │ └── get-filtered-attributions.test.ts │ │ ├── get-filtered-attributions.ts │ │ └── get-progress-data.ts │ │ ├── signals-worker.ts │ │ └── use-signals-worker.ts ├── e2e-tests │ ├── __tests__ │ │ ├── comparing-attribution-with-origin.test.ts │ │ ├── confirming-preselected-attributions.test.ts │ │ ├── creating-attributions.test.ts │ │ ├── deleting-attributions.test.ts │ │ ├── deleting-signals.test.ts │ │ ├── displaying-project-metadata.test.ts │ │ ├── filtering-attributions.test.ts │ │ ├── filtering-signals.test.ts │ │ ├── import-dialog.test.ts │ │ ├── interacting-with-linked-resources.test.ts │ │ ├── interacting-with-resources.test.ts │ │ ├── linking-attributions.test.ts │ │ ├── merge-dialog.test.ts │ │ ├── open-files.test.ts │ │ ├── opening-invalid-resource-urls.test.ts │ │ ├── preferring-attributions.test.ts │ │ ├── project-statistics.test.ts │ │ ├── replacing-attributions.test.ts │ │ ├── selecting-attributions.test.ts │ │ ├── selecting-resources.test.ts │ │ ├── selecting-signals.test.ts │ │ ├── sorting-signals.test.ts │ │ ├── toggle-showing-classification-criticality.test.ts │ │ ├── updating-attributions.test.ts │ │ └── using-app-without-a-file.test.ts │ ├── owasp-dependency-check-report.json │ ├── page-objects │ │ ├── AttributionDetails.ts │ │ ├── AttributionForm.ts │ │ ├── AttributionsPanel.ts │ │ ├── ConfirmDeletePopup.ts │ │ ├── ConfirmReplacePopup.ts │ │ ├── ConfirmSavePopup.ts │ │ ├── ConfirmationDialog.ts │ │ ├── DiffPopup.ts │ │ ├── ErrorPopup.ts │ │ ├── FileSupportPopup.ts │ │ ├── ImportDialog.ts │ │ ├── LinkedResourcesTree.ts │ │ ├── MenuBar.ts │ │ ├── MergeDialog.ts │ │ ├── NotSavedPopup.ts │ │ ├── PackageCard.ts │ │ ├── PathBar.ts │ │ ├── ProjectMetadataPopup.ts │ │ ├── ProjectStatisticsPopup.ts │ │ ├── ReportView.ts │ │ ├── ResourcesTree.ts │ │ ├── SignalsPanel.ts │ │ └── TopBar.ts │ ├── playwright.config.ts │ ├── scancode.json │ └── utils │ │ ├── fixtures.ts │ │ ├── index.ts │ │ └── retry.ts ├── index.tsx ├── shared │ ├── ipc-channels.ts │ ├── shared-constants.ts │ ├── shared-types.ts │ ├── text.ts │ └── write-file.ts ├── testing │ ├── Faker.ts │ ├── global-test-setup.ts │ ├── global-test-teardown.ts │ └── setup-tests.ts └── vite-env.d.ts ├── tools ├── build_linux_release.sh ├── checkNotices.sh ├── checkout_PR_and_start_opossum_ui.sh ├── downloadOpossumFile.mjs ├── generateNotices.mjs ├── get_app_version_for_windows.bat ├── notices.template.html ├── runScriptArch.mjs ├── start_linux_darwin.sh └── start_windows.bat ├── tsconfig.eslint.json ├── tsconfig.json ├── vite.config.mts └── yarn.lock /.env.sample: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | # GitHub token to use when downloading releases. 7 | GITHUB_TOKEN=gho_foobar 8 | 9 | # Number of workers Playwright will use to run tests. Can also be set to, e.g., "50%" of the number of CPU cores. 10 | WORKERS=1 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | * text=auto eol=lf 7 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | 28 | - OS: [e.g. iOS] 29 | 30 | **Additional context** 31 | Add any other context about the problem here. 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ### Summary of changes 2 | 3 | 4 | 5 | ### Context and reason for change 6 | 7 | 8 | 9 | ### How can the changes be tested 10 | 11 | 12 | 13 | Note: Please review the [guidelines for contributing](https://github.com/opossum-tool/OpossumUI/blob/main/CONTRIBUTING.md) to this repository. 14 | -------------------------------------------------------------------------------- /.github/workflows/build-and-e2e-test.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | name: Build and E2E Test 7 | 8 | on: 9 | push: 10 | branches: 11 | - main 12 | - 'renovate/*' 13 | pull_request: 14 | types: [opened, reopened, synchronize] 15 | workflow_dispatch: 16 | 17 | jobs: 18 | build-and-test: 19 | runs-on: ${{ matrix.os }} 20 | if: | 21 | !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'renovate/')) 22 | strategy: 23 | fail-fast: false 24 | matrix: 25 | os: [ubuntu-latest, macos-latest, windows-latest] 26 | include: 27 | - os: ubuntu-latest 28 | # https://github.com/microsoft/playwright/issues/11932 29 | E2E: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- yarn test:e2e:ci 30 | - os: macos-latest 31 | E2E: yarn test:e2e:ci 32 | - os: windows-latest 33 | E2E: yarn test:e2e:ci 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | steps: 37 | - uses: actions/checkout@v4 38 | 39 | - uses: actions/setup-node@v4 40 | with: 41 | cache: 'yarn' 42 | node-version: 22 43 | 44 | - run: yarn install --immutable 45 | 46 | - run: yarn ship:auto 47 | 48 | - run: yarn spdx 49 | 50 | - run: ${{ matrix.E2E }} 51 | 52 | - uses: actions/upload-artifact@v4 53 | if: failure() 54 | with: 55 | name: artifacts-${{ matrix.os }} 56 | path: src/e2e-tests/artifacts 57 | retention-days: 30 58 | -------------------------------------------------------------------------------- /.github/workflows/check-code-quality.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | name: Check code quality 7 | 8 | on: 9 | push: 10 | branches: 11 | - main 12 | - 'renovate/*' 13 | pull_request: 14 | types: [opened, reopened, synchronize] 15 | workflow_dispatch: 16 | 17 | jobs: 18 | check-code-quality: 19 | runs-on: ubuntu-latest 20 | if: | 21 | !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'renovate/')) 22 | env: 23 | CI: true 24 | TARGET_BRANCH: origin/${{ github.event_name == 'pull_request' && github.base_ref || 'main' }} 25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 26 | steps: 27 | - uses: actions/checkout@v4 28 | with: 29 | fetch-depth: 0 30 | 31 | - uses: actions/setup-node@v4 32 | with: 33 | cache: 'yarn' 34 | node-version: 22 35 | 36 | - run: yarn install --immutable 37 | 38 | - run: yarn format-check 39 | 40 | - run: yarn lint-commits 41 | 42 | - run: yarn lint-check 43 | 44 | - run: yarn typecheck 45 | 46 | - run: yarn circular-import-check 47 | 48 | - run: yarn knip 49 | 50 | - run: yarn test:unit 51 | -------------------------------------------------------------------------------- /.github/workflows/check-license-compliance.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | # 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | name: Check license compliance 7 | 8 | on: 9 | push: 10 | branches: 11 | - main 12 | - 'renovate/*' 13 | pull_request: 14 | types: [opened, reopened, synchronize] 15 | workflow_dispatch: 16 | 17 | jobs: 18 | check-license-compliance: 19 | runs-on: ubuntu-latest 20 | if: | 21 | !(github.event_name == 'pull_request' && startsWith(github.head_ref, 'renovate/')) 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - uses: fsfe/reuse-action@v5 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | 4 | # testing 5 | /coverage 6 | /src/commitInfo.json 7 | /example-files/*.opossum 8 | /example-files/*_attributions.json 9 | /example-files/*_follow_up.csv 10 | /example-files/*_component_list.csv 11 | /example-files/*.spdx.yaml 12 | /example-files/*.spdx.json 13 | /example-files/performance_tests/*.opossum 14 | /example-files/performance_tests/*_attributions.json 15 | /example-files/performance_tests/*_follow_up.csv 16 | /example-files/performance_tests/*_component_list.csv 17 | /src/e2e-tests/artifacts 18 | playwright-report 19 | /test-output 20 | /bin 21 | 22 | # production 23 | /build 24 | 25 | # release 26 | /dist-electron 27 | /release 28 | opossum-ui.spdx.json 29 | 30 | # misc 31 | .DS_Store 32 | .env.local 33 | .env.development.local 34 | .env.test.local 35 | .env.production.local 36 | 37 | yarn-debug.log* 38 | yarn-error.log* 39 | .yarn/cache 40 | .yarn/install-state.gz 41 | 42 | .idea 43 | /opossumUI.iml 44 | /notices 45 | 46 | /.vscode 47 | /.run 48 | 49 | .env 50 | 51 | .gitconfig 52 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 4 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 5 | # 6 | # SPDX-License-Identifier: Apache-2.0 7 | 8 | yarn commitlint --edit ${1} 9 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 4 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 5 | # 6 | # SPDX-License-Identifier: Apache-2.0 7 | 8 | yarn pre-commit 9 | -------------------------------------------------------------------------------- /.lintstagedrc.js: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | module.exports = { 7 | '*': [ 8 | () => 'yarn copyright-lint-check', 9 | () => 'knip', 10 | 'prettier --write --ignore-unknown', 11 | ], 12 | '*.{ts,tsx}': 'eslint', 13 | '!(src/ElectronBackend/**/*)*.{ts,tsx}': () => 'tsc -p ./', 14 | 'src/ElectronBackend/**/*.{ts,tsx}': () => 15 | 'tsc --noEmit -p src/ElectronBackend', 16 | }; 17 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Node 2 | **/.DS_Store 3 | **/.Rhistory 4 | **/node_modules 5 | 6 | # Builds 7 | build 8 | dist 9 | CHANGELOG.md 10 | 11 | # IDEs 12 | .vscode 13 | **/.idea 14 | **/coverage 15 | *.sublime-project 16 | *.sublime-workspace 17 | *.iml 18 | 19 | # Logs 20 | npm-debug.log* 21 | yarn-debug.log* 22 | yarn-error.log* 23 | logs 24 | *.log 25 | lerna-debug.log* 26 | 27 | # Yarn 28 | .yarn-integrity 29 | .pnp.* 30 | .yarn/* 31 | 32 | # dotenv environment variables file 33 | .env 34 | .env.test 35 | 36 | # Git hooks 37 | .husky 38 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "endOfLine": "lf", 4 | "importOrder": ["", "^[./]"], 5 | "importOrderCaseInsensitive": true, 6 | "importOrderParserPlugins": [ 7 | "classProperties", 8 | "decorators-legacy", 9 | "typescript", 10 | "jsx" 11 | ], 12 | "importOrderSeparation": true, 13 | "importOrderSortSpecifiers": true, 14 | "plugins": ["@trivago/prettier-plugin-sort-imports", "prettier-plugin-sh"], 15 | "semi": true, 16 | "singleQuote": true, 17 | "trailingComma": "all", 18 | "useTabs": false 19 | } 20 | -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Source: https://github.com/opossum-tool/opossumUI 3 | 4 | Files: *.json *.json.gz *.prettierrc *.prettierignore **.gitignore **yarn.lock **.opossum *yarn-*.cjs *.yarnrc.yml *.nvmrc 5 | Copyright: Meta Platforms, Inc. and its affiliates 6 | TNG Technology Consulting GmbH 7 | License: Apache-2.0 8 | 9 | Files: docs/logo.png 10 | Copyright: Meta Platforms, Inc. and its affiliates 11 | TNG Technology Consulting GmbH 12 | License: Apache-2.0 13 | 14 | Files: docs/* public/icons/* .github/pull_request_template.md .github/ISSUE_TEMPLATE/* public/assets/icons/* 15 | Copyright: Meta Platforms, Inc. and its affiliates 16 | TNG Technology Consulting GmbH 17 | License: CC0-1.0 18 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: mixed 2 | 3 | enableGlobalCache: false 4 | 5 | enableHardenedMode: false 6 | 7 | nodeLinker: node-modules 8 | 9 | plugins: 10 | - checksum: f850d56621bac3235ad891222942ac396f122ac3308e8e9e36bce43e1bcb8697cad4c81529fc55b164fc0f5e45aa8dc1585fa90bd1e0fa9d6a05f3a85e080ebb 11 | path: .yarn/plugins/@yarnpkg/plugin-licenses.cjs 12 | spec: 'https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.13.0/bundles/@yarnpkg/plugin-licenses.js' 13 | - checksum: 8f13acff9aef76f5fbfb5474b6d23b14ed3f49258cf4e344229e3515e42f4d6990e3c51b9ab176aa46c407fb9ca97fc0902c6400db5a44e9994d0b53512f3aed 14 | path: .yarn/plugins/@yarnpkg/plugin-engines.cjs 15 | spec: 'https://raw.githubusercontent.com/devoto13/yarn-plugin-engines/main/bundles/%40yarnpkg/plugin-engines.js' 16 | - checksum: 006d0325e832b7267fa88084a62d319de313ca2541dca62f8fea3125f095a4cc1b8791897f1d803d38179a972aa2152533d11525e463fb8073ca358ee8601f44 17 | path: .yarn/plugins/@yarnpkg/plugin-spdx.cjs 18 | spec: 'https://raw.githubusercontent.com/spdx/yarn-plugin-spdx/main/bundles/@yarnpkg/plugin-spdx.js' 19 | 20 | yarnPath: .yarn/releases/yarn-4.9.2.cjs 21 | -------------------------------------------------------------------------------- /LICENSES/Apache-2.0.txt: -------------------------------------------------------------------------------- 1 | ../LICENSE -------------------------------------------------------------------------------- /LICENSES/MIT.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "current" 8 | } 9 | } 10 | ], 11 | "@babel/preset-typescript", 12 | [ 13 | "@babel/preset-react", 14 | { 15 | "runtime": "automatic" 16 | } 17 | ] 18 | ], 19 | // https://github.com/vitejs/vite/issues/1149 20 | "plugins": ["babel-plugin-transform-import-meta"] 21 | } 22 | -------------------------------------------------------------------------------- /commitlint.config.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import type { UserConfig } from '@commitlint/types'; 6 | 7 | const config: UserConfig = { 8 | extends: ['@commitlint/config-conventional'], 9 | rules: { 10 | 'body-leading-blank': [2, 'always'], 11 | 'body-max-line-length': [2, 'always', 600], 12 | 'footer-leading-blank': [2, 'always'], 13 | }, 14 | }; 15 | 16 | export default config; 17 | -------------------------------------------------------------------------------- /docs/integration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/integration.png -------------------------------------------------------------------------------- /docs/integration.puml: -------------------------------------------------------------------------------- 1 | @startmindmap 2 | 28 | * OpossumUI 29 | --_ Opossum File (.opossum) 30 | --_ Opossum Legacy File (.json/.json.gz) 31 | --- oss-review-toolkit/ort 32 | ----_ OSS Review Toolkit JSON / YAML 33 | --_ ScanCode JSON 34 | --_ OWASP Dependency check JSON 35 | ++_ SPDX-2.2 (Lite) JSON / YAML 36 | ++_ CSV attributions list 37 | ++_ CSV follow-up list 38 | @endmindmap 39 | -------------------------------------------------------------------------------- /docs/intellij_playwright_plugin_test_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/intellij_playwright_plugin_test_config.png -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/logo.png -------------------------------------------------------------------------------- /docs/opossum_youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/opossum_youtube.png -------------------------------------------------------------------------------- /docs/run_plantuml.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 4 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 5 | # 6 | # SPDX-License-Identifier: Apache-2.0 7 | 8 | find "$(dirname "$0")" -iname '*.puml' -print -exec plantuml {} \; 9 | -------------------------------------------------------------------------------- /docs/screenshots_of_the_ui.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/screenshots_of_the_ui.gif -------------------------------------------------------------------------------- /docs/user_guide_screenshots/audit_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/audit_view.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/breakpoint_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/breakpoint_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/classification_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/classification_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/criticality_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/criticality_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/directory_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/directory_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/disabled_qa_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/disabled_qa_mode.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/enabled_qa_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/enabled_qa_mode.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/exclude_from_notice_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/exclude_from_notice_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/file_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/file_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/first_party_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/first_party_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/has_signals_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/has_signals_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/incomplete_information_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/incomplete_information_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/needs_follow_up_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/needs_follow_up_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/preferred_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/preferred_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/previously_preferred_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/previously_preferred_icon.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/report_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/report_view.png -------------------------------------------------------------------------------- /docs/user_guide_screenshots/top_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/docs/user_guide_screenshots/top_bar.png -------------------------------------------------------------------------------- /example-files/input_from_ort.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/example-files/input_from_ort.json.gz -------------------------------------------------------------------------------- /example-files/large_opossum_input.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/example-files/large_opossum_input.json.gz -------------------------------------------------------------------------------- /example-files/opossum_ui_scan_input.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/example-files/opossum_ui_scan_input.json.gz -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 19 | OpossumUI 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /jest.config.mjs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | /** @type {import('jest').Config} */ 7 | const config = { 8 | testEnvironment: 'jsdom', 9 | resetMocks: false, 10 | transformIgnorePatterns: [ 11 | '/node_modules/(?!d3-*|internmap|axios|react-hotkeys-hook)', 12 | ], 13 | setupFilesAfterEnv: ['./src/testing/setup-tests.ts'], 14 | watchAll: false, 15 | clearMocks: true, 16 | globalSetup: './src/testing/global-test-setup.ts', 17 | globalTeardown: './src/testing/global-test-teardown.ts', 18 | setupFiles: ['whatwg-fetch'], 19 | roots: ['/src/Frontend', '/src/ElectronBackend'], 20 | modulePathIgnorePatterns: ['/build/'], 21 | watchPlugins: [ 22 | 'jest-watch-typeahead/filename', 23 | 'jest-watch-typeahead/testname', 24 | ], 25 | }; 26 | 27 | export default config; 28 | -------------------------------------------------------------------------------- /knip.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/knip@5/schema.json", 3 | "entry": ["src/index.tsx", "src/ElectronBackend/{app,preload}.ts"], 4 | "project": ["**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}!"], 5 | "ignoreDependencies": ["cross-env", "dpdm"], 6 | "ignoreBinaries": [ 7 | "tools/*", 8 | "spdx", 9 | "reuse", 10 | "licenses", 11 | "codesign", 12 | "ship-mac" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /public/assets/icons/about-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/about-black.png -------------------------------------------------------------------------------- /public/assets/icons/about-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/about-white.png -------------------------------------------------------------------------------- /public/assets/icons/check-box-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/check-box-black.png -------------------------------------------------------------------------------- /public/assets/icons/check-box-blank-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/check-box-blank-black.png -------------------------------------------------------------------------------- /public/assets/icons/check-box-blank-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/check-box-blank-white.png -------------------------------------------------------------------------------- /public/assets/icons/check-box-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/check-box-white.png -------------------------------------------------------------------------------- /public/assets/icons/chromium-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/chromium-black.png -------------------------------------------------------------------------------- /public/assets/icons/chromium-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/chromium-white.png -------------------------------------------------------------------------------- /public/assets/icons/com-list-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/com-list-black.png -------------------------------------------------------------------------------- /public/assets/icons/com-list-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/com-list-white.png -------------------------------------------------------------------------------- /public/assets/icons/copy-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/copy-black.png -------------------------------------------------------------------------------- /public/assets/icons/copy-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/copy-white.png -------------------------------------------------------------------------------- /public/assets/icons/cut-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/cut-black.png -------------------------------------------------------------------------------- /public/assets/icons/cut-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/cut-white.png -------------------------------------------------------------------------------- /public/assets/icons/det-list-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/det-list-black.png -------------------------------------------------------------------------------- /public/assets/icons/det-list-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/det-list-white.png -------------------------------------------------------------------------------- /public/assets/icons/developer-tool-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/developer-tool-black.png -------------------------------------------------------------------------------- /public/assets/icons/developer-tool-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/developer-tool-white.png -------------------------------------------------------------------------------- /public/assets/icons/export-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/export-black.png -------------------------------------------------------------------------------- /public/assets/icons/export-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/export-white.png -------------------------------------------------------------------------------- /public/assets/icons/follow-up-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/follow-up-black.png -------------------------------------------------------------------------------- /public/assets/icons/follow-up-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/follow-up-white.png -------------------------------------------------------------------------------- /public/assets/icons/full-screen-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/full-screen-black.png -------------------------------------------------------------------------------- /public/assets/icons/full-screen-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/full-screen-white.png -------------------------------------------------------------------------------- /public/assets/icons/github-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/github-black.png -------------------------------------------------------------------------------- /public/assets/icons/github-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/github-white.png -------------------------------------------------------------------------------- /public/assets/icons/import-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/import-black.png -------------------------------------------------------------------------------- /public/assets/icons/import-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/import-white.png -------------------------------------------------------------------------------- /public/assets/icons/json-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/json-black.png -------------------------------------------------------------------------------- /public/assets/icons/json-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/json-white.png -------------------------------------------------------------------------------- /public/assets/icons/location-searching-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/location-searching-black.png -------------------------------------------------------------------------------- /public/assets/icons/location-searching-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/location-searching-white.png -------------------------------------------------------------------------------- /public/assets/icons/log-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/log-black.png -------------------------------------------------------------------------------- /public/assets/icons/log-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/log-white.png -------------------------------------------------------------------------------- /public/assets/icons/magnifying-glass-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/magnifying-glass-black.png -------------------------------------------------------------------------------- /public/assets/icons/magnifying-glass-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/magnifying-glass-white.png -------------------------------------------------------------------------------- /public/assets/icons/merge-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/merge-black.png -------------------------------------------------------------------------------- /public/assets/icons/merge-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/merge-white.png -------------------------------------------------------------------------------- /public/assets/icons/notice-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/notice-black.png -------------------------------------------------------------------------------- /public/assets/icons/notice-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/notice-white.png -------------------------------------------------------------------------------- /public/assets/icons/open-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/open-black.png -------------------------------------------------------------------------------- /public/assets/icons/open-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/open-white.png -------------------------------------------------------------------------------- /public/assets/icons/paste-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/paste-black.png -------------------------------------------------------------------------------- /public/assets/icons/paste-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/paste-white.png -------------------------------------------------------------------------------- /public/assets/icons/quit-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/quit-black.png -------------------------------------------------------------------------------- /public/assets/icons/quit-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/quit-white.png -------------------------------------------------------------------------------- /public/assets/icons/redo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/redo-black.png -------------------------------------------------------------------------------- /public/assets/icons/redo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/redo-white.png -------------------------------------------------------------------------------- /public/assets/icons/restore-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/restore-black.png -------------------------------------------------------------------------------- /public/assets/icons/restore-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/restore-white.png -------------------------------------------------------------------------------- /public/assets/icons/save-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/save-black.png -------------------------------------------------------------------------------- /public/assets/icons/save-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/save-white.png -------------------------------------------------------------------------------- /public/assets/icons/search-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/search-black.png -------------------------------------------------------------------------------- /public/assets/icons/search-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/search-white.png -------------------------------------------------------------------------------- /public/assets/icons/select-all-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/select-all-black.png -------------------------------------------------------------------------------- /public/assets/icons/select-all-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/select-all-white.png -------------------------------------------------------------------------------- /public/assets/icons/statictics-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/statictics-black.png -------------------------------------------------------------------------------- /public/assets/icons/statictics-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/statictics-white.png -------------------------------------------------------------------------------- /public/assets/icons/undo-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/undo-black.png -------------------------------------------------------------------------------- /public/assets/icons/undo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/undo-white.png -------------------------------------------------------------------------------- /public/assets/icons/update-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/update-black.png -------------------------------------------------------------------------------- /public/assets/icons/update-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/update-white.png -------------------------------------------------------------------------------- /public/assets/icons/user-guide-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/user-guide-black.png -------------------------------------------------------------------------------- /public/assets/icons/user-guide-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/user-guide-white.png -------------------------------------------------------------------------------- /public/assets/icons/yaml-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/yaml-black.png -------------------------------------------------------------------------------- /public/assets/icons/yaml-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/yaml-white.png -------------------------------------------------------------------------------- /public/assets/icons/zoom-in-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/zoom-in-black.png -------------------------------------------------------------------------------- /public/assets/icons/zoom-in-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/zoom-in-white.png -------------------------------------------------------------------------------- /public/assets/icons/zoom-out-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/zoom-out-black.png -------------------------------------------------------------------------------- /public/assets/icons/zoom-out-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/assets/icons/zoom-out-white.png -------------------------------------------------------------------------------- /public/icons/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/public/icons/icon_512x512.png -------------------------------------------------------------------------------- /public/icons/wave.svg: -------------------------------------------------------------------------------- 1 | 5 | 6 | 9 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended", 5 | ":dependencyDashboard", 6 | ":automergeTypes", 7 | ":automergeLinters", 8 | ":automergeTesters", 9 | "monorepo:yarn" 10 | ], 11 | "addLabels": ["dependencies"], 12 | "automergeType": "branch", 13 | "prConcurrentLimit": 5, 14 | "prCreation": "not-pending", 15 | "rangeStrategy": "bump", 16 | "minimumReleaseAge": "1 day", 17 | "nvm": { 18 | "enabled": false 19 | }, 20 | "packageRules": [ 21 | { 22 | "updateTypes": ["minor", "patch"], 23 | "automerge": true 24 | }, 25 | { 26 | "description": "Ignore engines field in package.json", 27 | "matchDepTypes": ["engines"], 28 | "enabled": false 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /src/ElectronBackend/app.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { app } from 'electron'; 6 | 7 | import { main } from './main/main'; 8 | 9 | app.on('ready', main); 10 | 11 | app.on('window-all-closed', () => { 12 | app.quit(); 13 | }); 14 | -------------------------------------------------------------------------------- /src/ElectronBackend/enums/enums.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | export enum LoadedFileFormat { 7 | Opossum = 'OPOSSUM', 8 | Json = 'JSON', 9 | } 10 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/ProcessingStatusUpdater.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { WebContents } from 'electron'; 6 | import log from 'electron-log'; 7 | 8 | import { AllowedFrontendChannels } from '../../shared/ipc-channels'; 9 | import { 10 | ProcessingDoneEvent, 11 | ProcessingStartedEvent, 12 | ProcessingStateUpdatedEvent, 13 | ProcessingStateUpdatedEventLevel, 14 | } from '../../shared/shared-types'; 15 | 16 | export class ProcessingStatusUpdater { 17 | readonly #webContents: WebContents; 18 | 19 | constructor(webContents: WebContents) { 20 | this.#webContents = webContents; 21 | } 22 | 23 | #sendToFrontend(message: string, level: ProcessingStateUpdatedEventLevel) { 24 | this.#webContents.send(AllowedFrontendChannels.ProcessingStateChanged, { 25 | type: 'ProcessingStateUpdated', 26 | date: new Date(), 27 | message, 28 | level, 29 | } satisfies ProcessingStateUpdatedEvent); 30 | } 31 | 32 | info(message: string) { 33 | this.#sendToFrontend(message, 'info'); 34 | log.info(message); 35 | } 36 | 37 | warn(message: string) { 38 | this.#sendToFrontend(message, 'warn'); 39 | log.warn(message); 40 | } 41 | 42 | error(message: string) { 43 | this.#sendToFrontend(message, 'error'); 44 | log.error(message); 45 | } 46 | 47 | startProcessing() { 48 | this.#webContents.send(AllowedFrontendChannels.ProcessingStateChanged, { 49 | type: 'ProcessingStarted', 50 | } satisfies ProcessingStartedEvent); 51 | } 52 | 53 | endProcessing() { 54 | this.#webContents.send(AllowedFrontendChannels.ProcessingStateChanged, { 55 | type: 'ProcessingDone', 56 | } satisfies ProcessingDoneEvent); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/__tests__/createWindowDev.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { createWindow, loadWebApp } from '../createWindow'; 6 | 7 | jest.mock('electron', () => ({ 8 | app: { 9 | on: jest.fn(), 10 | getPath: jest.fn(), 11 | getName: jest.fn(), 12 | getVersion: jest.fn(), 13 | whenReady: async (): Promise => Promise.resolve(true), 14 | isPackaged: false, 15 | }, 16 | BrowserWindow: class BrowserWindowMock { 17 | constructor() { 18 | return { 19 | loadURL: jest.fn(), 20 | webContents: { 21 | openDevTools: jest.fn(), 22 | session: { 23 | webRequest: { 24 | onHeadersReceived: jest.fn(), 25 | }, 26 | }, 27 | }, 28 | }; 29 | } 30 | }, 31 | Menu: { 32 | setApplicationMenu: jest.fn(), 33 | buildFromTemplate: jest.fn(), 34 | getApplicationMenu: jest.fn(), 35 | }, 36 | })); 37 | 38 | describe('createWindow', () => { 39 | it('returns correct BrowserWindow in devMode', async () => { 40 | const browserWindow = createWindow(); 41 | await loadWebApp(browserWindow); 42 | expect(browserWindow.webContents.openDevTools).toHaveBeenCalled(); 43 | expect(browserWindow.loadURL).toHaveBeenCalledWith( 44 | 'http://localhost:5173/', 45 | ); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/__tests__/createWindowProd.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { createWindow } from '../createWindow'; 6 | 7 | jest.mock('electron', () => ({ 8 | app: { 9 | on: jest.fn(), 10 | getPath: jest.fn(), 11 | getName: jest.fn(), 12 | getVersion: jest.fn(), 13 | whenReady: async (): Promise => Promise.resolve(true), 14 | isPackaged: true, 15 | }, 16 | BrowserWindow: class BrowserWindowMock { 17 | constructor() { 18 | return { 19 | loadURL: jest.fn(), 20 | webContents: { 21 | openDevTools: jest.fn(), 22 | session: { 23 | webRequest: { 24 | onHeadersReceived: jest.fn(), 25 | }, 26 | }, 27 | }, 28 | }; 29 | } 30 | }, 31 | Menu: { 32 | setApplicationMenu: jest.fn(), 33 | buildFromTemplate: jest.fn(), 34 | getApplicationMenu: jest.fn(), 35 | }, 36 | })); 37 | 38 | jest.mock('../iconHelpers', () => ({ 39 | getIconPath: (): string => { 40 | return 'icon/path.png'; 41 | }, 42 | getIconBasedOnTheme: (): string => { 43 | return 'icon/path-black.png'; 44 | }, 45 | })); 46 | 47 | describe('createWindow', () => { 48 | it('returns correct BrowserWindow in production', () => { 49 | const browserWindow = createWindow(); 50 | expect(browserWindow.webContents.openDevTools).not.toHaveBeenCalled(); 51 | expect(browserWindow.loadURL).not.toHaveBeenCalledWith( 52 | 'http://localhost:3000', 53 | ); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/__tests__/globalBackendState.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { GlobalBackendState } from '../../types/types'; 6 | import { 7 | getGlobalBackendState, 8 | setGlobalBackendState, 9 | } from '../globalBackendState'; 10 | 11 | describe('The global backend state', () => { 12 | const newGlobalBackendState: GlobalBackendState = { 13 | resourceFilePath: '/some/path.json', 14 | attributionFilePath: '/some/other_path.json', 15 | projectId: 'uuid_1', 16 | }; 17 | 18 | it('is empty upon initialization.', () => { 19 | expect(getGlobalBackendState()).toMatchObject({}); 20 | }); 21 | it('can be set and read', () => { 22 | setGlobalBackendState(newGlobalBackendState); 23 | expect(getGlobalBackendState()).toMatchObject(newGlobalBackendState); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/__tests__/mainErrorCase.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { dialog, ipcMain } from 'electron'; 6 | 7 | import { main } from '../main'; 8 | 9 | jest.mock('electron', () => ({ 10 | ipcMain: { 11 | handle: jest.fn(), 12 | }, 13 | app: { 14 | on: jest.fn(), 15 | getPath: jest.fn(), 16 | getName: jest.fn(), 17 | getVersion: jest.fn(), 18 | whenReady: (): Promise => Promise.resolve(true), 19 | isPackaged: true, 20 | }, 21 | BrowserWindow: class BrowserWindowMock { 22 | constructor() { 23 | return { 24 | loadURL: (): void => { 25 | throw Error('TEST_ERROR'); 26 | }, 27 | webContents: { 28 | openDevTools: jest.fn(), 29 | }, 30 | }; 31 | } 32 | }, 33 | Menu: { 34 | setApplicationMenu: jest.fn(), 35 | buildFromTemplate: jest.fn(), 36 | getApplicationMenu: jest.fn(), 37 | }, 38 | dialog: { 39 | showMessageBox: jest.fn(), 40 | }, 41 | })); 42 | describe('The App backend', () => { 43 | it('handles errors', async () => { 44 | await main(); 45 | 46 | expect(dialog.showMessageBox).toHaveBeenCalledWith( 47 | expect.objectContaining({ 48 | type: 'error', 49 | title: 'Error', 50 | }), 51 | ); 52 | 53 | expect(ipcMain.handle).toHaveBeenCalledTimes(0); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/createWindow.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // SPDX-FileCopyrightText: Nico Carl 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | import { app, BrowserWindow } from 'electron'; 7 | import path from 'path'; 8 | import upath from 'upath'; 9 | 10 | import { getIconPath } from './iconHelpers'; 11 | 12 | export async function loadWebApp( 13 | mainWindow: Electron.CrossProcessExports.BrowserWindow, 14 | ) { 15 | if (!app.isPackaged) { 16 | await mainWindow.loadURL('http://localhost:5173/'); 17 | 18 | mainWindow.webContents.openDevTools(); 19 | } else { 20 | await mainWindow.loadURL( 21 | `file://${path.join(upath.toUnix(__dirname), '../../index.html')}`, 22 | ); 23 | } 24 | } 25 | 26 | export function createWindow(): BrowserWindow { 27 | return new BrowserWindow({ 28 | width: 1920, 29 | height: 1080, 30 | minWidth: 500, 31 | minHeight: 400, 32 | webPreferences: { 33 | contextIsolation: true, 34 | nodeIntegration: false, 35 | sandbox: false, 36 | preload: path.join(upath.toUnix(__dirname), '../preload.js'), 37 | }, 38 | icon: getIconPath(), 39 | }); 40 | } 41 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/dialogs.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { BrowserWindow, dialog } from 'electron'; 6 | 7 | import { FileFormatInfo } from '../../shared/shared-types'; 8 | 9 | function openFileDialog( 10 | filters: Array, 11 | ): Array | undefined { 12 | const window = BrowserWindow.getFocusedWindow(); 13 | return window 14 | ? dialog.showOpenDialogSync(window, { 15 | properties: ['openFile'], 16 | filters, 17 | }) 18 | : undefined; 19 | } 20 | 21 | export function openOpossumFileDialog(): Array | undefined { 22 | return openFileDialog([ 23 | { 24 | name: 'Opossum File', 25 | extensions: ['opossum'], 26 | }, 27 | ]); 28 | } 29 | 30 | export function openNonOpossumFileDialog( 31 | fileFormat: FileFormatInfo, 32 | ): Array | undefined { 33 | return openFileDialog([ 34 | { 35 | name: `${fileFormat.name} Files (${fileFormat.extensions.map((ext) => `.${ext}`).join('/')})`, 36 | extensions: fileFormat.extensions, 37 | }, 38 | ]); 39 | } 40 | 41 | export function saveFileDialog(defaultPath?: string): string | undefined { 42 | const window = BrowserWindow.getFocusedWindow(); 43 | return window 44 | ? dialog.showSaveDialogSync(window, { defaultPath }) 45 | : undefined; 46 | } 47 | 48 | export function selectBaseURLDialog(): Array | undefined { 49 | const window = BrowserWindow.getFocusedWindow(); 50 | return window 51 | ? dialog.showOpenDialogSync(window, { 52 | buttonLabel: 'Select', 53 | properties: ['openDirectory'], 54 | title: 'Path to Sources', 55 | }) 56 | : undefined; 57 | } 58 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/getPath.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Tarun Samanta 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | import { app } from 'electron'; 5 | import path from 'path'; 6 | import upath from 'upath'; 7 | 8 | export function getBasePathOfAssets(): string { 9 | const basePath = app.isPackaged 10 | ? path.join(upath.toUnix(__dirname), '../../assets') 11 | : path.join(upath.toUnix(__dirname), '../../../public/assets'); 12 | return basePath; 13 | } 14 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/globalBackendState.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { GlobalBackendState } from '../types/types'; 6 | 7 | let globalBackendState: GlobalBackendState = {}; 8 | 9 | export function getGlobalBackendState(): GlobalBackendState { 10 | return globalBackendState; 11 | } 12 | 13 | export function setGlobalBackendState( 14 | newGlobalBackendState: GlobalBackendState, 15 | ): void { 16 | globalBackendState = newGlobalBackendState; 17 | } 18 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/iconHelpers.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import electron, { app } from 'electron'; 6 | import path from 'path'; 7 | import upath from 'upath'; 8 | 9 | import { getBasePathOfAssets } from './getPath'; 10 | 11 | export function getIconPath(): string { 12 | const basePath = app.isPackaged 13 | ? path.join(upath.toUnix(__dirname), '../..') 14 | : path.join(upath.toUnix(__dirname), '../../../public'); 15 | return path.join(basePath, 'icons/icon_512x512.png'); 16 | } 17 | 18 | export function getIconBasedOnTheme( 19 | white_icon: string, 20 | black_icon: string, 21 | ): string { 22 | return electron.nativeTheme?.shouldUseDarkColors 23 | ? path.join(getBasePathOfAssets(), white_icon) 24 | : path.join(getBasePathOfAssets(), black_icon); 25 | } 26 | 27 | export function getCheckboxBasedOnThemeAndCheckState(checked: boolean): string { 28 | if (checked) { 29 | return getIconBasedOnTheme( 30 | 'icons/check-box-white.png', 31 | 'icons/check-box-black.png', 32 | ); 33 | } 34 | 35 | return getIconBasedOnTheme( 36 | 'icons/check-box-blank-white.png', 37 | 'icons/check-box-blank-black.png', 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/logger.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { BrowserWindow } from 'electron'; 6 | import log from 'electron-log'; 7 | 8 | import { AllowedFrontendChannels } from '../../shared/ipc-channels'; 9 | import { Log } from '../../shared/shared-types'; 10 | 11 | class Logger { 12 | private sendLogToRenderer( 13 | message: string, 14 | { level }: Pick, 15 | ): void { 16 | // NOTE: there are situations where BrowserWindow.getAllWindows() returns a 17 | // non-empty array but BrowserWindow.getFocusedWindow() returns null. 18 | // Thus, using getAllWindows here is more robust than getFocusedWindow 19 | BrowserWindow.getAllWindows()[0]?.webContents.send( 20 | AllowedFrontendChannels.Logging, 21 | { 22 | date: new Date(), 23 | message, 24 | level, 25 | } satisfies Log, 26 | ); 27 | } 28 | 29 | public info(message: string): void { 30 | log.info(message); 31 | this.sendLogToRenderer(message, { level: 'info' }); 32 | } 33 | 34 | public warn(message: string): void { 35 | log.warn(message); 36 | this.sendLogToRenderer(message, { level: 'warn' }); 37 | } 38 | 39 | public error(message: string): void { 40 | log.error(message); 41 | this.sendLogToRenderer(message, { level: 'error' }); 42 | } 43 | } 44 | 45 | const logger = new Logger(); 46 | 47 | export default logger; 48 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/menu.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // SPDX-FileCopyrightText: Nico Carl 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | import { BrowserWindow, Menu, MenuItemConstructorOptions } from 'electron'; 7 | import os from 'os'; 8 | 9 | import { getAboutMenu } from './menu/aboutMenu'; 10 | import { getEditMenu } from './menu/editMenu'; 11 | import { getFileMenu } from './menu/fileMenu'; 12 | import { getHelpMenu } from './menu/helpMenu'; 13 | import { getViewMenu } from './menu/viewMenu'; 14 | 15 | export async function createMenu(mainWindow: BrowserWindow): Promise { 16 | const webContents = mainWindow.webContents; 17 | 18 | const updateMenu = () => createMenu(mainWindow); 19 | return Menu.setApplicationMenu( 20 | Menu.buildFromTemplate([ 21 | ...(os.platform() === 'darwin' 22 | ? [{ role: 'appMenu' } satisfies MenuItemConstructorOptions] 23 | : []), 24 | await getFileMenu(mainWindow, updateMenu), 25 | getEditMenu(webContents), 26 | await getViewMenu(updateMenu), 27 | getAboutMenu(), 28 | getHelpMenu(webContents), 29 | ]), 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/menu/aboutMenu.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // SPDX-FileCopyrightText: Nico Carl 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | import { MenuItemConstructorOptions, shell } from 'electron'; 7 | 8 | import { text } from '../../../shared/text'; 9 | import { getIconBasedOnTheme } from '../iconHelpers'; 10 | import { 11 | getPathOfChromiumNoticeDocument, 12 | getPathOfNoticeDocument, 13 | } from '../notice-document-helpers'; 14 | 15 | function getOpenOnGithub(): MenuItemConstructorOptions { 16 | return { 17 | icon: getIconBasedOnTheme( 18 | 'icons/github-white.png', 19 | 'icons/github-black.png', 20 | ), 21 | label: text.menu.aboutSubmenu.openOnGithub, 22 | click: () => 23 | shell.openExternal('https://github.com/opossum-tool/opossumUI'), 24 | }; 25 | } 26 | 27 | function getOpossumUiNotices(): MenuItemConstructorOptions { 28 | return { 29 | icon: getIconBasedOnTheme( 30 | 'icons/notice-white.png', 31 | 'icons/notice-black.png', 32 | ), 33 | label: text.menu.aboutSubmenu.opossumUINotices, 34 | click: () => shell.openPath(getPathOfNoticeDocument()), 35 | }; 36 | } 37 | 38 | function getChromiumNotices(): MenuItemConstructorOptions { 39 | return { 40 | icon: getIconBasedOnTheme( 41 | 'icons/chromium-white.png', 42 | 'icons/chromium-black.png', 43 | ), 44 | label: text.menu.aboutSubmenu.chromiumNotices, 45 | click: () => shell.openPath(getPathOfChromiumNoticeDocument()), 46 | }; 47 | } 48 | 49 | export function getAboutMenu(): MenuItemConstructorOptions { 50 | return { 51 | label: text.menu.about, 52 | submenu: [getOpenOnGithub(), getOpossumUiNotices(), getChromiumNotices()], 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/menu/switchableMenuItem.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { MenuItemConstructorOptions } from 'electron'; 6 | 7 | import { UserSettings as IUserSettings } from '../../../shared/shared-types'; 8 | import { getCheckboxBasedOnThemeAndCheckState } from '../iconHelpers'; 9 | import { UserSettingsService } from '../user-settings-service'; 10 | 11 | interface SwitchableItemOptions { 12 | id: string; 13 | label: string; 14 | userSettingsKey: keyof IUserSettings; 15 | } 16 | 17 | export async function switchableMenuItem( 18 | updateMenu: () => Promise, 19 | options: SwitchableItemOptions, 20 | ): Promise { 21 | const state = !!(await UserSettingsService.get(options.userSettingsKey)); 22 | return { 23 | icon: getCheckboxBasedOnThemeAndCheckState(state), 24 | id: state ? `enabled-${options.id}` : `disabled-${options.id}`, 25 | label: options.label, 26 | click: async () => { 27 | await UserSettingsService.update( 28 | Object.fromEntries([[options.userSettingsKey, !state]]), 29 | ); 30 | await updateMenu(); 31 | }, 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/notice-document-helpers.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { app } from 'electron'; 6 | import path from 'path'; 7 | 8 | function getNoticesDirectory(): string { 9 | if (!app.isPackaged) { 10 | return path.join(__dirname, '..', '..', '..', 'notices'); 11 | } 12 | 13 | return path.join(process.resourcesPath, 'notices'); 14 | } 15 | 16 | export function getPathOfNoticeDocument(): string { 17 | return path.join(getNoticesDirectory(), 'notices.html'); 18 | } 19 | 20 | export function getPathOfChromiumNoticeDocument(): string { 21 | return path.join(getNoticesDirectory(), 'LICENSES.chromium.html'); 22 | } 23 | -------------------------------------------------------------------------------- /src/ElectronBackend/main/openFileFromCliOrEnvVariableIfProvided.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { BrowserWindow } from 'electron'; 6 | import log from 'electron-log'; 7 | 8 | import { handleOpeningFile } from './listeners'; 9 | 10 | export async function openFileFromCliOrEnvVariableIfProvided( 11 | mainWindow: BrowserWindow, 12 | updateMenu: () => Promise, 13 | ): Promise { 14 | let inputFileName: string | null = null; 15 | 16 | function fileHasValidEnding(arg: string): boolean { 17 | return arg.endsWith('.opossum'); 18 | } 19 | 20 | for (const arg of process.argv) { 21 | if (fileHasValidEnding(arg)) { 22 | inputFileName = arg; 23 | break; 24 | } 25 | } 26 | 27 | const inputFileFromEnvVariable: string | undefined = process.env.OPOSSUM_FILE; 28 | if (!inputFileName && inputFileFromEnvVariable) { 29 | if (fileHasValidEnding(inputFileFromEnvVariable)) { 30 | inputFileName = inputFileFromEnvVariable; 31 | } else { 32 | log.warn( 33 | `File "${inputFileFromEnvVariable}" which was provided by env variable is not valid. ` + 34 | 'Opening OpossumUI without loading a file.', 35 | ); 36 | } 37 | } 38 | 39 | if (inputFileName) { 40 | await handleOpeningFile(mainWindow, inputFileName, updateMenu); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/ElectronBackend/opossum-file/ExternalFileConverter.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { text } from '../../shared/text'; 6 | import { FileConverter } from './FileConverter'; 7 | 8 | export abstract class ExternalFileConverter extends FileConverter { 9 | protected override preConvertFile(_: string): Promise { 10 | return new Promise((resolve) => resolve(null)); 11 | } 12 | 13 | override async convertToOpossum( 14 | toBeConvertedFilePath: string, 15 | opossumSaveLocation: string, 16 | ): Promise { 17 | try { 18 | await this.execFile(this.OPOSSUM_FILE_EXECUTABLE, [ 19 | 'generate', 20 | '-o', 21 | opossumSaveLocation, 22 | this.fileTypeSwitch, 23 | toBeConvertedFilePath, 24 | ]); 25 | } catch (error) { 26 | throw new Error(text.backendError.inputFileInvalid(this.fileTypeName)); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/ElectronBackend/opossum-file/__tests__/legacy.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "projectId": "2a58a469-738e-4508-98d3-a27bce6e71f7", 4 | "projectTitle": "Test Title", 5 | "fileCreationDate": "2020-07-23 11:47:13.764544" 6 | }, 7 | "resources": { 8 | "index.html": 1 9 | }, 10 | "externalAttributions": {}, 11 | "resourcesToAttributions": {}, 12 | "frequentLicenses": [], 13 | "attributionBreakpoints": [], 14 | "filesWithChildren": [], 15 | "baseUrlsForSources": {}, 16 | "externalAttributionSources": {} 17 | } 18 | -------------------------------------------------------------------------------- /src/ElectronBackend/opossum-file/__tests__/merge_base.opossum: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/opossum-tool/OpossumUI/8f25b16c407041d4e09898033df15cd00cd484ce/src/ElectronBackend/opossum-file/__tests__/merge_base.opossum -------------------------------------------------------------------------------- /src/ElectronBackend/opossum-file/opossum-file.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { FileType } from '../../shared/shared-types'; 6 | import { ExternalFileConverter } from './ExternalFileConverter'; 7 | import { FileConverter } from './FileConverter'; 8 | import { LegacyFileConverter } from './LegacyFileConverter'; 9 | 10 | const fileTypeToConverter: Record = { 11 | [FileType.LEGACY_OPOSSUM]: new LegacyFileConverter(), 12 | [FileType.SCANCODE_JSON]: new (class extends ExternalFileConverter { 13 | readonly fileTypeSwitch: string = '--scan-code-json'; 14 | readonly fileTypeName: string = 'ScanCode'; 15 | })(), 16 | [FileType.OWASP_JSON]: new (class extends ExternalFileConverter { 17 | readonly fileTypeSwitch: string = '--owasp-json'; 18 | readonly fileTypeName: string = 'OWASP Dependency-Check'; 19 | })(), 20 | }; 21 | 22 | export async function convertToOpossum( 23 | toBeConvertedFilePath: string, 24 | opossumSaveLocation: string, 25 | fileType: FileType, 26 | ): Promise { 27 | await fileTypeToConverter[fileType].convertToOpossum( 28 | toBeConvertedFilePath, 29 | opossumSaveLocation, 30 | ); 31 | } 32 | 33 | export async function mergeFileIntoOpossum( 34 | toBeConvertedFilePath: string, 35 | pathToOpossumFile: string, 36 | fileType: FileType, 37 | ): Promise { 38 | await fileTypeToConverter[fileType].mergeFileIntoOpossum( 39 | toBeConvertedFilePath, 40 | pathToOpossumFile, 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /src/ElectronBackend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs", 5 | "outDir": "../../build", 6 | "rootDir": "../", 7 | "noEmitOnError": true, 8 | "noEmit": false 9 | }, 10 | "include": ["**/*"], 11 | "exclude": [] 12 | } 13 | -------------------------------------------------------------------------------- /src/ElectronBackend/utils/getFilePathWithAppendix.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // SPDX-FileCopyrightText: Nico Carl 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | import fs from 'fs'; 7 | import path from 'path'; 8 | import upath from 'upath'; 9 | 10 | export function getFilePathWithAppendix( 11 | resourceFilePath: fs.PathLike, 12 | appendix: string, 13 | ): string { 14 | const { baseFileName, basePath } = getBasePaths(resourceFilePath); 15 | 16 | const fileNameWithAppendix = baseFileName.concat(appendix); 17 | return basePath.concat(fileNameWithAppendix); 18 | } 19 | 20 | function getBasePaths(resourceFilePath: fs.PathLike): { 21 | baseFileName: string; 22 | basePath: string; 23 | } { 24 | const baseFileName: string = path.basename( 25 | resourceFilePath.toString(), 26 | getFileExtension(resourceFilePath), 27 | ); 28 | const parent_folder = path.dirname(resourceFilePath.toString()); 29 | const basePath = path.join(upath.toUnix(parent_folder), '/'); 30 | return { baseFileName, basePath }; 31 | } 32 | 33 | function getFileExtension(resourceFilePath: fs.PathLike): string { 34 | const gzipFileExtension = '.gz'; 35 | const fileIsGziped = 36 | path.extname(resourceFilePath.toString()) === gzipFileExtension; 37 | 38 | return fileIsGziped 39 | ? path.extname( 40 | path.basename(resourceFilePath.toString(), gzipFileExtension), 41 | ) + gzipFileExtension 42 | : path.extname(resourceFilePath.toString()); 43 | } 44 | -------------------------------------------------------------------------------- /src/ElectronBackend/utils/getLoadedFile.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { LoadedFileFormat } from '../enums/enums'; 6 | import { GlobalBackendState } from '../types/types'; 7 | 8 | export function getLoadedFilePath( 9 | globalBackendState: GlobalBackendState, 10 | ): string | null { 11 | if (globalBackendState.resourceFilePath) { 12 | return globalBackendState.resourceFilePath; 13 | } else if (globalBackendState.opossumFilePath) { 14 | return globalBackendState.opossumFilePath; 15 | } 16 | return null; 17 | } 18 | 19 | export function isFileLoaded(globalBackendState: GlobalBackendState): boolean { 20 | return ( 21 | globalBackendState.resourceFilePath !== undefined || 22 | globalBackendState.opossumFilePath !== undefined 23 | ); 24 | } 25 | 26 | export function getLoadedFileType( 27 | globalBackendState: GlobalBackendState, 28 | ): LoadedFileFormat { 29 | if (globalBackendState.resourceFilePath) { 30 | return LoadedFileFormat.Json; 31 | } else if (globalBackendState.opossumFilePath) { 32 | return LoadedFileFormat.Opossum; 33 | } 34 | throw Error('Tried to get file type when no file is loaded'); 35 | } 36 | -------------------------------------------------------------------------------- /src/ElectronBackend/utils/isOpossumFileFormat.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import path from 'path'; 6 | 7 | import { OPOSSUM_FILE_EXTENSION } from '../../shared/write-file'; 8 | 9 | export function isOpossumFileFormat(filePath?: string): boolean { 10 | if (!filePath) { 11 | return false; 12 | } 13 | return path.extname(filePath) === OPOSSUM_FILE_EXTENSION; 14 | } 15 | -------------------------------------------------------------------------------- /src/Frontend/Components/AppContainer/AppContainer.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // SPDX-FileCopyrightText: Nico Carl 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; 7 | import dayjs from 'dayjs'; 8 | import localizedFormat from 'dayjs/plugin/localizedFormat'; 9 | import { StrictMode } from 'react'; 10 | import { Provider } from 'react-redux'; 11 | 12 | import { createAppStore } from '../../state/configure-store'; 13 | import { App } from '../App/App'; 14 | import { Toaster } from '../Toaster/Toaster'; 15 | 16 | dayjs.extend(localizedFormat); 17 | 18 | const store = createAppStore(); 19 | const queryClient = new QueryClient({ 20 | defaultOptions: { queries: { refetchOnWindowFocus: false, retry: false } }, 21 | }); 22 | 23 | export function AppContainer() { 24 | return ( 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /src/Frontend/Components/AttributionDetails/ButtonRow/ButtonRow.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | import MuiBox from '@mui/system/Box'; 7 | 8 | export const Container = styled(MuiBox)({ 9 | display: 'flex', 10 | gap: '16px', 11 | justifyContent: 'flex-end', 12 | flexWrap: 'wrap', 13 | padding: '12px', 14 | }); 15 | -------------------------------------------------------------------------------- /src/Frontend/Components/AttributionForm/AttributionForm.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | export const attributionColumnClasses = { 7 | panel: { 8 | display: 'flex', 9 | flexDirection: 'column', 10 | gap: '12px', 11 | }, 12 | textBox: { 13 | flex: 1, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /src/Frontend/Components/AttributionPanels/AttributionPanels.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | import Paper from '@mui/material/Paper'; 7 | 8 | import { OpossumColors } from '../../shared-styles'; 9 | 10 | export const Container = styled(Paper)({ 11 | display: 'flex', 12 | background: OpossumColors.lightestBlue, 13 | zIndex: 3, 14 | }); 15 | -------------------------------------------------------------------------------- /src/Frontend/Components/AttributionPanels/SignalsPanel/IncludeExcludeButton/IncludeExcludeButton.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import VisibilityIcon from '@mui/icons-material/Visibility'; 6 | import VisibilityOffIcon from '@mui/icons-material/VisibilityOff'; 7 | import MuiIconButton from '@mui/material/IconButton'; 8 | import MuiTooltip from '@mui/material/Tooltip'; 9 | import MuiBox from '@mui/system/Box'; 10 | 11 | import { text } from '../../../../../shared/text'; 12 | import { useUserSettings } from '../../../../state/variables/use-user-setting'; 13 | 14 | export const IncludeExcludeButton: React.FC = () => { 15 | const [userSettings, updateUserSettings] = useUserSettings(); 16 | const areHiddenSignalsVisible = userSettings.areHiddenSignalsVisible; 17 | const label = areHiddenSignalsVisible 18 | ? text.packageLists.hideDeleted 19 | : text.packageLists.showDeleted; 20 | 21 | return ( 22 | { 26 | updateUserSettings((currentSettings) => ({ 27 | areHiddenSignalsVisible: !currentSettings.areHiddenSignalsVisible, 28 | })); 29 | }} 30 | > 31 | 32 | 33 | {areHiddenSignalsVisible ? : } 34 | 35 | 36 | 37 | ); 38 | }; 39 | -------------------------------------------------------------------------------- /src/Frontend/Components/AttributionPanels/SignalsPanel/SignalsList/SignalsList.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | import MuiTypography from '@mui/material/Typography'; 7 | 8 | export const GroupName = styled(MuiTypography)({ 9 | flex: 1, 10 | overflow: 'hidden', 11 | textOverflow: 'ellipsis', 12 | whiteSpace: 'nowrap', 13 | marginTop: '1px', 14 | userSelect: 'none', 15 | }); 16 | -------------------------------------------------------------------------------- /src/Frontend/Components/AttributionPanels/SignalsPanel/SignalsPanel.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import MuiBox from '@mui/material/Box'; 6 | 7 | import { SIGNAL_FILTERS } from '../../../shared-constants'; 8 | import { useAttributionIdsForReplacement } from '../../../state/variables/use-attribution-ids-for-replacement'; 9 | import { useFilteredSignals } from '../../../state/variables/use-filtered-data'; 10 | import { PackagesPanel } from '../PackagesPanel/PackagesPanel'; 11 | import { DeleteButton } from './DeleteButton/DeleteButton'; 12 | import { IncludeExcludeButton } from './IncludeExcludeButton/IncludeExcludeButton'; 13 | import { LinkButton } from './LinkButton/LinkButton'; 14 | import { RestoreButton } from './RestoreButton/RestoreButton'; 15 | import { SignalsList } from './SignalsList/SignalsList'; 16 | 17 | export function SignalsPanel() { 18 | const [attributionIdsForReplacement] = useAttributionIdsForReplacement(); 19 | 20 | return ( 21 | ( 25 | <> 26 | 27 | 28 | 29 | 30 | 31 | 32 | )} 33 | useFilteredData={useFilteredSignals} 34 | testId={'signals-panel'} 35 | > 36 | {(props) => } 37 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /src/Frontend/Components/AuditView/AuditView.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | import MuiBox from '@mui/material/Box'; 7 | 8 | export const ColumnsContainer = styled(MuiBox)({ 9 | width: '100%', 10 | height: '100%', 11 | display: 'flex', 12 | overflow: 'hidden', 13 | }); 14 | -------------------------------------------------------------------------------- /src/Frontend/Components/AuditView/AuditView.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { AttributionDetails } from '../AttributionDetails/AttributionDetails'; 6 | import { AttributionPanels } from '../AttributionPanels/AttributionPanels'; 7 | import { PathBar } from '../PathBar/PathBar'; 8 | import { ResourceBrowser } from '../ResourceBrowser/ResourceBrowser'; 9 | import { ColumnsContainer } from './AuditView.style'; 10 | 11 | export const AuditView: React.FC = () => { 12 | return ( 13 | <> 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /src/Frontend/Components/Autocomplete/Listbox/Listbox.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled, SxProps } from '@mui/material'; 6 | 7 | import { OpossumColors } from '../../../shared-styles'; 8 | 9 | export const GroupContainer = styled('div')({ 10 | display: 'flex', 11 | alignItems: 'center', 12 | gap: '8px', 13 | padding: '4px 10px', 14 | backgroundColor: OpossumColors.lightBlue, 15 | }); 16 | 17 | export const styles = { 18 | overflowEllipsis: { 19 | overflow: 'hidden', 20 | textOverflow: 'ellipsis', 21 | whiteSpace: 'nowrap', 22 | }, 23 | virtuoso: { 24 | maxHeight: '40vh', 25 | transition: 'height all 0.2s ease-out', 26 | }, 27 | } satisfies SxProps; 28 | -------------------------------------------------------------------------------- /src/Frontend/Components/CardList/CardList.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | 7 | import { OpossumColors } from '../../shared-styles'; 8 | import { List } from '../List/List'; 9 | import { PACKAGE_CARD_HEIGHT } from '../PackageCard/PackageCard'; 10 | 11 | const MAX_NUMBER_OF_CARDS = 4; 12 | 13 | export const CardList = styled(List)(({ data }) => { 14 | const height = 15 | Math.min(MAX_NUMBER_OF_CARDS, data?.length ?? 0) * 16 | (PACKAGE_CARD_HEIGHT + 1) + 17 | 1; 18 | 19 | return { 20 | background: OpossumColors.lightestBlue, 21 | border: '1px solid rgba(0, 0, 0, 0.12)', 22 | boxSizing: 'border-box', 23 | maxHeight: height, 24 | minHeight: height, 25 | height, 26 | }; 27 | }); 28 | -------------------------------------------------------------------------------- /src/Frontend/Components/Checkbox/Checkbox.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { 6 | FormControlLabel, 7 | FormControlLabelProps, 8 | SxProps, 9 | } from '@mui/material'; 10 | import MuiCheckbox from '@mui/material/Checkbox'; 11 | 12 | interface CheckboxProps extends Pick { 13 | checked: boolean; 14 | disableRipple?: boolean; 15 | disabled?: boolean; 16 | indeterminate?: boolean; 17 | label?: string; 18 | onChange(event: React.ChangeEvent): void; 19 | ref?: React.RefObject; 20 | sx?: SxProps; 21 | } 22 | 23 | export const Checkbox: React.FC = ({ 24 | checked, 25 | disableRipple, 26 | disabled, 27 | indeterminate, 28 | label, 29 | labelPlacement, 30 | onChange, 31 | ref, 32 | sx, 33 | ...props 34 | }) => { 35 | return ( 36 | 60 | } 61 | /> 62 | ); 63 | }; 64 | -------------------------------------------------------------------------------- /src/Frontend/Components/ConfirmDeletePopup/ConfirmDeletePopup.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | 7 | import { NotificationPopup } from '../NotificationPopup/NotificationPopup'; 8 | 9 | export const StyledNotificationPopup = styled(NotificationPopup)({ 10 | display: 'flex', 11 | flexDirection: 'column', 12 | gap: '8px', 13 | height: '400px', 14 | }); 15 | -------------------------------------------------------------------------------- /src/Frontend/Components/ConfirmReplacePopup/ConfirmReplacePopup.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | 7 | import { NotificationPopup } from '../NotificationPopup/NotificationPopup'; 8 | 9 | export const StyledNotificationPopup = styled(NotificationPopup)({ 10 | display: 'flex', 11 | flexDirection: 'column', 12 | gap: '8px', 13 | }); 14 | -------------------------------------------------------------------------------- /src/Frontend/Components/ConfirmSavePopup/ConfirmSavePopup.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | 7 | import { NotificationPopup } from '../NotificationPopup/NotificationPopup'; 8 | 9 | export const StyledNotificationPopup = styled(NotificationPopup)({ 10 | display: 'flex', 11 | flexDirection: 'column', 12 | gap: '8px', 13 | height: '400px', 14 | }); 15 | -------------------------------------------------------------------------------- /src/Frontend/Components/DialogLogDisplay/DialogLogDisplay.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/system'; 6 | 7 | import { LogDisplay } from '../LogDisplay/LogDisplay'; 8 | 9 | export const DialogLogDisplay = styled(LogDisplay)({ 10 | display: 'flex', 11 | alignItems: 'center', 12 | columnGap: '4px', 13 | flexGrow: 1, 14 | flexBasis: 0, 15 | minWidth: 0, 16 | }); 17 | -------------------------------------------------------------------------------- /src/Frontend/Components/DiffEndIcon/DiffEndIcon.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import RedoIcon from '@mui/icons-material/Redo'; 6 | import UndoIcon from '@mui/icons-material/Undo'; 7 | 8 | import { clickableIcon } from '../../shared-styles'; 9 | import { IconButton } from '../IconButton/IconButton'; 10 | 11 | const classes = { 12 | bigRevertIcon: { 13 | ...clickableIcon, 14 | width: 24, 15 | height: 24, 16 | margin: 0, 17 | }, 18 | }; 19 | 20 | interface EndIconProps { 21 | variant: 'undo' | 'redo'; 22 | onClick: () => void; 23 | size?: 'small' | 'big'; 24 | 'data-testid'?: string; 25 | } 26 | 27 | export function DiffEndIcon({ 28 | variant, 29 | onClick, 30 | 'data-testid': dataTestId, 31 | size = 'small', 32 | }: EndIconProps) { 33 | const Icon = variant === 'undo' ? UndoIcon : RedoIcon; 34 | return ( 35 | 39 | } 40 | data-testid={dataTestId} 41 | /> 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /src/Frontend/Components/DiffPopup/DiffPopup.style.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | import MuiBox from '@mui/material/Box'; 7 | 8 | export const DiffPopupContainer = styled(MuiBox)({ 9 | display: 'flex', 10 | }); 11 | -------------------------------------------------------------------------------- /src/Frontend/Components/EmptyPlaceholder/EmptyPlaceholder.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | import MuiBox from '@mui/material/Box'; 7 | 8 | export const Container = styled(MuiBox)({ 9 | display: 'flex', 10 | height: '100%', 11 | justifyContent: 'center', 12 | alignItems: 'center', 13 | opacity: 0.5, 14 | }); 15 | -------------------------------------------------------------------------------- /src/Frontend/Components/EmptyPlaceholder/EmptyPlaceholder.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import MuiTypography from '@mui/material/Typography'; 6 | 7 | import { text } from '../../../shared/text'; 8 | import { useVirtuosoComponent } from '../VirtuosoComponentContext/VirtuosoComponentContext'; 9 | import { Container } from './EmptyPlaceholder.style'; 10 | 11 | export const EmptyPlaceholder: React.FC = () => { 12 | const { loading } = useVirtuosoComponent(); 13 | 14 | if (loading) { 15 | return null; 16 | } 17 | 18 | return ( 19 | 20 | 21 | {text.generic.noResults} 22 | 23 | 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /src/Frontend/Components/ErrorFallback/ErrorFallback.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | 7 | export const Container = styled('div')({ 8 | display: 'flex', 9 | flexDirection: 'row', 10 | height: '100%', 11 | width: '100%', 12 | alignItems: 'center', 13 | justifyContent: 'center', 14 | }); 15 | 16 | export const TextContainer = styled('div')({ 17 | display: 'flex', 18 | flexDirection: 'column', 19 | gap: '20px', 20 | width: 'fit-content', 21 | maxWidth: '600px', 22 | }); 23 | -------------------------------------------------------------------------------- /src/Frontend/Components/ErrorFallback/ErrorFallback.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import MuiButton from '@mui/material/Button'; 6 | import MuiButtonGroup from '@mui/material/ButtonGroup'; 7 | import MuiTypography from '@mui/material/Typography'; 8 | import { FallbackProps } from 'react-error-boundary'; 9 | 10 | import { text } from '../../../shared/text'; 11 | import { OpossumColors } from '../../shared-styles'; 12 | import { Container, TextContainer } from './ErrorFallback.style'; 13 | 14 | export const ErrorFallback: React.FC = ({ 15 | error, 16 | resetErrorBoundary, 17 | }) => { 18 | return ( 19 | 20 | 21 | 22 | {text.errorBoundary.unexpectedError} 23 | 24 | 28 | {error.message} 29 | 30 | 31 | { 34 | resetErrorBoundary(); 35 | window.electronAPI.relaunch(); 36 | }} 37 | > 38 | {text.errorBoundary.relaunch} 39 | 40 | { 43 | window.electronAPI.quit(); 44 | }} 45 | > 46 | {text.errorBoundary.quit} 47 | 48 | 49 | 50 | 51 | ); 52 | }; 53 | -------------------------------------------------------------------------------- /src/Frontend/Components/ErrorPopup/ErrorPopup.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { closePopup } from '../../state/actions/view-actions/view-actions'; 6 | import { useAppDispatch } from '../../state/hooks'; 7 | import { NotificationPopup } from '../NotificationPopup/NotificationPopup'; 8 | 9 | const TIME_POPUP_IS_DISPLAYED = 1500; 10 | 11 | interface ErrorPopupProps { 12 | content: string; 13 | } 14 | 15 | export const ErrorPopup: React.FC = (props) => { 16 | const dispatch = useAppDispatch(); 17 | 18 | function close(): void { 19 | dispatch(closePopup()); 20 | } 21 | 22 | setTimeout(() => close(), TIME_POPUP_IS_DISPLAYED); 23 | 24 | return ( 25 | 32 | {props.content} 33 | 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /src/Frontend/Components/ErrorPopup/__tests__/ErrorPopup.test.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { screen } from '@testing-library/react'; 6 | 7 | import { renderComponent } from '../../../test-helpers/render'; 8 | import { ErrorPopup } from '../ErrorPopup'; 9 | 10 | describe('Error popup', () => { 11 | it('renders', () => { 12 | renderComponent(); 13 | 14 | expect(screen.getByText('Error')).toBeInTheDocument(); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /src/Frontend/Components/FilePathInput/FilePathInput.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import AttachFileIcon from '@mui/icons-material/AttachFile'; 6 | import { TooltipProps } from '@mui/material/Tooltip'; 7 | import MuiTypography from '@mui/material/Typography'; 8 | 9 | import { baseIcon } from '../../shared-styles'; 10 | import { TextBox, TextBoxCustomInputProps } from '../TextBox/TextBox'; 11 | 12 | const CustomInput: React.FC = (props) => { 13 | return ( 14 | 18 | {props.value} 19 | 20 | ); 21 | }; 22 | 23 | interface FilePathInputProps { 24 | label: string; 25 | text: string; 26 | onClick: () => void; 27 | tooltipProps?: Partial; 28 | disabled: boolean; 29 | } 30 | 31 | export const FilePathInput: React.FC = (props) => { 32 | return ( 33 | } 38 | cursor={'pointer'} 39 | showTooltip={true} 40 | tooltipProps={props.tooltipProps} 41 | // using a custom input component allows us to disable a lot of TextField 42 | // behavior (e.g. horizontal text scrolling) that we don't want here 43 | inputComponent={CustomInput} 44 | sx={{ marginTop: '20px' }} 45 | disabled={props.disabled} 46 | /> 47 | ); 48 | }; 49 | -------------------------------------------------------------------------------- /src/Frontend/Components/FilterButton/FilterButton.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import ClearIcon from '@mui/icons-material/Clear'; 6 | import { styled } from '@mui/material'; 7 | import MuiIconButton from '@mui/material/IconButton'; 8 | 9 | import { OpossumColors } from '../../shared-styles'; 10 | 11 | export const ClearButton = styled(ClearIcon)({ 12 | padding: '2px', 13 | borderRadius: '50%', 14 | cursor: 'pointer', 15 | '&:hover': { 16 | background: OpossumColors.lightestGrey, 17 | }, 18 | }); 19 | 20 | export const IconButton = styled(MuiIconButton, { 21 | shouldForwardProp: (name: string) => !['isClearHovered'].includes(name), 22 | })<{ isClearHovered: boolean }>(({ isClearHovered }) => ({ 23 | '&:hover': { 24 | background: isClearHovered ? 'none' : OpossumColors.lightestGrey, 25 | }, 26 | })); 27 | -------------------------------------------------------------------------------- /src/Frontend/Components/GroupedList/GroupedList.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | import MuiLinearProgress from '@mui/material/LinearProgress'; 7 | 8 | export const GroupContainer = styled('div')({ 9 | display: 'flex', 10 | height: '20px', 11 | alignItems: 'center', 12 | gap: '8px', 13 | padding: '4px 10px', 14 | backgroundColor: '#cacfdb', 15 | }); 16 | 17 | export const StyledLinearProgress = styled(MuiLinearProgress)({ 18 | position: 'absolute', 19 | width: '100%', 20 | height: 2, 21 | zIndex: 2, 22 | top: 0, 23 | left: 0, 24 | }); 25 | -------------------------------------------------------------------------------- /src/Frontend/Components/GroupedList/__tests__/GroupedList.test.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { screen } from '@testing-library/react'; 6 | 7 | import { text } from '../../../../shared/text'; 8 | import { faker } from '../../../../testing/Faker'; 9 | import { renderComponent } from '../../../test-helpers/render'; 10 | import { GroupedList } from '../GroupedList'; 11 | 12 | describe('GroupedList', () => { 13 | it('renders list items', () => { 14 | const data = faker.helpers.multiple(faker.string.uuid); 15 | renderComponent( 16 |
{id}
} 19 | />, 20 | ); 21 | 22 | data.forEach((id) => { 23 | expect(screen.getByText(id)).toBeInTheDocument(); 24 | }); 25 | expect(screen.queryByTestId('loading')).not.toBeInTheDocument(); 26 | expect(screen.queryByText(text.generic.noResults)).not.toBeInTheDocument(); 27 | }); 28 | 29 | it('renders loading state', () => { 30 | const data = faker.helpers.multiple(faker.string.uuid); 31 | renderComponent( 32 |
{id}
} 36 | />, 37 | ); 38 | 39 | expect(screen.getByTestId('loading')).toBeInTheDocument(); 40 | expect(screen.queryByText(text.generic.noResults)).not.toBeInTheDocument(); 41 | }); 42 | 43 | it('renders empty placeholder when no results', () => { 44 | renderComponent( 45 |
{id}
} />, 46 | ); 47 | 48 | expect(screen.getByText(text.generic.noResults)).toBeInTheDocument(); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /src/Frontend/Components/IconButton/IconButton.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import MuiButtonBase from '@mui/material/ButtonBase'; 6 | import MuiTooltip, { TooltipProps } from '@mui/material/Tooltip'; 7 | 8 | import { OpossumColors } from '../../shared-styles'; 9 | 10 | interface IconButtonProps { 11 | tooltipTitle?: string; 12 | tooltipPlacement?: TooltipProps['placement']; 13 | onClick?: React.MouseEventHandler; 14 | icon: React.ReactElement; 15 | disabled?: boolean; 16 | hidden?: boolean; 17 | 'data-testid'?: string; 18 | } 19 | 20 | export function IconButton(props: IconButtonProps) { 21 | if (props.hidden) { 22 | return null; 23 | } 24 | 25 | return ( 26 | 33 | 34 | { 37 | event.stopPropagation(); 38 | props.onClick?.(event); 39 | }} 40 | disabled={props.disabled} 41 | data-testid={props['data-testid']} 42 | sx={{ 43 | '&.Mui-focusVisible': { 44 | background: OpossumColors.middleBlue, 45 | }, 46 | }} 47 | > 48 | {props.icon} 49 | 50 | 51 | 52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /src/Frontend/Components/List/List.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/material'; 6 | import MuiLinearProgress from '@mui/material/LinearProgress'; 7 | 8 | export const StyledLinearProgress = styled(MuiLinearProgress)({ 9 | position: 'absolute', 10 | width: '100%', 11 | height: 2, 12 | zIndex: 2, 13 | top: 0, 14 | left: 0, 15 | }); 16 | -------------------------------------------------------------------------------- /src/Frontend/Components/List/__tests__/List.test.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { screen } from '@testing-library/react'; 6 | 7 | import { text } from '../../../../shared/text'; 8 | import { faker } from '../../../../testing/Faker'; 9 | import { renderComponent } from '../../../test-helpers/render'; 10 | import { List } from '../List'; 11 | 12 | describe('List', () => { 13 | it('renders list items', () => { 14 | const data = faker.helpers.multiple(faker.string.uuid); 15 | renderComponent( 16 |
{id}
} />, 17 | ); 18 | 19 | data.forEach((id) => { 20 | expect(screen.getByText(id)).toBeInTheDocument(); 21 | }); 22 | expect(screen.queryByTestId('loading')).not.toBeInTheDocument(); 23 | expect(screen.queryByText(text.generic.noResults)).not.toBeInTheDocument(); 24 | }); 25 | 26 | it('renders loading state', () => { 27 | const data = faker.helpers.multiple(faker.string.uuid); 28 | renderComponent( 29 |
{id}
} />, 30 | ); 31 | 32 | expect(screen.getByTestId('loading')).toBeInTheDocument(); 33 | expect(screen.queryByText(text.generic.noResults)).not.toBeInTheDocument(); 34 | }); 35 | 36 | it('renders empty placeholder when no results', () => { 37 | renderComponent( 38 |
{id}
} />, 39 | ); 40 | 41 | expect(screen.getByText(text.generic.noResults)).toBeInTheDocument(); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /src/Frontend/Components/LoadingMask/LoadingMask.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { styled } from '@mui/system'; 6 | 7 | export const Anchor = styled('div')({ 8 | position: 'relative', 9 | width: '100%', 10 | height: '100%', 11 | }); 12 | 13 | export const Mask = styled('div')({ 14 | position: 'absolute', 15 | width: '100%', 16 | height: '100%', 17 | top: 0, 18 | left: 0, 19 | zIndex: 100, 20 | opacity: 0.5, 21 | backgroundColor: 'white', 22 | }); 23 | -------------------------------------------------------------------------------- /src/Frontend/Components/LoadingMask/LoadingMask.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { SxProps } from '@mui/system'; 6 | 7 | import { Anchor, Mask } from './LoadingMask.style'; 8 | 9 | interface LoadingMaskProps { 10 | active: boolean | undefined; 11 | children: React.ReactNode; 12 | sx?: SxProps; 13 | className?: string; 14 | testId?: string; 15 | } 16 | 17 | export const LoadingMask: React.FC = ({ 18 | active, 19 | children, 20 | sx, 21 | className, 22 | testId, 23 | ...props 24 | }) => { 25 | return ( 26 | 27 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /src/Frontend/Components/LogDisplay/LogDisplay.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { Typography } from '@mui/material'; 6 | import { styled } from '@mui/system'; 7 | 8 | export const EllipsisTypography = styled(Typography)({ 9 | overflow: 'hidden', 10 | textOverflow: 'ellipsis', 11 | whiteSpace: 'nowrap', 12 | }); 13 | 14 | export const BreakableTypography = styled(Typography)({ 15 | wordBreak: 'break-all', 16 | }); 17 | -------------------------------------------------------------------------------- /src/Frontend/Components/NotSavedPopup/NotSavedPopup.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { text } from '../../../shared/text'; 6 | import { 7 | closePopupAndUnsetTargets, 8 | proceedFromUnsavedPopup, 9 | } from '../../state/actions/popup-actions/popup-actions'; 10 | import { useAppDispatch } from '../../state/hooks'; 11 | import { NotificationPopup } from '../NotificationPopup/NotificationPopup'; 12 | 13 | export function NotSavedPopup() { 14 | const dispatch = useAppDispatch(); 15 | 16 | return ( 17 | dispatch(proceedFromUnsavedPopup()), 21 | buttonText: text.unsavedChangesPopup.discard, 22 | color: 'secondary', 23 | }} 24 | rightButtonConfig={{ 25 | onClick: () => dispatch(closePopupAndUnsetTargets()), 26 | buttonText: text.buttons.cancel, 27 | }} 28 | isOpen 29 | aria-label={'unsaved changes popup'} 30 | > 31 | {text.unsavedChangesPopup.message} 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /src/Frontend/Components/ProcessPopup/ProcessPopup.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import MuiDialogContent from '@mui/material/DialogContent'; 6 | import { styled } from '@mui/system'; 7 | 8 | import { LogDisplay } from '../LogDisplay/LogDisplay'; 9 | 10 | export const DialogContent = styled(MuiDialogContent)({ 11 | display: 'grid', 12 | gridTemplateRows: 'repeat(auto-fill, 1fr)', 13 | rowGap: '4px', 14 | }); 15 | 16 | export const GridLogDisplay = styled(LogDisplay)({ 17 | display: 'grid', 18 | gridTemplateColumns: '24px 80px 1fr', 19 | columnGap: '8px', 20 | }); 21 | -------------------------------------------------------------------------------- /src/Frontend/Components/ProcessPopup/ProcessPopup.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import MuiDialog from '@mui/material/Dialog'; 6 | import MuiDialogTitle from '@mui/material/DialogTitle'; 7 | 8 | import { text } from '../../../shared/text'; 9 | import { useAppSelector } from '../../state/hooks'; 10 | import { getOpenPopup } from '../../state/selectors/view-selector'; 11 | import { useProcessingStatusUpdated } from '../../util/use-processing-status-updated'; 12 | import { DialogContent, GridLogDisplay } from './ProcessPopup.style'; 13 | 14 | export function ProcessPopup() { 15 | const isOtherPopupOpen = !!useAppSelector(getOpenPopup); 16 | 17 | const { processingStatusUpdatedEvents, processing } = 18 | useProcessingStatusUpdated(); 19 | return ( 20 | 21 | {text.processPopup.title} 22 | {renderDialogContent()} 23 | 24 | ); 25 | 26 | function renderDialogContent() { 27 | return ( 28 | 29 | {processingStatusUpdatedEvents.map((log, index) => ( 30 | 36 | ))} 37 | 38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Frontend/Components/ProjectMetadataPopup/ProjectMetadataPopup.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { text } from '../../../shared/text'; 6 | import { closePopup } from '../../state/actions/view-actions/view-actions'; 7 | import { useAppDispatch } from '../../state/hooks'; 8 | import { NotificationPopup } from '../NotificationPopup/NotificationPopup'; 9 | import { ProjectMetadataTable } from '../ProjectMetadataTable/ProjectMetadataTable'; 10 | 11 | export const ProjectMetadataPopup: React.FC = () => { 12 | const dispatch = useAppDispatch(); 13 | 14 | function close(): void { 15 | dispatch(closePopup()); 16 | } 17 | 18 | return ( 19 | 28 | 29 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /src/Frontend/Components/ProjectStatisticsPopup/ProjectStatisticsPopup.style.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import MuiPaper from '@mui/material/Paper'; 6 | import { styled } from '@mui/system'; 7 | 8 | import { OpossumColors } from '../../shared-styles'; 9 | 10 | export const ChartCard = styled(MuiPaper)({ 11 | backgroundColor: OpossumColors.lightestBlue, 12 | borderRadius: '10px', 13 | padding: '12px', 14 | display: 'flex', 15 | flexDirection: 'column', 16 | alignItems: 'center', 17 | flex: 1, 18 | }); 19 | -------------------------------------------------------------------------------- /src/Frontend/Components/ReportTableHeader/__tests__/ReportTableHeader.test.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { screen } from '@testing-library/react'; 6 | 7 | import { renderComponent } from '../../../test-helpers/render'; 8 | import { ReportTableHeader } from '../ReportTableHeader'; 9 | 10 | describe('The report view table header', () => { 11 | it('renders', () => { 12 | renderComponent( 13 | 14 | 15 | 16 | 17 |
, 18 | ); 19 | 20 | expect(screen.getByText('License')).toBeInTheDocument(); 21 | expect(screen.getByText('Version')).toBeInTheDocument(); 22 | expect(screen.getAllByText('Name')).toHaveLength(1); 23 | expect(screen.getByText('Copyright')).toBeInTheDocument(); 24 | expect(screen.getByText('License Text')).toBeInTheDocument(); 25 | expect(screen.getByText('Confidence')).toBeInTheDocument(); 26 | expect(screen.getByText('Comment')).toBeInTheDocument(); 27 | expect(screen.getByText('URL')).toBeInTheDocument(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/Frontend/Components/ReportTableItem/ReportTableItem.util.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { compact } from 'lodash'; 6 | 7 | import { PackageInfo } from '../../../shared/shared-types'; 8 | import { TableConfig } from '../ReportView/TableConfig'; 9 | 10 | export function getFormattedCellData( 11 | config: TableConfig, 12 | packageInfo: PackageInfo, 13 | ): string | number { 14 | let cellData: string | number; 15 | switch (config.attributionProperty) { 16 | case 'excludeFromNotice': 17 | case 'firstParty': 18 | case 'followUp': 19 | case 'needsReview': 20 | case 'preSelected': 21 | case 'preferred': 22 | case 'wasPreferred': 23 | cellData = packageInfo[config.attributionProperty] ? 'Yes' : 'No'; 24 | break; 25 | case 'source': 26 | cellData = packageInfo[config.attributionProperty]?.name.trim() || ''; 27 | break; 28 | case 'id': 29 | case 'originIds': 30 | case 'originalAttributionId': 31 | case 'originalAttributionSource': 32 | case 'originalAttributionWasPreferred': 33 | case 'preferredOverOriginIds': 34 | case 'resources': 35 | case 'synthetic': 36 | cellData = ''; 37 | break; 38 | case 'packageName': 39 | cellData = compact([ 40 | packageInfo.packageName, 41 | packageInfo.packageNamespace, 42 | ]).join(':'); 43 | break; 44 | default: 45 | cellData = packageInfo[config.attributionProperty] || ''; 46 | cellData = typeof cellData === 'string' ? cellData.trim() : cellData; 47 | } 48 | 49 | return cellData; 50 | } 51 | -------------------------------------------------------------------------------- /src/Frontend/Components/ResizableBox/ResizableBox.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { SxProps } from '@mui/system'; 6 | import { Resizable, ResizableProps } from 're-resizable'; 7 | 8 | interface Props extends Omit { 9 | children: React.ReactNode; 10 | ref?: React.RefObject; 11 | sx?: SxProps; 12 | } 13 | 14 | export const ResizableBox: React.FC = ({ 15 | children, 16 | enable, 17 | ref, 18 | sx, 19 | ...props 20 | }) => { 21 | return ( 22 | 45 | {children} 46 | 47 | ); 48 | }; 49 | -------------------------------------------------------------------------------- /src/Frontend/Components/ResizePanels/ResizeButton/ResizeButton.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | /* eslint-disable @typescript-eslint/no-magic-numbers */ 6 | import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; 7 | import { alpha } from '@mui/material'; 8 | import MuiFab from '@mui/material/Fab'; 9 | 10 | import { OpossumColors, TRANSITION } from '../../../shared-styles'; 11 | 12 | interface ResizeButtonProps { 13 | onClick: () => void; 14 | invert: boolean; 15 | disabled?: boolean; 16 | } 17 | 18 | export const ResizeButton: React.FC = ({ 19 | onClick, 20 | invert, 21 | disabled, 22 | }) => { 23 | return ( 24 | 41 | 50 | 51 | ); 52 | }; 53 | -------------------------------------------------------------------------------- /src/Frontend/Components/SearchList/SearchList.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { useHotkeys } from 'react-hotkeys-hook'; 6 | import { ListProps } from 'react-virtuoso'; 7 | 8 | import { useSearchRef } from '../SearchRefContext/SearchRefContext'; 9 | import { useVirtuosoComponent } from '../VirtuosoComponentContext/VirtuosoComponentContext'; 10 | 11 | export const SearchList: React.FC = (props) => { 12 | const searchRef = useSearchRef(); 13 | const { isVirtuosoFocused } = useVirtuosoComponent(); 14 | useHotkeys( 15 | 'mod+f', 16 | () => searchRef?.current?.focus(), 17 | { 18 | enabled: isVirtuosoFocused, 19 | }, 20 | [isVirtuosoFocused], 21 | ); 22 | 23 | return
; 24 | }; 25 | -------------------------------------------------------------------------------- /src/Frontend/Components/SearchRefContext/SearchRefContext.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { createContext, useContext } from 'react'; 6 | 7 | export const SearchRefContext = 8 | createContext | null>(null); 9 | 10 | export const useSearchRef = () => { 11 | return useContext(SearchRefContext); 12 | }; 13 | -------------------------------------------------------------------------------- /src/Frontend/Components/Spinner/Spinner.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import MuiCircularProgress from '@mui/material/CircularProgress'; 6 | import { SxProps } from '@mui/system'; 7 | 8 | import { baseIcon } from '../../shared-styles'; 9 | 10 | const DEFAULT_SIZE = 12; 11 | 12 | interface SpinnerProps { 13 | size?: number; 14 | sx?: SxProps; 15 | } 16 | 17 | export function Spinner({ size = DEFAULT_SIZE, sx }: SpinnerProps) { 18 | return ( 19 | 25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /src/Frontend/Components/TextBox/__tests__/TextBox.test.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { render, screen } from '@testing-library/react'; 6 | 7 | import { TextBox } from '../TextBox'; 8 | 9 | describe('TextBox', () => { 10 | it('renders text and label', () => { 11 | render(); 12 | 13 | expect(screen.queryAllByText('Test Title')).toHaveLength(2); 14 | expect(screen.getByDisplayValue('Test Content')).toBeInTheDocument(); 15 | }); 16 | 17 | it('renders icon', () => { 18 | render( 19 | Test Icon
} 23 | />, 24 | ); 25 | 26 | expect(screen.getByText('Test Icon')).toBeInTheDocument(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/Frontend/Components/Toaster/Toaster.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | /* eslint-disable no-restricted-imports */ 6 | import CheckCircleIcon from '@mui/icons-material/CheckCircle'; 7 | import ErrorIcon from '@mui/icons-material/Error'; 8 | import InfoIcon from '@mui/icons-material/Info'; 9 | import { styled, Typography } from '@mui/material'; 10 | import { Toaster as RHTToaster, ToastBar, ToastType } from 'react-hot-toast'; 11 | 12 | const icons: Record = { 13 | error: , 14 | success: , 15 | loading: null, 16 | blank: , 17 | custom: null, 18 | }; 19 | 20 | const ToastContainer = styled('div')({ 21 | display: 'flex', 22 | alignItems: 'center', 23 | gap: '8px', 24 | width: '340px', 25 | }); 26 | 27 | export function Toaster() { 28 | return ( 29 | 36 | {(toast) => ( 37 | 38 | {() => ( 39 | 40 | {icons[toast.type]} 41 | {typeof toast.message === 'function' ? ( 42 | toast.message(toast) 43 | ) : ( 44 | {toast.message} 45 | )} 46 | 47 | )} 48 | 49 | )} 50 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /src/Frontend/Components/Toaster/Toaster.util.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | /* eslint-disable no-restricted-imports */ 6 | import toaster, { ToastOptions } from 'react-hot-toast'; 7 | 8 | class Toast { 9 | public success(message: string, options?: ToastOptions) { 10 | toaster.success(message, { id: message, ...options }); 11 | } 12 | 13 | public error(message: string, options?: ToastOptions) { 14 | toaster.error(message, { id: message, ...options }); 15 | } 16 | 17 | public info(message: string, options?: ToastOptions) { 18 | toaster(message, { id: message, ...options }); 19 | } 20 | } 21 | 22 | export const toast = new Toast(); 23 | -------------------------------------------------------------------------------- /src/Frontend/Components/Toaster/index.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | export * from './Toaster.util'; 7 | -------------------------------------------------------------------------------- /src/Frontend/Components/TopBar/__tests__/TopBar.test.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // SPDX-FileCopyrightText: Nico Carl 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | import { fireEvent, screen } from '@testing-library/react'; 7 | 8 | import { View } from '../../../enums/enums'; 9 | import { initialResourceState } from '../../../state/reducers/resource-reducer'; 10 | import { 11 | isAuditViewSelected, 12 | isReportViewSelected, 13 | } from '../../../state/selectors/view-selector'; 14 | import { renderComponent } from '../../../test-helpers/render'; 15 | import { TopBar } from '../TopBar'; 16 | 17 | describe('TopBar', () => { 18 | it('renders an open file icon', () => { 19 | const { store } = renderComponent(); 20 | 21 | fireEvent.click(screen.getByLabelText('open file')); 22 | 23 | expect(store.getState().resourceState).toMatchObject(initialResourceState); 24 | expect(window.electronAPI.openFile).toHaveBeenCalledTimes(1); 25 | }); 26 | 27 | it('switches between views', () => { 28 | const { store } = renderComponent(); 29 | 30 | fireEvent.click(screen.getByText(View.Audit)); 31 | expect(isAuditViewSelected(store.getState())).toBe(true); 32 | expect(isReportViewSelected(store.getState())).toBe(false); 33 | 34 | fireEvent.click(screen.getByText(View.Report)); 35 | expect(isAuditViewSelected(store.getState())).toBe(false); 36 | expect(isReportViewSelected(store.getState())).toBe(true); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/Frontend/Components/UpdateAppPopup/UpdateAppPopup.util.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { useQuery } from '@tanstack/react-query'; 6 | 7 | interface LatestReleaseResponse { 8 | tag_name: string; 9 | html_url: string; 10 | } 11 | 12 | export function useLatestRelease() { 13 | const { isLoading, data, error } = useQuery({ 14 | queryKey: ['latestRelease'], 15 | queryFn: async () => { 16 | const response = await fetch( 17 | 'https://api.github.com/repos/opossum-tool/OpossumUI/releases/latest', 18 | ); 19 | const { html_url, tag_name }: LatestReleaseResponse = 20 | await response.json(); 21 | 22 | return { html_url, tag_name }; 23 | }, 24 | }); 25 | 26 | return { 27 | latestReleaseLoading: isLoading, 28 | latestReleaseError: error, 29 | latestRelease: 30 | data?.tag_name && data.html_url 31 | ? { 32 | name: data.tag_name, 33 | url: data.html_url, 34 | } 35 | : undefined, 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /src/Frontend/Components/VirtualizedTree/VirtualizedTreeNode/VirtualizedTreeNode.util.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { Resources } from '../../../../shared/shared-types'; 6 | 7 | export function getNodeIdsToExpand( 8 | nodeId: string, 9 | node: Resources | 1, 10 | ): Array { 11 | const nodeIdsToExpand = [nodeId]; 12 | addNodeIdsToExpand(nodeIdsToExpand, node); 13 | return nodeIdsToExpand; 14 | } 15 | 16 | function addNodeIdsToExpand( 17 | nodeIdsToExpand: Array, 18 | node: Resources | 1, 19 | ): void { 20 | const containedNodes = Object.keys(node); 21 | const firstContainedNode = containedNodes[0]; 22 | if ( 23 | node !== 1 && 24 | containedNodes.length === 1 && 25 | node[firstContainedNode] !== 1 26 | ) { 27 | nodeIdsToExpand.push( 28 | `${nodeIdsToExpand[nodeIdsToExpand.length - 1]}${firstContainedNode}/`, 29 | ); 30 | addNodeIdsToExpand(nodeIdsToExpand, node[firstContainedNode]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Frontend/Components/VirtualizedTree/__tests__/VirtualizedTree.test.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { screen } from '@testing-library/react'; 6 | 7 | import { ROOT_PATH } from '../../../shared-constants'; 8 | import { renderComponent } from '../../../test-helpers/render'; 9 | import { VirtualizedTree } from '../VirtualizedTree'; 10 | 11 | describe('The VirtualizedTree', () => { 12 | it('renders VirtualizedTree', () => { 13 | renderComponent( 14 |
{nodeName || '/'}
} 27 | />, 28 | ); 29 | 30 | for (const label of [ 31 | ROOT_PATH, 32 | 'thirdParty', 33 | 'package_1.tr.gz', 34 | 'package_2.tr.gz', 35 | 'root', 36 | 'src', 37 | 'something.js', 38 | 'package.json', 39 | 'docs', 40 | 'readme.md', 41 | ]) { 42 | expect(screen.getByText(label)).toBeInTheDocument(); 43 | } 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /src/Frontend/Components/VirtuosoComponentContext/VirtuosoComponentContext.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { createContext, useContext } from 'react'; 6 | 7 | export const VirtuosoComponentContext = createContext<{ 8 | isVirtuosoFocused: boolean; 9 | loading: boolean | undefined; 10 | }>({ 11 | isVirtuosoFocused: false, 12 | loading: undefined, 13 | }); 14 | 15 | export const useVirtuosoComponent = () => { 16 | return useContext(VirtuosoComponentContext); 17 | }; 18 | -------------------------------------------------------------------------------- /src/Frontend/enums/enums.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // SPDX-FileCopyrightText: Nico Carl 4 | // 5 | // SPDX-License-Identifier: Apache-2.0 6 | 7 | export enum View { 8 | Audit = 'Audit', 9 | Report = 'Report', 10 | } 11 | 12 | export enum PopupType { 13 | InvalidLinkPopup = 'InvalidLinkPopup', 14 | NotSavedPopup = 'NotSavedPopup', 15 | ProjectMetadataPopup = 'ProjectMetadataPopup', 16 | ProjectStatisticsPopup = 'ProjectStatisticsPopup', 17 | UpdateAppPopup = 'UpdateAppPopup', 18 | ImportDialog = 'ImportDialog', 19 | MergeDialog = 'MergeDialog', 20 | } 21 | 22 | export enum AttributionType { 23 | FirstParty = 'First Party', 24 | ThirdParty = 'Third Party', 25 | } 26 | -------------------------------------------------------------------------------- /src/Frontend/state/actions/user-settings-actions/__tests__/user-settings-actions.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { waitFor } from '@testing-library/react'; 6 | 7 | import { DEFAULT_USER_SETTINGS } from '../../../../../shared/shared-constants'; 8 | import { createAppStore } from '../../../configure-store'; 9 | import { fetchUserSettings } from '../user-settings-actions'; 10 | 11 | describe('user-settings-actions', () => { 12 | it('loads the user settings from the backend', async () => { 13 | const store = createAppStore(); 14 | const backendCall = jest.mocked(window.electronAPI.getUserSettings); 15 | backendCall.mockReturnValue( 16 | Promise.resolve({ 17 | ...DEFAULT_USER_SETTINGS, 18 | qaMode: true, 19 | }), 20 | ); 21 | 22 | store.dispatch(fetchUserSettings()); 23 | 24 | await waitFor(() => { 25 | expect(store.getState().userSettingsState?.qaMode).toBe(true); 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/Frontend/state/actions/user-settings-actions/types.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { UserSettings } from '../../../../shared/shared-types'; 6 | 7 | export interface SetUserSetting { 8 | type: typeof ACTION_SET_USER_SETTING; 9 | payload: Partial; 10 | } 11 | 12 | export const ACTION_SET_USER_SETTING = 'ACTION_SET_USER_SETTING'; 13 | 14 | export type UserSettingsAction = SetUserSetting; 15 | -------------------------------------------------------------------------------- /src/Frontend/state/actions/user-settings-actions/user-settings-actions.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { UserSettings } from '../../../../shared/shared-types'; 6 | import { AppThunkAction } from '../../types'; 7 | import { ACTION_SET_USER_SETTING, SetUserSetting } from './types'; 8 | 9 | export function setUserSetting(setting: Partial): SetUserSetting { 10 | return { 11 | type: ACTION_SET_USER_SETTING, 12 | payload: setting, 13 | }; 14 | } 15 | 16 | export function fetchUserSettings(): AppThunkAction { 17 | return async (dispatch) => { 18 | const userSettings = await window.electronAPI.getUserSettings(); 19 | dispatch(setUserSetting(userSettings)); 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/Frontend/state/actions/variables-actions/types.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | export const SET_VARIABLE = 'SET_VARIABLE'; 6 | export type SET_VARIABLE = typeof SET_VARIABLE; 7 | -------------------------------------------------------------------------------- /src/Frontend/state/actions/variables-actions/variables-actions.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { ResetResourceStateAction } from '../resource-actions/types'; 6 | import { SET_VARIABLE } from './types'; 7 | 8 | export type VariablesAction = SetVariable | ResetResourceStateAction; 9 | 10 | interface SetVariable { 11 | type: SET_VARIABLE; 12 | name: string; 13 | value: T; 14 | } 15 | 16 | export function setVariable(name: string, value: T): SetVariable { 17 | return { 18 | type: SET_VARIABLE, 19 | name, 20 | value, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/Frontend/state/configure-store.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { configureStore } from '@reduxjs/toolkit'; 6 | 7 | import { reducer } from './reducer'; 8 | import { AppThunkAction } from './types'; 9 | 10 | type Store = ReturnType; 11 | export type Action = AppThunkAction | Parameters[0]; 12 | 13 | export function createAppStore() { 14 | return configureStore({ 15 | reducer, 16 | devTools: process.env.NODE_ENV !== 'production', 17 | middleware: (getDefaultMiddleware) => 18 | getDefaultMiddleware({ 19 | // TECH DEBT: we should not be putting sets into the store 20 | // https://redux.js.org/style-guide/#do-not-put-non-serializable-values-in-state-or-actions 21 | serializableCheck: false, 22 | // We only use this check in the CI because it significantly slows down the development server. 23 | immutableCheck: process.env.CI === 'true', 24 | }), 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /src/Frontend/state/helpers/__tests__/resource-helpers.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { 6 | getResourceIdsFromResources, 7 | getResourcesFromIds, 8 | } from '../resources-helpers'; 9 | 10 | describe('getResourceIdsFromResources', () => { 11 | it('returns IDs from resources', () => { 12 | expect( 13 | getResourceIdsFromResources({ 14 | thirdParty: { 15 | 'package_1.tr.gz': 1, 16 | 'package_2.tr.gz': 1, 17 | }, 18 | root: { 19 | src: { 20 | 'something.js': 1, 21 | }, 22 | 'readme.md': 1, 23 | }, 24 | }).sort(), 25 | ).toEqual([ 26 | '/root/', 27 | '/root/readme.md', 28 | '/root/src/', 29 | '/root/src/something.js', 30 | '/thirdParty/', 31 | '/thirdParty/package_1.tr.gz', 32 | '/thirdParty/package_2.tr.gz', 33 | ]); 34 | }); 35 | }); 36 | 37 | describe('getResourcesFromIds', () => { 38 | it('returns resources from IDs', () => { 39 | expect( 40 | getResourcesFromIds([ 41 | '/root/', 42 | '/root/readme.md', 43 | '/root/src/', 44 | '/root/src/something.js', 45 | '/thirdParty/', 46 | '/thirdParty/package_1.tr.gz', 47 | '/thirdParty/package_2.tr.gz', 48 | ]), 49 | ).toEqual({ 50 | thirdParty: { 51 | 'package_1.tr.gz': 1, 52 | 'package_2.tr.gz': 1, 53 | }, 54 | root: { 55 | src: { 56 | 'something.js': 1, 57 | }, 58 | 'readme.md': 1, 59 | }, 60 | }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /src/Frontend/state/helpers/get-parents.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | export function getParents(pathToBeSplit: string): Array { 7 | const parents: Array = []; 8 | for ( 9 | let characterIndex = 0; 10 | characterIndex < pathToBeSplit.length - 1; 11 | characterIndex++ 12 | ) { 13 | if (pathToBeSplit[characterIndex] === '/') { 14 | parents.push(pathToBeSplit.slice(0, characterIndex + 1)); 15 | } 16 | } 17 | return parents; 18 | } 19 | 20 | export function getParentsUpToNextAttributionBreakpoint( 21 | path: string, 22 | attributionBreakpoints: Set, 23 | ): Array { 24 | // A breakpoint has no parents. 25 | if (attributionBreakpoints.has(path)) { 26 | return []; 27 | } 28 | 29 | const allParents = getParents(path); 30 | for (let idx = allParents.length - 1; idx >= 0; --idx) { 31 | if (attributionBreakpoints.has(allParents[idx])) { 32 | return allParents.slice(idx + 1); 33 | } 34 | } 35 | return allParents; 36 | } 37 | -------------------------------------------------------------------------------- /src/Frontend/state/hooks.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { memoize } from 'proxy-memoize'; 6 | import { useCallback } from 'react'; 7 | import { useDispatch, useSelector, useStore } from 'react-redux'; 8 | 9 | import { State } from '../types/types'; 10 | import { AppThunkDispatch } from './types'; 11 | 12 | export const useAppDispatch = useDispatch; 13 | 14 | export const useAppSelector = ( 15 | fn: (state: State) => T, 16 | deps: Array = [], 17 | ): T => 18 | // eslint-disable-next-line react-hooks/exhaustive-deps 19 | useSelector(useCallback(memoize(fn), deps)); 20 | 21 | export const useAppStore = useStore; 22 | -------------------------------------------------------------------------------- /src/Frontend/state/reducer.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { combineReducers } from '@reduxjs/toolkit'; 6 | 7 | import { resourceState } from './reducers/resource-reducer'; 8 | import { userSettingsState } from './reducers/user-settings-reducer'; 9 | import { variablesState } from './reducers/variables-reducer'; 10 | import { viewState } from './reducers/view-reducer'; 11 | 12 | export const reducer = combineReducers({ 13 | viewState, 14 | resourceState, 15 | variablesState, 16 | userSettingsState, 17 | }); 18 | -------------------------------------------------------------------------------- /src/Frontend/state/reducers/user-settings-reducer.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { DEFAULT_USER_SETTINGS } from '../../../shared/shared-constants'; 6 | import { UserSettings } from '../../../shared/shared-types'; 7 | import { 8 | ACTION_SET_USER_SETTING, 9 | UserSettingsAction, 10 | } from '../actions/user-settings-actions/types'; 11 | 12 | export function userSettingsState( 13 | state: UserSettings = DEFAULT_USER_SETTINGS, 14 | action: UserSettingsAction, 15 | ): UserSettings { 16 | switch (action.type) { 17 | case ACTION_SET_USER_SETTING: 18 | return { 19 | ...state, 20 | ...action.payload, 21 | }; 22 | default: 23 | return state; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Frontend/state/reducers/variables-reducer.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { omit } from '../../util/lodash-extension-utils'; 6 | import { ACTION_RESET_RESOURCE_STATE } from '../actions/resource-actions/types'; 7 | import { SET_VARIABLE } from '../actions/variables-actions/types'; 8 | import { VariablesAction } from '../actions/variables-actions/variables-actions'; 9 | import { 10 | FILTERED_ATTRIBUTIONS_AUDIT, 11 | FILTERED_ATTRIBUTIONS_REPORT, 12 | FILTERED_SIGNALS, 13 | } from '../variables/use-filtered-data'; 14 | import { PROGRESS_DATA } from '../variables/use-progress-data'; 15 | 16 | export type VariablesState = Record; 17 | 18 | export function variablesState( 19 | state: VariablesState = {}, 20 | action: VariablesAction, 21 | ): VariablesState { 22 | switch (action.type) { 23 | case ACTION_RESET_RESOURCE_STATE: 24 | return omit(state, [ 25 | FILTERED_ATTRIBUTIONS_AUDIT, 26 | FILTERED_ATTRIBUTIONS_REPORT, 27 | FILTERED_SIGNALS, 28 | PROGRESS_DATA, 29 | ]); 30 | case SET_VARIABLE: 31 | return { 32 | ...state, 33 | [action.name]: action.value, 34 | }; 35 | default: 36 | return state; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Frontend/state/selectors/user-settings-selector.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { UserSettings } from '../../../shared/shared-types'; 6 | import { State } from '../../types/types'; 7 | 8 | export function getUserSettings(state: State): UserSettings { 9 | return state.userSettingsState; 10 | } 11 | -------------------------------------------------------------------------------- /src/Frontend/state/types.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { Action, ThunkAction, ThunkDispatch } from '@reduxjs/toolkit'; 6 | 7 | import { State } from '../types/types'; 8 | 9 | export type AppThunkAction = ThunkAction>; 10 | 11 | export type AppThunkDispatch = ThunkDispatch; 12 | -------------------------------------------------------------------------------- /src/Frontend/state/variables/__tests__/use-variable.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { act } from '@testing-library/react'; 6 | 7 | import { faker } from '../../../../testing/Faker'; 8 | import { renderHook } from '../../../test-helpers/render'; 9 | import { useVariable } from '../use-variable'; 10 | 11 | describe('useVariable', () => { 12 | it('returns initial value', () => { 13 | const key = faker.string.sample(); 14 | const initialValue = faker.string.sample(); 15 | const { result } = renderHook(() => useVariable(key, initialValue)); 16 | 17 | expect(result.current[0]).toBe(initialValue); 18 | }); 19 | 20 | it('updates variable and persists it in store', () => { 21 | const key = faker.string.sample(); 22 | const initialValue = faker.string.sample(); 23 | const newValue = faker.string.sample(); 24 | const { result } = renderHook(() => useVariable(key, initialValue)); 25 | 26 | act(() => { 27 | result.current[1](newValue); 28 | }); 29 | 30 | expect(result.current[0]).toBe(newValue); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /src/Frontend/state/variables/use-attribution-ids-for-replacement.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { useVariable } from './use-variable'; 6 | 7 | export const ATTRIBUTION_IDS_FOR_REPLACEMENT = 8 | 'attribution-ids-for-replacement'; 9 | 10 | export function useAttributionIdsForReplacement() { 11 | return useVariable>(ATTRIBUTION_IDS_FOR_REPLACEMENT, []); 12 | } 13 | -------------------------------------------------------------------------------- /src/Frontend/state/variables/use-panel-sizes.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { PanelSizes } from '../../../shared/shared-types'; 6 | import { useUserSettings } from './use-user-setting'; 7 | 8 | export const usePanelSizes = (): { 9 | panelSizes: PanelSizes; 10 | setPanelSizes: (panelsSizes: Partial) => void; 11 | } => { 12 | const [userSettings, updateUserSettings] = useUserSettings(); 13 | const panelSizes = userSettings.panelSizes; 14 | const setPanelSizes = (panelSizes: Partial) => 15 | updateUserSettings((currentSettings) => ({ 16 | panelSizes: { ...currentSettings.panelSizes, ...panelSizes }, 17 | })); 18 | return { panelSizes, setPanelSizes }; 19 | }; 20 | -------------------------------------------------------------------------------- /src/Frontend/state/variables/use-progress-data.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { ProgressBarData } from '../../types/types'; 6 | import { useVariable } from './use-variable'; 7 | 8 | export const PROGRESS_DATA = 'progress-data'; 9 | 10 | export function useProgressData() { 11 | return useVariable(PROGRESS_DATA, null); 12 | } 13 | -------------------------------------------------------------------------------- /src/Frontend/state/variables/use-variable.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { isFunction } from 'lodash'; 6 | import { useCallback } from 'react'; 7 | import { useSelector } from 'react-redux'; 8 | 9 | import { State } from '../../types/types'; 10 | import { setVariable } from '../actions/variables-actions/variables-actions'; 11 | import { useAppDispatch, useAppStore } from '../hooks'; 12 | 13 | /** 14 | * Similar to `useState` but persists the value in the redux store. 15 | * @param name The name of the variable in the redux store. 16 | * @param initialValue The initial value of the variable. 17 | * @returns A tuple containing the current value and a setter function. 18 | */ 19 | export function useVariable( 20 | name: string, 21 | initialValue: T, 22 | ): [T, (newValue: T | ((prev: T) => T | Promise)) => void] { 23 | const dispatch = useAppDispatch(); 24 | const store = useAppStore(); 25 | const getValue = useCallback( 26 | (state: State) => { 27 | if (name in state.variablesState) { 28 | return state.variablesState[name] as T; 29 | } 30 | 31 | return initialValue; 32 | }, 33 | [initialValue, name], 34 | ); 35 | 36 | return [ 37 | useSelector(getValue), 38 | useCallback( 39 | (newValue: T | ((prev: T) => T | Promise)) => { 40 | dispatch( 41 | setVariable( 42 | name, 43 | isFunction(newValue) 44 | ? newValue(getValue(store.getState())) 45 | : newValue, 46 | ), 47 | ); 48 | }, 49 | [dispatch, getValue, name, store], 50 | ), 51 | ]; 52 | } 53 | -------------------------------------------------------------------------------- /src/Frontend/util/__tests__/can-have-children.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { Resources } from '../../../shared/shared-types'; 6 | import { 7 | canResourceHaveChildren, 8 | isIdOfResourceWithChildren, 9 | } from '../can-resource-have-children'; 10 | 11 | describe('canHaveChildren', () => { 12 | it('returns true for a folder', () => { 13 | const testResources: Resources = {}; 14 | 15 | expect(canResourceHaveChildren(testResources)).toBe(true); 16 | }); 17 | 18 | it('returns false for a file', () => { 19 | const testFileFromResources = 1; 20 | 21 | expect(canResourceHaveChildren(testFileFromResources)).toBe(false); 22 | }); 23 | }); 24 | 25 | describe('isIdOfResourceWithChildren', () => { 26 | it('returns true for a folder id', () => { 27 | const testFolderPath = '/some_folder/'; 28 | 29 | expect(isIdOfResourceWithChildren(testFolderPath)).toBe(true); 30 | }); 31 | 32 | it('returns false for a file id', () => { 33 | const testFilePath = '/some_folder/some_file'; 34 | 35 | expect(isIdOfResourceWithChildren(testFilePath)).toBe(false); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /src/Frontend/util/__tests__/maybe-pluralize.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { maybePluralize } from '../maybe-pluralize'; 6 | 7 | describe('maybePluralize', () => { 8 | it('uses provided plural', () => { 9 | expect(maybePluralize(2, 'Deputy', { pluralNoun: 'Deputies' })).toBe( 10 | '2 Deputies', 11 | ); 12 | }); 13 | 14 | it('makes plural by adding s if no plural is provided', () => { 15 | expect(maybePluralize(2, 'user')).toBe('2 users'); 16 | }); 17 | 18 | it('uses plural when value is zero', () => { 19 | expect(maybePluralize(0, 'user')).toBe('0 users'); 20 | }); 21 | 22 | it('does not add suffix when value is 1', () => { 23 | expect(maybePluralize(1, 'user')).toBe('user'); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/Frontend/util/__tests__/open-url.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { openUrl } from '../open-url'; 6 | 7 | describe('openUrl', () => { 8 | it('checks protocol is getting added if originally missing', () => { 9 | const urlString = 'www.google.com'; 10 | openUrl(urlString); 11 | expect(window.electronAPI.openLink).toHaveBeenCalledWith( 12 | `https://${urlString}`, 13 | ); 14 | }); 15 | 16 | it('does not add protocol if originally present', () => { 17 | const urlString = 'https://www.google.com'; 18 | openUrl(urlString); 19 | expect(window.electronAPI.openLink).toHaveBeenCalledWith(urlString); 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /src/Frontend/util/__tests__/prettify-source.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { ExternalAttributionSources } from '../../../shared/shared-types'; 6 | import { prettifySource } from '../prettify-source'; 7 | 8 | const testAttributionSources: ExternalAttributionSources = { 9 | MERGER: { name: 'Suggested', priority: 11 }, 10 | HHC: { name: 'High High Compute', priority: 10 }, 11 | MS: { name: 'Metadata Scanner', priority: 9 }, 12 | 'REUSER:HHC': { name: 'High High Compute (old scan)', priority: 8 }, 13 | 'REUSER:MS': { name: 'Metadata Scanner (old scan)', priority: 7 }, 14 | 'REUSER:SC': { name: 'ScanCode (old scan)', priority: 6 }, 15 | 'REUSER:HC': { name: 'High Compute (old scan)', priority: 5 }, 16 | 'REUSER:MERGER': { name: 'Suggested (old scan)', priority: 4 }, 17 | SC: { name: 'ScanCode', priority: 3 }, 18 | HC: { name: 'High Compute', priority: 2 }, 19 | HINT: { name: 'Hint', priority: 1 }, 20 | }; 21 | 22 | describe('prettifySource', () => { 23 | it.each([ 24 | ['HC', 'High Compute'], 25 | ['HHC', 'High High Compute'], 26 | ['SC', 'ScanCode'], 27 | ['REUSER:HC', 'High Compute (old scan)'], 28 | ['REUSER:HHC', 'High High Compute (old scan)'], 29 | ['REUSER:SC', 'ScanCode (old scan)'], 30 | ['HHHC', 'HHHC'], 31 | ['Crystal Ball', 'Crystal Ball'], 32 | ['REUSER:Crystal Ball', 'REUSER:Crystal Ball'], 33 | ['MS', 'Metadata Scanner'], 34 | ['REUSER:MS', 'Metadata Scanner (old scan)'], 35 | ])( 36 | 'transforms known sources and only those', 37 | (src: string, expectedResult: string) => { 38 | expect(prettifySource(src, testAttributionSources)).toBe(expectedResult); 39 | }, 40 | ); 41 | }); 42 | -------------------------------------------------------------------------------- /src/Frontend/util/__tests__/search-package-info.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { Criticality, PackageInfo } from '../../../shared/shared-types'; 6 | import { packageInfoContainsSearchTerm } from '../search-package-info'; 7 | 8 | describe('packageInfoContainsSearchTerm', () => { 9 | it('searches by package name', () => { 10 | const testPackageInfo: PackageInfo = { 11 | packageName: 'Search_term package', 12 | criticality: Criticality.None, 13 | id: 'uuid1', 14 | }; 15 | 16 | expect(packageInfoContainsSearchTerm(testPackageInfo, 'SeArCh_TeRm')).toBe( 17 | true, 18 | ); 19 | }); 20 | 21 | it('searches by copyright', () => { 22 | const testPackageInfo: PackageInfo = { 23 | copyright: '(c) Search_term 2022', 24 | criticality: Criticality.None, 25 | id: 'uuid2', 26 | }; 27 | 28 | expect(packageInfoContainsSearchTerm(testPackageInfo, 'SeArCh_TeRm')).toBe( 29 | true, 30 | ); 31 | }); 32 | 33 | it('searches by package version', () => { 34 | const testPackageInfo: PackageInfo = { 35 | packageVersion: 'version search_term', 36 | criticality: Criticality.None, 37 | id: 'uuid4', 38 | }; 39 | 40 | expect(packageInfoContainsSearchTerm(testPackageInfo, 'SeArCh_TeRm')).toBe( 41 | true, 42 | ); 43 | }); 44 | 45 | it('ignores other fields', () => { 46 | const testPackageInfo: PackageInfo = { 47 | licenseText: 'text search_term', 48 | url: 'www.search_term.com', 49 | criticality: Criticality.None, 50 | id: 'uuid5', 51 | }; 52 | 53 | expect(packageInfoContainsSearchTerm(testPackageInfo, 'SeArCh_TeRm')).toBe( 54 | false, 55 | ); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/Frontend/util/__tests__/tryit.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { faker } from '../../../testing/Faker'; 6 | import { tryit } from '../tryit'; 7 | 8 | describe('tryit', () => { 9 | it('converts error to undefined', async () => { 10 | expect(await tryit(() => Promise.reject())()).toBeUndefined(); 11 | }); 12 | 13 | it('yields return value when no error occurs', async () => { 14 | const value = faker.string.sample(); 15 | expect(await tryit(() => Promise.resolve(value))()).toBe(value); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /src/Frontend/util/can-resource-have-children.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { Resources } from '../../shared/shared-types'; 6 | 7 | export function canResourceHaveChildren( 8 | resource: Resources | 1 | undefined, 9 | ): resource is Resources { 10 | return resource !== 1 && resource !== undefined; 11 | } 12 | 13 | export function isIdOfResourceWithChildren(resourceId: string): boolean { 14 | return resourceId.slice(-1) === '/'; 15 | } 16 | -------------------------------------------------------------------------------- /src/Frontend/util/ensure-array.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | export function ensureArray(elementOrArray: T | Array): Array { 7 | if (Array.isArray(elementOrArray)) { 8 | return elementOrArray; 9 | } 10 | if (elementOrArray === undefined) { 11 | return []; 12 | } 13 | return [elementOrArray]; 14 | } 15 | -------------------------------------------------------------------------------- /src/Frontend/util/get-comparable-attributes.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { pickBy } from 'lodash'; 6 | 7 | import { PackageInfo } from '../../shared/shared-types'; 8 | import { thirdPartyKeys } from '../shared-constants'; 9 | 10 | export const FORM_ATTRIBUTES = [ 11 | 'packageName', 12 | 'packageVersion', 13 | 'packageNamespace', 14 | 'packageType', 15 | 'url', 16 | 'copyright', 17 | 'licenseName', 18 | 'licenseText', 19 | 'firstParty', 20 | 'comment', 21 | ] satisfies Array; 22 | 23 | export type FormAttribute = (typeof FORM_ATTRIBUTES)[number]; 24 | 25 | export function getComparableAttributes(packageInfo: PackageInfo) { 26 | return pickBy( 27 | packageInfo, 28 | (value, key) => 29 | FORM_ATTRIBUTES.some((attribute) => attribute === key) && 30 | (packageInfo.firstParty 31 | ? !thirdPartyKeys.includes(key as keyof PackageInfo) 32 | : true) && 33 | !!value, 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /src/Frontend/util/get-contained-attribution-count.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { 6 | ResourcesToAttributions, 7 | ResourcesWithAttributedChildren, 8 | } from '../../shared/shared-types'; 9 | 10 | export function getContainedAttributionCount({ 11 | resolvedExternalAttributions, 12 | resourceId, 13 | resourcesToAttributions, 14 | resourcesWithAttributedChildren: { 15 | attributedChildren, 16 | paths, 17 | pathsToIndices, 18 | }, 19 | }: { 20 | resolvedExternalAttributions?: Set; 21 | resourceId: string; 22 | resourcesToAttributions: ResourcesToAttributions; 23 | resourcesWithAttributedChildren: ResourcesWithAttributedChildren; 24 | }): Record { 25 | const resourceIndex = pathsToIndices[resourceId] as number | undefined; 26 | const resourceAttributions = resourcesToAttributions[resourceId] as 27 | | Array 28 | | undefined; 29 | 30 | const attributionCount: Record = {}; 31 | 32 | resourceIndex !== undefined && 33 | attributedChildren[resourceIndex]?.forEach((pathIndex) => { 34 | const childId = paths[pathIndex] as string | undefined; 35 | childId && 36 | resourcesToAttributions[childId]?.forEach((attributionId) => { 37 | if ( 38 | !resolvedExternalAttributions?.has(attributionId) && 39 | !resourceAttributions?.includes(attributionId) 40 | ) { 41 | attributionCount[attributionId] = 42 | (attributionCount[attributionId] || 0) + 1; 43 | } 44 | }); 45 | }); 46 | 47 | return attributionCount; 48 | } 49 | -------------------------------------------------------------------------------- /src/Frontend/util/handle-purl.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { PackageURL } from 'packageurl-js'; 6 | 7 | import { PackageInfo } from '../../shared/shared-types'; 8 | import { text } from '../../shared/text'; 9 | 10 | export function parsePurl(purl: string): PackageURL | undefined { 11 | try { 12 | return PackageURL.fromString(purl); 13 | } catch { 14 | return undefined; 15 | } 16 | } 17 | 18 | export function generatePurl(packageInfo: PackageInfo): string { 19 | try { 20 | return packageInfo.packageType?.trim() && packageInfo.packageName?.trim() 21 | ? new PackageURL( 22 | packageInfo.packageType.trim(), 23 | packageInfo?.packageNamespace?.trim(), 24 | packageInfo.packageName.trim(), 25 | packageInfo?.packageVersion?.trim(), 26 | undefined, 27 | undefined, 28 | ).toString() 29 | : ''; 30 | } catch (error) { 31 | return text.attributionColumn.invalidPurl; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Frontend/util/http-client.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { text } from '../../shared/text'; 6 | 7 | export interface RequestProps { 8 | baseUrl: string; 9 | body?: object; 10 | headers?: Record; 11 | method?: 'GET' | 'POST' | 'PUT' | 'DELETE'; 12 | params?: Record; 13 | path?: string; 14 | throwForStatus?: boolean; 15 | } 16 | 17 | export class HttpClient { 18 | public async request({ 19 | baseUrl, 20 | body, 21 | headers, 22 | method = 'GET', 23 | params = {}, 24 | path, 25 | throwForStatus = true, 26 | }: RequestProps): Promise { 27 | const url = path ? new URL(path, baseUrl) : new URL(baseUrl); 28 | 29 | Object.entries(params).forEach(([key, value]) => { 30 | if (value !== undefined) { 31 | url.searchParams.append(key, value.toString()); 32 | } 33 | }); 34 | 35 | const response = await fetch(url, { 36 | method, 37 | headers, 38 | body: JSON.stringify(body), 39 | }); 40 | 41 | if (!response.ok && throwForStatus) { 42 | throw new Error( 43 | `${response.status}(${response.statusText || text.generic.unknown})`, 44 | ); 45 | } 46 | 47 | return response; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/Frontend/util/maybe-pluralize.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | /** 7 | * Adds 's' depending on value, for example user vs users 8 | * @param count 9 | * @param noun 10 | * @param pluralNoun 11 | * @example maybePluralize(0, 'User') returns '0 Users' 12 | */ 13 | export function maybePluralize( 14 | count: number, 15 | noun: string, 16 | { 17 | pluralNoun, 18 | showOne, 19 | }: Partial<{ pluralNoun: string; showOne: boolean }> = {}, 20 | ) { 21 | if (count === 1) { 22 | return showOne ? `${count} ${noun}` : noun; 23 | } 24 | return `${new Intl.NumberFormat().format(count)} ${pluralNoun || `${noun}s`}`; 25 | } 26 | -------------------------------------------------------------------------------- /src/Frontend/util/open-url.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | export function openUrl(urlString: string | undefined): void { 7 | if (!urlString) { 8 | return; 9 | } 10 | 11 | if (!urlString.startsWith('https://') && !urlString.startsWith('http://')) { 12 | urlString = `https://${urlString}`; 13 | } 14 | 15 | void window.electronAPI.openLink(urlString); 16 | } 17 | -------------------------------------------------------------------------------- /src/Frontend/util/prettify-source.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { ExternalAttributionSources } from '../../shared/shared-types'; 6 | 7 | export function prettifySource( 8 | source: string | undefined | null, 9 | attributionSources: ExternalAttributionSources, 10 | ): string { 11 | return source ? attributionSources[source]?.name || source : ''; 12 | } 13 | -------------------------------------------------------------------------------- /src/Frontend/util/search-package-info.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { PackageInfo } from '../../shared/shared-types'; 6 | 7 | export function packageInfoContainsSearchTerm( 8 | { 9 | copyright, 10 | comment, 11 | packageName, 12 | packageNamespace, 13 | packageVersion, 14 | }: PackageInfo, 15 | search: string, 16 | ): boolean { 17 | return ( 18 | search === '' || 19 | [copyright, comment, packageName, packageNamespace, packageVersion] 20 | .map((value) => value?.toLowerCase()) 21 | .some((value) => value?.includes(search.toLowerCase())) 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /src/Frontend/util/tryit.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | /** 7 | * Converts a function that might throw an error into a function that returns undefined instead. 8 | * @param func The function that might throw an error. It can be async. 9 | * @returns 10 | */ 11 | export function tryit, R extends Promise>( 12 | func: (...args: A) => R, 13 | ): (...args: A) => R extends Promise ? Promise

: never { 14 | //@ts-expect-error fixing this type error would just repeat the definition above 15 | return async (...args) => { 16 | try { 17 | return await func(...args); 18 | } catch (error) { 19 | return undefined; 20 | } 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/Frontend/util/use-debounced-input.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { useEffect, useState } from 'react'; 6 | 7 | const default_delay = 500; 8 | 9 | export function useDebouncedInput(input: T, delay = default_delay): T { 10 | const [debouncedInput, setDebouncedInput] = useState(input); 11 | 12 | useEffect(() => { 13 | const handler = setTimeout(() => { 14 | setDebouncedInput(input); 15 | }, delay); 16 | 17 | return (): void => { 18 | clearTimeout(handler); 19 | }; 20 | }, [delay, input]); 21 | 22 | return debouncedInput; 23 | } 24 | -------------------------------------------------------------------------------- /src/Frontend/util/use-previous.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { useEffect, useRef } from 'react'; 6 | 7 | export function usePrevious(value: T, fallback: T): T; 8 | export function usePrevious(value: T, fallback?: T): T | undefined; 9 | export function usePrevious(value: T, fallback?: T): T | undefined { 10 | const ref = useRef(undefined); 11 | useEffect(() => { 12 | ref.current = value; 13 | }); 14 | return ref.current ?? fallback; 15 | } 16 | -------------------------------------------------------------------------------- /src/Frontend/web-workers/__tests__/use-signals-worker.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { act } from '@testing-library/react'; 6 | 7 | import { faker } from '../../../testing/Faker'; 8 | import { setProjectMetadata } from '../../state/actions/resource-actions/all-views-simple-actions'; 9 | import { renderHook } from '../../test-helpers/render'; 10 | import { useSignalsWorker } from '../use-signals-worker'; 11 | 12 | const mockPostMessage = jest.fn(); 13 | const mockTerminate = jest.fn(); 14 | 15 | class Worker { 16 | url: string; 17 | postMessage = mockPostMessage; 18 | terminate = mockTerminate; 19 | 20 | constructor(scriptURL: string) { 21 | this.url = scriptURL; 22 | } 23 | } 24 | 25 | describe('useSignalsWorker', () => { 26 | beforeEach(() => { 27 | Object.defineProperty(window, 'Worker', { 28 | writable: true, 29 | value: Worker, 30 | }); 31 | }); 32 | 33 | it('does not re-initialize worker when project ID is stable', () => { 34 | const metadata = faker.opossum.metadata(); 35 | renderHook(useSignalsWorker, { 36 | actions: [setProjectMetadata(metadata)], 37 | }); 38 | 39 | expect(mockTerminate).not.toHaveBeenCalled(); 40 | }); 41 | 42 | it('re-initializes worker when project ID changes', () => { 43 | const metadata = faker.opossum.metadata(); 44 | const { store } = renderHook(useSignalsWorker, { 45 | actions: [setProjectMetadata(metadata)], 46 | }); 47 | 48 | act(() => { 49 | store.dispatch( 50 | setProjectMetadata({ ...metadata, projectId: faker.string.sample() }), 51 | ); 52 | }); 53 | 54 | expect(mockTerminate).toHaveBeenCalledTimes(1); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /src/Frontend/web-workers/scripts/get-progress-data.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { 6 | AttributionData, 7 | ClassificationsConfig, 8 | Resources, 9 | } from '../../../shared/shared-types'; 10 | import { getUpdatedProgressBarData } from '../../state/helpers/progress-bar-data-helpers'; 11 | import { ProgressBarData } from '../../types/types'; 12 | 13 | interface Props { 14 | attributionBreakpoints: Set; 15 | externalData: AttributionData; 16 | filesWithChildren: Set; 17 | manualData: AttributionData; 18 | resolvedExternalAttributions: Set; 19 | resources: Resources; 20 | classifications: ClassificationsConfig; 21 | } 22 | 23 | export function getProgressData({ 24 | attributionBreakpoints, 25 | externalData, 26 | filesWithChildren, 27 | manualData, 28 | resolvedExternalAttributions, 29 | resources, 30 | classifications, 31 | }: Props): ProgressBarData { 32 | return getUpdatedProgressBarData({ 33 | resources, 34 | manualAttributions: manualData.attributions, 35 | externalAttributions: externalData.attributions, 36 | resourcesToManualAttributions: manualData.resourcesToAttributions, 37 | resourcesToExternalAttributions: externalData.resourcesToAttributions, 38 | resolvedExternalAttributions, 39 | attributionBreakpoints, 40 | filesWithChildren, 41 | classifications, 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /src/e2e-tests/__tests__/displaying-project-metadata.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { faker, test } from '../utils'; 6 | 7 | const metadata = faker.opossum.metadata(); 8 | 9 | test.use({ 10 | data: { 11 | inputData: faker.opossum.inputData({ metadata }), 12 | }, 13 | }); 14 | 15 | test('opens, displays, and closes project metadata', async ({ 16 | menuBar, 17 | projectMetadataPopup, 18 | }) => { 19 | await menuBar.openProjectMetadata(); 20 | await projectMetadataPopup.assert.titleIsVisible(); 21 | await projectMetadataPopup.assert.attributeIsVisible(metadata.projectId); 22 | 23 | await projectMetadataPopup.closeButton.click(); 24 | await projectMetadataPopup.assert.titleIsHidden(); 25 | }); 26 | -------------------------------------------------------------------------------- /src/e2e-tests/__tests__/using-app-without-a-file.test.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { test } from '../utils'; 6 | 7 | test('provides expected functionality when no file is open', async ({ 8 | menuBar, 9 | resourcesTree, 10 | topBar, 11 | }) => { 12 | await menuBar.assert.hasTitle('OpossumUI'); 13 | await resourcesTree.assert.isHidden(); 14 | await topBar.assert.openFileButtonIsVisible(); 15 | await topBar.assert.modeButtonsAreVisible(); 16 | await topBar.assert.auditViewIsActive(); 17 | 18 | await topBar.gotoReportView(); 19 | await topBar.assert.reportViewIsActive(); 20 | }); 21 | -------------------------------------------------------------------------------- /src/e2e-tests/page-objects/ConfirmDeletePopup.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { expect, type Locator, type Page } from '@playwright/test'; 6 | 7 | import { text } from '../../shared/text'; 8 | 9 | export class ConfirmDeletePopup { 10 | private readonly node: Locator; 11 | readonly cancelButton: Locator; 12 | readonly deleteButton: Locator; 13 | readonly deleteGloballyButton: Locator; 14 | readonly deleteLocallyButton: Locator; 15 | 16 | constructor(window: Page) { 17 | this.node = window.getByLabel('confirm delete popup'); 18 | this.cancelButton = this.node.getByRole('button', { 19 | name: text.buttons.cancel, 20 | exact: true, 21 | }); 22 | this.deleteButton = this.node.getByRole('button', { 23 | name: text.deleteAttributionsPopup.delete, 24 | exact: true, 25 | }); 26 | this.deleteGloballyButton = this.node.getByRole('button', { 27 | name: text.deleteAttributionsPopup.deleteGlobally, 28 | exact: true, 29 | }); 30 | this.deleteLocallyButton = this.node.getByRole('button', { 31 | name: text.deleteAttributionsPopup.deleteLocally, 32 | exact: true, 33 | }); 34 | } 35 | 36 | public assert = { 37 | isVisible: async (): Promise => { 38 | await expect(this.node).toBeVisible(); 39 | }, 40 | isHidden: async (): Promise => { 41 | await expect(this.node).toBeHidden(); 42 | }, 43 | hasText: async (text: string): Promise => { 44 | await expect(this.node.getByText(text)).toBeVisible(); 45 | }, 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /src/e2e-tests/page-objects/ConfirmReplacePopup.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { expect, type Locator, type Page } from '@playwright/test'; 6 | 7 | import { text } from '../../shared/text'; 8 | 9 | export class ConfirmReplacePopup { 10 | private readonly node: Locator; 11 | readonly cancelButton: Locator; 12 | readonly replaceButton: Locator; 13 | 14 | constructor(window: Page) { 15 | this.node = window.getByLabel('confirm replace popup'); 16 | this.cancelButton = this.node.getByRole('button', { 17 | name: text.buttons.cancel, 18 | }); 19 | this.replaceButton = this.node.getByRole('button', { 20 | name: text.replaceAttributionsPopup.replace, 21 | }); 22 | } 23 | 24 | public assert = { 25 | isVisible: async (): Promise => { 26 | await expect(this.node).toBeVisible(); 27 | }, 28 | isHidden: async (): Promise => { 29 | await expect(this.node).toBeHidden(); 30 | }, 31 | hasText: async (text: string): Promise => { 32 | await expect(this.node.getByText(text)).toBeVisible(); 33 | }, 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /src/e2e-tests/page-objects/ConfirmationDialog.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { expect, type Locator, type Page } from '@playwright/test'; 6 | 7 | import { text } from '../../shared/text'; 8 | 9 | export class ConfirmationDialog { 10 | private readonly window: Page; 11 | private readonly node: Locator; 12 | readonly cancelButton: Locator; 13 | readonly okButton: Locator; 14 | 15 | constructor(window: Page) { 16 | this.window = window; 17 | this.node = window.getByLabel('confirmation dialog'); 18 | this.cancelButton = this.node.getByRole('button', { 19 | name: text.buttons.cancel, 20 | exact: true, 21 | }); 22 | this.okButton = this.node.getByRole('button', { 23 | name: text.buttons.ok, 24 | exact: true, 25 | }); 26 | } 27 | 28 | public assert = { 29 | isVisible: async (): Promise => { 30 | await expect(this.node).toBeVisible(); 31 | }, 32 | isHidden: async (): Promise => { 33 | await expect(this.node).toBeHidden(); 34 | }, 35 | }; 36 | 37 | async close(): Promise { 38 | await this.window.keyboard.press('Escape'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/e2e-tests/page-objects/ErrorPopup.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { expect, type Locator, type Page } from '@playwright/test'; 6 | 7 | export class ErrorPopup { 8 | private readonly window: Page; 9 | private readonly node: Locator; 10 | 11 | constructor(window: Page) { 12 | this.window = window; 13 | this.node = window.getByLabel('error popup'); 14 | } 15 | 16 | public assert = { 17 | isVisible: async (): Promise => { 18 | await expect(this.node).toBeVisible(); 19 | }, 20 | isHidden: async (): Promise => { 21 | await expect(this.node).toBeHidden(); 22 | }, 23 | errorMessageIsVisible: async (errorMessage: string): Promise => { 24 | await expect(this.node.getByText(errorMessage)).toBeVisible(); 25 | }, 26 | }; 27 | 28 | async close(): Promise { 29 | await this.window.keyboard.press('Escape'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/e2e-tests/page-objects/FileSupportPopup.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { expect, type Locator, type Page } from '@playwright/test'; 6 | 7 | export class FileSupportPopup { 8 | private readonly node: Locator; 9 | readonly title: Locator; 10 | readonly keepButton: Locator; 11 | readonly convertButton: Locator; 12 | 13 | constructor(window: Page) { 14 | this.node = window.getByLabel('file support'); 15 | this.title = this.node.getByText('outdated input file format'); 16 | this.keepButton = this.node.getByRole('button', { name: 'keep' }); 17 | this.convertButton = this.node.getByRole('button', { 18 | name: 'create and proceed', 19 | }); 20 | } 21 | 22 | public assert = { 23 | titleIsVisible: async (): Promise => { 24 | await expect(this.title).toBeVisible(); 25 | }, 26 | titleIsHidden: async (): Promise => { 27 | await expect(this.title).toBeHidden(); 28 | }, 29 | }; 30 | } 31 | -------------------------------------------------------------------------------- /src/e2e-tests/page-objects/LinkedResourcesTree.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { expect, type Locator, type Page } from '@playwright/test'; 6 | 7 | export class LinkedResourcesTree { 8 | private readonly node: Locator; 9 | private readonly header: Locator; 10 | readonly searchField: Locator; 11 | readonly clearSearchButton: Locator; 12 | 13 | constructor(window: Page) { 14 | this.node = window.getByTestId('linked-resources-tree'); 15 | this.header = window.getByTestId('linked-resources-tree-header'); 16 | this.searchField = this.header.getByRole('searchbox'); 17 | this.clearSearchButton = this.header.getByLabel('clear search'); 18 | } 19 | 20 | public assert = { 21 | isVisible: async (): Promise => { 22 | await expect(this.node).toBeVisible(); 23 | }, 24 | isHidden: async (): Promise => { 25 | await expect(this.node).toBeHidden(); 26 | }, 27 | resourceIsVisible: async (resourceName: string): Promise => { 28 | await expect( 29 | this.node.getByText(resourceName, { exact: true }), 30 | ).toBeVisible(); 31 | }, 32 | resourceIsHidden: async (resourceName: string): Promise => { 33 | await expect( 34 | this.node.getByText(resourceName, { exact: true }), 35 | ).toBeHidden(); 36 | }, 37 | }; 38 | 39 | async gotoRoot(): Promise { 40 | await this.node.getByText('/', { exact: true }).click(); 41 | } 42 | 43 | async goto(...resourceNames: Array): Promise { 44 | for (const resourceName of resourceNames) { 45 | await this.node.getByText(resourceName, { exact: true }).click(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/e2e-tests/page-objects/MergeDialog.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { expect, Locator, Page } from '@playwright/test'; 6 | import path from 'path'; 7 | 8 | export class MergeDialog { 9 | private readonly node: Locator; 10 | readonly title: Locator; 11 | readonly inputFileSelection: Locator; 12 | readonly mergeButton: Locator; 13 | readonly cancelButton: Locator; 14 | readonly errorIcon: Locator; 15 | 16 | readonly scancodeFilePath: string; 17 | readonly owaspFilePath: string; 18 | 19 | constructor(window: Page) { 20 | this.node = window.getByLabel('merge dialog'); 21 | this.title = this.node.getByRole('heading').getByText('Merge'); 22 | this.inputFileSelection = this.node 23 | .getByLabel('Select file to merge') 24 | .locator('..'); 25 | this.mergeButton = this.node.getByRole('button', { name: 'Merge' }); 26 | this.cancelButton = this.node.getByRole('button', { name: 'Cancel' }); 27 | this.errorIcon = this.node.getByTestId('ErrorIcon').locator('path'); 28 | 29 | this.scancodeFilePath = path.resolve(__dirname, '..', 'scancode.json'); 30 | this.owaspFilePath = path.resolve( 31 | __dirname, 32 | '..', 33 | 'owasp-dependency-check-report.json', 34 | ); 35 | } 36 | 37 | public assert = { 38 | titleIsVisible: async (): Promise => { 39 | await expect(this.title).toBeVisible(); 40 | }, 41 | titleIsHidden: async (): Promise => { 42 | await expect(this.title).toBeHidden({ timeout: 30000 }); 43 | }, 44 | showsError: async (): Promise => { 45 | await expect(this.errorIcon).toBeVisible(); 46 | }, 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /src/e2e-tests/page-objects/NotSavedPopup.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { expect, type Locator, type Page } from '@playwright/test'; 6 | 7 | import { text } from '../../shared/text'; 8 | 9 | export class NotSavedPopup { 10 | private readonly node: Locator; 11 | readonly cancelButton: Locator; 12 | readonly discardButton: Locator; 13 | 14 | constructor(window: Page) { 15 | this.node = window.getByLabel('unsaved changes popup'); 16 | this.cancelButton = this.node.getByRole('button', { 17 | name: text.buttons.cancel, 18 | exact: true, 19 | }); 20 | this.discardButton = this.node.getByRole('button', { 21 | name: text.unsavedChangesPopup.discard, 22 | exact: true, 23 | }); 24 | } 25 | 26 | public assert = { 27 | isVisible: async (): Promise => { 28 | await expect(this.node).toBeVisible(); 29 | }, 30 | isHidden: async (): Promise => { 31 | await expect(this.node).toBeHidden(); 32 | }, 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /src/e2e-tests/page-objects/ProjectMetadataPopup.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { expect, type Locator, type Page } from '@playwright/test'; 6 | 7 | export class ProjectMetadataPopup { 8 | private readonly node: Locator; 9 | readonly title: Locator; 10 | readonly closeButton: Locator; 11 | 12 | constructor(window: Page) { 13 | this.node = window.getByLabel('project metadata'); 14 | this.title = this.node.getByText('Project Metadata'); 15 | this.closeButton = this.node.getByRole('button', { name: 'Close' }); 16 | } 17 | 18 | public assert = { 19 | titleIsVisible: async (): Promise => { 20 | await expect(this.title).toBeVisible(); 21 | }, 22 | titleIsHidden: async (): Promise => { 23 | await expect(this.title).toBeHidden(); 24 | }, 25 | attributeIsVisible: async (attribute: string): Promise => { 26 | await expect( 27 | this.node.getByText(attribute, { exact: true }), 28 | ).toBeVisible(); 29 | }, 30 | attributeIsHidden: async (attribute: string): Promise => { 31 | await expect( 32 | this.node.getByText(attribute, { exact: true }), 33 | ).toBeHidden(); 34 | }, 35 | }; 36 | } 37 | -------------------------------------------------------------------------------- /src/e2e-tests/page-objects/ResourcesTree.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { expect, type Locator, type Page } from '@playwright/test'; 6 | 7 | export class ResourcesTree { 8 | private readonly node: Locator; 9 | private readonly header: Locator; 10 | readonly searchField: Locator; 11 | readonly clearSearchButton: Locator; 12 | 13 | constructor(window: Page) { 14 | this.node = window.getByTestId('resources-tree'); 15 | this.header = window.getByTestId('resources-tree-header'); 16 | this.searchField = this.header.getByRole('searchbox'); 17 | this.clearSearchButton = this.header.getByLabel('clear search'); 18 | } 19 | 20 | public assert = { 21 | isVisible: async (): Promise => { 22 | await expect(this.node).toBeVisible(); 23 | }, 24 | isHidden: async (): Promise => { 25 | await expect(this.node).toBeHidden(); 26 | }, 27 | resourceIsVisible: async (resourceName: string): Promise => { 28 | await expect( 29 | this.node.getByText(resourceName, { exact: true }), 30 | ).toBeVisible(); 31 | }, 32 | resourceIsHidden: async (resourceName: string): Promise => { 33 | await expect( 34 | this.node.getByText(resourceName, { exact: true }), 35 | ).toBeHidden(); 36 | }, 37 | }; 38 | 39 | async gotoRoot(): Promise { 40 | await this.node.getByText('/', { exact: true }).click(); 41 | } 42 | 43 | async goto(...resourceNames: Array): Promise { 44 | for (const resourceName of resourceNames) { 45 | await this.node.getByText(resourceName, { exact: true }).click(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/e2e-tests/playwright.config.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { PlaywrightTestConfig } from '@playwright/test'; 6 | import dotenv from 'dotenv'; 7 | import path from 'path'; 8 | 9 | dotenv.config({ path: path.resolve(process.cwd(), '.env') }); 10 | 11 | const CI_SINGLE_TEST_TIMEOUT = 60000; 12 | const GLOBAL_TIMEOUT = 3000000; 13 | 14 | const devWebServer: PlaywrightTestConfig['webServer'] = { 15 | command: 'yarn test:prepare', 16 | url: 'http://localhost:5173/index.html', 17 | reuseExistingServer: true, 18 | stderr: 'pipe', 19 | stdout: 'pipe', 20 | gracefulShutdown: { 21 | timeout: 500, 22 | signal: 'SIGTERM', 23 | }, 24 | }; 25 | 26 | const config: PlaywrightTestConfig = { 27 | outputDir: 'artifacts', 28 | preserveOutput: process.env.CI ? 'failures-only' : 'always', 29 | quiet: !!process.env.CI, 30 | reportSlowTests: null, 31 | retries: process.env.CI ? 2 : 0, 32 | reporter: process.env.CI ? 'github' : 'list', 33 | timeout: process.env.CI ? CI_SINGLE_TEST_TIMEOUT : undefined, 34 | workers: process.env.CI ? 1 : (process.env.WORKERS ?? 1), 35 | globalTimeout: process.env.CI ? GLOBAL_TIMEOUT : undefined, 36 | webServer: process.env.CI || process.env.RELEASE ? undefined : devWebServer, 37 | }; 38 | 39 | export default config; 40 | -------------------------------------------------------------------------------- /src/e2e-tests/utils/index.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | export * from '../../testing/Faker'; 6 | export * from './fixtures'; 7 | export * from './retry'; 8 | -------------------------------------------------------------------------------- /src/e2e-tests/utils/retry.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | const RETRY_COUNT = 3; 7 | 8 | export async function retry( 9 | fn: () => Promise, 10 | { 11 | times = RETRY_COUNT, 12 | onError, 13 | }: Partial<{ 14 | times?: number; 15 | onError?: () => Promise; 16 | }> = {}, 17 | ): Promise { 18 | let error; 19 | 20 | for (let i = 0; i < times; i++) { 21 | try { 22 | await fn(); 23 | return; 24 | } catch (e) { 25 | error = e; 26 | await onError?.(); 27 | } 28 | } 29 | 30 | throw error; 31 | } 32 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { createRoot } from 'react-dom/client'; 6 | 7 | import { AppContainer } from './Frontend/Components/AppContainer/AppContainer'; 8 | 9 | const container = document.getElementById('root'); 10 | const root = createRoot(container as Element); 11 | root.render(); 12 | -------------------------------------------------------------------------------- /src/shared/shared-constants.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { UserSettings } from './shared-types'; 6 | 7 | export const DEFAULT_PANEL_SIZES: NonNullable = { 8 | resourceBrowserWidth: 340, 9 | packageListsWidth: 340, 10 | linkedResourcesPanelHeight: null, 11 | signalsPanelHeight: null, 12 | }; 13 | 14 | export const DEFAULT_USER_SETTINGS: UserSettings = { 15 | qaMode: false, 16 | showProjectStatistics: false, 17 | areHiddenSignalsVisible: false, 18 | showCriticality: true, 19 | showClassifications: true, 20 | panelSizes: DEFAULT_PANEL_SIZES, 21 | recentlyOpenedPaths: [], 22 | }; 23 | -------------------------------------------------------------------------------- /src/testing/global-test-setup.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import fs from 'fs'; 6 | 7 | export default async function globalSetup(): Promise { 8 | await fs.promises.mkdir('test-output', { recursive: true }); 9 | } 10 | -------------------------------------------------------------------------------- /src/testing/global-test-teardown.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import fs from 'fs'; 6 | 7 | export default async function globalTeardown(): Promise { 8 | await fs.promises.rm('test-output', { recursive: true, force: true }); 9 | } 10 | -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | 6 | /// 7 | -------------------------------------------------------------------------------- /tools/build_linux_release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 4 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 5 | # 6 | # SPDX-License-Identifier: Apache-2.0 7 | 8 | set -e 9 | 10 | electron-builder --linux --x64 --publish never 11 | mkdir -p release/linux 12 | mv 'release/opossum-ui_0.1.0_amd64.snap' 'release/linux/OpossumUI-for-linux.snap' 13 | mv 'release/OpossumUI-0.1.0.AppImage' 'release/linux/OpossumUI-for-linux.AppImage' 14 | -------------------------------------------------------------------------------- /tools/checkNotices.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 4 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 5 | # 6 | # SPDX-License-Identifier: Apache-2.0 7 | 8 | NOTICE_HEADER="THE FOLLOWING SETS FORTH ATTRIBUTION NOTICES FOR THIRD PARTY SOFTWARE THAT MAY BE CONTAINED IN PORTIONS OF THE OPOSSUM UI PRODUCT." 9 | 10 | grep -q "${NOTICE_HEADER}" ./notices/notices.txt || { 11 | echo "Error: Attributions not found in notices.txt" 12 | exit 1 13 | } 14 | grep -q "${NOTICE_HEADER}" ./notices/notices.html || { 15 | echo "Error: Attributions not found in notices.html" 16 | exit 1 17 | } 18 | -------------------------------------------------------------------------------- /tools/checkout_PR_and_start_opossum_ui.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 4 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 5 | # 6 | # SPDX-License-Identifier: Apache-2.0 7 | 8 | set -euo pipefail 9 | 10 | pr_number="" 11 | commit_hash="" 12 | remote_name="origin" 13 | file_path="" 14 | checkout_only=false: 15 | 16 | usage() { 17 | echo "Usage: $0 [OPTIONS]" 18 | echo "Options:" 19 | echo " -p, Set the number of the PR to use" 20 | echo " -c, Set the commit hash to use" 21 | echo " -n, Set the name of the remote, default: origin" 22 | echo " -f, Set absolute path to file which should be opened" 23 | echo " -o, Checkout only, don't open the app" 24 | echo "Note: either use -c or -p" 25 | echo "Note: The script assumes to be run in the root directory of a local clone of the original repo" 26 | } 27 | 28 | while getopts p:c:n:f:o flag; do 29 | case "${flag}" in 30 | p) pr_number=${OPTARG} ;; 31 | c) commit_hash=${OPTARG} ;; 32 | n) remote_name=${OPTARG} ;; 33 | f) file_path=${OPTARG} ;; 34 | o) checkout_only=true ;; 35 | *) usage ;; 36 | esac 37 | done 38 | if [[ -z "$pr_number" && -z "$commit_hash" || ! (-z "$pr_number") && ! (-z "$commit_hash") ]]; then 39 | usage 40 | exit 1 41 | fi 42 | 43 | # Checkout main and fetch latest changes 44 | git checkout main 45 | git fetch "$remote_name" 46 | 47 | if [[ ! (-z "$pr_number") ]]; then 48 | echo "Checking out PR $pr_number" 49 | git fetch "$remote_name" "pull/$pr_number/head:pull_$pr_number" 50 | git checkout "pull_$pr_number" 51 | else 52 | git pull 53 | git checkout "$commit_hash" 54 | fi 55 | 56 | if [[ "$checkout_only" = true ]]; then 57 | exit 0 58 | fi 59 | 60 | yarn install 61 | yarn start "$file_path" 62 | -------------------------------------------------------------------------------- /tools/generateNotices.mjs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { copyFileSync, readFileSync, writeFileSync } from 'fs'; 6 | import nunjucks from 'nunjucks'; 7 | import { dirname, join } from 'path'; 8 | import { fileURLToPath } from 'url'; 9 | 10 | const __dirname = dirname(fileURLToPath(import.meta.url)); 11 | 12 | function generateNotices() { 13 | const noticeDocumentFolder = join(__dirname, '..', 'notices'); 14 | const noticeContent = readFileSync(join(noticeDocumentFolder, 'notices.txt')); 15 | 16 | copyFileSync( 17 | join( 18 | __dirname, 19 | '..', 20 | 'node_modules', 21 | 'electron', 22 | 'dist', 23 | 'LICENSES.chromium.html', 24 | ), 25 | join(noticeDocumentFolder, 'LICENSES.chromium.html'), 26 | ); 27 | writeFileSync( 28 | join(noticeDocumentFolder, 'notices.html'), 29 | nunjucks.render(join(__dirname, 'notices.template.html'), { 30 | noticeContent, 31 | }), 32 | ); 33 | } 34 | 35 | generateNotices(); 36 | -------------------------------------------------------------------------------- /tools/get_app_version_for_windows.bat: -------------------------------------------------------------------------------- 1 | @REM SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | @REM SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | @REM 4 | @REM SPDX-License-Identifier: Apache-2.0 5 | 6 | FOR /F "tokens=*" %%g IN ('call git describe --exact-match --tags --abbrev^=0') do (SET OPTION1=%%g) 7 | FOR /F "tokens=*" %%g IN ('call git rev-parse --short HEAD') do (SET OPTION2=%%g) 8 | if [%OPTION1%]==[] (echo {"commitInfo" : "%OPTION2%" } > "src\commitInfo.json") else (echo {"commitInfo" : "%OPTION1%" } > "src\commitInfo.json") 9 | 10 | -------------------------------------------------------------------------------- /tools/notices.template.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | Notices 13 | 14 | 15 |

{{ noticeContent }}
16 | 17 | 18 | -------------------------------------------------------------------------------- /tools/runScriptArch.mjs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import { execSync } from 'child_process'; 6 | import * as os from 'os'; 7 | 8 | const command = process.argv[2]; 9 | const arch = os.arch(); 10 | 11 | execSync(`yarn ${command}:${arch}`, { shell: true, stdio: 'inherit' }); 12 | -------------------------------------------------------------------------------- /tools/start_linux_darwin.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 4 | # SPDX-FileCopyrightText: TNG Technology Consulting GmbH 5 | # 6 | # SPDX-License-Identifier: Apache-2.0 7 | 8 | # This script is used to start the app with vite. To be able to directly open an .opossum file when starting the app 9 | # we need to set the environment variable OPOSSUM_FILE. Arguments appended to yarn commands are only appended at 10 | # the end, thus we need this script to set the environment variable properly. 11 | 12 | FILE_PATH=$1 13 | 14 | if [ -n "$FILE_PATH" ]; then 15 | echo "File path provided: $FILE_PATH" 16 | fi 17 | 18 | yarn generate-notice && yarn tsc -p src/ElectronBackend && cross-env OPOSSUM_FILE=$FILE_PATH yarn vite 19 | -------------------------------------------------------------------------------- /tools/start_windows.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 3 | REM SPDX-FileCopyrightText: TNG Technology Consulting GmbH 4 | REM 5 | REM SPDX-License-Identifier: Apache-2.0 6 | 7 | REM This script is used to start the app with vite. To be able to directly open an .opossum file when starting the app 8 | REM we need to set the environment variable OPOSSUM_FILE. Arguments appended to yarn commands are only appended at 9 | REM the end, thus we need this script to set the environment variable properly. 10 | 11 | SET FILE_PATH=%1 12 | 13 | if defined FILE_PATH ( 14 | echo File path provided: %FILE_PATH% 15 | ) 16 | 17 | yarn generate-notice && yarn tsc -p src/ElectronBackend && cross-env OPOSSUM_FILE=%FILE_PATH% yarn vite 18 | -------------------------------------------------------------------------------- /tsconfig.eslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "types": ["@types/node"], 4 | "noEmit": true, 5 | "allowJs": true 6 | }, 7 | "extends": "./tsconfig.json", 8 | "include": ["tools/**/*"] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "allowSyntheticDefaultImports": true, 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "isolatedModules": true, 8 | "jsx": "react-jsx", 9 | "lib": ["dom", "dom.iterable", "esnext"], 10 | "module": "ESNext", 11 | "moduleResolution": "node", 12 | "noEmit": true, 13 | "noFallthroughCasesInSwitch": true, 14 | "noImplicitOverride": true, 15 | "noImplicitReturns": true, 16 | "noUnusedLocals": true, 17 | "noUnusedParameters": true, 18 | "outDir": "./build/lib", 19 | "resolveJsonModule": true, 20 | "skipLibCheck": true, 21 | "sourceMap": true, 22 | "strict": true, 23 | "target": "ESNext", 24 | "types": [ 25 | "vite/client", 26 | "vite-plugin-svgr/client", 27 | "jest", 28 | "@testing-library/jest-dom" 29 | ] 30 | }, 31 | "include": ["src/**/*"], 32 | "exclude": ["src/ElectronBackend/**/*"] 33 | } 34 | -------------------------------------------------------------------------------- /vite.config.mts: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates 2 | // SPDX-FileCopyrightText: TNG Technology Consulting GmbH 3 | // 4 | // SPDX-License-Identifier: Apache-2.0 5 | import react from '@vitejs/plugin-react'; 6 | import { defineConfig, loadEnv } from 'vite'; 7 | import electron from 'vite-plugin-electron'; 8 | import svgrPlugin from 'vite-plugin-svgr'; 9 | import viteTsconfigPaths from 'vite-tsconfig-paths'; 10 | 11 | export default defineConfig(({ mode }) => ({ 12 | plugins: [ 13 | react(), 14 | viteTsconfigPaths(), 15 | svgrPlugin(), 16 | ...(mode === 'e2e' 17 | ? [] 18 | : electron({ 19 | entry: 'src/ElectronBackend/main/main.ts', 20 | })), 21 | ], 22 | define: { 23 | 'process.env.CI': loadEnv(mode, process.cwd()).CI, 24 | }, 25 | build: { 26 | outDir: 'build', 27 | }, 28 | resolve: { 29 | conditions: ['mui-modern', 'module', 'browser', 'development|production'], 30 | }, 31 | })); 32 | --------------------------------------------------------------------------------