feat: add improved search (#1051)
* feat: add improved search * wip: add support for sorting, rename use-options to use-query-options, add use-options for local usage, add pages search group * feat: add help links from manage layout to help search mode * feat: add additional search engines * feat: add group search details * refactor: improve users search group type * feat: add apps search group, add disabled search interaction * feat: add integrations and boards for search * wip: hook issue with react * fix: hook issue regarding actions and interactions * chore: address pull request feedback * fix: format issues * feat: add additional global actions to search * chore: remove unused code * fix: search engine short key * fix: typecheck issues * fix: deepsource issues * fix: eslint issue * fix: lint issues * fix: unordered dependencies * chore: address pull request feedback
This commit is contained in:
8
packages/spotlight/src/modes/page/index.tsx
Normal file
8
packages/spotlight/src/modes/page/index.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { SearchMode } from "../../lib/mode";
|
||||
import { pagesSearchGroup } from "./pages-search-group";
|
||||
|
||||
export const pageMode = {
|
||||
modeKey: "page",
|
||||
character: "/",
|
||||
groups: [pagesSearchGroup],
|
||||
} satisfies SearchMode;
|
||||
156
packages/spotlight/src/modes/page/pages-search-group.tsx
Normal file
156
packages/spotlight/src/modes/page/pages-search-group.tsx
Normal file
@@ -0,0 +1,156 @@
|
||||
import { Group, Text } from "@mantine/core";
|
||||
import {
|
||||
IconBox,
|
||||
IconBrandDocker,
|
||||
IconHome,
|
||||
IconInfoSmall,
|
||||
IconLayoutDashboard,
|
||||
IconLogs,
|
||||
IconMailForward,
|
||||
IconPlug,
|
||||
IconReport,
|
||||
IconSettings,
|
||||
IconUsers,
|
||||
IconUsersGroup,
|
||||
} from "@tabler/icons-react";
|
||||
|
||||
import { useSession } from "@homarr/auth/client";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
import type { TablerIcon } from "@homarr/ui";
|
||||
|
||||
import { createGroup } from "../../lib/group";
|
||||
import { interaction } from "../../lib/interaction";
|
||||
|
||||
export const pagesSearchGroup = createGroup<{
|
||||
icon: TablerIcon;
|
||||
name: string;
|
||||
path: string;
|
||||
}>({
|
||||
keyPath: "path",
|
||||
title: (t) => t("search.mode.page.group.page.title"),
|
||||
component: ({ name, icon: Icon }) => (
|
||||
<Group px="md" py="sm">
|
||||
<Icon stroke={1.5} />
|
||||
<Text>{name}</Text>
|
||||
</Group>
|
||||
),
|
||||
useInteraction: interaction.link(({ path }) => ({ href: path })),
|
||||
filter: (query, { name, path }) => {
|
||||
const normalizedQuery = query.trim().toLowerCase();
|
||||
return name.toLowerCase().includes(normalizedQuery) || path.toLowerCase().includes(normalizedQuery);
|
||||
},
|
||||
sort: (query, options) => {
|
||||
const normalizedQuery = query.trim().toLowerCase();
|
||||
|
||||
const nameMatches = options.map((option) => option.name.toLowerCase().includes(normalizedQuery));
|
||||
const pathMatches = options.map((option) => option.path.toLowerCase().includes(normalizedQuery));
|
||||
|
||||
if (nameMatches.every(Boolean) && pathMatches.every(Boolean)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nameMatches.every(Boolean) && !pathMatches.every(Boolean)) {
|
||||
return pathMatches[0] ? -1 : 1;
|
||||
}
|
||||
|
||||
return nameMatches[0] ? -1 : 1;
|
||||
},
|
||||
useOptions() {
|
||||
const { data: session } = useSession();
|
||||
const t = useScopedI18n("search.mode.page.group.page.option");
|
||||
|
||||
const managePages = [
|
||||
{
|
||||
icon: IconHome,
|
||||
path: "/manage",
|
||||
name: t("manageHome.label"),
|
||||
},
|
||||
{
|
||||
icon: IconLayoutDashboard,
|
||||
path: "/manage/boards",
|
||||
name: t("manageBoard.label"),
|
||||
},
|
||||
{
|
||||
icon: IconBox,
|
||||
path: "/manage/apps",
|
||||
name: t("manageApp.label"),
|
||||
hidden: !session,
|
||||
},
|
||||
{
|
||||
icon: IconPlug,
|
||||
path: "/manage/integrations",
|
||||
name: t("manageIntegration.label"),
|
||||
hidden: !session,
|
||||
},
|
||||
{
|
||||
icon: IconUsers,
|
||||
path: "/manage/users",
|
||||
name: t("manageUser.label"),
|
||||
hidden: !session,
|
||||
},
|
||||
{
|
||||
icon: IconMailForward,
|
||||
path: "/manage/users/invites",
|
||||
name: t("manageInvite.label"),
|
||||
hidden: !session?.user.permissions.includes("admin"),
|
||||
},
|
||||
{
|
||||
icon: IconUsersGroup,
|
||||
path: "/manage/users/groups",
|
||||
name: t("manageGroup.label"),
|
||||
hidden: !session,
|
||||
},
|
||||
{
|
||||
icon: IconBrandDocker,
|
||||
path: "/manage/tools/docker",
|
||||
name: "Manage Docker",
|
||||
hidden: !session?.user.permissions.includes("admin"),
|
||||
},
|
||||
{
|
||||
icon: IconPlug,
|
||||
path: "/manage/tools/api",
|
||||
name: t("manageApi.label"),
|
||||
hidden: !session,
|
||||
},
|
||||
{
|
||||
icon: IconLogs,
|
||||
path: "/manage/tools/logs",
|
||||
name: t("manageLog.label"),
|
||||
hidden: !session?.user.permissions.includes("admin"),
|
||||
},
|
||||
{
|
||||
icon: IconReport,
|
||||
path: "/manage/tools/tasks",
|
||||
name: t("manageTask.label"),
|
||||
hidden: !session?.user.permissions.includes("admin"),
|
||||
},
|
||||
{
|
||||
icon: IconSettings,
|
||||
path: "/manage/settings",
|
||||
name: t("manageSettings.label"),
|
||||
hidden: !session?.user.permissions.includes("admin"),
|
||||
},
|
||||
{
|
||||
icon: IconInfoSmall,
|
||||
path: "/manage/about",
|
||||
name: t("about.label"),
|
||||
},
|
||||
];
|
||||
|
||||
const otherPages = [
|
||||
{
|
||||
icon: IconHome,
|
||||
path: "/boards",
|
||||
name: t("homeBoard.label"),
|
||||
},
|
||||
{
|
||||
icon: IconSettings,
|
||||
path: `/manage/users/${session?.user.id}/general`,
|
||||
name: t("preferences.label"),
|
||||
hidden: !session,
|
||||
},
|
||||
];
|
||||
|
||||
return otherPages.concat(managePages).filter(({ hidden }) => !hidden);
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user