import { FunctionComponent, useCallback, useMemo, useRef, useState, } from "react"; import { AutocompleteProps, Button, Divider, Group, SimpleGrid, Stack, Text as MantineText, } from "@mantine/core"; import { useForm } from "@mantine/form"; import { capitalize } from "lodash"; import { Selector } from "@/components"; import { useModals, withModal } from "@/modules/modals"; import { Card, Check, Chips, Message, Password, ProviderTestButton, Selector as GlobalSelector, Text, } from "@/pages/Settings/components"; import { FormContext, FormValues, runHooks, useFormActions, useStagedValues, } from "@/pages/Settings/utilities/FormValues"; import { useSettingValue } from "@/pages/Settings/utilities/hooks"; import { SettingsProvider, useSettings, } from "@/pages/Settings/utilities/SettingsProvider"; import { BuildKey, useSelectorOptions } from "@/utilities"; import { ASSERT } from "@/utilities/console"; import { ProviderInfo } from "./list"; type SettingsKey = | "settings-general-enabled_providers" | "settings-general-enabled_integrations"; interface ProviderViewProps { availableOptions: Readonly; settingsKey: SettingsKey; } interface ProviderSelect { value: string; payload: ProviderInfo; } export const ProviderView: FunctionComponent = ({ availableOptions, settingsKey, }) => { const settings = useSettings(); const staged = useStagedValues(); const providers = useSettingValue(settingsKey); const { update } = useFormActions(); const modals = useModals(); const select = useCallback( (v?: ProviderInfo) => { if (settings) { modals.openContextModal(ProviderModal, { payload: v ?? null, enabledProviders: providers ?? [], staged, settings, onChange: update, availableOptions: availableOptions, settingsKey: settingsKey, }); } }, [ modals, providers, settings, staged, update, availableOptions, settingsKey, ], ); const cards = useMemo(() => { if (providers) { return providers .flatMap((v) => { const item = availableOptions.find((inn) => inn.key === v); if (item) { return item; } else { return []; } }) .map((v, idx) => ( select(v)} > )); } else { return []; } }, [providers, select, availableOptions]); return ( {cards} select()}> ); }; interface ProviderToolProps { payload: ProviderInfo | null; // TODO: Find a better solution to pass this info to modal enabledProviders: readonly string[]; staged: LooseObject; settings: Settings; onChange: (v: LooseObject) => void; availableOptions: Readonly; settingsKey: Readonly; } const SelectItem: AutocompleteProps["renderOption"] = ({ option }) => { const provider = option as ProviderSelect; return ( {provider.value} {provider.payload.description} ); }; const ProviderTool: FunctionComponent = ({ payload, enabledProviders, staged, settings, onChange, availableOptions, settingsKey, }) => { const modals = useModals(); const onChangeRef = useRef(onChange); onChangeRef.current = onChange; const [info, setInfo] = useState>(payload); const form = useForm({ initialValues: { settings: staged, hooks: {}, }, }); const deletePayload = useCallback(() => { if (payload && enabledProviders) { const idx = enabledProviders.findIndex((v) => v === payload.key); if (idx !== -1) { const newProviders = [...enabledProviders]; newProviders.splice(idx, 1); onChangeRef.current({ [settingsKey]: newProviders }); modals.closeAll(); } } }, [payload, enabledProviders, modals, settingsKey]); const submit = useCallback( (values: FormValues) => { if (info && enabledProviders) { const changes = { ...values.settings }; const hooks = values.hooks; // Add this provider if not exist if (enabledProviders.find((v) => v === info.key) === undefined) { changes[settingsKey] = [...enabledProviders, info.key]; } // Apply submit hooks runHooks(hooks, changes); onChangeRef.current(changes); modals.closeAll(); } }, [info, enabledProviders, modals, settingsKey], ); const canSave = info !== null; const onSelect = useCallback((item: Nullable) => { if (item) { setInfo(item); } else { setInfo({ key: "", description: "Unknown Provider", }); } }, []); const options = useMemo( () => availableOptions.filter( (v) => enabledProviders?.find((p) => p === v.key && p !== info?.key) === undefined, ), [info?.key, enabledProviders, availableOptions], ); const selectorOptions = useSelectorOptions( options, (v) => v.name ?? capitalize(v.key), ); const inputs = useMemo(() => { if (info === null || info.inputs === undefined) { return null; } const itemKey = info.key; const elements: JSX.Element[] = []; info.inputs?.forEach((value) => { const key = value.key; const label = value.name ?? capitalize(value.key); const options = value.options ?? []; switch (value.type) { case "text": elements.push( , ); return; case "password": elements.push( , ); return; case "switch": elements.push( , ); return; case "select": elements.push( , ); return; case "testbutton": elements.push( , ); return; case "chips": elements.push( , ); return; default: ASSERT(false, "Implement your new input here"); } }); return {elements}; }, [info]); return ( {info?.description} {inputs} ); }; const ProviderModal = withModal(ProviderTool, "provider-tool", { title: "Provider", size: "calc(50vw)", });