Repository: oliverschwendener/ueli
Pull request #1175 (2024-08-25 09:44:59)

refactor: moved all default action handlers to their dedicated modules


Patch:
diff --git a/src/main/Core/ActionHandler/ActionHandlerModule.ts b/src/main/Core/ActionHandler/ActionHandlerModule.ts
index 65533038..21e0d6d4 100644
--- a/src/main/Core/ActionHandler/ActionHandlerModule.ts
+++ b/src/main/Core/ActionHandler/ActionHandlerModule.ts
@@ -2,18 +2,6 @@ import type { Dependencies } from "@Core/Dependencies";
 import type { DependencyRegistry } from "@Core/DependencyRegistry";
 import type { SearchResultItemAction } from "@common/Core";
 import { ActionHandlerRegistry } from "./ActionHandlerRegistry";
-import type { ActionHandler } from "./Contract";
-import {
-    CommandlineActionHandler,
-    CopyToClipboardActionHandler,
-    ExcludeFromSearchResultsActionHandler,
-    FavoritesActionHandler,
-    NavigateToActionHandler,
-    OpenFilePathActionHandler,
-    PowershellActionHandler,
-    ShowItemInFileExplorerActionHandler,
-    UrlActionHandler,
-} from "./DefaultActionHandlers";
 
 export class ActionHandlerModule {
     public static bootstrap(dependencyRegistry: DependencyRegistry<Dependencies>) {
@@ -24,25 +12,6 @@ export class ActionHandlerModule {
 
         dependencyRegistry.register("ActionHandlerRegistry", actionHandlerRegistry);
 
-        const actionHandlers: ActionHandler[] = [
-            new CommandlineActionHandler(dependencyRegistry.get("CommandlineUtility")),
-            new CopyToClipboardActionHandler(
-                dependencyRegistry.get("Clipboard"),
-                dependencyRegistry.get("BrowserWindowNotifier"),
-            ),
-            new ExcludeFromSearchResultsActionHandler(dependencyRegistry.get("ExcludedSearchResults")),
-            new FavoritesActionHandler(dependencyRegistry.get("FavoriteManager")),
-            new NavigateToActionHandler(eventEmitter),
-            new OpenFilePathActionHandler(dependencyRegistry.get("Shell")),
-            new PowershellActionHandler(dependencyRegistry.get("PowershellUtility")),
-            new ShowItemInFileExplorerActionHandler(dependencyRegistry.get("Shell")),
-            new UrlActionHandler(dependencyRegistry.get("Shell")),
-        ];
-
-        for (const actionHandler of actionHandlers) {
-            actionHandlerRegistry.register(actionHandler);
-        }
-
         ipcMain.handle("invokeAction", async (_, { action }: { action: SearchResultItemAction }) => {
             await actionHandlerRegistry.getById(action.handlerId).invokeAction(action);
             eventEmitter.emitEvent("actionInvoked", { action });
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/index.ts b/src/main/Core/ActionHandler/DefaultActionHandlers/index.ts
deleted file mode 100644
index 8801fba5..00000000
--- a/src/main/Core/ActionHandler/DefaultActionHandlers/index.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-export * from "./CommandlineActionHandler";
-export * from "./CopyToClipboardActionHandler";
-export * from "./ExcludeFromSearchResultsActionHandler";
-export * from "./FavoritesActionHandler";
-export * from "./NavigateToActionHandler";
-export * from "./OpenFilePathActionHandler";
-export * from "./PowershellActionHandler";
-export * from "./ShowItemInFileExplorerActionHandler";
-export * from "./UrlActionHandler";
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/NavigateToActionHandler.test.ts b/src/main/Core/BrowserWindow/ActionHandler/NavigateToActionHandler.test.ts
similarity index 100%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/NavigateToActionHandler.test.ts
rename to src/main/Core/BrowserWindow/ActionHandler/NavigateToActionHandler.test.ts
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/NavigateToActionHandler.ts b/src/main/Core/BrowserWindow/ActionHandler/NavigateToActionHandler.ts
similarity index 92%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/NavigateToActionHandler.ts
rename to src/main/Core/BrowserWindow/ActionHandler/NavigateToActionHandler.ts
index cbaa6279..00dfe321 100644
--- a/src/main/Core/ActionHandler/DefaultActionHandlers/NavigateToActionHandler.ts
+++ b/src/main/Core/BrowserWindow/ActionHandler/NavigateToActionHandler.ts
@@ -1,6 +1,6 @@
+import type { ActionHandler } from "@Core/ActionHandler";
 import type { EventEmitter } from "@Core/EventEmitter";
 import type { SearchResultItemAction } from "@common/Core";
-import type { ActionHandler } from "../Contract";
 
 /**
  * Action handler for navigating to a specific path in the renderer process.
diff --git a/src/main/Core/BrowserWindow/ActionHandler/index.ts b/src/main/Core/BrowserWindow/ActionHandler/index.ts
new file mode 100644
index 00000000..7398127d
--- /dev/null
+++ b/src/main/Core/BrowserWindow/ActionHandler/index.ts
@@ -0,0 +1,1 @@
+export * from "./NavigateToActionHandler";
diff --git a/src/main/Core/BrowserWindow/BrowserWindowModule.ts b/src/main/Core/BrowserWindow/BrowserWindowModule.ts
index 91b16edf..b0945c84 100644
--- a/src/main/Core/BrowserWindow/BrowserWindowModule.ts
+++ b/src/main/Core/BrowserWindow/BrowserWindowModule.ts
@@ -7,6 +7,7 @@ import type { UeliCommand, UeliCommandInvokedEvent } from "@Core/UeliCommand";
 import type { OperatingSystem, SearchResultItemAction } from "@common/Core";
 import type { BrowserWindow, IpcMain } from "electron";
 import { join } from "path";
+import { NavigateToActionHandler } from "./ActionHandler";
 import { AppIconFilePathResolver } from "./AppIconFilePathResolver";
 import type { BrowserWindowConstructorOptionsProvider } from "./BrowserWindowConstructorOptionsProvider";
 import {
@@ -96,6 +97,10 @@ export class BrowserWindowModule {
             ipcMain,
         );
 
+        dependencyRegistry
+            .get("ActionHandlerRegistry")
+            .register(new NavigateToActionHandler(dependencyRegistry.get("EventEmitter")));
+
         await BrowserWindowModule.loadFileOrUrl(browserWindow, dependencyRegistry.get("EnvironmentVariableProvider"));
     }
 
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/CopyToClipboardActionHandler.test.ts b/src/main/Core/Clipboard/ActionHandler/CopyToClipboardActionHandler.test.ts
similarity index 100%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/CopyToClipboardActionHandler.test.ts
rename to src/main/Core/Clipboard/ActionHandler/CopyToClipboardActionHandler.test.ts
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/CopyToClipboardActionHandler.ts b/src/main/Core/Clipboard/ActionHandler/CopyToClipboardActionHandler.ts
similarity index 94%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/CopyToClipboardActionHandler.ts
rename to src/main/Core/Clipboard/ActionHandler/CopyToClipboardActionHandler.ts
index 18386aeb..9ff269f7 100644
--- a/src/main/Core/ActionHandler/DefaultActionHandlers/CopyToClipboardActionHandler.ts
+++ b/src/main/Core/Clipboard/ActionHandler/CopyToClipboardActionHandler.ts
@@ -1,7 +1,7 @@
+import type { ActionHandler } from "@Core/ActionHandler";
 import type { BrowserWindowNotifier } from "@Core/BrowserWindowNotifier";
 import type { SearchResultItemAction } from "@common/Core";
 import type { Clipboard } from "electron";
-import type { ActionHandler } from "../Contract";
 
 /**
  * Action handler for copying a string to the clipboard.
diff --git a/src/main/Core/Clipboard/ActionHandler/index.ts b/src/main/Core/Clipboard/ActionHandler/index.ts
new file mode 100644
index 00000000..4a597ebc
--- /dev/null
+++ b/src/main/Core/Clipboard/ActionHandler/index.ts
@@ -0,0 +1,1 @@
+export * from "./CopyToClipboardActionHandler";
diff --git a/src/main/Core/Clipboard/ClipboardModule.ts b/src/main/Core/Clipboard/ClipboardModule.ts
index aaf8ad75..45eadc5c 100644
--- a/src/main/Core/Clipboard/ClipboardModule.ts
+++ b/src/main/Core/Clipboard/ClipboardModule.ts
@@ -1,11 +1,16 @@
 import type { Dependencies } from "@Core/Dependencies";
 import type { DependencyRegistry } from "@Core/DependencyRegistry";
+import { CopyToClipboardActionHandler } from "./ActionHandler";
 
 export class ClipboardModule {
     public static bootstrap(dependencyRegistry: DependencyRegistry<Dependencies>) {
         const clipboard = dependencyRegistry.get("Clipboard");
         const ipcMain = dependencyRegistry.get("IpcMain");
 
+        dependencyRegistry
+            .get("ActionHandlerRegistry")
+            .register(new CopyToClipboardActionHandler(clipboard, dependencyRegistry.get("BrowserWindowNotifier")));
+
         ipcMain.on("copyTextToClipboard", (_, { textToCopy }: { textToCopy: string }) => {
             clipboard.writeText(textToCopy);
         });
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/CommandlineActionHandler.ts b/src/main/Core/CommandlineUtility/ActionHandler/CommandlineActionHandler.ts
similarity index 85%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/CommandlineActionHandler.ts
rename to src/main/Core/CommandlineUtility/ActionHandler/CommandlineActionHandler.ts
index 855c6689..0afd8adb 100644
--- a/src/main/Core/ActionHandler/DefaultActionHandlers/CommandlineActionHandler.ts
+++ b/src/main/Core/CommandlineUtility/ActionHandler/CommandlineActionHandler.ts
@@ -1,6 +1,6 @@
 import type { SearchResultItemAction } from "@common/Core";
-import type { CommandlineUtility } from "../../CommandlineUtility";
-import type { ActionHandler } from "../Contract";
+import type { ActionHandler } from "@Core/ActionHandler";
+import type { CommandlineUtility } from "../Contract";
 
 /**
  * Action handler for executing a CLI command.
diff --git a/src/main/Core/CommandlineUtility/ActionHandler/index.ts b/src/main/Core/CommandlineUtility/ActionHandler/index.ts
new file mode 100644
index 00000000..173e3704
--- /dev/null
+++ b/src/main/Core/CommandlineUtility/ActionHandler/index.ts
@@ -0,0 +1,1 @@
+export * from "./CommandlineActionHandler";
diff --git a/src/main/Core/CommandlineUtility/CommandlineUtilityModule.ts b/src/main/Core/CommandlineUtility/CommandlineUtilityModule.ts
index 22738ff9..13623c66 100644
--- a/src/main/Core/CommandlineUtility/CommandlineUtilityModule.ts
+++ b/src/main/Core/CommandlineUtility/CommandlineUtilityModule.ts
@@ -1,9 +1,13 @@
 import type { Dependencies } from "@Core/Dependencies";
 import type { DependencyRegistry } from "@Core/DependencyRegistry";
+import { CommandlineActionHandler } from "./ActionHandler";
 import { NodeJsCommandlineUtility } from "./NodeJsCommandlineUtility";
 
 export class CommandlineUtilityModule {
     public static bootstrap(dependencyRegistry: DependencyRegistry<Dependencies>) {
-        dependencyRegistry.register("CommandlineUtility", new NodeJsCommandlineUtility());
+        const commandlineUtility = new NodeJsCommandlineUtility();
+
+        dependencyRegistry.register("CommandlineUtility", commandlineUtility);
+        dependencyRegistry.get("ActionHandlerRegistry").register(new CommandlineActionHandler(commandlineUtility));
     }
 }
diff --git a/src/main/Core/Dependencies.ts b/src/main/Core/Dependencies.ts
index 66f56c6c..626b2683 100644
--- a/src/main/Core/Dependencies.ts
+++ b/src/main/Core/Dependencies.ts
@@ -17,9 +17,7 @@ export type Dependencies = {
     EnvironmentVariableProvider?: Core.EnvironmentVariableProvider;
     EventEmitter?: Core.EventEmitter;
     EventSubscriber?: Core.EventSubscriber;
-    ExcludedSearchResults?: Core.ExcludedSearchResults;
     ExtensionRegistry?: Core.ExtensionRegistry;
-    FavoriteManager?: Core.FavoriteManager;
     FileImageGenerator?: Core.FileImageGenerator;
     FileSystemUtility?: Core.FileSystemUtility;
     GlobalShortcut?: Electron.GlobalShortcut;
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/ExcludeFromSearchResultsActionHandler.ts b/src/main/Core/ExcludedSearchResults/ActionHandler/ExcludeFromSearchResultsActionHandler.ts
similarity index 83%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/ExcludeFromSearchResultsActionHandler.ts
rename to src/main/Core/ExcludedSearchResults/ActionHandler/ExcludeFromSearchResultsActionHandler.ts
index ac294762..d32214bc 100644
--- a/src/main/Core/ActionHandler/DefaultActionHandlers/ExcludeFromSearchResultsActionHandler.ts
+++ b/src/main/Core/ExcludedSearchResults/ActionHandler/ExcludeFromSearchResultsActionHandler.ts
@@ -1,6 +1,6 @@
-import type { ExcludedSearchResults } from "@Core/ExcludedSearchResults";
+import type { ActionHandler } from "@Core/ActionHandler";
 import type { SearchResultItemAction } from "@common/Core";
-import type { ActionHandler } from "../Contract";
+import type { ExcludedSearchResults } from "../ExcludedSearchResults";
 
 /**
  * Action handler for excluding a search result from the search results.
diff --git a/src/main/Core/ExcludedSearchResults/ActionHandler/index.ts b/src/main/Core/ExcludedSearchResults/ActionHandler/index.ts
new file mode 100644
index 00000000..ed2bfd74
--- /dev/null
+++ b/src/main/Core/ExcludedSearchResults/ActionHandler/index.ts
@@ -0,0 +1,1 @@
+export * from "./ExcludeFromSearchResultsActionHandler";
diff --git a/src/main/Core/ExcludedSearchResults/Contract/ExcludedSearchResults.ts b/src/main/Core/ExcludedSearchResults/Contract/ExcludedSearchResults.ts
deleted file mode 100644
index 2569f65c..00000000
--- a/src/main/Core/ExcludedSearchResults/Contract/ExcludedSearchResults.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface ExcludedSearchResults {
-    add(id: string): Promise<void>;
-    remove(id: string): Promise<void>;
-    getExcludedIds(): string[];
-}
diff --git a/src/main/Core/ExcludedSearchResults/Contract/index.ts b/src/main/Core/ExcludedSearchResults/Contract/index.ts
deleted file mode 100644
index 1bdb6b9f..00000000
--- a/src/main/Core/ExcludedSearchResults/Contract/index.ts
+++ /dev/null
@@ -1,1 +0,0 @@
-export * from "./ExcludedSearchResults";
diff --git a/src/main/Core/ExcludedSearchResults/ExcludedSearchResults.ts b/src/main/Core/ExcludedSearchResults/ExcludedSearchResults.ts
index b679fa04..e482458a 100644
--- a/src/main/Core/ExcludedSearchResults/ExcludedSearchResults.ts
+++ b/src/main/Core/ExcludedSearchResults/ExcludedSearchResults.ts
@@ -1,8 +1,7 @@
 import type { BrowserWindowNotifier } from "@Core/BrowserWindowNotifier";
 import type { SettingsManager } from "@Core/SettingsManager";
-import type { ExcludedSearchResults as ExcludedSearchResultsInterface } from "./Contract";
 
-export class ExcludedSearchResults implements ExcludedSearchResultsInterface {
+export class ExcludedSearchResults {
     private static readonly settingKey = "searchEngine.excludedItems";
 
     private readonly items: string[] = [];
diff --git a/src/main/Core/ExcludedSearchResults/ExcludedSearchResultsModule.ts b/src/main/Core/ExcludedSearchResults/ExcludedSearchResultsModule.ts
index 1e3e8848..a8e94c74 100644
--- a/src/main/Core/ExcludedSearchResults/ExcludedSearchResultsModule.ts
+++ b/src/main/Core/ExcludedSearchResults/ExcludedSearchResultsModule.ts
@@ -1,5 +1,6 @@
 import type { Dependencies } from "@Core/Dependencies";
 import type { DependencyRegistry } from "@Core/DependencyRegistry";
+import { ExcludeFromSearchResultsActionHandler } from "./ActionHandler";
 import { ExcludedSearchResults } from "./ExcludedSearchResults";
 
 export class ExcludedSearchResultsModule {
@@ -11,7 +12,9 @@ export class ExcludedSearchResultsModule {
             dependencyRegistry.get("SettingsManager"),
         );
 
-        dependencyRegistry.register("ExcludedSearchResults", excludedSearchResults);
+        dependencyRegistry
+            .get("ActionHandlerRegistry")
+            .register(new ExcludeFromSearchResultsActionHandler(excludedSearchResults));
 
         ipcMain.on(
             "getExcludedSearchResultItemIds",
diff --git a/src/main/Core/ExcludedSearchResults/index.ts b/src/main/Core/ExcludedSearchResults/index.ts
index 66323a16..1ae2ad41 100644
--- a/src/main/Core/ExcludedSearchResults/index.ts
+++ b/src/main/Core/ExcludedSearchResults/index.ts
@@ -1,2 +1,1 @@
-export * from "./Contract";
 export * from "./ExcludedSearchResultsModule";
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/FavoritesActionHandler.ts b/src/main/Core/FavoriteManager/ActionHandler/FavoritesActionHandler.ts
similarity index 89%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/FavoritesActionHandler.ts
rename to src/main/Core/FavoriteManager/ActionHandler/FavoritesActionHandler.ts
index 02c5ba7b..c4da34a8 100644
--- a/src/main/Core/ActionHandler/DefaultActionHandlers/FavoritesActionHandler.ts
+++ b/src/main/Core/FavoriteManager/ActionHandler/FavoritesActionHandler.ts
@@ -1,6 +1,6 @@
-import type { FavoriteManager } from "@Core/FavoriteManager";
+import type { ActionHandler } from "@Core/ActionHandler";
 import type { SearchResultItemAction } from "@common/Core";
-import type { ActionHandler } from "../Contract";
+import type { FavoriteManager } from "../FavoriteManager";
 
 /**
  * Action handler for adding and removing favorites.
diff --git a/src/main/Core/FavoriteManager/ActionHandler/index.ts b/src/main/Core/FavoriteManager/ActionHandler/index.ts
new file mode 100644
index 00000000..ff9b3989
--- /dev/null
+++ b/src/main/Core/FavoriteManager/ActionHandler/index.ts
@@ -0,0 +1,1 @@
+export * from "./FavoritesActionHandler";
diff --git a/src/main/Core/FavoriteManager/Contract/FavoriteManager.ts b/src/main/Core/FavoriteManager/Contract/FavoriteManager.ts
deleted file mode 100644
index c8c0be7c..00000000
--- a/src/main/Core/FavoriteManager/Contract/FavoriteManager.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export interface FavoriteManager {
-    add(id: string): Promise<void>;
-    remove(id: string): Promise<void>;
-    getAll(): string[];
-}
diff --git a/src/main/Core/FavoriteManager/Contract/index.ts b/src/main/Core/FavoriteManager/Contract/index.ts
deleted file mode 100644
index 08950be8..00000000
--- a/src/main/Core/FavoriteManager/Contract/index.ts
+++ /dev/null
@@ -1,1 +0,0 @@
-export * from "./FavoriteManager";
diff --git a/src/main/Core/FavoriteManager/FavoriteManager.ts b/src/main/Core/FavoriteManager/FavoriteManager.ts
index da0da7df..23af4697 100644
--- a/src/main/Core/FavoriteManager/FavoriteManager.ts
+++ b/src/main/Core/FavoriteManager/FavoriteManager.ts
@@ -1,8 +1,7 @@
 import type { BrowserWindowNotifier } from "@Core/BrowserWindowNotifier";
 import type { SettingsManager } from "@Core/SettingsManager";
-import type { FavoriteManager as FavoriteManagerInterface } from "./Contract";
 
-export class FavoriteManager implements FavoriteManagerInterface {
+export class FavoriteManager {
     private readonly settingKey = "favorites";
 
     public readonly favorites: string[];
diff --git a/src/main/Core/FavoriteManager/FavoriteManagerModule.ts b/src/main/Core/FavoriteManager/FavoriteManagerModule.ts
index 12c854a8..86b575e3 100644
--- a/src/main/Core/FavoriteManager/FavoriteManagerModule.ts
+++ b/src/main/Core/FavoriteManager/FavoriteManagerModule.ts
@@ -1,5 +1,6 @@
 import type { Dependencies } from "@Core/Dependencies";
 import type { DependencyRegistry } from "@Core/DependencyRegistry";
+import { FavoritesActionHandler } from "./ActionHandler";
 import { FavoriteManager } from "./FavoriteManager";
 
 export class FavoriteManagerModule {
@@ -11,7 +12,7 @@ export class FavoriteManagerModule {
             dependencyRegistry.get("BrowserWindowNotifier"),
         );
 
-        dependencyRegistry.register("FavoriteManager", favoriteManager);
+        dependencyRegistry.get("ActionHandlerRegistry").register(new FavoritesActionHandler(favoriteManager));
 
         ipcMain.on("getFavorites", (event) => (event.returnValue = favoriteManager.getAll()));
 
diff --git a/src/main/Core/FavoriteManager/index.ts b/src/main/Core/FavoriteManager/index.ts
index e1f35952..9ded3d6c 100644
--- a/src/main/Core/FavoriteManager/index.ts
+++ b/src/main/Core/FavoriteManager/index.ts
@@ -1,2 +1,1 @@
-export * from "./Contract";
 export * from "./FavoriteManagerModule";
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/PowershellActionHandler.test.ts b/src/main/Core/PowershellUtility/ActionHandler/PowershellActionHandler.test.ts
similarity index 100%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/PowershellActionHandler.test.ts
rename to src/main/Core/PowershellUtility/ActionHandler/PowershellActionHandler.test.ts
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/PowershellActionHandler.ts b/src/main/Core/PowershellUtility/ActionHandler/PowershellActionHandler.ts
similarity index 100%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/PowershellActionHandler.ts
rename to src/main/Core/PowershellUtility/ActionHandler/PowershellActionHandler.ts
diff --git a/src/main/Core/PowershellUtility/ActionHandler/index.ts b/src/main/Core/PowershellUtility/ActionHandler/index.ts
new file mode 100644
index 00000000..9803892b
--- /dev/null
+++ b/src/main/Core/PowershellUtility/ActionHandler/index.ts
@@ -0,0 +1,1 @@
+export * from "./PowershellActionHandler";
diff --git a/src/main/Core/PowershellUtility/PowershellUtilityModule.ts b/src/main/Core/PowershellUtility/PowershellUtilityModule.ts
index d3277245..e7871b89 100644
--- a/src/main/Core/PowershellUtility/PowershellUtilityModule.ts
+++ b/src/main/Core/PowershellUtility/PowershellUtilityModule.ts
@@ -1,22 +1,25 @@
 import type { Dependencies } from "@Core/Dependencies";
 import type { DependencyRegistry } from "@Core/DependencyRegistry";
 import { join } from "path";
+import { PowershellActionHandler } from "./ActionHandler";
 import { PowershellUtility } from "./PowershellUtility";
 
 export class PowershellUtilityModule {
     public static async bootstrap(dependencyRegistry: DependencyRegistry<Dependencies>) {
         const fileSystemUtility = dependencyRegistry.get("FileSystemUtility");
-        const commandlineUtility = dependencyRegistry.get("CommandlineUtility");
         const app = dependencyRegistry.get("App");
-        const randomStringProvider = dependencyRegistry.get("RandomStringProvider");
-
         const powershellScriptFolder = join(app.getPath("userData"), "PowershellUtility");
 
         await fileSystemUtility.createFolderIfDoesntExist(powershellScriptFolder);
 
-        dependencyRegistry.register(
-            "PowershellUtility",
-            new PowershellUtility(fileSystemUtility, commandlineUtility, powershellScriptFolder, randomStringProvider),
+        const powershellUtility = new PowershellUtility(
+            fileSystemUtility,
+            dependencyRegistry.get("CommandlineUtility"),
+            powershellScriptFolder,
+            dependencyRegistry.get("RandomStringProvider"),
         );
+
+        dependencyRegistry.register("PowershellUtility", powershellUtility);
+        dependencyRegistry.get("ActionHandlerRegistry").register(new PowershellActionHandler(powershellUtility));
     }
 }
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/OpenFilePathActionHandler.test.ts b/src/main/Core/Shell/ActionHandler/OpenFilePathActionHandler.test.ts
similarity index 100%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/OpenFilePathActionHandler.test.ts
rename to src/main/Core/Shell/ActionHandler/OpenFilePathActionHandler.test.ts
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/OpenFilePathActionHandler.ts b/src/main/Core/Shell/ActionHandler/OpenFilePathActionHandler.ts
similarity index 100%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/OpenFilePathActionHandler.ts
rename to src/main/Core/Shell/ActionHandler/OpenFilePathActionHandler.ts
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/ShowItemInFileExplorerActionHandler.test.ts b/src/main/Core/Shell/ActionHandler/ShowItemInFileExplorerActionHandler.test.ts
similarity index 100%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/ShowItemInFileExplorerActionHandler.test.ts
rename to src/main/Core/Shell/ActionHandler/ShowItemInFileExplorerActionHandler.test.ts
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/ShowItemInFileExplorerActionHandler.ts b/src/main/Core/Shell/ActionHandler/ShowItemInFileExplorerActionHandler.ts
similarity index 100%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/ShowItemInFileExplorerActionHandler.ts
rename to src/main/Core/Shell/ActionHandler/ShowItemInFileExplorerActionHandler.ts
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/UrlActionHandler.test.ts b/src/main/Core/Shell/ActionHandler/UrlActionHandler.test.ts
similarity index 100%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/UrlActionHandler.test.ts
rename to src/main/Core/Shell/ActionHandler/UrlActionHandler.test.ts
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/UrlActionHandler.ts b/src/main/Core/Shell/ActionHandler/UrlActionHandler.ts
similarity index 100%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/UrlActionHandler.ts
rename to src/main/Core/Shell/ActionHandler/UrlActionHandler.ts
diff --git a/src/main/Core/Shell/ActionHandler/index.ts b/src/main/Core/Shell/ActionHandler/index.ts
new file mode 100644
index 00000000..4dffeb2c
--- /dev/null
+++ b/src/main/Core/Shell/ActionHandler/index.ts
@@ -0,0 +1,3 @@
+export * from "./OpenFilePathActionHandler";
+export * from "./ShowItemInFileExplorerActionHandler";
+export * from "./UrlActionHandler";
diff --git a/src/main/Core/Shell/ShellModule.ts b/src/main/Core/Shell/ShellModule.ts
index 09d8a158..3f593f30 100644
--- a/src/main/Core/Shell/ShellModule.ts
+++ b/src/main/Core/Shell/ShellModule.ts
@@ -1,12 +1,19 @@
 import type { Dependencies } from "@Core/Dependencies";
 import type { DependencyRegistry } from "@Core/DependencyRegistry";
 import type { OpenExternalOptions } from "electron";
+import { OpenFilePathActionHandler, ShowItemInFileExplorerActionHandler, UrlActionHandler } from "./ActionHandler";
 
 export class ShellModule {
     public static bootstrap(dependencyRegistry: DependencyRegistry<Dependencies>) {
         const shell = dependencyRegistry.get("Shell");
         const ipcMain = dependencyRegistry.get("IpcMain");
 
+        const actionHandlerRegistry = dependencyRegistry.get("ActionHandlerRegistry");
+
+        actionHandlerRegistry.register(new OpenFilePathActionHandler(shell));
+        actionHandlerRegistry.register(new ShowItemInFileExplorerActionHandler(shell));
+        actionHandlerRegistry.register(new UrlActionHandler(shell));
+
         ipcMain.handle("openExternal", (_, { url, options }: { url: string; options?: OpenExternalOptions }) =>
             shell.openExternal(url, options),
         );
diff --git a/src/main/index.ts b/src/main/index.ts
index 697237f2..5acbbdaf 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -36,6 +36,8 @@ import * as Extensions from "./Extensions";
     Core.IniFileParserModule.bootstrap(dependencyRegistry);
     Core.EventEmitterModule.bootstrap(dependencyRegistry);
     Core.EventSubscriberModule.bootstrap(dependencyRegistry);
+    Core.BrowserWindowNotifierModule.bootstrap(dependencyRegistry);
+    Core.ActionHandlerModule.bootstrap(dependencyRegistry);
     Core.RandomStringProviderModule.bootstrap(dependencyRegistry);
     Core.SafeStorageEncryptionModule.bootstrap(dependencyRegistry);
     Core.AssetPathResolverModule.bootstrap(dependencyRegistry);
@@ -43,7 +45,6 @@ import * as Extensions from "./Extensions";
     Core.ClipboardModule.bootstrap(dependencyRegistry);
     Core.DateProviderModule.bootstrap(dependencyRegistry);
     Core.AboutUeliModule.bootstrap(dependencyRegistry);
-    Core.BrowserWindowNotifierModule.bootstrap(dependencyRegistry);
     Core.LoggerModule.bootstrap(dependencyRegistry);
     Core.CommandlineUtilityModule.bootstrap(dependencyRegistry);
     Core.AppleScriptUtilityModule.bootstrap(dependencyRegistry);
@@ -61,7 +62,6 @@ import * as Extensions from "./Extensions";
     Core.AutostartModule.bootstrap(dependencyRegistry);
     Core.ExcludedSearchResultsModule.bootstrap(dependencyRegistry);
     Core.FavoriteManagerModule.bootstrap(dependencyRegistry);
-    Core.ActionHandlerModule.bootstrap(dependencyRegistry);
     Core.UeliCommandModule.bootstrap(dependencyRegistry);
     await Core.TrayIconModule.bootstrap(dependencyRegistry);
     Core.DialogModule.bootstrap(dependencyRegistry);


Test patch:
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/CommandlineActionHandler.test.ts b/src/main/Core/CommandlineUtility/ActionHandler/CommandlineActionHandler.test.ts
similarity index 91%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/CommandlineActionHandler.test.ts
rename to src/main/Core/CommandlineUtility/ActionHandler/CommandlineActionHandler.test.ts
index a488b1f2..7a091291 100644
--- a/src/main/Core/ActionHandler/DefaultActionHandlers/CommandlineActionHandler.test.ts
+++ b/src/main/Core/CommandlineUtility/ActionHandler/CommandlineActionHandler.test.ts
@@ -1,6 +1,6 @@
 import type { SearchResultItemAction } from "@common/Core";
 import { describe, expect, it, vi } from "vitest";
-import type { CommandlineUtility } from "../../CommandlineUtility";
+import type { CommandlineUtility } from "../Contract";
 import { CommandlineActionHandler } from "./CommandlineActionHandler";
 
 describe(CommandlineActionHandler, () => {
diff --git a/src/main/Core/CommandlineUtility/CommandlineUtilityModule.test.ts b/src/main/Core/CommandlineUtility/CommandlineUtilityModule.test.ts
index 3c3e0305..b1729f53 100644
--- a/src/main/Core/CommandlineUtility/CommandlineUtilityModule.test.ts
+++ b/src/main/Core/CommandlineUtility/CommandlineUtilityModule.test.ts
@@ -1,18 +1,31 @@
+import type { ActionHandlerRegistry } from "@Core/ActionHandler";
 import type { Dependencies } from "@Core/Dependencies";
 import type { DependencyRegistry } from "@Core/DependencyRegistry";
 import { describe, expect, it, vi } from "vitest";
+import { CommandlineActionHandler } from "./ActionHandler";
 import { CommandlineUtilityModule } from "./CommandlineUtilityModule";
 import { NodeJsCommandlineUtility } from "./NodeJsCommandlineUtility";
 
 describe(CommandlineUtilityModule, () => {
     it("should register the NodeJsCommandlineUtility", () => {
+        const actionHandlerRegistryMock = <ActionHandlerRegistry>{
+            register: vi.fn(),
+            getAll: vi.fn(),
+            getById: vi.fn(),
+        };
+
         const dependencyRegistry = <DependencyRegistry<Dependencies>>{
-            get: vi.fn(),
+            get: vi.fn().mockReturnValue(actionHandlerRegistryMock),
             register: vi.fn(),
         };
 
         CommandlineUtilityModule.bootstrap(dependencyRegistry);
 
         expect(dependencyRegistry.register).toHaveBeenCalledWith("CommandlineUtility", new NodeJsCommandlineUtility());
+
+        expect(dependencyRegistry.get).toBeCalledWith("ActionHandlerRegistry");
+        expect(actionHandlerRegistryMock.register).toHaveBeenCalledWith(
+            new CommandlineActionHandler(new NodeJsCommandlineUtility()),
+        );
     });
 });
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/ExcludeFromSearchResultsActionHandler.test.ts b/src/main/Core/ExcludedSearchResults/ActionHandler/ExcludeFromSearchResultsActionHandler.test.ts
similarity index 91%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/ExcludeFromSearchResultsActionHandler.test.ts
rename to src/main/Core/ExcludedSearchResults/ActionHandler/ExcludeFromSearchResultsActionHandler.test.ts
index 07f8cc8b..b48e4792 100644
--- a/src/main/Core/ActionHandler/DefaultActionHandlers/ExcludeFromSearchResultsActionHandler.test.ts
+++ b/src/main/Core/ExcludedSearchResults/ActionHandler/ExcludeFromSearchResultsActionHandler.test.ts
@@ -1,6 +1,6 @@
-import type { ExcludedSearchResults } from "@Core/ExcludedSearchResults";
 import type { SearchResultItemAction } from "@common/Core";
 import { describe, expect, it, vi } from "vitest";
+import type { ExcludedSearchResults } from "../ExcludedSearchResults";
 import { ExcludeFromSearchResultsActionHandler } from "./ExcludeFromSearchResultsActionHandler";
 
 describe(ExcludeFromSearchResultsActionHandler, () => {
diff --git a/src/main/Core/ActionHandler/DefaultActionHandlers/FavoritesActionHandler.test.ts b/src/main/Core/FavoriteManager/ActionHandler/FavoritesActionHandler.test.ts
similarity index 96%
rename from src/main/Core/ActionHandler/DefaultActionHandlers/FavoritesActionHandler.test.ts
rename to src/main/Core/FavoriteManager/ActionHandler/FavoritesActionHandler.test.ts
index dec02b01..a1512b0d 100644
--- a/src/main/Core/ActionHandler/DefaultActionHandlers/FavoritesActionHandler.test.ts
+++ b/src/main/Core/FavoriteManager/ActionHandler/FavoritesActionHandler.test.ts
@@ -1,6 +1,6 @@
-import type { FavoriteManager } from "@Core/FavoriteManager";
 import type { SearchResultItemAction } from "@common/Core";
 import { describe, expect, it, vi } from "vitest";
+import type { FavoriteManager } from "../FavoriteManager";
 import { FavoritesActionHandler } from "./FavoritesActionHandler";
 
 describe(FavoritesActionHandler, () => {