feat: add context specific search and actions (#1570)

This commit is contained in:
Meier Lukas
2024-12-06 19:07:27 +01:00
committed by GitHub
parent aaa3e7ce0c
commit c840ff85bc
18 changed files with 517 additions and 183 deletions

View File

@@ -8,6 +8,7 @@ import combineClasses from "clsx";
import { clientApi } from "@homarr/api/client";
import { parseAppHrefWithVariablesClient } from "@homarr/common/client";
import { useRegisterSpotlightContextResults } from "@homarr/spotlight";
import { useI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../definition";
@@ -28,6 +29,24 @@ export default function AppWidget({ options, isEditMode }: WidgetComponentProps<
retry: false,
},
);
useRegisterSpotlightContextResults(
`app-${app.id}`,
[
{
id: app.id,
name: app.name,
icon: app.iconUrl,
interaction() {
return {
type: "link",
href: parseAppHrefWithVariablesClient(app.href ?? ""),
newTab: options.openInNewTab,
};
},
},
],
[app, options.openInNewTab],
);
return (
<AppLink

View File

@@ -4,17 +4,36 @@ import { Anchor, Box, Card, Divider, Flex, Group, Stack, Text, Title, UnstyledBu
import type { RouterOutputs } from "@homarr/api";
import { clientApi } from "@homarr/api/client";
import { parseAppHrefWithVariablesClient } from "@homarr/common/client";
import { useRegisterSpotlightContextResults } from "@homarr/spotlight";
import type { WidgetComponentProps } from "../definition";
import classes from "./bookmark.module.css";
export default function BookmarksWidget({ options, width, height }: WidgetComponentProps<"bookmarks">) {
export default function BookmarksWidget({ options, width, height, itemId }: WidgetComponentProps<"bookmarks">) {
const [data] = clientApi.app.byIds.useSuspenseQuery(options.items, {
select(data) {
return data.sort((appA, appB) => options.items.indexOf(appA.id) - options.items.indexOf(appB.id));
},
});
useRegisterSpotlightContextResults(
`bookmark-${itemId}`,
data.map((app) => ({
id: app.id,
name: app.name,
icon: app.iconUrl,
interaction() {
return {
type: "link",
href: parseAppHrefWithVariablesClient(app.href ?? ""),
newTab: false,
};
},
})),
[data],
);
return (
<Stack h="100%" gap="sm" p="sm">
<Title order={4} px="0.25rem">

View File

@@ -2,8 +2,10 @@
import { useCallback } from "react";
import { Center, Stack, Text, UnstyledButton } from "@mantine/core";
import { IconBinaryTree } from "@tabler/icons-react";
import { clientApi } from "@homarr/api/client";
import { useRegisterSpotlightContextActions } from "@homarr/spotlight";
import type { WidgetComponentProps } from "../../definition";
import { NoIntegrationSelectedError } from "../../errors";
@@ -60,6 +62,27 @@ const InnerComponent = ({ options, integrationId, isEditMode }: InnerComponentPr
});
}, [integrationId, isEditMode, mutate, options.clickable, options.entityId]);
useRegisterSpotlightContextActions(
`smartHome-entityState-${options.entityId}`,
[
{
id: options.entityId,
name: options.displayName,
icon: IconBinaryTree,
interaction() {
return {
type: "javaScript",
onSelect() {
handleClick();
},
};
},
disabled: !options.clickable,
},
],
[handleClick, options.clickable, options.displayName, options.entityId],
);
return (
<UnstyledButton
onClick={handleClick}

View File

@@ -6,6 +6,8 @@ import { useDisclosure, useTimeout } from "@mantine/hooks";
import { IconAutomation, IconCheck } from "@tabler/icons-react";
import { clientApi } from "@homarr/api/client";
import { useRegisterSpotlightContextActions } from "@homarr/spotlight";
import { useI18n } from "@homarr/translation/client";
import type { WidgetComponentProps } from "../../definition";
@@ -34,6 +36,29 @@ export default function SmartHomeTriggerAutomationWidget({
integrationId: integrationIds[0] ?? "",
});
}, [integrationIds, isEditMode, mutateAsync, options.automationId]);
const t = useI18n();
useRegisterSpotlightContextActions(
`smartHome-automation-${options.automationId}`,
[
{
id: options.automationId,
name: t("widget.smartHome-executeAutomation.spotlightAction.run", { name: options.displayName }),
icon: IconAutomation,
interaction() {
return {
type: "javaScript",
// eslint-disable-next-line no-restricted-syntax
async onSelect() {
await handleClick();
},
};
},
},
],
[handleClick, options.automationId, options.displayName],
);
return (
<UnstyledButton onClick={handleClick} style={{ cursor: !isEditMode ? "pointer" : "initial" }} w="100%" h="100%">
{isShowSuccess && (