"use client"; import { useMemo, useState } from "react"; import { Alert, Anchor, Avatar, Badge, Combobox, Group, InputBase, Loader, Stack, Text, useCombobox, } from "@mantine/core"; import { IconAlertTriangle, IconApi } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { useSession } from "@homarr/auth/client"; import { useOptionalBoard } from "@homarr/boards/context"; import { useScopedI18n } from "@homarr/translation/client"; import { Link } from "@homarr/ui"; import type { CommonWidgetInputProps } from "./common"; import { useWidgetInputTranslation } from "./common"; import { useFormContext } from "./form"; export const WidgetCustomWidgetSelectInput = ({ property, kind, options, }: CommonWidgetInputProps<"customWidgetSelect">) => { const t = useWidgetInputTranslation(kind, property); const labels = useScopedI18n("widget.customApi.picker"); const { data: session } = useSession(); const isAdmin = session?.user.permissions.includes("admin") ?? false; const form = useFormContext(); const board = useOptionalBoard(); const currentValue = form.values.options[property] as string; const { data, isLoading } = clientApi.customWidget.available.useQuery( { boardId: board?.id ?? "", currentId: currentValue || undefined }, { enabled: board !== null }, ); const [search, setSearch] = useState(""); const definitions = useMemo( () => (data ?? []).map((definition) => ({ ...definition, value: definition.id, label: definition.name })), [data], ); const filteredOptions = useMemo( () => definitions.filter( (def) => def.label.toLowerCase().includes(search.toLowerCase()) || def.value.toLowerCase().includes(search.toLowerCase()), ), [definitions, search], ); const selectedDefinition = definitions.find((definition) => definition.value === currentValue); const selectedLabel = selectedDefinition?.label; const combobox = useCombobox({ onDropdownClose: () => { combobox.resetSelectedOption(); setSearch(""); }, }); return ( { const definition = definitions.find((candidate) => candidate.value === val); if (!definition || definition.migrationRequired) return; form.setFieldValue(`options.${property}`, val); form.setFieldValue("options.configuration", definition?.defaultOptions ?? {}); form.setFieldValue( "options.configurationVersion", definition?.updatedAt instanceof Date ? definition.updatedAt.getTime() : Date.now(), ); combobox.closeDropdown(); }} > : } rightSectionPointerEvents="none" value={combobox.dropdownOpened ? search : (selectedLabel ?? currentValue)} onChange={(event) => { setSearch(event.currentTarget.value); combobox.openDropdown(); combobox.updateSelectedOptionIndex(); }} onClick={() => combobox.openDropdown()} onFocus={() => combobox.openDropdown()} onBlur={() => combobox.closeDropdown()} placeholder={t("label")} /> {filteredOptions.map((def) => ( {def.label} {def.description && ( {def.description} )} {def.migrationRequired && ( {labels("migrationRequired")} )} {labels("sources", { count: def.sources.length })} {labels("requests", { count: def.requestCapabilities.length })} ))} {filteredOptions.length === 0 && !isLoading && {labels("empty")}} {selectedDefinition?.migrationRequired && ( } title={labels("migrationRequired")} > {labels("migrationDescription")} {isAdmin ? ( {labels("manageMigration")} ) : ( {labels("contactAdmin")} )} )} ); };