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:
Meier Lukas
2024-09-20 16:51:42 +02:00
committed by GitHub
parent 0c44af2f67
commit ce1ef3cbe7
64 changed files with 1985 additions and 628 deletions

View 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;

View 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);
},
});