Repository: opossum-tool/OpossumUI (ts)

Issue:
Loading attribution list in attribution view for the first time is very slow
**Describe the bug**
Loading attribution list in attribution view for the first time is very slow in the case that there are several thousand attributions of which are many pre-selected.

**To Reproduce**
Steps to reproduce the behavior:

1. Open a opossum input file that contains thousands of attributions
2. Navigate to the attribution view
3. Observe that the filter's loading spinner spins for a long time, while most attributions are only loaded after approx 25 seconds 

**Expected behavior**
Loading the list of attributions should be reasonably fast.


Pull request description:
fix: avoid unnecessary initial filter loading state
### Summary of changes

- use all manual attributions as filtered attributions when no filter is set
- separate concerns of signals worker hook from those of the hooks accessing variables from the Redux store

### Context and reason for change

closes #2502

### How can the changes be tested

Open a large Opossum file and notice that the attribution list immediately displays attributions without any filter loading spinner spinning.

Patch:
diff --git a/src/Frontend/Components/AggregatedAttributionsPanel/AggregatedAttributionsPanel.tsx b/src/Frontend/Components/AggregatedAttributionsPanel/AggregatedAttributionsPanel.tsx
index 33ba01c2..5be15f4b 100644
--- a/src/Frontend/Components/AggregatedAttributionsPanel/AggregatedAttributionsPanel.tsx
+++ b/src/Frontend/Components/AggregatedAttributionsPanel/AggregatedAttributionsPanel.tsx
@@ -11,10 +11,10 @@ import {
   getExternalData,
 } from '../../state/selectors/all-views-resource-selectors';
 import { getSelectedResourceId } from '../../state/selectors/audit-view-resource-selectors';
+import { usePanelData } from '../../state/variables/use-panel-data';
 import { AttributionIdWithCount } from '../../types/types';
 import { isIdOfResourceWithChildren } from '../../util/can-resource-have-children';
 import { getExternalAttributionIdsWithCount } from '../../util/get-contained-packages';
-import { usePanelData } from '../../web-workers/use-signals-worker';
 import { AccordionPanel } from './AccordionPanel';
 import { SyncAccordionPanel } from './SyncAccordionPanel';
 
@@ -30,7 +30,7 @@ export const AggregatedAttributionsPanel = memo(
     );
     const selectedResourceId = useAppSelector(getSelectedResourceId);
 
-    const { signalsInFolderContent, attributionsInFolderContent } =
+    const [{ signalsInFolderContent, attributionsInFolderContent }] =
       usePanelData();
 
     return (
diff --git a/src/Frontend/Components/AggregatedAttributionsPanel/SyncAccordionPanel.tsx b/src/Frontend/Components/AggregatedAttributionsPanel/SyncAccordionPanel.tsx
index 1c7560c7..4dfa3086 100644
--- a/src/Frontend/Components/AggregatedAttributionsPanel/SyncAccordionPanel.tsx
+++ b/src/Frontend/Components/AggregatedAttributionsPanel/SyncAccordionPanel.tsx
@@ -7,8 +7,8 @@ import {
 } from '../../../shared/shared-types';
 import { text } from '../../../shared/text';
 import { PackagePanelTitle } from '../../enums/enums';
+import { useActiveSortingInAuditView } from '../../state/variables/use-active-sorting';
 import { AttributionIdWithCount } from '../../types/types';
-import { useActiveSortingInAuditView } from '../../util/use-active-sorting';
 import { AccordionPanel } from './AccordionPanel';
 import { getExternalDisplayPackageInfosWithCount } from './AccordionPanel.util';
 
diff --git a/src/Frontend/Components/AllAttributionsPanel/AllAttributionsPanel.tsx b/src/Frontend/Components/AllAttributionsPanel/AllAttributionsPanel.tsx
index bb147400..e0188b8f 100644
--- a/src/Frontend/Components/AllAttributionsPanel/AllAttributionsPanel.tsx
+++ b/src/Frontend/Components/AllAttributionsPanel/AllAttributionsPanel.tsx
@@ -11,10 +11,10 @@ import { OpossumColors } from '../../shared-styles';
 import { selectPackageCardInAuditViewOrOpenUnsavedPopup } from '../../state/actions/popup-actions/popup-actions';
 import { addToSelectedResource } from '../../state/actions/resource-actions/save-actions';
 import { useAppDispatch } from '../../state/hooks';
+import { useActiveSortingInAuditView } from '../../state/variables/use-active-sorting';
 import { DisplayPackageInfos, PackageCardConfig } from '../../types/types';
 import { convertDisplayPackageInfoToPackageInfo } from '../../util/convert-package-info';
 import { getAlphabeticalComparerForAttributions } from '../../util/get-alphabetical-comparer';
-import { useActiveSortingInAuditView } from '../../util/use-active-sorting';
 import { PackageCard } from '../PackageCard/PackageCard';
 import { PackageList } from '../PackageList/PackageList';
 
diff --git a/src/Frontend/Components/AttributionColumn/PackageAutocomplete.tsx b/src/Frontend/Components/AttributionColumn/PackageAutocomplete.tsx
index 93e0fd05..d6256cd7 100644
--- a/src/Frontend/Components/AttributionColumn/PackageAutocomplete.tsx
+++ b/src/Frontend/Components/AttributionColumn/PackageAutocomplete.tsx
@@ -26,13 +26,13 @@ import {
   getTemporaryDisplayPackageInfo,
 } from '../../state/selectors/all-views-resource-selectors';
 import { isAuditViewSelected } from '../../state/selectors/view-selector';
+import { useAutocompleteSignals } from '../../state/variables/use-autocomplete-signals';
 import { generatePurl } from '../../util/handle-purl';
 import { isImportantAttributionInformationMissing } from '../../util/is-important-attribution-information-missing';
 import { omit, pick } from '../../util/lodash-extension-utils';
 import { maybePluralize } from '../../util/maybe-pluralize';
 import { openUrl } from '../../util/open-url';
 import { PackageSearchHooks } from '../../util/package-search-hooks';
-import { useAutocompleteSignals } from '../../web-workers/use-signals-worker';
 import { Autocomplete } from '../Autocomplete/Autocomplete';
 import { Confirm } from '../ConfirmationDialog/ConfirmationDialog';
 import { IconButton } from '../IconButton/IconButton';
@@ -91,7 +91,7 @@ export function PackageAutocomplete({
 
   const { enrichPackageInfo } = PackageSearchHooks.useEnrichPackageInfo();
 
-  const autocompleteSignals = useAutocompleteSignals();
+  const [autocompleteSignals] = useAutocompleteSignals();
   const filteredSignals = useMemo(
     () =>
       isAuditView
diff --git a/src/Frontend/Components/AttributionList/AttributionList.tsx b/src/Frontend/Components/AttributionList/AttributionList.tsx
index 725719dd..d88f5ce9 100644
--- a/src/Frontend/Components/AttributionList/AttributionList.tsx
+++ b/src/Frontend/Components/AttributionList/AttributionList.tsx
@@ -28,9 +28,9 @@ import {
 import {
   SORT_ICONS,
   useActiveSortingInAttributionView,
-} from '../../util/use-active-sorting';
+} from '../../state/variables/use-active-sorting';
+import { useFilteredAttributions } from '../../state/variables/use-filtered-attributions';
 import { usePrevious } from '../../util/use-previous';
-import { useFilteredAttributions } from '../../web-workers/use-signals-worker';
 import { Checkbox } from '../Checkbox/Checkbox';
 import { List } from '../List/List';
 import { PACKAGE_CARD_HEIGHT, PackageCard } from '../PackageCard/PackageCard';
diff --git a/src/Frontend/Components/AttributionList/AttributionList.util.tsx b/src/Frontend/Components/AttributionList/AttributionList.util.tsx
index c753d212..14d4808f 100644
--- a/src/Frontend/Components/AttributionList/AttributionList.util.tsx
+++ b/src/Frontend/Components/AttributionList/AttributionList.util.tsx
@@ -10,6 +10,7 @@ import { useEffect, useMemo } from 'react';
 
 import { Attributions } from '../../../shared/shared-types';
 import { baseIcon, OpossumColors } from '../../shared-styles';
+import { useFilteredAttributions } from '../../state/variables/use-filtered-attributions';
 import { DisplayPackageInfos } from '../../types/types';
 import { convertPackageInfoToDisplayPackageInfo } from '../../util/convert-package-info';
 import { getAlphabeticalComparerForAttributions } from '../../util/get-alphabetical-comparer';
@@ -20,7 +21,6 @@ import {
   filters,
   qaFilters,
 } from '../../web-workers/scripts/get-filtered-attributions';
-import { useFilteredAttributions } from '../../web-workers/use-signals-worker';
 import {
   ExcludeFromNoticeIcon,
   FirstPartyIcon,
diff --git a/src/Frontend/Components/ProgressBar/FolderProgressBar.tsx b/src/Frontend/Components/ProgressBar/FolderProgressBar.tsx
index 6bff2ab8..b71e6d34 100644
--- a/src/Frontend/Components/ProgressBar/FolderProgressBar.tsx
+++ b/src/Frontend/Components/ProgressBar/FolderProgressBar.tsx
@@ -5,7 +5,7 @@
 import MuiSkeleton from '@mui/material/Skeleton';
 import { ReactElement } from 'react';
 
-import { useFolderProgressData } from '../../web-workers/use-signals-worker';
+import { useFolderProgressData } from '../../state/variables/use-folder-progress-data';
 import { ProgressBar } from './ProgressBar';
 
 const classes = {
@@ -15,7 +15,7 @@ const classes = {
 };
 
 export function FolderProgressBar(): ReactElement {
-  const progressData = useFolderProgressData();
+  const [progressData] = useFolderProgressData();
 
   return progressData ? (
     <ProgressBar
diff --git a/src/Frontend/Components/ProgressBar/TopProgressBar.tsx b/src/Frontend/Components/ProgressBar/TopProgressBar.tsx
index 97b212ec..b23c1dc8 100644
--- a/src/Frontend/Components/ProgressBar/TopProgressBar.tsx
+++ b/src/Frontend/Components/ProgressBar/TopProgressBar.tsx
@@ -5,7 +5,7 @@
 import MuiBox from '@mui/material/Box';
 import { ReactElement, useState } from 'react';
 
-import { useOverallProgressData } from '../../web-workers/use-signals-worker';
+import { useOverallProgressData } from '../../state/variables/use-overall-progress-data';
 import { SwitchWithTooltip } from '../SwitchWithTooltip/SwitchWithTooltip';
 import { ProgressBar } from './ProgressBar';
 
@@ -32,7 +32,7 @@ export function TopProgressBar(): ReactElement {
     ? 'Critical signals progress bar selected'
     : 'Progress bar selected';
 
-  const progressData = useOverallProgressData();
+  const [progressData] = useOverallProgressData();
 
   return progressData ? (
     <MuiBox sx={classes.root}>
diff --git a/src/Frontend/Components/ReportView/ReportView.tsx b/src/Frontend/Components/ReportView/ReportView.tsx
index 17ed5b38..be7f616b 100644
--- a/src/Frontend/Components/ReportView/ReportView.tsx
+++ b/src/Frontend/Components/ReportView/ReportView.tsx
@@ -4,7 +4,7 @@
 // SPDX-License-Identifier: Apache-2.0
 import MuiBox from '@mui/material/Box';
 import { pickBy } from 'lodash';
-import { useMemo } from 'react';
+import { useMemo, useState } from 'react';
 
 import { View } from '../../enums/enums';
 import { OpossumColors } from '../../shared-styles';
@@ -19,7 +19,6 @@ import {
 } from '../../state/selectors/all-views-resource-selectors';
 import { getAttributionsWithResources } from '../../util/get-attributions-with-resources';
 import { getFileWithChildrenCheck } from '../../util/is-file-with-children';
-import { useVariable } from '../../util/use-variable';
 import {
   Filter,
   FILTER_FUNCTIONS,
@@ -46,10 +45,7 @@ export function ReportView() {
   const externalAttributions = useAppSelector(getExternalAttributions);
   const filesWithChildren = useAppSelector(getFilesWithChildren);
 
-  const [selectedFilters, setActiveFilters] = useVariable<Array<Filter>>(
-    'active-filters',
-    [],
-  );
+  const [selectedFilters, setActiveFilters] = useState<Array<Filter>>([]);
   const isFileWithChildren = getFileWithChildrenCheck(filesWithChildren);
   const dispatch = useAppDispatch();
 
diff --git a/src/Frontend/Components/ResourceDetailsTabs/ResourceDetailsTabs.tsx b/src/Frontend/Components/ResourceDetailsTabs/ResourceDetailsTabs.tsx
index e42c4b55..c0161cb0 100644
--- a/src/Frontend/Components/ResourceDetailsTabs/ResourceDetailsTabs.tsx
+++ b/src/Frontend/Components/ResourceDetailsTabs/ResourceDetailsTabs.tsx
@@ -27,13 +27,13 @@ import {
   getPackageSearchTerm,
   getSelectedResourceId,
 } from '../../state/selectors/audit-view-resource-selectors';
-import { DisplayPackageInfos } from '../../types/types';
-import { createPackageCardId } from '../../util/create-package-card-id';
-import { getDisplayPackageInfoWithCountFromAttributions } from '../../util/get-display-attributions-with-count-from-attributions';
 import {
   AuditViewSorting,
   useActiveSortingInAuditView,
-} from '../../util/use-active-sorting';
+} from '../../state/variables/use-active-sorting';
+import { DisplayPackageInfos } from '../../types/types';
+import { createPackageCardId } from '../../util/create-package-card-id';
+import { getDisplayPackageInfoWithCountFromAttributions } from '../../util/get-display-attributions-with-count-from-attributions';
 import { AggregatedAttributionsPanel } from '../AggregatedAttributionsPanel/AggregatedAttributionsPanel';
 import { AllAttributionsPanel } from '../AllAttributionsPanel/AllAttributionsPanel';
 import { IconButton } from '../IconButton/IconButton';
diff --git a/src/Frontend/util/use-active-sorting.tsx b/src/Frontend/state/variables/use-active-sorting.tsx
similarity index 91%
rename from src/Frontend/util/use-active-sorting.tsx
rename to src/Frontend/state/variables/use-active-sorting.tsx
index 988dfe61..65c8ac9a 100644
--- a/src/Frontend/util/use-active-sorting.tsx
+++ b/src/Frontend/state/variables/use-active-sorting.tsx
@@ -7,10 +7,10 @@ import FormatListNumberedIcon from '@mui/icons-material/FormatListNumbered';
 import SortByAlphaIcon from '@mui/icons-material/SortByAlpha';
 import { useMemo } from 'react';
 
-import { text } from '../../shared/text';
-import { MenuItem } from '../Components/InputElements/Dropdown';
-import { SelectMenuOption } from '../Components/SelectMenu/SelectMenu';
-import { baseIcon } from '../shared-styles';
+import { text } from '../../../shared/text';
+import { MenuItem } from '../../Components/InputElements/Dropdown';
+import { SelectMenuOption } from '../../Components/SelectMenu/SelectMenu';
+import { baseIcon } from '../../shared-styles';
 import { useVariable } from './use-variable';
 
 export const auditViewSorting = Object.values(text.auditViewSorting);
diff --git a/src/Frontend/state/variables/use-autocomplete-signals.ts b/src/Frontend/state/variables/use-autocomplete-signals.ts
new file mode 100644
index 00000000..ef661999
--- /dev/null
+++ b/src/Frontend/state/variables/use-autocomplete-signals.ts
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
+// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
+//
+// SPDX-License-Identifier: Apache-2.0
+import { AutocompleteSignal } from '../../../shared/shared-types';
+import { useVariable } from './use-variable';
+
+export const AUTOCOMPLETE_SIGNALS = 'autocomplete-signals';
+
+export function useAutocompleteSignals() {
+  return useVariable<Array<AutocompleteSignal>>(AUTOCOMPLETE_SIGNALS, []);
+}
diff --git a/src/Frontend/state/variables/use-filtered-attributions.ts b/src/Frontend/state/variables/use-filtered-attributions.ts
new file mode 100644
index 00000000..55e4a9c2
--- /dev/null
+++ b/src/Frontend/state/variables/use-filtered-attributions.ts
@@ -0,0 +1,56 @@
+// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
+// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
+//
+// SPDX-License-Identifier: Apache-2.0
+import { useEffect } from 'react';
+
+import { Attributions } from '../../../shared/shared-types';
+import {
+  Filter,
+  FilterCounts,
+} from '../../web-workers/scripts/get-filtered-attributions';
+import { useAppSelector } from '../hooks';
+import { getManualAttributions } from '../selectors/all-views-resource-selectors';
+import { useVariable } from './use-variable';
+
+export const FILTERED_ATTRIBUTIONS = 'filtered-attributions';
+
+export interface FilteredAttributions {
+  selectedFilters: Array<Filter>;
+  attributions: Attributions;
+  counts: FilterCounts | null;
+  loading: boolean;
+  search: string;
+}
+
+export const initialFilteredAttributions: FilteredAttributions = {
+  selectedFilters: [],
+  attributions: {},
+  counts: null,
+  loading: false,
+  search: '',
+};
+
+export function useFilteredAttributions() {
+  const attributions = useAppSelector(getManualAttributions);
+  const [filteredAttributions, setFilteredAttributions] =
+    useVariable<FilteredAttributions>(
+      FILTERED_ATTRIBUTIONS,
+      initialFilteredAttributions,
+    );
+
+  useEffect(() => {
+    if (!filteredAttributions.selectedFilters.length) {
+      setFilteredAttributions((prev) => ({
+        ...prev,
+        attributions,
+      }));
+    }
+  }, [
+    attributions,
+    filteredAttributions.selectedFilters.length,
+    setFilteredAttributions,
+  ]);
+
+  return [filteredAttributions, setFilteredAttributions] as const;
+}
diff --git a/src/Frontend/state/variables/use-folder-progress-data.ts b/src/Frontend/state/variables/use-folder-progress-data.ts
new file mode 100644
index 00000000..9472e74e
--- /dev/null
+++ b/src/Frontend/state/variables/use-folder-progress-data.ts
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
+// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
+//
+// SPDX-License-Identifier: Apache-2.0
+import { ProgressBarData } from '../../types/types';
+import { useVariable } from './use-variable';
+
+export const FOLDER_PROGRESS_DATA = 'folder-progress-data';
+
+export function useFolderProgressData() {
+  return useVariable<ProgressBarData | null>(FOLDER_PROGRESS_DATA, null);
+}
diff --git a/src/Frontend/state/variables/use-overall-progress-data.ts b/src/Frontend/state/variables/use-overall-progress-data.ts
new file mode 100644
index 00000000..84842165
--- /dev/null
+++ b/src/Frontend/state/variables/use-overall-progress-data.ts
@@ -0,0 +1,12 @@
+// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
+// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
+//
+// SPDX-License-Identifier: Apache-2.0
+import { ProgressBarData } from '../../types/types';
+import { useVariable } from './use-variable';
+
+export const OVERALL_PROGRESS_DATA = 'overall-progress-data';
+
+export function useOverallProgressData() {
+  return useVariable<ProgressBarData | null>(OVERALL_PROGRESS_DATA, null);
+}
diff --git a/src/Frontend/state/variables/use-panel-data.ts b/src/Frontend/state/variables/use-panel-data.ts
new file mode 100644
index 00000000..f3a6ec3b
--- /dev/null
+++ b/src/Frontend/state/variables/use-panel-data.ts
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
+// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
+//
+// SPDX-License-Identifier: Apache-2.0
+import { PanelData } from '../../types/types';
+import { useVariable } from './use-variable';
+
+export const PANEL_DATA = 'panel-data';
+
+interface WorkerPanelData {
+  attributionsInFolderContent: PanelData;
+  signalsInFolderContent: PanelData;
+}
+
+const initialWorkerPanelData: WorkerPanelData = {
+  attributionsInFolderContent: {
+    sortedPackageCardIds: [],
+    displayPackageInfosWithCount: {},
+  },
+  signalsInFolderContent: {
+    sortedPackageCardIds: [],
+    displayPackageInfosWithCount: {},
+  },
+};
+
+export function usePanelData() {
+  return useVariable<WorkerPanelData>(PANEL_DATA, initialWorkerPanelData);
+}
diff --git a/src/Frontend/util/use-variable.ts b/src/Frontend/state/variables/use-variable.ts
similarity index 87%
rename from src/Frontend/util/use-variable.ts
rename to src/Frontend/state/variables/use-variable.ts
index f836ded6..82419cc9 100644
--- a/src/Frontend/util/use-variable.ts
+++ b/src/Frontend/state/variables/use-variable.ts
@@ -6,9 +6,9 @@ import { isFunction } from 'lodash';
 import { useCallback } from 'react';
 import { useSelector } from 'react-redux';
 
-import { setVariable } from '../state/actions/variables-actions/variables-actions';
-import { useAppDispatch, useAppStore } from '../state/hooks';
-import { State } from '../types/types';
+import { State } from '../../types/types';
+import { setVariable } from '../actions/variables-actions/variables-actions';
+import { useAppDispatch, useAppStore } from '../hooks';
 
 /**
  * Similar to `useState` but persists the value in the redux store.
diff --git a/src/Frontend/util/use-user-setting.ts b/src/Frontend/util/use-user-setting.ts
index c00b5da1..fe30dd5b 100644
--- a/src/Frontend/util/use-user-setting.ts
+++ b/src/Frontend/util/use-user-setting.ts
@@ -6,8 +6,8 @@ import { DependencyList, useCallback, useEffect } from 'react';
 
 import { AllowedFrontendChannels } from '../../shared/ipc-channels';
 import { UserSettings } from '../../shared/shared-types';
+import { useVariable } from '../state/variables/use-variable';
 import { useIpcRenderer } from './use-ipc-renderer';
-import { useVariable } from './use-variable';
 
 /**
  * Use this hook to get and set app-wide user settings.
diff --git a/src/Frontend/web-workers/use-signals-worker.ts b/src/Frontend/web-workers/use-signals-worker.ts
index 7c45281a..b43e8d75 100644
--- a/src/Frontend/web-workers/use-signals-worker.ts
+++ b/src/Frontend/web-workers/use-signals-worker.ts
@@ -4,7 +4,6 @@
 // SPDX-License-Identifier: Apache-2.0
 import { useEffect, useState } from 'react';
 
-import { Attributions, AutocompleteSignal } from '../../shared/shared-types';
 import { text } from '../../shared/text';
 import { useAppSelector } from '../state/hooks';
 import {
@@ -22,99 +21,15 @@ import {
   getSelectedResourceId,
 } from '../state/selectors/audit-view-resource-selectors';
 import { isAuditViewSelected } from '../state/selectors/view-selector';
-import { PanelData, ProgressBarData } from '../types/types';
+import { useActiveSortingInAuditView } from '../state/variables/use-active-sorting';
+import { useAutocompleteSignals } from '../state/variables/use-autocomplete-signals';
+import { useFilteredAttributions } from '../state/variables/use-filtered-attributions';
+import { useFolderProgressData } from '../state/variables/use-folder-progress-data';
+import { useOverallProgressData } from '../state/variables/use-overall-progress-data';
+import { usePanelData } from '../state/variables/use-panel-data';
 import { shouldNotBeCalled } from '../util/should-not-be-called';
-import { useActiveSortingInAuditView } from '../util/use-active-sorting';
-import { useVariable } from '../util/use-variable';
-import { Filter, FilterCounts } from './scripts/get-filtered-attributions';
 import { SignalsWorkerInput, SignalsWorkerOutput } from './signals-worker';
 
-export enum WORKER_REDUX_KEYS {
-  AUTOCOMPLETE_SIGNALS = 'autocomplete-signals',
-  PANEL_DATA = 'panel-data',
-  OVERALL_PROGRESS_DATA = 'overall-progress-data',
-  FOLDER_PROGRESS_DATA = 'folder-progress-data',
-  FILTERED_ATTRIBUTIONS = 'filtered-attributions',
-  ACTIVE_FILTERS = 'active-filters',
-}
-
-interface WorkerPanelData {
-  attributionsInFolderContent: PanelData;
-  signalsInFolderContent: PanelData;
-}
-
-export interface FilteredAttributions {
-  selectedFilters: Array<Filter>;
-  attributions: Attributions;
-  counts: FilterCounts | null;
-  loading: boolean;
-  search: string;
-}
-
-export const initialFilteredAttributions: FilteredAttributions = {
-  selectedFilters: [],
-  attributions: {},
-  counts: null,
-  loading: false,
-  search: '',
-};
-
-const initialWorkerPanelData: WorkerPanelData = {
-  attributionsInFolderContent: {
-    sortedPackageCardIds: [],
-    displayPackageInfosWithCount: {},
-  },
-  signalsInFolderContent: {
-    sortedPackageCardIds: [],
-    displayPackageInfosWithCount: {},
-  },
-};
-
-export function useAutocompleteSignals() {
-  const [autocompleteSignals] = useVariable<Array<AutocompleteSignal>>(
-    WORKER_REDUX_KEYS.AUTOCOMPLETE_SIGNALS,
-    [],
-  );
-
-  return autocompleteSignals;
-}
-
-export function usePanelData() {
-  const [panelData] = useVariable<WorkerPanelData>(
-    WORKER_REDUX_KEYS.PANEL_DATA,
-    initialWorkerPanelData,
-  );
-
-  return panelData;
-}
-
-export function useOverallProgressData() {
-  const [overallProgressData] = useVariable<ProgressBarData | null>(
-    WORKER_REDUX_KEYS.OVERALL_PROGRESS_DATA,
-    null,
-  );
-
-  return overallProgressData;
-}
-
-export function useFolderProgressData() {
-  const [folderProgressData] = useVariable<ProgressBarData | null>(
-    WORKER_REDUX_KEYS.FOLDER_PROGRESS_DATA,
-    null,
-  );
-
-  return folderProgressData;
-}
-
-export function useFilteredAttributions() {
-  const [data, setFilteredAttributions] = useVariable<FilteredAttributions>(
-    WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-    initialFilteredAttributions,
-  );
-
-  return [data, setFilteredAttributions] as const;
-}
-
 export function useSignalsWorker() {
   const resourceId = useAppSelector(getSelectedResourceId);
   const externalData = useAppSelector(getExternalData);
@@ -129,27 +44,15 @@ export function useSignalsWorker() {
   const filesWithChildren = useAppSelector(getFilesWithChildren);
   const isAuditView = useAppSelector(isAuditViewSelected);
   const { projectId } = useAppSelector(getProjectMetadata);
+  const [worker, setWorker] = useState<Worker>();
+
   const { activeSorting } = useActiveSortingInAuditView();
   const [{ selectedFilters }, setFilteredAttributions] =
     useFilteredAttributions();
-
-  const [worker, setWorker] = useState<Worker>();
-  const [, setAutocompleteSignals] = useVariable<Array<AutocompleteSignal>>(
-    WORKER_REDUX_KEYS.AUTOCOMPLETE_SIGNALS,
-    [],
-  );
-  const [, setPanelData] = useVariable<WorkerPanelData>(
-    WORKER_REDUX_KEYS.PANEL_DATA,
-    initialWorkerPanelData,
-  );
-  const [, setOverallProgressData] = useVariable<ProgressBarData | null>(
-    WORKER_REDUX_KEYS.OVERALL_PROGRESS_DATA,
-    null,
-  );
-  const [, setFolderProgressData] = useVariable<ProgressBarData | null>(
-    WORKER_REDUX_KEYS.FOLDER_PROGRESS_DATA,
-    null,
-  );
+  const [, setAutocompleteSignals] = useAutocompleteSignals();
+  const [, setPanelData] = usePanelData();
+  const [, setOverallProgressData] = useOverallProgressData();
+  const [, setFolderProgressData] = useFolderProgressData();
 
   useEffect(() => {
     if (!projectId) {
@@ -304,14 +207,16 @@ export function useSignalsWorker() {
   }, [activeSorting, worker]);
 
   useEffect(() => {
-    worker?.postMessage({
-      name: 'selectedFilters',
-      data: selectedFilters,
-    } satisfies SignalsWorkerInput);
+    if (selectedFilters.length) {
+      worker?.postMessage({
+        name: 'selectedFilters',
+        data: selectedFilters,
+      } satisfies SignalsWorkerInput);
 
-    setFilteredAttributions((prev) => ({
-      ...prev,
-      loading: true,
-    }));
+      setFilteredAttributions((prev) => ({
+        ...prev,
+        loading: true,
+      }));
+    }
   }, [selectedFilters, setFilteredAttributions, worker]);
 }


Test patch:
diff --git a/src/Frontend/Components/AttributionList/__tests__/AttributionList.test.tsx b/src/Frontend/Components/AttributionList/__tests__/AttributionList.test.tsx
index 5daddb5d..fc0b8e82 100644
--- a/src/Frontend/Components/AttributionList/__tests__/AttributionList.test.tsx
+++ b/src/Frontend/Components/AttributionList/__tests__/AttributionList.test.tsx
@@ -16,20 +16,20 @@ import { setVariable } from '../../../state/actions/variables-actions/variables-
 import { getManualAttributions } from '../../../state/selectors/all-views-resource-selectors';
 import { getSelectedAttributionIdInAttributionView } from '../../../state/selectors/attribution-view-resource-selectors';
 import { getOpenPopup } from '../../../state/selectors/view-selector';
+import { AttributionViewSorting } from '../../../state/variables/use-active-sorting';
+import {
+  FILTERED_ATTRIBUTIONS,
+  FilteredAttributions,
+  initialFilteredAttributions,
+} from '../../../state/variables/use-filtered-attributions';
 import { getParsedInputFileEnrichedWithTestData } from '../../../test-helpers/general-test-helpers';
 import { renderComponent } from '../../../test-helpers/render';
 import { getStrippedPackageInfo } from '../../../util/get-stripped-package-info';
-import { AttributionViewSorting } from '../../../util/use-active-sorting';
 import {
   FilterCounts,
   filters,
   qaFilters,
 } from '../../../web-workers/scripts/get-filtered-attributions';
-import {
-  FilteredAttributions,
-  initialFilteredAttributions,
-  WORKER_REDUX_KEYS,
-} from '../../../web-workers/use-signals-worker';
 import { AttributionList } from '../AttributionList';
 
 describe('AttributionList', () => {
@@ -60,13 +60,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -106,13 +103,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
         setVariable<AttributionViewSorting>(
           'active-sorting-attribution-view',
           text.attributionViewSorting.byCriticality,
@@ -149,13 +143,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -185,13 +176,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -219,13 +207,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -254,13 +239,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -293,13 +275,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -330,13 +309,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -364,13 +340,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -403,13 +376,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -440,13 +410,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -477,13 +444,10 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
       ],
     });
 
@@ -509,19 +473,16 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-            counts: fromPairs(
-              filters.map((filter) => [
-                filter,
-                filter === text.attributionFilters.firstParty ? 1 : 0,
-              ]),
-            ) as FilterCounts,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+          counts: fromPairs(
+            filters.map((filter) => [
+              filter,
+              filter === text.attributionFilters.firstParty ? 1 : 0,
+            ]),
+          ) as FilterCounts,
+        }),
       ],
     });
 
@@ -551,16 +512,13 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-            counts: fromPairs(
-              filters.map((filter) => [filter, 1]),
-            ) as FilterCounts,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+          counts: fromPairs(
+            filters.map((filter) => [filter, 1]),
+          ) as FilterCounts,
+        }),
       ],
     });
 
@@ -587,16 +545,13 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-            counts: fromPairs(
-              filters.map((filter) => [filter, 1]),
-            ) as FilterCounts,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+          counts: fromPairs(
+            filters.map((filter) => [filter, 1]),
+          ) as FilterCounts,
+        }),
       ],
     });
 
@@ -620,17 +575,14 @@ describe('AttributionList', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-            selectedFilters: filters,
-            counts: fromPairs(
-              filters.map((filter) => [filter, 0]),
-            ) as FilterCounts,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+          selectedFilters: filters,
+          counts: fromPairs(
+            filters.map((filter) => [filter, 0]),
+          ) as FilterCounts,
+        }),
       ],
     });
 
@@ -638,7 +590,7 @@ describe('AttributionList', () => {
       expect(
         (
           store.getState().variablesState[
-            WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS
+            FILTERED_ATTRIBUTIONS
           ] as FilteredAttributions
         ).selectedFilters,
       ).toHaveLength(0),
diff --git a/src/Frontend/Components/AttributionView/__tests__/AttributionView.test.tsx b/src/Frontend/Components/AttributionView/__tests__/AttributionView.test.tsx
index 28d6caa8..6b182f8f 100644
--- a/src/Frontend/Components/AttributionView/__tests__/AttributionView.test.tsx
+++ b/src/Frontend/Components/AttributionView/__tests__/AttributionView.test.tsx
@@ -11,13 +11,13 @@ import { setProjectMetadata } from '../../../state/actions/resource-actions/all-
 import { loadFromFile } from '../../../state/actions/resource-actions/load-actions';
 import { setVariable } from '../../../state/actions/variables-actions/variables-actions';
 import { navigateToView } from '../../../state/actions/view-actions/view-actions';
-import { getParsedInputFileEnrichedWithTestData } from '../../../test-helpers/general-test-helpers';
-import { renderComponent } from '../../../test-helpers/render';
 import {
+  FILTERED_ATTRIBUTIONS,
   FilteredAttributions,
   initialFilteredAttributions,
-  WORKER_REDUX_KEYS,
-} from '../../../web-workers/use-signals-worker';
+} from '../../../state/variables/use-filtered-attributions';
+import { getParsedInputFileEnrichedWithTestData } from '../../../test-helpers/general-test-helpers';
+import { renderComponent } from '../../../test-helpers/render';
 import { AttributionView } from '../AttributionView';
 
 describe('The Attribution View', () => {
@@ -42,13 +42,10 @@ describe('The Attribution View', () => {
           }),
         ),
         setProjectMetadata(faker.opossum.metadata()),
-        setVariable<FilteredAttributions>(
-          WORKER_REDUX_KEYS.FILTERED_ATTRIBUTIONS,
-          {
-            ...initialFilteredAttributions,
-            attributions: manualAttributions,
-          },
-        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          attributions: manualAttributions,
+        }),
         navigateToView(View.Attribution),
       ],
     });
diff --git a/src/Frontend/Components/ProgressBar/__tests__/FolderProgressBar.test.tsx b/src/Frontend/Components/ProgressBar/__tests__/FolderProgressBar.test.tsx
index 7a495a85..86ab5ec9 100644
--- a/src/Frontend/Components/ProgressBar/__tests__/FolderProgressBar.test.tsx
+++ b/src/Frontend/Components/ProgressBar/__tests__/FolderProgressBar.test.tsx
@@ -6,9 +6,9 @@ import { screen } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 
 import { setVariable } from '../../../state/actions/variables-actions/variables-actions';
+import { FOLDER_PROGRESS_DATA } from '../../../state/variables/use-folder-progress-data';
 import { renderComponent } from '../../../test-helpers/render';
 import { ProgressBarData } from '../../../types/types';
-import { WORKER_REDUX_KEYS } from '../../../web-workers/use-signals-worker';
 import { FolderProgressBar } from '../FolderProgressBar';
 
 describe('FolderProgressBar', () => {
@@ -17,7 +17,7 @@ describe('FolderProgressBar', () => {
   it('renders correctly when folder has no attributions', async () => {
     renderComponent(<FolderProgressBar />, {
       actions: [
-        setVariable<ProgressBarData>(WORKER_REDUX_KEYS.FOLDER_PROGRESS_DATA, {
+        setVariable<ProgressBarData>(FOLDER_PROGRESS_DATA, {
           fileCount: 2,
           filesWithHighlyCriticalExternalAttributionsCount: 1,
           filesWithMediumCriticalExternalAttributionsCount: 1,
@@ -46,7 +46,7 @@ describe('FolderProgressBar', () => {
   it('renders correctly if folder has an attribution', async () => {
     renderComponent(<FolderProgressBar />, {
       actions: [
-        setVariable<ProgressBarData>(WORKER_REDUX_KEYS.FOLDER_PROGRESS_DATA, {
+        setVariable<ProgressBarData>(FOLDER_PROGRESS_DATA, {
           fileCount: 2,
           filesWithHighlyCriticalExternalAttributionsCount: 1,
           filesWithMediumCriticalExternalAttributionsCount: 1,
diff --git a/src/Frontend/Components/ProgressBar/__tests__/TopProgressBar.test.tsx b/src/Frontend/Components/ProgressBar/__tests__/TopProgressBar.test.tsx
index 73848688..05346d30 100644
--- a/src/Frontend/Components/ProgressBar/__tests__/TopProgressBar.test.tsx
+++ b/src/Frontend/Components/ProgressBar/__tests__/TopProgressBar.test.tsx
@@ -6,9 +6,9 @@ import { screen } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 
 import { setVariable } from '../../../state/actions/variables-actions/variables-actions';
+import { OVERALL_PROGRESS_DATA } from '../../../state/variables/use-overall-progress-data';
 import { renderComponent } from '../../../test-helpers/render';
 import { ProgressBarData } from '../../../types/types';
-import { WORKER_REDUX_KEYS } from '../../../web-workers/use-signals-worker';
 import { TopProgressBar } from '../TopProgressBar';
 
 describe('TopProgressBar', () => {
@@ -17,7 +17,7 @@ describe('TopProgressBar', () => {
   it('renders regular progress bar', async () => {
     renderComponent(<TopProgressBar />, {
       actions: [
-        setVariable<ProgressBarData>(WORKER_REDUX_KEYS.OVERALL_PROGRESS_DATA, {
+        setVariable<ProgressBarData>(OVERALL_PROGRESS_DATA, {
           fileCount: 6,
           filesWithHighlyCriticalExternalAttributionsCount: 1,
           filesWithMediumCriticalExternalAttributionsCount: 1,
@@ -46,7 +46,7 @@ describe('TopProgressBar', () => {
   it('renders in criticality view', async () => {
     renderComponent(<TopProgressBar />, {
       actions: [
-        setVariable<ProgressBarData>(WORKER_REDUX_KEYS.OVERALL_PROGRESS_DATA, {
+        setVariable<ProgressBarData>(OVERALL_PROGRESS_DATA, {
           fileCount: 6,
           filesWithHighlyCriticalExternalAttributionsCount: 1,
           filesWithMediumCriticalExternalAttributionsCount: 1,
diff --git a/src/Frontend/state/variables/__tests__/use-filtered-attributions.test.ts b/src/Frontend/state/variables/__tests__/use-filtered-attributions.test.ts
new file mode 100644
index 00000000..30f81dca
--- /dev/null
+++ b/src/Frontend/state/variables/__tests__/use-filtered-attributions.test.ts
@@ -0,0 +1,48 @@
+// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
+// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
+//
+// SPDX-License-Identifier: Apache-2.0
+import { faker } from '../../../../testing/Faker';
+import { renderHook } from '../../../test-helpers/render';
+import { setManualData } from '../../actions/resource-actions/all-views-simple-actions';
+import { setVariable } from '../../actions/variables-actions/variables-actions';
+import {
+  FILTERED_ATTRIBUTIONS,
+  FilteredAttributions,
+  initialFilteredAttributions,
+  useFilteredAttributions,
+} from '../use-filtered-attributions';
+
+describe('useFilteredAttributions', () => {
+  it('returns all manual attributions when no filters set', () => {
+    const manualAttributions = faker.opossum.manualAttributions();
+    const { result } = renderHook(() => useFilteredAttributions(), {
+      actions: [
+        setManualData(
+          manualAttributions,
+          faker.opossum.resourcesToAttributions(),
+        ),
+      ],
+    });
+
+    expect(result.current[0].attributions).toEqual(manualAttributions);
+  });
+
+  it('returns filtered manual attributions when filters set', () => {
+    const manualAttributions = faker.opossum.manualAttributions();
+    const { result } = renderHook(() => useFilteredAttributions(), {
+      actions: [
+        setManualData(
+          manualAttributions,
+          faker.opossum.resourcesToAttributions(),
+        ),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          selectedFilters: ['First Party'],
+        }),
+      ],
+    });
+
+    expect(result.current[0].attributions).toEqual({});
+  });
+});
diff --git a/src/Frontend/util/__tests__/use-variable.test.ts b/src/Frontend/state/variables/__tests__/use-variable.test.ts
similarity index 89%
rename from src/Frontend/util/__tests__/use-variable.test.ts
rename to src/Frontend/state/variables/__tests__/use-variable.test.ts
index 601e9c79..38fcac67 100644
--- a/src/Frontend/util/__tests__/use-variable.test.ts
+++ b/src/Frontend/state/variables/__tests__/use-variable.test.ts
@@ -4,8 +4,8 @@
 // SPDX-License-Identifier: Apache-2.0
 import { act } from '@testing-library/react';
 
-import { faker } from '../../../testing/Faker';
-import { renderHook } from '../../test-helpers/render';
+import { faker } from '../../../../testing/Faker';
+import { renderHook } from '../../../test-helpers/render';
 import { useVariable } from '../use-variable';
 
 describe('useVariable', () => {
diff --git a/src/Frontend/web-workers/__tests__/use-signals-worker.test.ts b/src/Frontend/web-workers/__tests__/use-signals-worker.test.ts
index c8f9cada..56379c7d 100644
--- a/src/Frontend/web-workers/__tests__/use-signals-worker.test.ts
+++ b/src/Frontend/web-workers/__tests__/use-signals-worker.test.ts
@@ -8,7 +8,13 @@ import { faker } from '../../../testing/Faker';
 import { View } from '../../enums/enums';
 import { setProjectMetadata } from '../../state/actions/resource-actions/all-views-simple-actions';
 import { setSelectedResourceId } from '../../state/actions/resource-actions/audit-view-simple-actions';
+import { setVariable } from '../../state/actions/variables-actions/variables-actions';
 import { setView } from '../../state/actions/view-actions/view-actions';
+import {
+  FILTERED_ATTRIBUTIONS,
+  FilteredAttributions,
+  initialFilteredAttributions,
+} from '../../state/variables/use-filtered-attributions';
 import { renderHook } from '../../test-helpers/render';
 import { SignalsWorkerInput } from '../signals-worker';
 import { useSignalsWorker } from '../use-signals-worker';
@@ -104,4 +110,35 @@ describe('useSignalsWorker', () => {
 
     expect(mockTerminate).toHaveBeenCalledTimes(1);
   });
+
+  it('does not send selected filters when none are set', () => {
+    const metadata = faker.opossum.metadata();
+    renderHook(useSignalsWorker, { actions: [setProjectMetadata(metadata)] });
+
+    expect(mockPostMessage).not.toHaveBeenCalledWith<[SignalsWorkerInput]>({
+      name: 'selectedFilters',
+      data: expect.anything(),
+    });
+  });
+
+  it('sends selected filters when some are set', () => {
+    const metadata = faker.opossum.metadata();
+    const selectedFilters: FilteredAttributions['selectedFilters'] = [
+      'First Party',
+    ];
+    renderHook(useSignalsWorker, {
+      actions: [
+        setProjectMetadata(metadata),
+        setVariable<FilteredAttributions>(FILTERED_ATTRIBUTIONS, {
+          ...initialFilteredAttributions,
+          selectedFilters,
+        }),
+      ],
+    });
+
+    expect(mockPostMessage).toHaveBeenCalledWith<[SignalsWorkerInput]>({
+      name: 'selectedFilters',
+      data: selectedFilters,
+    });
+  });
 });