diff --git a/apps/web/core/components/navigation/top-nav-power-k.tsx b/apps/web/core/components/navigation/top-nav-power-k.tsx index 22825d4b7e3..af3e1d2651c 100644 --- a/apps/web/core/components/navigation/top-nav-power-k.tsx +++ b/apps/web/core/components/navigation/top-nav-power-k.tsx @@ -14,6 +14,7 @@ import { cn } from "@plane/utils"; // power-k import type { TPowerKCommandConfig, TPowerKContext } from "@/components/power-k/core/types"; import { ProjectsAppPowerKCommandsList } from "@/components/power-k/ui/modal/commands-list"; +import { powerKCommandFilter } from "@/components/power-k/ui/modal/filter"; import { PowerKModalFooter } from "@/components/power-k/ui/modal/footer"; import { useIssueDetail } from "@/hooks/store/use-issue-detail"; import { usePowerK } from "@/hooks/store/use-power-k"; @@ -256,11 +257,7 @@ export const TopNavPowerK = observer(() => { > {isOpen && ( { - if (i18nValue === "no-results") return 1; - if (i18nValue.toLowerCase().includes(search.toLowerCase())) return 1; - return 0; - }} + filter={powerKCommandFilter} shouldFilter={searchTerm.length > 0} className="flex h-full w-full flex-col" > diff --git a/apps/web/core/components/power-k/ui/modal/filter.ts b/apps/web/core/components/power-k/ui/modal/filter.ts new file mode 100644 index 00000000000..160643df6fa --- /dev/null +++ b/apps/web/core/components/power-k/ui/modal/filter.ts @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2023-present Plane Software, Inc. and contributors + * SPDX-License-Identifier: AGPL-3.0-only + * See the LICENSE file for details. + */ + +/** + * Prefix marking a `Command.Item` whose match was decided by the search API + * rather than by the text cmdk can see. + */ +export const POWER_K_SERVER_RESULT_PREFIX = "server-result:"; + +/** + * Filter for the Power-K palette. + * + * Static commands still match on their visible label. Server-driven search + * results are passed through untouched: the API matched them against fields + * the palette never renders — a work item's description, for one — so + * re-filtering here on the visible title would silently discard exactly the + * results the search was meant to surface. It would also drop multi-word + * matches whose words are not adjacent in the title, since this is a + * contiguous substring test. + */ +export const powerKCommandFilter = (value: string, search: string): number => { + if (value === "no-results") return 1; + if (value.startsWith(POWER_K_SERVER_RESULT_PREFIX)) return 1; + return value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0; +}; diff --git a/apps/web/core/components/power-k/ui/modal/search-results.tsx b/apps/web/core/components/power-k/ui/modal/search-results.tsx index eaa5eb9b876..c6e51bed8d4 100644 --- a/apps/web/core/components/power-k/ui/modal/search-results.tsx +++ b/apps/web/core/components/power-k/ui/modal/search-results.tsx @@ -13,6 +13,7 @@ import type { IWorkspaceSearchResults } from "@plane/types"; import { useAppRouter } from "@/hooks/use-app-router"; // helpers import { PowerKModalCommandItem } from "./command-item"; +import { POWER_K_SERVER_RESULT_PREFIX } from "./filter"; import { POWER_K_SEARCH_RESULTS_GROUPS_MAP } from "./search-results-map"; type Props = { @@ -40,7 +41,7 @@ export const PowerKModalSearchResults = observer(function PowerKModalSearchResul return ( {section.map((item) => { - let value = `${key}-${item?.id}-${item.name}`; + let value = `${POWER_K_SERVER_RESULT_PREFIX}${key}-${item?.id}-${item.name}`; if ("project__identifier" in item) { value = `${value}-${item.project__identifier}`; diff --git a/apps/web/core/components/power-k/ui/modal/wrapper.tsx b/apps/web/core/components/power-k/ui/modal/wrapper.tsx index 0c2a0c9b15c..8250cf0fa05 100644 --- a/apps/web/core/components/power-k/ui/modal/wrapper.tsx +++ b/apps/web/core/components/power-k/ui/modal/wrapper.tsx @@ -13,6 +13,7 @@ import { usePowerK } from "@/hooks/store/use-power-k"; // local imports import type { TPowerKCommandConfig, TPowerKContext } from "../../core/types"; import type { TPowerKCommandsListProps } from "./commands-list"; +import { powerKCommandFilter } from "./filter"; import { PowerKModalFooter } from "./footer"; import { PowerKModalHeader } from "./header"; @@ -145,11 +146,7 @@ export const ProjectsAppPowerKModalWrapper = observer(function ProjectsAppPowerK > { - if (i18nValue === "no-results") return 1; - if (i18nValue.toLowerCase().includes(search.toLowerCase())) return 1; - return 0; - }} + filter={powerKCommandFilter} shouldFilter={searchTerm.length > 0} onKeyDown={handleKeyDown} className="w-full"