feat: add notes for creation of apps and integrations in widget edit modal (#1297)
* feat: add notes for creation of apps and integrations in widget edit modal * fix: unit test failing when with-description flag missing
This commit is contained in:
@@ -576,6 +576,7 @@ export default {
|
||||
tryAgain: "Try again",
|
||||
loading: "Loading",
|
||||
},
|
||||
here: "here",
|
||||
iconPicker: {
|
||||
label: "Icon URL",
|
||||
header: "Type name or objects to filter for icons... Homarr will search through {countIcons} icons for you.",
|
||||
@@ -1157,6 +1158,14 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
integration: {
|
||||
noData: "No integration found",
|
||||
description: "Click {here} to create a new integration",
|
||||
},
|
||||
app: {
|
||||
noData: "No app found",
|
||||
description: "Click {here} to create a new app",
|
||||
},
|
||||
error: {
|
||||
action: {
|
||||
logs: "Check logs for more details",
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import { memo, useMemo } from "react";
|
||||
import Link from "next/link";
|
||||
import type { SelectProps } from "@mantine/core";
|
||||
import { Group, Loader, Select } from "@mantine/core";
|
||||
import { Anchor, Group, Loader, Select, Text } from "@mantine/core";
|
||||
import { IconCheck } from "@tabler/icons-react";
|
||||
|
||||
import type { RouterOutputs } from "@homarr/api";
|
||||
import { clientApi } from "@homarr/api/client";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
|
||||
import type { CommonWidgetInputProps } from "./common";
|
||||
import { useWidgetInputTranslation } from "./common";
|
||||
import { useFormContext } from "./form";
|
||||
|
||||
export const WidgetAppInput = ({ property, kind, options }: CommonWidgetInputProps<"app">) => {
|
||||
const t = useWidgetInputTranslation(kind, property);
|
||||
export const WidgetAppInput = ({ property, kind }: CommonWidgetInputProps<"app">) => {
|
||||
const t = useI18n();
|
||||
const tInput = useWidgetInputTranslation(kind, property);
|
||||
const form = useFormContext();
|
||||
const { data: apps, isPending } = clientApi.app.selectable.useQuery();
|
||||
|
||||
@@ -24,10 +27,11 @@ export const WidgetAppInput = ({ property, kind, options }: CommonWidgetInputPro
|
||||
|
||||
return (
|
||||
<Select
|
||||
label={t("label")}
|
||||
label={tInput("label")}
|
||||
searchable
|
||||
limit={10}
|
||||
leftSection={<MemoizedLeftSection isPending={isPending} currentApp={currentApp} />}
|
||||
nothingFoundMessage={t("widget.common.app.noData")}
|
||||
renderOption={renderSelectOption}
|
||||
data={
|
||||
apps?.map((app) => ({
|
||||
@@ -36,7 +40,18 @@ export const WidgetAppInput = ({ property, kind, options }: CommonWidgetInputPro
|
||||
iconUrl: app.iconUrl,
|
||||
})) ?? []
|
||||
}
|
||||
description={options.withDescription ? t("description") : undefined}
|
||||
inputWrapperOrder={["label", "input", "description", "error"]}
|
||||
description={
|
||||
<Text size="xs">
|
||||
{t("widget.common.app.description", {
|
||||
here: (
|
||||
<Anchor size="xs" component={Link} target="_blank" href="/manage/apps/new">
|
||||
{t("common.here")}
|
||||
</Anchor>
|
||||
),
|
||||
})}
|
||||
</Text>
|
||||
}
|
||||
{...form.getInputProps(`options.${property}`)}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -104,10 +104,10 @@ const optionsFactory = {
|
||||
values: [] as string[],
|
||||
validate: input?.validate,
|
||||
}),
|
||||
app: (input?: Omit<CommonInput<string>, "defaultValue">) => ({
|
||||
app: () => ({
|
||||
type: "app" as const,
|
||||
defaultValue: "",
|
||||
withDescription: input?.withDescription ?? false,
|
||||
withDescription: false,
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import type { FocusEventHandler } from "react";
|
||||
import Link from "next/link";
|
||||
import {
|
||||
Anchor,
|
||||
Avatar,
|
||||
CheckIcon,
|
||||
CloseButton,
|
||||
@@ -86,7 +88,23 @@ export const WidgetIntegrationSelect = ({
|
||||
return (
|
||||
<Combobox store={combobox} onOptionSubmit={handleValueSelect} withinPortal={false}>
|
||||
<Combobox.DropdownTarget>
|
||||
<PillsInput pointer onClick={() => combobox.toggleDropdown()} {...props}>
|
||||
<PillsInput
|
||||
inputWrapperOrder={["label", "input", "description", "error"]}
|
||||
description={
|
||||
<Text size="xs">
|
||||
{t("widget.common.integration.description", {
|
||||
here: (
|
||||
<Anchor size="xs" component={Link} target="_blank" href="/manage/integrations">
|
||||
{t("common.here")}
|
||||
</Anchor>
|
||||
),
|
||||
})}
|
||||
</Text>
|
||||
}
|
||||
pointer
|
||||
onClick={() => combobox.toggleDropdown()}
|
||||
{...props}
|
||||
>
|
||||
<Pill.Group>
|
||||
{values.length > 0 ? values : <Input.Placeholder>{t("common.multiSelect.placeholder")}</Input.Placeholder>}
|
||||
|
||||
@@ -108,7 +126,15 @@ export const WidgetIntegrationSelect = ({
|
||||
</Combobox.DropdownTarget>
|
||||
|
||||
<Combobox.Dropdown>
|
||||
<Combobox.Options>{options}</Combobox.Options>
|
||||
<Combobox.Options>
|
||||
{options.length >= 1 ? (
|
||||
options
|
||||
) : (
|
||||
<Text p={4} size="sm" ta="center" c="var(--mantine-color-dimmed)">
|
||||
{t("widget.common.integration.noData")}
|
||||
</Text>
|
||||
)}
|
||||
</Combobox.Options>
|
||||
</Combobox.Dropdown>
|
||||
</Combobox>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user