From 8a0c438a7d99ce5a9cc72f5c88bcaeaa1261e194 Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Sat, 30 May 2026 00:56:24 +0200 Subject: [PATCH] fix(spotlight): add media mode to Modes list and remove from search results Media request search now appears in the Modes section (with no keyboard shortcut) instead of being mixed into search results when typing. Changed keyPath from 'character' to 'modeKey' to support modes without a trigger character. Removed the mediaRequestSearchEntry from home search results since it is now accessible via the Modes list. --- .../src/modes/help/home-empty-groups.tsx | 7 ++- .../modes/home/home-search-engine-group.tsx | 61 ++++--------------- 2 files changed, 16 insertions(+), 52 deletions(-) diff --git a/packages/spotlight/src/modes/help/home-empty-groups.tsx b/packages/spotlight/src/modes/help/home-empty-groups.tsx index e035e66b9..28933696b 100644 --- a/packages/spotlight/src/modes/help/home-empty-groups.tsx +++ b/packages/spotlight/src/modes/help/home-empty-groups.tsx @@ -19,6 +19,7 @@ import type { SearchMode } from "../../lib/mode"; import { appIntegrationBoardMode } from "../app-integration-board"; import { commandMode } from "../command"; import { externalMode } from "../external"; +import { mediaMode } from "../media"; import { pageMode } from "../page"; import { userGroupMode } from "../user-group"; @@ -33,7 +34,7 @@ type QuickLinkOption = { export const useHomeEmptyGroups = () => { const { data: session } = useSession(); const tPages = useScopedI18n("search.mode.page.group.page.option"); - const visibleSearchModes: SearchMode[] = [appIntegrationBoardMode, externalMode, commandMode, pageMode]; + const visibleSearchModes: SearchMode[] = [appIntegrationBoardMode, externalMode, mediaMode, commandMode, pageMode]; if (session?.user.permissions.includes("admin")) { visibleSearchModes.unshift(userGroupMode); @@ -87,7 +88,7 @@ export const useHomeEmptyGroups = () => { useInteraction: interaction.link(({ path }) => ({ href: path })), }), createGroup({ - keyPath: "character", + keyPath: "modeKey", title: (t) => t("search.mode.help.group.mode.title"), options: visibleSearchModes.map(({ character, modeKey }) => ({ character, modeKey })), Component: ({ modeKey, character }) => { @@ -96,7 +97,7 @@ export const useHomeEmptyGroups = () => { return ( {t("help")} - {character} + {character && {character}} ); }, diff --git a/packages/spotlight/src/modes/home/home-search-engine-group.tsx b/packages/spotlight/src/modes/home/home-search-engine-group.tsx index 4aff71a52..0bd304e23 100644 --- a/packages/spotlight/src/modes/home/home-search-engine-group.tsx +++ b/packages/spotlight/src/modes/home/home-search-engine-group.tsx @@ -1,5 +1,5 @@ import { Box, Group, Stack, Text } from "@mantine/core"; -import { IconMovie, IconSearch, IconSearchOff } from "@tabler/icons-react"; +import { IconSearch, IconSearchOff } from "@tabler/icons-react"; import type { RouterOutputs } from "@homarr/api"; import { clientApi } from "@homarr/api/client"; @@ -64,10 +64,6 @@ export const homeSearchEngineGroup = createGroup({ clientApi.searchEngine.getDefaultSearchEngine.useQuery(undefined, { enabled: status !== "loading", }); - const { data: mediaRequestSearchTargets, ...mediaRequestSearchTargetsQuery } = - clientApi.integration.mediaRequestSearchTargets.useQuery(undefined, { - enabled: status !== "loading" && session?.user !== undefined, - }); const fromIntegrationEnabled = defaultSearchEngine?.type === "fromIntegration" && query.length > 0; const { data: results, ...resultQuery } = clientApi.integration.searchInIntegration.useQuery( { @@ -83,14 +79,12 @@ export const homeSearchEngineGroup = createGroup({ return { isLoading: defaultSearchEngineQuery.isLoading || - mediaRequestSearchTargetsQuery.isLoading || (resultQuery.isLoading && fromIntegrationEnabled) || status === "loading", isError: defaultSearchEngineQuery.isError || - mediaRequestSearchTargetsQuery.isError || (resultQuery.isError && fromIntegrationEnabled), - data: createDefaultSearchEntries(defaultSearchEngine, results, mediaRequestSearchTargets, session, query, t), + data: createDefaultSearchEntries(defaultSearchEngine, results, session, query, t), }; }, }); @@ -98,40 +92,14 @@ export const homeSearchEngineGroup = createGroup({ const createDefaultSearchEntries = ( defaultSearchEngine: RouterOutputs["searchEngine"]["getDefaultSearchEngine"] | null, results: RouterOutputs["integration"]["searchInIntegration"] | undefined, - mediaRequestSearchTargets: RouterOutputs["integration"]["mediaRequestSearchTargets"] | undefined, session: Session | null, query: string, t: TranslationFunction, ): GroupItem[] => { - const mediaRequestSearchEntry: GroupItem = { - id: "media-request-search", - name: t("search.mode.media.action.search.label"), - description: - mediaRequestSearchTargets && mediaRequestSearchTargets.length === 0 - ? t("search.mode.media.action.search.disabled.noIntegration") - : t("search.mode.media.action.search.description"), - icon: IconMovie, - disabled: !mediaRequestSearchTargets || mediaRequestSearchTargets.length === 0, - useInteraction(query) { - if (!mediaRequestSearchTargets || mediaRequestSearchTargets.length === 0) { - return { - type: "none", - }; - } - - return { - type: "mode", - mode: "media", - query, - }; - }, - }; - - if (!session?.user && !defaultSearchEngine) return [mediaRequestSearchEntry]; + if (!session?.user && !defaultSearchEngine) return []; if (!defaultSearchEngine) { return [ - mediaRequestSearchEntry, { id: "no-default", name: t("search.mode.home.group.search.option.no-default.label"), @@ -150,7 +118,6 @@ const createDefaultSearchEntries = ( if (defaultSearchEngine.type === "generic") { return [ - mediaRequestSearchEntry, { id: "search", name: t("search.mode.home.group.search.option.search.label", { @@ -173,7 +140,6 @@ const createDefaultSearchEntries = ( if (!results) { return [ - mediaRequestSearchEntry, { id: "from-integration", name: defaultSearchEngine.name, @@ -188,16 +154,13 @@ const createDefaultSearchEntries = ( ]; } - return [ - mediaRequestSearchEntry, - ...results.map((result) => ({ - id: `search-${result.id}`, - name: result.name, - description: result.text, - icon: result.image ?? IconSearch, - useInteraction() { - return useFromIntegrationSearchInteraction(defaultSearchEngine, result); - }, - })), - ]; + return results.map((result) => ({ + id: `search-${result.id}`, + name: result.name, + description: result.text, + icon: result.image ?? IconSearch, + useInteraction() { + return useFromIntegrationSearchInteraction(defaultSearchEngine, result); + }, + })); };