feat: add app actions (#322)
* feat: add app actions * fix: broken lockfile * fix: app should only load when one is selected and server data not fail when no app found * fix: add missing dependency * fix: format issue
This commit is contained in:
@@ -5,7 +5,7 @@ import useDeepCompareEffect from "use-deep-compare-effect";
|
|||||||
import type { SpotlightActionData, SpotlightActionGroup } from "./type";
|
import type { SpotlightActionData, SpotlightActionGroup } from "./type";
|
||||||
|
|
||||||
const defaultGroups = ["all", "web", "action"] as const;
|
const defaultGroups = ["all", "web", "action"] as const;
|
||||||
const reversedDefaultGroups = [...defaultGroups].reverse();
|
const reversedDefaultGroups = [...defaultGroups].reverse() as string[];
|
||||||
const actionsAtom = atom<Record<string, readonly SpotlightActionData[]>>({});
|
const actionsAtom = atom<Record<string, readonly SpotlightActionData[]>>({});
|
||||||
export const actionsAtomRead = atom((get) =>
|
export const actionsAtomRead = atom((get) =>
|
||||||
Object.values(get(actionsAtom)).flatMap((item) => item),
|
Object.values(get(actionsAtom)).flatMap((item) => item),
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ export default {
|
|||||||
all: "All",
|
all: "All",
|
||||||
web: "Web",
|
web: "Web",
|
||||||
action: "Actions",
|
action: "Actions",
|
||||||
|
app: "Apps",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
userAvatar: {
|
userAvatar: {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
"@homarr/form": "workspace:^0.1.0",
|
"@homarr/form": "workspace:^0.1.0",
|
||||||
"@homarr/modals": "workspace:^0.1.0",
|
"@homarr/modals": "workspace:^0.1.0",
|
||||||
"@homarr/notifications": "workspace:^0.1.0",
|
"@homarr/notifications": "workspace:^0.1.0",
|
||||||
|
"@homarr/spotlight": "workspace:^0.1.0",
|
||||||
"@homarr/redis": "workspace:^0.1.0",
|
"@homarr/redis": "workspace:^0.1.0",
|
||||||
"@homarr/translation": "workspace:^0.1.0",
|
"@homarr/translation": "workspace:^0.1.0",
|
||||||
"@homarr/ui": "workspace:^0.1.0",
|
"@homarr/ui": "workspace:^0.1.0",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import type { PropsWithChildren } from "react";
|
import type { PropsWithChildren } from "react";
|
||||||
|
|
||||||
import { clientApi } from "@homarr/api/client";
|
import { clientApi } from "@homarr/api/client";
|
||||||
|
import { useRegisterSpotlightActions } from "@homarr/spotlight";
|
||||||
import { useScopedI18n } from "@homarr/translation/client";
|
import { useScopedI18n } from "@homarr/translation/client";
|
||||||
import {
|
import {
|
||||||
Center,
|
Center,
|
||||||
@@ -26,6 +27,7 @@ export default function AppWidget({
|
|||||||
height,
|
height,
|
||||||
}: WidgetComponentProps<"app">) {
|
}: WidgetComponentProps<"app">) {
|
||||||
const t = useScopedI18n("widget.app");
|
const t = useScopedI18n("widget.app");
|
||||||
|
const isQueryEnabled = Boolean(options.appId);
|
||||||
const {
|
const {
|
||||||
data: app,
|
data: app,
|
||||||
isPending,
|
isPending,
|
||||||
@@ -37,14 +39,34 @@ export default function AppWidget({
|
|||||||
{
|
{
|
||||||
initialData:
|
initialData:
|
||||||
// We need to check if the id's match because otherwise the same initialData for a changed id will be used
|
// We need to check if the id's match because otherwise the same initialData for a changed id will be used
|
||||||
serverData?.app.id === options.appId ? serverData?.app : undefined,
|
serverData?.app?.id === options.appId ? serverData?.app : undefined,
|
||||||
refetchOnMount: false,
|
refetchOnMount: false,
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
refetchOnReconnect: false,
|
refetchOnReconnect: false,
|
||||||
|
enabled: isQueryEnabled,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isPending) {
|
useRegisterSpotlightActions(
|
||||||
|
`app-${options.appId}`,
|
||||||
|
app?.href
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
id: `app-${options.appId}`,
|
||||||
|
title: app?.name,
|
||||||
|
description: app?.description ?? "",
|
||||||
|
icon: app?.iconUrl,
|
||||||
|
group: "app",
|
||||||
|
type: "link",
|
||||||
|
href: app?.href,
|
||||||
|
openInNewTab: options.openInNewTab,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [],
|
||||||
|
[app, options.appId, options.openInNewTab],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isPending && isQueryEnabled) {
|
||||||
return (
|
return (
|
||||||
<Center h="100%">
|
<Center h="100%">
|
||||||
<Loader />
|
<Loader />
|
||||||
@@ -52,7 +74,7 @@ export default function AppWidget({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isError) {
|
if (isError || !isQueryEnabled) {
|
||||||
return (
|
return (
|
||||||
<Tooltip.Floating label={t("error.notFound.tooltip")}>
|
<Tooltip.Floating label={t("error.notFound.tooltip")}>
|
||||||
<Stack gap="xs" align="center" justify="center" h="100%" w="100%">
|
<Stack gap="xs" align="center" justify="center" h="100%" w="100%">
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ import { api } from "@homarr/api/server";
|
|||||||
import type { WidgetProps } from "../definition";
|
import type { WidgetProps } from "../definition";
|
||||||
|
|
||||||
export default async function getServerData({ options }: WidgetProps<"app">) {
|
export default async function getServerData({ options }: WidgetProps<"app">) {
|
||||||
const app = await api.app.byId({ id: options.appId });
|
try {
|
||||||
return { app };
|
const app = await api.app.byId({ id: options.appId });
|
||||||
|
return { app };
|
||||||
|
} catch (error) {
|
||||||
|
return { app: null };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -804,6 +804,9 @@ importers:
|
|||||||
'@homarr/redis':
|
'@homarr/redis':
|
||||||
specifier: workspace:^0.1.0
|
specifier: workspace:^0.1.0
|
||||||
version: link:../redis
|
version: link:../redis
|
||||||
|
'@homarr/spotlight':
|
||||||
|
specifier: workspace:^0.1.0
|
||||||
|
version: link:../spotlight
|
||||||
'@homarr/translation':
|
'@homarr/translation':
|
||||||
specifier: workspace:^0.1.0
|
specifier: workspace:^0.1.0
|
||||||
version: link:../translation
|
version: link:../translation
|
||||||
|
|||||||
Reference in New Issue
Block a user