feat(integrations): add app linking (#4338)
This commit is contained in:
@@ -2,6 +2,7 @@ import { useMemo, useState } from "react";
|
||||
import { Button, Card, Center, Grid, Input, Stack, Text } from "@mantine/core";
|
||||
import { IconPlus, IconSearch } from "@tabler/icons-react";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { createModal, useModalAction } from "@homarr/modals";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
@@ -9,7 +10,8 @@ import { useI18n } from "@homarr/translation/client";
|
||||
import { QuickAddAppModal } from "./quick-add-app/quick-add-app-modal";
|
||||
|
||||
interface AppSelectModalProps {
|
||||
onSelect?: (appId: string) => void;
|
||||
onSelect?: (app: RouterOutputs["app"]["selectable"][number]) => void;
|
||||
withCreate: boolean;
|
||||
}
|
||||
|
||||
export const AppSelectModal = createModal<AppSelectModalProps>(({ actions, innerProps }) => {
|
||||
@@ -26,18 +28,18 @@ export const AppSelectModal = createModal<AppSelectModalProps>(({ actions, inner
|
||||
[apps, search],
|
||||
);
|
||||
|
||||
const handleSelect = (appId: string) => {
|
||||
const handleSelect = (app: RouterOutputs["app"]["selectable"][number]) => {
|
||||
if (innerProps.onSelect) {
|
||||
innerProps.onSelect(appId);
|
||||
innerProps.onSelect(app);
|
||||
}
|
||||
actions.closeModal();
|
||||
};
|
||||
|
||||
const handleAddNewApp = () => {
|
||||
openQuickAddAppModal({
|
||||
onClose(createdAppId) {
|
||||
onClose(app) {
|
||||
if (innerProps.onSelect) {
|
||||
innerProps.onSelect(createdAppId);
|
||||
innerProps.onSelect(app);
|
||||
}
|
||||
actions.closeModal();
|
||||
},
|
||||
@@ -54,32 +56,34 @@ export const AppSelectModal = createModal<AppSelectModalProps>(({ actions, inner
|
||||
data-autofocus
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" && filteredApps.length === 1 && filteredApps[0]) {
|
||||
handleSelect(filteredApps[0].id);
|
||||
handleSelect(filteredApps[0]);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<Grid>
|
||||
<Grid.Col span={{ xs: 12, sm: 4, md: 3 }}>
|
||||
<Card h="100%">
|
||||
<Stack justify="space-between" h="100%">
|
||||
<Stack gap="xs">
|
||||
<Center>
|
||||
<IconPlus size={24} />
|
||||
</Center>
|
||||
<Text lh={1.2} style={{ whiteSpace: "normal" }} ta="center">
|
||||
{t("app.action.create.title")}
|
||||
</Text>
|
||||
<Text lh={1.2} style={{ whiteSpace: "normal" }} size="xs" ta="center" c="dimmed">
|
||||
{t("app.action.create.description")}
|
||||
</Text>
|
||||
{innerProps.withCreate && (
|
||||
<Grid.Col span={{ xs: 12, sm: 4, md: 3 }}>
|
||||
<Card h="100%">
|
||||
<Stack justify="space-between" h="100%">
|
||||
<Stack gap="xs">
|
||||
<Center>
|
||||
<IconPlus size={24} />
|
||||
</Center>
|
||||
<Text lh={1.2} style={{ whiteSpace: "normal" }} ta="center">
|
||||
{t("app.action.create.title")}
|
||||
</Text>
|
||||
<Text lh={1.2} style={{ whiteSpace: "normal" }} size="xs" ta="center" c="dimmed">
|
||||
{t("app.action.create.description")}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Button onClick={handleAddNewApp} variant="light" size="xs" mt="auto" radius="md" fullWidth>
|
||||
{t("app.action.create.action")}
|
||||
</Button>
|
||||
</Stack>
|
||||
<Button onClick={handleAddNewApp} variant="light" size="xs" mt="auto" radius="md" fullWidth>
|
||||
{t("app.action.create.action")}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
)}
|
||||
|
||||
{filteredApps.map((app) => (
|
||||
<Grid.Col key={app.id} span={{ xs: 12, sm: 4, md: 3 }}>
|
||||
@@ -96,7 +100,7 @@ export const AppSelectModal = createModal<AppSelectModalProps>(({ actions, inner
|
||||
{app.description ?? ""}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Button onClick={() => handleSelect(app.id)} variant="light" size="xs" mt="auto" radius="md" fullWidth>
|
||||
<Button onClick={() => handleSelect(app)} variant="light" size="xs" mt="auto" radius="md" fullWidth>
|
||||
{t("app.action.select.action", { app: app.name })}
|
||||
</Button>
|
||||
</Stack>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { z } from "zod/v4";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import type { MaybePromise } from "@homarr/common/types";
|
||||
import { AppForm } from "@homarr/forms-collection";
|
||||
@@ -9,7 +10,7 @@ import { useI18n, useScopedI18n } from "@homarr/translation/client";
|
||||
import type { appManageSchema } from "@homarr/validation/app";
|
||||
|
||||
interface QuickAddAppModalProps {
|
||||
onClose: (createdAppId: string) => MaybePromise<void>;
|
||||
onClose: (createdApp: Omit<RouterOutputs["app"]["create"], "appId">) => MaybePromise<void>;
|
||||
}
|
||||
|
||||
export const QuickAddAppModal = createModal<QuickAddAppModalProps>(({ actions, innerProps }) => {
|
||||
@@ -27,13 +28,13 @@ export const QuickAddAppModal = createModal<QuickAddAppModalProps>(({ actions, i
|
||||
|
||||
const handleSubmit = (values: z.infer<typeof appManageSchema>) => {
|
||||
mutate(values, {
|
||||
async onSuccess({ appId }) {
|
||||
async onSuccess(app) {
|
||||
showSuccessNotification({
|
||||
title: tScoped("success.title"),
|
||||
message: tScoped("success.message"),
|
||||
});
|
||||
|
||||
await innerProps.onClose(appId);
|
||||
await innerProps.onClose(app);
|
||||
actions.closeModal();
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user