@workos-inc/widgets 1.17.3 → 1.18.0-next.1788904392369

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/pipes.tsx"],"sourcesContent":["\"use client\";\nimport { Callout, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport * as CardList from \"./card-list.js\";\nimport { DataIntegrationIcon } from \"./data-integration-icon.js\";\nimport { ProviderIcon } from \"./provider-icon.js\";\nimport {\n DotsHorizontalIcon,\n ExternalLinkIcon,\n GlobeIcon,\n LockClosedIcon,\n} from \"@radix-ui/react-icons\";\nimport {\n AlertDialog,\n Button,\n Dialog,\n DropdownMenu,\n IconButton,\n Label,\n PasswordField,\n Skeleton,\n TextField,\n} from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { Status } from \"./status.js\";\nimport {\n DataIntegration,\n DataIntegrationConfigField,\n getMyDataIntegrationsQueryKey,\n useAuthorizeDataIntegrationHook,\n useDeleteDataInstallation,\n useSettings,\n useUpsertDataIntegrationApiKey,\n useUpsertDataIntegrationClientCredentials,\n} from \"../api/endpoint.js\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { GenericError } from \"./generic-error.js\";\nimport { getDomProps, WidgetRootDomProps, WidgetRootState } from \"./utils.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\nimport { ApiError } from \"../api/errors.js\";\nimport { buildRedactedSecret, isRedactedSecret } from \"./redacted-secret.js\";\n\ninterface PipesProps extends WidgetRootDomProps {\n integrations: DataIntegration[];\n}\n\nconst HANDOFF_INTERVAL_MS = 100;\nconst HANDOFF_MAX_ATTEMPTS = 100; // 10 seconds worth of attempts\n\ntype DataIntegrationAuthMethod = NonNullable<\n DataIntegration[\"authMethods\"]\n>[number];\n\n/** Supported connect methods, in the order they're offered to the user. */\nconst CONNECT_AUTH_METHODS: DataIntegrationAuthMethod[] = [\n \"oauth\",\n \"client_credentials\",\n \"api_key\",\n];\n\nconst useOpenDataIntegrationAuthorizeUrl = (integration: DataIntegration) => {\n const authorizeDataIntegration = useAuthorizeDataIntegrationHook();\n const settings = useSettings();\n const baseUrl = settings.data?.authkitOrigin ?? \"\";\n const intervalRef = useRef<ReturnType<typeof setInterval> | undefined>(\n undefined,\n );\n const messageHandlerRef = useRef<((event: MessageEvent) => void) | undefined>(\n undefined,\n );\n\n useEffect(() => {\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n }\n if (messageHandlerRef.current) {\n window.removeEventListener(\"message\", messageHandlerRef.current);\n }\n };\n }, []);\n\n return useCallback(\n async (config?: Record<string, string>) => {\n // Clear any existing interval from a previous invocation\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n // Remove any existing message handler\n if (messageHandlerRef.current) {\n window.removeEventListener(\"message\", messageHandlerRef.current);\n messageHandlerRef.current = undefined;\n }\n\n // need to do this synchronously in the event handler to avoid popup blocker notifications\n const win = window.open(`${baseUrl}/pipes/redirecting`, \"_blank\");\n // A blocked popup yields null; fail loudly (caller catches) instead of\n // authorizing and then discarding the redirect into a phantom success.\n if (!win) {\n throw new Error(\"Unable to open the authorization window.\");\n }\n\n // caller will catch. Close the popup on failure so a network/permission/\n // config error doesn't strand a blank /pipes/redirecting tab.\n let authorization;\n try {\n authorization = await authorizeDataIntegration(integration.slug, {\n requireHandoff: true,\n config,\n });\n } catch (error) {\n win.close();\n throw error;\n }\n const { url, handoffToken, redirectToken } = authorization;\n if (win) {\n win.location = url;\n const parsedUrl = new URL(url);\n const payload = { handoffToken, redirectToken };\n\n const cleanup = () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n if (messageHandlerRef.current) {\n window.removeEventListener(\"message\", messageHandlerRef.current);\n messageHandlerRef.current = undefined;\n }\n };\n\n messageHandlerRef.current = (event: MessageEvent) => {\n if (\n event.origin === parsedUrl.origin &&\n event.data?.redirectToken === redirectToken\n ) {\n cleanup();\n }\n };\n window.addEventListener(\"message\", messageHandlerRef.current);\n\n let attempts = 0;\n intervalRef.current = setInterval(() => {\n attempts += 1;\n\n if (attempts >= HANDOFF_MAX_ATTEMPTS) {\n cleanup();\n return;\n }\n\n if (win && !win.closed) {\n win.postMessage(payload, parsedUrl.origin);\n } else {\n cleanup();\n }\n }, HANDOFF_INTERVAL_MS);\n }\n },\n [authorizeDataIntegration, integration.slug, baseUrl],\n );\n};\n\n/**\n * Returns the provider-declared `installation`-scope config fields that the\n * integration has not pinned a value for, sorted by descriptor `order`. These\n * are the fields the connect flow must prompt for (pin / prompt-if-unset).\n */\nfunction getUnpinnedInstallationFields(\n integration: DataIntegration,\n): DataIntegrationConfigField[] {\n return (integration.configFields ?? [])\n .filter(\n (field) =>\n field.scope === \"installation\" && !integration.config?.[field.key],\n )\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\n/**\n * Seed values for the descriptors from a stored `config` object, stringifying\n * the scalar values the inputs can round-trip and skipping anything else.\n */\nfunction getInitialConfigValues(\n fields: DataIntegrationConfigField[],\n storedConfig: Record<string, unknown>,\n): Record<string, string> {\n const values: Record<string, string> = {};\n for (const field of fields) {\n const stored = storedConfig[field.key];\n if (\n typeof stored === \"string\" ||\n typeof stored === \"number\" ||\n typeof stored === \"boolean\"\n ) {\n values[field.key] = String(stored);\n }\n }\n return values;\n}\n\n/**\n * Compile a descriptor `pattern` (+ optional flags), returning undefined when\n * it isn't valid regex syntax so the server's validation remains the backstop.\n *\n * Anchored as `^(?:…)$` to match the server, so an unanchored descriptor\n * pattern surfaces the same inline error here instead of passing client\n * validation and being rejected on submit.\n */\nfunction compileConfigFieldPattern(\n pattern: string,\n flags: string | undefined,\n): RegExp | undefined {\n try {\n return new RegExp(`^(?:${pattern})$`, flags);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Form state for a set of provider-declared config-field descriptors: the\n * collected values, inline validation against `required` / `pattern`, and the\n * `config` payload the connect endpoints accept. Shared by every connect\n * surface so descriptors are rendered and validated in exactly one place.\n *\n * `initialValues` prefills the inputs (e.g. from an existing installation's\n * stored config); `isDirty` reports whether the user actually changed any of\n * them, which callers use to decide whether to send `config` at all.\n */\nfunction useConfigFieldsForm(\n fields: DataIntegrationConfigField[],\n initialValues: Record<string, string> = {},\n) {\n const [values, setValues] = useState<Record<string, string>>(initialValues);\n const [errors, setErrors] = useState<Record<string, string | null>>({});\n const translate = useTranslation();\n\n const requiredMessage = translate({\n defaultMessage: \"This field is required\",\n id: \"B2HvfC\",\n description:\n \"Validation error shown when a required configuration field is left empty\",\n });\n const patternMessage = translate({\n defaultMessage: \"Enter a valid value.\",\n id: \"2XWaGz\",\n description:\n \"Validation error shown when a configuration field value does not match the expected format\",\n });\n\n const setValue = (key: string, value: string) => {\n setValues((prev) => ({ ...prev, [key]: value }));\n setErrors((prev) => (prev[key] ? { ...prev, [key]: null } : prev));\n };\n\n const reset = () => {\n setValues(initialValues);\n setErrors({});\n };\n\n const validate = () => {\n const nextErrors: Record<string, string | null> = {};\n let valid = true;\n for (const field of fields) {\n const value = (values[field.key] ?? \"\").trim();\n if (field.required && !value) {\n nextErrors[field.key] = requiredMessage;\n valid = false;\n continue;\n }\n if (value && field.pattern) {\n const patternRegExp = compileConfigFieldPattern(\n field.pattern,\n field.patternFlags,\n );\n if (patternRegExp && !patternRegExp.test(value)) {\n nextErrors[field.key] = patternMessage;\n valid = false;\n continue;\n }\n }\n nextErrors[field.key] = null;\n }\n setErrors(nextErrors);\n return valid;\n };\n\n const buildConfig = () => {\n const config: Record<string, string> = {};\n for (const field of fields) {\n const value = (values[field.key] ?? \"\").trim();\n if (value) {\n config[field.key] = value;\n }\n }\n return config;\n };\n\n /**\n * The full `config` object to write, given the config the API returned for\n * the installation. The write is a wholesale replace, so keys the widget\n * never rendered (pinned at the integration level, or unknown to these\n * descriptors) are preserved as received rather than dropped.\n */\n const buildConfigPayload = (storedConfig: Record<string, unknown>) => {\n const payload: Record<string, unknown> = { ...storedConfig };\n for (const field of fields) {\n const value = (values[field.key] ?? \"\").trim();\n if (value) {\n payload[field.key] = value;\n } else {\n delete payload[field.key];\n }\n }\n return payload;\n };\n\n const hasMissingRequired = fields.some(\n (field) => field.required && !(values[field.key] ?? \"\").trim(),\n );\n\n const isDirty = fields.some(\n (field) => (values[field.key] ?? \"\") !== (initialValues[field.key] ?? \"\"),\n );\n\n return {\n values,\n errors,\n setValue,\n reset,\n validate,\n buildConfig,\n buildConfigPayload,\n hasMissingRequired,\n isDirty,\n };\n}\n\n/**\n * Renders config-field descriptors as labelled inputs (secret descriptors get a\n * password field), with inline validation errors wired up via `aria-invalid` /\n * `aria-describedby`.\n *\n * Stacks as label → description → input → hint, so the description is read\n * before the field is filled and the `default` hint sits with the value it\n * describes. (The dashboard's config form instead merges both into one help\n * line below the input; the copy matches, the placement follows the widget's\n * existing description-above-input layout.)\n *\n * The `default` — falling back to the display-only `example` — is the\n * placeholder, and is never filled in as a value: submitting it would pin it and\n * freeze it, while leaving the field empty lets the API resolve the default on\n * read, so a later change to it reaches existing installations.\n */\nfunction ConfigFieldInputs({\n idPrefix,\n fields,\n values,\n errors,\n onChange,\n}: {\n idPrefix: string;\n fields: DataIntegrationConfigField[];\n values: Record<string, string>;\n errors: Record<string, string | null>;\n onChange: (key: string, value: string) => void;\n}) {\n return fields.map((field) => {\n const fieldId = `${idPrefix}-${field.key}`;\n const errorId = `${fieldId}-error`;\n const descriptionId = `${fieldId}-description`;\n const error = errors[field.key];\n const Control = field.secret ? PasswordField : TextField;\n const defaultHint =\n field.default !== undefined ? (\n <Translation\n defaultMessage=\"Defaults to {value} when left blank.\"\n id=\"MTNqSC\"\n description=\"Hint naming the value used when a configuration field is left blank\"\n values={{ value: field.default }}\n />\n ) : null;\n // The hint and the error share the slot under the input; the error wins.\n const hintId = `${fieldId}-hint`;\n const showHint = !error && defaultHint;\n const describedBy =\n [\n field.description ? descriptionId : null,\n showHint ? hintId : null,\n error ? errorId : null,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n return (\n <Flex key={field.key} direction=\"column\" gap=\"1\">\n <Label htmlFor={fieldId}>{field.label}</Label>\n {field.description ? (\n <Text color=\"gray\" size=\"2\" id={descriptionId} mb=\"1\">\n {field.description}\n </Text>\n ) : null}\n <Control\n id={fieldId}\n value={values[field.key] ?? \"\"}\n placeholder={field.default ?? field.example}\n autoComplete=\"off\"\n required={field.required || undefined}\n aria-invalid={!!error || undefined}\n aria-describedby={describedBy}\n onChange={(event) => onChange(field.key, event.target.value)}\n />\n {showHint ? (\n <Text color=\"gray\" size=\"2\" id={hintId}>\n {defaultHint}\n </Text>\n ) : null}\n {error ? (\n <Text color=\"red\" size=\"2\" id={errorId}>\n {error}\n </Text>\n ) : null}\n </Flex>\n );\n });\n}\n\n/** Gray dot separator shown between the logos in the connect-dialog header. */\nfunction LogoSeparator() {\n return (\n <DotsHorizontalIcon\n width=\"20\"\n height=\"20\"\n style={{ color: \"var(--gray-8)\" }}\n />\n );\n}\n\n/**\n * Shared connect-dialog header: the WorkOS → provider icon row and the\n * \"{app} uses WorkOS to connect to {provider}\" title.\n */\nfunction ConnectDialogHeader({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n const settings = useSettings();\n const logo = settings.data?.logoDarkPath ?? settings.data?.logoLightPath;\n const appName = settings.data?.teamName ?? \"This application\";\n\n return (\n <>\n <Flex justify=\"center\" align=\"center\" gap=\"2\" mt=\"2\">\n {logo && (\n <>\n <IconPanel color=\"panel\" style={{ width: \"48px\", height: \"48px\" }}>\n <ProviderIcon\n size=\"2\"\n provider=\"workos\"\n style={{ backgroundImage: `url(${logo})` }}\n />\n </IconPanel>\n <LogoSeparator />\n </>\n )}\n <IconPanel\n color=\"panel\"\n style={{\n ...(logo ? { borderWidth: 0 } : undefined),\n width: \"48px\",\n height: \"48px\",\n }}\n >\n <ProviderIcon size=\"2\" provider=\"workos\" />\n </IconPanel>\n <LogoSeparator />\n <IconPanel color=\"panel\" style={{ width: \"48px\", height: \"48px\" }}>\n <DataIntegrationIcon size=\"2\" integration={integration} />\n </IconPanel>\n </Flex>\n <Dialog.Title size=\"2\" mt=\"5\" mb=\"5\" weight={\"bold\"} align=\"center\">\n <Translation\n defaultMessage=\"{appName} uses WorkOS to connect to {integrationName}.\"\n id=\"ujRDBH\"\n description=\"Dialog title explaining the app connection flow\"\n values={{ appName, integrationName: integration.name }}\n />\n </Dialog.Title>\n </>\n );\n}\n\n/**\n * Shared connect-dialog explainer card: \"you'll be redirected to sign in\" +\n * \"your credentials remain secure\".\n */\nfunction ConnectExplainerCard({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n return (\n <Card>\n <Flex direction=\"column\" gap=\"4\">\n <Flex gap=\"2\" align=\"center\">\n <IconPanel color=\"gray\" style={{ width: \"32px\", height: \"32px\" }}>\n <GlobeIcon />\n </IconPanel>\n <Flex direction=\"column\">\n <Text size=\"1\" weight=\"bold\">\n <Translation\n defaultMessage=\"You'll be redirected to sign in with {integrationName}.\"\n id=\"g+n4aY\"\n description=\"Instruction about redirect to sign in\"\n values={{ integrationName: integration.name }}\n />\n </Text>\n <Text size=\"1\">\n <Translation\n defaultMessage=\"Authorize access to connect your account.\"\n id=\"fxVS34\"\n description=\"Instruction to authorize access\"\n />\n </Text>\n </Flex>\n </Flex>\n <Flex gap=\"2\" align=\"center\">\n <IconPanel color=\"gray\" style={{ width: \"32px\", height: \"32px\" }}>\n <LockClosedIcon />\n </IconPanel>\n <Flex direction=\"column\">\n <Text size=\"1\" weight=\"bold\">\n <Translation\n defaultMessage=\"Your credentials remain secure.\"\n id=\"gM3bot\"\n description=\"Security message about credentials\"\n />\n </Text>\n <Text size=\"1\">\n <Translation\n defaultMessage=\"WorkOS never sees your credentials.\"\n id=\"kC9Fwe\"\n description=\"Security message about WorkOS not seeing credentials\"\n />\n </Text>\n </Flex>\n </Flex>\n </Flex>\n </Card>\n );\n}\n\n/**\n * The single connect dialog for all non-API (OAuth) providers. When the\n * provider declares unpinned `installation`-scope config fields (e.g. a Zendesk\n * subdomain), it opens on a field-collection step (values validated against the\n * descriptor `required` / `pattern`) before the redirect explainer; otherwise\n * it opens directly on the explainer. Collected values are submitted as\n * `config` on the POST authorize call. Controlled so it backs the initial\n * connect flow, the dual-method OAuth option, and reauthorization.\n */\nfunction ConnectDialog({\n integration,\n fields,\n open,\n onOpenChange,\n}: {\n integration: DataIntegration;\n fields: DataIntegrationConfigField[];\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n // Providers without fields to collect skip straight to the explainer.\n const initialStep = fields.length > 0 ? \"fields\" : \"review\";\n const [step, setStep] = useState<\"fields\" | \"review\">(initialStep);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const configForm = useConfigFieldsForm(fields);\n const eventHandler = useOpenDataIntegrationAuthorizeUrl(integration);\n const translate = useTranslation();\n\n const genericConnectError = translate({\n defaultMessage: \"We couldn't start the connection. Please try again.\",\n id: \"zGw1ma\",\n description:\n \"Fallback error shown when starting the connection fails for a non-specific reason\",\n });\n\n const reset = () => {\n setStep(initialStep);\n configForm.reset();\n setSubmitError(null);\n setIsSubmitting(false);\n };\n\n const handleConnect = async () => {\n setSubmitError(null);\n setIsSubmitting(true);\n try {\n // Opens the popup synchronously within this click before awaiting.\n await eventHandler(configForm.buildConfig());\n onOpenChange(false);\n } catch (error) {\n // Surface a message for every failure mode (ApiError, network, blocked\n // popup, etc.) so the dialog never fails silently.\n setSubmitError(\n error instanceof ApiError && error.message\n ? error.message\n : genericConnectError,\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return (\n <Dialog.Root\n open={open}\n onOpenChange={(next) => {\n onOpenChange(next);\n if (!next) {\n reset();\n }\n }}\n >\n <Dialog.Content maxWidth=\"430px\">\n <ConnectDialogHeader integration={integration} />\n\n {step === \"fields\" ? (\n <>\n <Card>\n <Flex direction=\"column\" gap=\"4\">\n <ConfigFieldInputs\n idPrefix=\"pipes-config\"\n fields={fields}\n values={configForm.values}\n errors={configForm.errors}\n onChange={configForm.setValue}\n />\n </Flex>\n </Card>\n <Flex justify=\"end\" gap=\"3\" mt=\"5\">\n <Dialog.Close>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <Button\n type=\"button\"\n disabled={configForm.hasMissingRequired}\n onClick={() => {\n if (configForm.validate()) {\n setStep(\"review\");\n }\n }}\n >\n <Translation\n defaultMessage=\"Next\"\n id=\"L2fmxK\"\n description=\"Button to advance to the next step of the connect flow\"\n />\n </Button>\n </Flex>\n </>\n ) : (\n <>\n {submitError && (\n <Callout.Root mb=\"3\" color=\"red\" role=\"alert\">\n <Callout.Text>{submitError}</Callout.Text>\n </Callout.Root>\n )}\n <ConnectExplainerCard integration={integration} />\n <Flex justify=\"end\" gap=\"3\" mt=\"5\">\n {fields.length > 0 ? (\n <Button\n variant=\"secondary\"\n type=\"button\"\n onClick={() => setStep(\"fields\")}\n >\n <Translation\n defaultMessage=\"Back\"\n id=\"J9MvVP\"\n description=\"Button to return to the previous step of the connect flow\"\n />\n </Button>\n ) : (\n <Dialog.Close>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n )}\n <Button\n type=\"button\"\n loading={isSubmitting}\n disabled={isSubmitting}\n onClick={handleConnect}\n >\n <Translation\n defaultMessage=\"Connect\"\n id=\"16WmG0\"\n description=\"Connect button with external link\"\n trailingSpace\n />\n <ExternalLinkIcon aria-hidden />\n </Button>\n </Flex>\n </>\n )}\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\n/**\n * Connect button for a not-yet-connected OAuth provider. Opens the unified\n * {@link ConnectDialog}, which prompts for any unpinned `installation`-scope\n * config fields before the redirect explainer.\n */\nfunction ConnectIntegrationButton({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n const [open, setOpen] = useState(false);\n const fields = getUnpinnedInstallationFields(integration);\n\n return (\n <>\n <ConnectDialog\n integration={integration}\n fields={fields}\n open={open}\n onOpenChange={setOpen}\n />\n <Button variant=\"secondary\" onClick={() => setOpen(true)}>\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n </Button>\n </>\n );\n}\n\nconst API_KEY_REDACTED_PREFIX = \"••••\";\n\nfunction ApiKeyDialog({\n integration,\n open,\n onOpenChange,\n}: {\n integration: DataIntegration;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const queryClient = useQueryClient();\n const installation = integration.installation;\n const isRotation =\n installation?.auth_method === \"api_key\" &&\n installation.state === \"connected\";\n const last4 = installation?.api_key_last_4;\n const maskedKey = last4 ? `${API_KEY_REDACTED_PREFIX}${last4}` : \"\";\n\n const [secret, setSecret] = useState(\"\");\n const translate = useTranslation();\n\n const apiKeyPlaceholder = translate({\n defaultMessage: \"Enter your API key\",\n id: \"MzSxEF\",\n description: \"Placeholder for the API key input field\",\n });\n\n const {\n mutate: upsertApiKey,\n error,\n reset,\n isPending,\n } = useUpsertDataIntegrationApiKey({\n mutation: {\n onSuccess: () => {\n onOpenChange(false);\n queryClient.invalidateQueries({\n queryKey: getMyDataIntegrationsQueryKey(),\n });\n },\n },\n });\n\n // The component is only mounted while open (conditional rendering in\n // ApiKeyConnectButton / ProviderStatus), so state resets on mount.\n // We only need to reset the mutation state when the dialog opens in\n // case the same instance was reused.\n useEffect(() => {\n reset();\n }, [reset]);\n\n const errorMessage = (() => {\n if (!error) return null;\n if (error instanceof ApiError && error.message) {\n return error.message;\n }\n return null;\n })();\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Content maxWidth=\"430px\">\n <Dialog.Title size=\"3\" weight=\"bold\">\n {isRotation ? (\n <Translation\n defaultMessage=\"Rotate API key for {integrationName}\"\n id=\"8+NN3t\"\n description=\"Dialog title for rotating an API key\"\n values={{ integrationName: integration.name }}\n />\n ) : (\n <Translation\n defaultMessage=\"Connect {integrationName} with API key\"\n id=\"EyItbA\"\n description=\"Dialog title for connecting with an API key\"\n values={{ integrationName: integration.name }}\n />\n )}\n </Dialog.Title>\n\n {/*\n * The provider's own description. Built-in providers are self-evident,\n * but a custom provider's definition copy is the only thing telling the\n * tenant which key to paste and where to mint it. Rendered as the\n * dialog's description so it's announced with the dialog rather than\n * being an unassociated paragraph.\n */}\n {integration.description && (\n <Dialog.Description color=\"gray\" mt=\"1\">\n {integration.description}\n </Dialog.Description>\n )}\n\n {error && (\n <Callout.Root my=\"3\" color=\"red\" role=\"alert\">\n <Callout.Text>\n {errorMessage ?? (\n <Translation\n defaultMessage=\"An error occurred. Please check the value and try again.\"\n id=\"bYLbLL\"\n description=\"Generic error message for API key submission failure\"\n />\n )}\n </Callout.Text>\n </Callout.Root>\n )}\n\n <Flex direction=\"column\" gap=\"4\" mt=\"2\">\n {isRotation && last4 && (\n <Flex direction=\"column\" gap=\"1\">\n <Label>\n <Translation\n defaultMessage=\"Current API key\"\n id=\"+odk8g\"\n description=\"Label for the current masked API key\"\n />\n </Label>\n <Text size=\"2\" color=\"gray\">\n {maskedKey}\n </Text>\n </Flex>\n )}\n\n <Flex direction=\"column\" gap=\"1\">\n <Label>\n {isRotation ? (\n <Translation\n defaultMessage=\"New API key\"\n id=\"L3AmMK\"\n description=\"Label for the new API key input when rotating\"\n />\n ) : (\n <Translation\n defaultMessage=\"API key\"\n id=\"Xnkv+J\"\n description=\"Label for the API key input\"\n />\n )}\n </Label>\n <PasswordField\n value={secret}\n autoComplete=\"off\"\n placeholder={apiKeyPlaceholder}\n onChange={(event) => setSecret(event.target.value)}\n />\n </Flex>\n </Flex>\n\n <Flex justify=\"end\" gap=\"3\" mt=\"5\">\n <Dialog.Close>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <Button\n type=\"button\"\n disabled={isPending || !secret.trim()}\n loading={isPending}\n onClick={() =>\n upsertApiKey({\n slug: integration.slug,\n data: { secret: secret.trim() },\n })\n }\n >\n {isRotation ? (\n <Translation\n defaultMessage=\"Rotate\"\n id=\"LAh+p5\"\n description=\"Button to rotate an API key\"\n />\n ) : (\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n )}\n </Button>\n </Flex>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\nfunction ApiKeyConnectButton({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n const [open, setOpen] = useState(false);\n\n return (\n <>\n {open && (\n <ApiKeyDialog\n integration={integration}\n open={open}\n onOpenChange={setOpen}\n />\n )}\n <Button variant=\"secondary\" onClick={() => setOpen(true)}>\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n </Button>\n </>\n );\n}\n\n/**\n * Connect form for the `client_credentials` auth method: the provider's client\n * id and secret plus any unpinned `installation`-scope config fields, rendered\n * generically from the descriptors via {@link ConfigFieldInputs}. Submits to\n * PUT `/DataIntegrations/:slug/client-credentials`, which also handles\n * replacing the credentials of an existing client-credentials installation.\n *\n * For an existing installation the form is prefilled from it: the client id as\n * received, the stored secret as a redacted mask that clears on focus (the\n * real value is never sent to the widget, so a new secret must be re-entered\n * to save), and the config fields from `installation.config`. `config` is only\n * included in the payload when the user edits a config field, since the API\n * keeps the stored config when the key is absent; when it is included it is\n * the full round-tripped object, because the write replaces config wholesale.\n */\nfunction ClientCredentialsDialog({\n integration,\n fields,\n open,\n onOpenChange,\n}: {\n integration: DataIntegration;\n fields: DataIntegrationConfigField[];\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const queryClient = useQueryClient();\n const installation = integration.installation;\n const isUpdate = installation?.auth_method === \"client_credentials\";\n const storedConfig = useMemo(\n () => (isUpdate ? (installation?.config ?? {}) : {}),\n [isUpdate, installation?.config],\n );\n const initialConfigValues = useMemo(\n () => getInitialConfigValues(fields, storedConfig),\n [fields, storedConfig],\n );\n const redactedSecret = buildRedactedSecret(\n isUpdate ? installation?.client_secret_last_4 : null,\n );\n\n const [clientId, setClientId] = useState(\n (isUpdate ? installation?.client_id : null) ?? \"\",\n );\n const [clientSecret, setClientSecret] = useState(redactedSecret);\n const configForm = useConfigFieldsForm(fields, initialConfigValues);\n const translate = useTranslation();\n\n const clientIdPlaceholder = translate({\n defaultMessage: \"Enter your client ID\",\n id: \"5YTAFo\",\n description: \"Placeholder for the client credentials client ID input\",\n });\n const clientSecretPlaceholder = translate({\n defaultMessage: \"Enter your client secret\",\n id: \"53f0B7\",\n description: \"Placeholder for the client credentials client secret input\",\n });\n\n // The widget never holds the real secret, so the prefilled mask can't be\n // submitted: the PUT requires a client secret and re-entry is the only way\n // to supply one.\n const secretMissing = !clientSecret.trim() || isRedactedSecret(clientSecret);\n\n const {\n mutate: upsertClientCredentials,\n error,\n isPending,\n } = useUpsertDataIntegrationClientCredentials({\n mutation: {\n onSuccess: () => {\n onOpenChange(false);\n queryClient.invalidateQueries({\n queryKey: getMyDataIntegrationsQueryKey(),\n });\n },\n },\n });\n\n // Server errors — including the 409 raised when an installation already\n // exists with a different auth method — are surfaced in the banner.\n const errorMessage =\n error instanceof ApiError && error.message ? error.message : null;\n\n const handleSubmit = () => {\n if (!configForm.validate()) {\n return;\n }\n // Untouched config fields mean no `config` key at all: the API preserves\n // the stored config when it's absent, and sending the prefilled object\n // back would make every credential update a config write too.\n const config = configForm.isDirty\n ? configForm.buildConfigPayload(storedConfig)\n : undefined;\n upsertClientCredentials({\n slug: integration.slug,\n data: {\n client_id: clientId.trim(),\n client_secret: clientSecret.trim(),\n ...(config ? { config } : {}),\n },\n });\n };\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Content maxWidth=\"430px\">\n <Dialog.Title size=\"3\" weight=\"bold\">\n {isUpdate ? (\n <Translation\n defaultMessage=\"Update client credentials for {integrationName}\"\n id=\"/D85zF\"\n description=\"Dialog title for updating stored client credentials\"\n values={{ integrationName: integration.name }}\n />\n ) : (\n <Translation\n defaultMessage=\"Connect {integrationName} with client credentials\"\n id=\"x+7tw3\"\n description=\"Dialog title for connecting with client credentials\"\n values={{ integrationName: integration.name }}\n />\n )}\n </Dialog.Title>\n\n {error && (\n <Callout.Root my=\"3\" color=\"red\" role=\"alert\">\n <Callout.Text>\n {errorMessage ?? (\n <Translation\n defaultMessage=\"An error occurred. Please check the value and try again.\"\n id=\"bYLbLL\"\n description=\"Generic error message for API key submission failure\"\n />\n )}\n </Callout.Text>\n </Callout.Root>\n )}\n\n <Flex direction=\"column\" gap=\"4\" mt=\"2\">\n <Flex direction=\"column\" gap=\"1\">\n <Label htmlFor=\"pipes-client-credentials-client-id\">\n <Translation\n defaultMessage=\"Client ID\"\n id=\"/Cv5P1\"\n description=\"Label for the client credentials client ID input\"\n />\n </Label>\n <TextField\n id=\"pipes-client-credentials-client-id\"\n value={clientId}\n autoComplete=\"off\"\n placeholder={clientIdPlaceholder}\n onChange={(event) => setClientId(event.target.value)}\n />\n </Flex>\n\n <Flex direction=\"column\" gap=\"1\">\n <Label htmlFor=\"pipes-client-credentials-client-secret\">\n <Translation\n defaultMessage=\"Client secret\"\n id=\"uScBDj\"\n description=\"Label for the client credentials client secret input\"\n />\n </Label>\n {isUpdate && (\n <Text\n color=\"gray\"\n size=\"2\"\n id=\"pipes-client-credentials-client-secret-description\"\n mb=\"1\"\n >\n <Translation\n defaultMessage=\"Enter the client secret again to save any changes.\"\n id=\"ZrNPCF\"\n description=\"Help text explaining the client secret must be re-entered to save an update\"\n />\n </Text>\n )}\n <PasswordField\n id=\"pipes-client-credentials-client-secret\"\n value={clientSecret}\n autoComplete=\"off\"\n // The mask is what's shown, so render it as text: a password\n // input would re-bullet its last four digits away.\n type={isRedactedSecret(clientSecret) ? \"text\" : undefined}\n placeholder={clientSecretPlaceholder}\n aria-describedby={\n isUpdate\n ? \"pipes-client-credentials-client-secret-description\"\n : undefined\n }\n onChange={(event) => setClientSecret(event.target.value)}\n onFocus={() => {\n if (isRedactedSecret(clientSecret)) {\n setClientSecret(\"\");\n }\n }}\n onBlur={() => {\n if (clientSecret === \"\") {\n setClientSecret(redactedSecret);\n }\n }}\n />\n </Flex>\n\n <ConfigFieldInputs\n idPrefix=\"pipes-client-credentials-config\"\n fields={fields}\n values={configForm.values}\n errors={configForm.errors}\n onChange={configForm.setValue}\n />\n </Flex>\n\n <Flex justify=\"end\" gap=\"3\" mt=\"5\">\n <Dialog.Close>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <Button\n type=\"button\"\n disabled={\n isPending ||\n !clientId.trim() ||\n secretMissing ||\n configForm.hasMissingRequired\n }\n loading={isPending}\n onClick={handleSubmit}\n >\n {isUpdate ? (\n <Translation\n defaultMessage=\"Save\"\n id=\"RT8KNi\"\n description=\"Save button text\"\n />\n ) : (\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n )}\n </Button>\n </Flex>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\nfunction ClientCredentialsConnectButton({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n const [open, setOpen] = useState(false);\n const fields = getUnpinnedInstallationFields(integration);\n\n return (\n <>\n {open && (\n <ClientCredentialsDialog\n integration={integration}\n fields={fields}\n open={open}\n onOpenChange={setOpen}\n />\n )}\n <Button variant=\"secondary\" onClick={() => setOpen(true)}>\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n </Button>\n </>\n );\n}\n\n/**\n * Connect entry point for a provider that supports more than one auth method:\n * a menu with one item per method, each opening that method's dialog.\n */\nfunction MultiMethodConnectButton({\n integration,\n methods,\n}: {\n integration: DataIntegration;\n methods: DataIntegrationAuthMethod[];\n}) {\n const [apiKeyOpen, setApiKeyOpen] = useState(false);\n const [oauthOpen, setOauthOpen] = useState(false);\n const [clientCredentialsOpen, setClientCredentialsOpen] = useState(false);\n const fields = getUnpinnedInstallationFields(integration);\n\n return (\n <>\n {apiKeyOpen && (\n <ApiKeyDialog\n integration={integration}\n open={apiKeyOpen}\n onOpenChange={setApiKeyOpen}\n />\n )}\n {clientCredentialsOpen && (\n <ClientCredentialsDialog\n integration={integration}\n fields={fields}\n open={clientCredentialsOpen}\n onOpenChange={setClientCredentialsOpen}\n />\n )}\n {methods.includes(\"oauth\") && (\n <ConnectDialog\n integration={integration}\n fields={fields}\n open={oauthOpen}\n onOpenChange={setOauthOpen}\n />\n )}\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n {methods.includes(\"oauth\") && (\n <DropdownMenu.Item onClick={() => setOauthOpen(true)}>\n <Flex gap=\"4\" width=\"100%\" justify=\"between\" align=\"center\">\n <Translation\n defaultMessage=\"Sign in with OAuth\"\n id=\"ssNz+0\"\n description=\"Menu option to connect via OAuth\"\n trailingSpace\n />\n <ExternalLinkIcon aria-hidden />\n </Flex>\n </DropdownMenu.Item>\n )}\n {methods.includes(\"client_credentials\") && (\n <DropdownMenu.Item onClick={() => setClientCredentialsOpen(true)}>\n <Translation\n defaultMessage=\"Enter client credentials\"\n id=\"Y/87Vt\"\n description=\"Menu option to connect via client credentials\"\n />\n </DropdownMenu.Item>\n )}\n {methods.includes(\"api_key\") && (\n <DropdownMenu.Item onClick={() => setApiKeyOpen(true)}>\n <Translation\n defaultMessage=\"Enter API key\"\n id=\"8mq2DA\"\n description=\"Menu option to connect via API key\"\n />\n </DropdownMenu.Item>\n )}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n </>\n );\n}\n\nfunction ProviderStatus({ integration }: { integration: DataIntegration }) {\n const [disconnectOpen, setDisconnectOpen] = useState(false);\n const [apiKeyOpen, setApiKeyOpen] = useState(false);\n const [clientCredentialsOpen, setClientCredentialsOpen] = useState(false);\n const [reauthConfigOpen, setReauthConfigOpen] = useState(false);\n const authorizeEventHandler = useOpenDataIntegrationAuthorizeUrl(integration);\n const translate = useTranslation();\n\n const pipeActionsTitle = translate({\n defaultMessage: \"Pipe actions\",\n id: \"1uF9ve\",\n description: \"Title for pipe actions dropdown button\",\n });\n\n // Unpinned installation fields must be re-collected on reauthorization too;\n // the authorize endpoint rejects them as missing otherwise.\n const unpinnedFields = getUnpinnedInstallationFields(integration);\n\n if (integration.installation) {\n const connected = integration.installation.state === \"connected\";\n const isApiKeyInstallation =\n integration.installation.auth_method === \"api_key\";\n const isClientCredentialsInstallation =\n integration.installation.auth_method === \"client_credentials\";\n\n return (\n <>\n <DisconnectAccountDialog\n integrationName={integration.name}\n installationId={integration.installation.id}\n open={disconnectOpen}\n onOpenChange={setDisconnectOpen}\n />\n {apiKeyOpen && (\n <ApiKeyDialog\n integration={integration}\n open={apiKeyOpen}\n onOpenChange={setApiKeyOpen}\n />\n )}\n {clientCredentialsOpen && (\n <ClientCredentialsDialog\n integration={integration}\n fields={unpinnedFields}\n open={clientCredentialsOpen}\n onOpenChange={setClientCredentialsOpen}\n />\n )}\n {unpinnedFields.length > 0 && !isClientCredentialsInstallation && (\n <ConnectDialog\n integration={integration}\n fields={unpinnedFields}\n open={reauthConfigOpen}\n onOpenChange={setReauthConfigOpen}\n />\n )}\n <Flex align=\"center\" gap=\"4\">\n <Status state={connected ? \"success\" : \"error\"}>\n {connected ? (\n <Translation\n defaultMessage=\"Connected\"\n id=\"i6Hxoz\"\n description=\"Status text for connected integration\"\n />\n ) : (\n <Translation\n defaultMessage=\"Requires reauthorization\"\n id=\"dqczQS\"\n description=\"Status text for integration needing reauthorization\"\n />\n )}\n </Status>\n {isClientCredentialsInstallation ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton title={pipeActionsTitle}>\n <DotsHorizontalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item\n onClick={() => setClientCredentialsOpen(true)}\n >\n <Translation\n defaultMessage=\"Update client credentials\"\n id=\"daHKWE\"\n description=\"Menu option to update stored client credentials\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Item\n variant=\"destructive\"\n onClick={() => setDisconnectOpen(true)}\n >\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"esZQrd\"\n description=\"Menu option to disconnect an account\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : connected && isApiKeyInstallation ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton title={pipeActionsTitle}>\n <DotsHorizontalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item onClick={() => setApiKeyOpen(true)}>\n <Translation\n defaultMessage=\"Rotate API key\"\n id=\"GML+c8\"\n description=\"Menu option to rotate the API key\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Item\n variant=\"destructive\"\n onClick={() => setDisconnectOpen(true)}\n >\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"esZQrd\"\n description=\"Menu option to disconnect an account\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : connected ? (\n <Button variant=\"secondary\" onClick={() => setDisconnectOpen(true)}>\n <Translation\n defaultMessage=\"Disconnect\"\n id=\"vMVXQh\"\n description=\"Button to disconnect an account\"\n />\n </Button>\n ) : isApiKeyInstallation ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton title={pipeActionsTitle}>\n <DotsHorizontalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item onClick={() => setApiKeyOpen(true)}>\n <Translation\n defaultMessage=\"Update API key\"\n id=\"E7pMj/\"\n description=\"Menu option to update the API key for a needs-reauthorization installation\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Item\n variant=\"destructive\"\n onClick={() => setDisconnectOpen(true)}\n >\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"esZQrd\"\n description=\"Menu option to disconnect an account\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton title={pipeActionsTitle}>\n <DotsHorizontalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item\n onClick={async () => {\n if (unpinnedFields.length > 0) {\n setReauthConfigOpen(true);\n return;\n }\n try {\n await authorizeEventHandler();\n } catch {\n // pass - error displayed in new tab\n }\n }}\n >\n <Flex gap=\"4\" width=\"100%\" justify=\"between\" align=\"center\">\n <Translation\n defaultMessage=\"Reauthorize\"\n id=\"0E29F1\"\n description=\"Menu option to reauthorize an integration\"\n trailingSpace\n />\n <ExternalLinkIcon aria-hidden />\n </Flex>\n </DropdownMenu.Item>\n <DropdownMenu.Item\n variant=\"destructive\"\n onClick={() => setDisconnectOpen(true)}\n >\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"esZQrd\"\n description=\"Menu option to disconnect an account\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n )}\n </Flex>\n </>\n );\n }\n\n // Not connected: choose the connect entry point from the supported methods.\n // More than one: a menu of methods; otherwise that method's own button, with\n // OAuth as the default for a provider that declares nothing.\n const authMethods = integration.authMethods ?? [];\n const methods = CONNECT_AUTH_METHODS.filter((method) =>\n authMethods.includes(method),\n );\n\n return (\n <Flex align=\"center\" gap=\"4\">\n <Status state=\"neutral\">\n <Translation\n defaultMessage=\"Not connected\"\n id=\"J7bTZa\"\n description=\"Status text for an integration that is not connected\"\n />\n </Status>\n {methods.length > 1 ? (\n <MultiMethodConnectButton integration={integration} methods={methods} />\n ) : methods.length === 1 && methods[0] === \"api_key\" ? (\n <ApiKeyConnectButton integration={integration} />\n ) : methods.length === 1 && methods[0] === \"client_credentials\" ? (\n <ClientCredentialsConnectButton integration={integration} />\n ) : (\n <ConnectIntegrationButton integration={integration} />\n )}\n </Flex>\n );\n}\n\nfunction DisconnectAccountDialog({\n integrationName,\n installationId,\n open,\n onOpenChange,\n}: {\n integrationName: string;\n installationId: string;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const queryClient = useQueryClient();\n const {\n mutate: deleteDataInstallation,\n error,\n reset,\n isPending,\n } = useDeleteDataInstallation({\n mutation: {\n onSuccess: () => {\n onOpenChange(false);\n queryClient.invalidateQueries({\n queryKey: getMyDataIntegrationsQueryKey(),\n });\n },\n },\n });\n\n useEffect(() => {\n if (open) {\n reset();\n }\n }, [open, reset]);\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange}>\n <AlertDialog.Content style={{ width: \"80vw\", maxWidth: \"520px\" }}>\n <AlertDialog.Title>\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"9ABlCr\"\n description=\"Dialog title for disconnecting an account\"\n />\n </AlertDialog.Title>\n {error && (\n <Callout.Root my=\"5\" color=\"red\" role=\"alert\">\n <Callout.Text>\n <Translation\n defaultMessage=\"An error occurred while disconnecting your account. Please refresh the page and try again.\"\n id=\"qKBKF7\"\n description=\"Error message when disconnecting an account fails\"\n />\n </Callout.Text>\n </Callout.Root>\n )}\n <AlertDialog.Description>\n <Translation\n defaultMessage=\"Are you sure you want to disconnect your {integrationName} account?\"\n id=\"eEXeqP\"\n description=\"Confirmation message for disconnecting an account\"\n values={{\n integrationName: (\n <Text as=\"span\" weight=\"bold\">\n {integrationName}\n </Text>\n ),\n }}\n />\n </AlertDialog.Description>\n <Flex gap=\"3\" justify=\"end\" mt=\"5\">\n <AlertDialog.Cancel>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </AlertDialog.Cancel>\n <Button\n variant=\"destructive\"\n disabled={isPending}\n loading={isPending}\n onClick={() => deleteDataInstallation({ installationId })}\n >\n <Translation\n defaultMessage=\"Disconnect\"\n id=\"vMVXQh\"\n description=\"Button to disconnect an account\"\n />\n </Button>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n}\n\ninterface PipesLoadingProps extends WidgetRootDomProps {\n count: number;\n}\n\nconst PipesLoading: React.FC<PipesLoadingProps> = ({ count, ...domProps }) => {\n return (\n <CardList.Root {...getWidgetRootDomProps(\"loading\", domProps)}>\n {Array.from({ length: count }).map((_, index) => (\n <CardList.Item key={index}>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel>\n <ProviderIcon provider=\"google\" size=\"2\" />\n </IconPanel>\n </Skeleton>\n <Skeleton>\n <Text size=\"2\" weight=\"bold\">\n <Translation\n defaultMessage=\"Google Drive\"\n id=\"g11OOu\"\n description=\"Placeholder text for loading state\"\n />\n </Text>\n </Skeleton>\n </Flex>\n <Skeleton>\n <Button variant=\"secondary\" disabled>\n <Translation\n defaultMessage=\"Connect\"\n id=\"8TuDfA\"\n description=\"Placeholder button text for loading state\"\n />\n </Button>\n </Skeleton>\n </Flex>\n </CardList.Item>\n ))}\n </CardList.Root>\n );\n};\n\nconst Pipes: React.FC<PipesProps> = ({ integrations, ...domProps }) => {\n return (\n <CardList.Root {...getWidgetRootDomProps(\"resolved\", domProps)}>\n {integrations.map((integration) => (\n <CardList.Item key={integration.id}>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <IconPanel color=\"panel\">\n <DataIntegrationIcon integration={integration} size=\"2\" />\n </IconPanel>\n <Text size=\"2\" weight=\"bold\">\n {integration.name}\n </Text>\n </Flex>\n <ProviderStatus integration={integration} />\n </Flex>\n </CardList.Item>\n ))}\n </CardList.Root>\n );\n};\n\ninterface PipesErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst PipesError: React.FC<PipesErrorProps> = ({ error, ...domProps }) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"pipes\",\n widgetState: state,\n });\n}\n\nexport type { PipesProps, PipesLoadingProps, PipesErrorProps };\nexport { Pipes, PipesLoading, PipesError };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/lib/pipes.tsx"],"sourcesContent":["\"use client\";\nimport { Callout, Card, Flex, Text } from \"@radix-ui/themes\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport * as CardList from \"./card-list.js\";\nimport { DataIntegrationIcon } from \"./data-integration-icon.js\";\nimport { ProviderIcon } from \"./provider-icon.js\";\nimport {\n DotsHorizontalIcon,\n ExternalLinkIcon,\n GlobeIcon,\n LockClosedIcon,\n} from \"@radix-ui/react-icons\";\nimport {\n AlertDialog,\n Button,\n Dialog,\n DropdownMenu,\n IconButton,\n Label,\n PasswordField,\n Skeleton,\n TextField,\n} from \"./elements.js\";\nimport { IconPanel } from \"./icon-panel.js\";\nimport { Status } from \"./status.js\";\nimport {\n DataIntegration,\n DataIntegrationConfigField,\n SharedDataConnection,\n getMyDataIntegrationsQueryKey,\n useAuthorizeDataIntegrationHook,\n useDeleteDataInstallation,\n useSettings,\n useUpsertDataIntegrationApiKey,\n useUpsertDataIntegrationClientCredentials,\n} from \"../api/endpoint.js\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { GenericError } from \"./generic-error.js\";\nimport { getDomProps, WidgetRootDomProps, WidgetRootState } from \"./utils.js\";\nimport { Translation } from \"./i18n/translation.js\";\nimport { useTranslation } from \"./i18n/use-translation.js\";\nimport { ApiError } from \"../api/errors.js\";\nimport { buildRedactedSecret, isRedactedSecret } from \"./redacted-secret.js\";\n\ninterface PipesProps extends WidgetRootDomProps {\n integrations: DataIntegration[];\n /**\n * Whether the endpoint returned any connections before the host's `filter`\n * ran, which is what tells an organization with nothing enabled yet apart\n * from a filter that matched nothing. Defaults to whatever survived, the\n * reading for an unfiltered list.\n */\n hasUnfilteredIntegrations?: boolean;\n}\n\ninterface PipesSectionsProps extends PipesProps {\n /**\n * Organization-owned connections, as returned by the shared-connections\n * endpoint. Empty both when the organization shares nothing and when the\n * request failed, since neither is something a member can act on.\n */\n sharedConnections: SharedDataConnection[];\n /**\n * {@link PipesProps.hasUnfilteredIntegrations} for the shared section. The\n * section is dropped entirely unless the organization shares something, so\n * this only ever decides whether a filtered-out lane says so.\n */\n hasUnfilteredSharedConnections?: boolean;\n /** Renders the shared section as skeleton rows while it resolves. */\n isSharedLoading?: boolean;\n /** Names the owning organization in the shared section's description. */\n organizationName?: string;\n}\n\nconst HANDOFF_INTERVAL_MS = 100;\nconst HANDOFF_MAX_ATTEMPTS = 100; // 10 seconds worth of attempts\n\ntype DataIntegrationAuthMethod = NonNullable<\n DataIntegration[\"authMethods\"]\n>[number];\n\n/** Supported connect methods, in the order they're offered to the user. */\nconst CONNECT_AUTH_METHODS: DataIntegrationAuthMethod[] = [\n \"oauth\",\n \"client_credentials\",\n \"api_key\",\n];\n\nconst useOpenDataIntegrationAuthorizeUrl = (integration: DataIntegration) => {\n const authorizeDataIntegration = useAuthorizeDataIntegrationHook();\n const settings = useSettings();\n const baseUrl = settings.data?.authkitOrigin ?? \"\";\n const intervalRef = useRef<ReturnType<typeof setInterval> | undefined>(\n undefined,\n );\n const messageHandlerRef = useRef<((event: MessageEvent) => void) | undefined>(\n undefined,\n );\n\n useEffect(() => {\n return () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n }\n if (messageHandlerRef.current) {\n window.removeEventListener(\"message\", messageHandlerRef.current);\n }\n };\n }, []);\n\n return useCallback(\n async (config?: Record<string, string>) => {\n // Clear any existing interval from a previous invocation\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n // Remove any existing message handler\n if (messageHandlerRef.current) {\n window.removeEventListener(\"message\", messageHandlerRef.current);\n messageHandlerRef.current = undefined;\n }\n\n // need to do this synchronously in the event handler to avoid popup blocker notifications\n const win = window.open(`${baseUrl}/pipes/redirecting`, \"_blank\");\n // A blocked popup yields null; fail loudly (caller catches) instead of\n // authorizing and then discarding the redirect into a phantom success.\n if (!win) {\n throw new Error(\"Unable to open the authorization window.\");\n }\n\n // caller will catch. Close the popup on failure so a network/permission/\n // config error doesn't strand a blank /pipes/redirecting tab.\n let authorization;\n try {\n authorization = await authorizeDataIntegration(integration.slug, {\n requireHandoff: true,\n config,\n });\n } catch (error) {\n win.close();\n throw error;\n }\n const { url, handoffToken, redirectToken } = authorization;\n if (win) {\n win.location = url;\n const parsedUrl = new URL(url);\n const payload = { handoffToken, redirectToken };\n\n const cleanup = () => {\n if (intervalRef.current) {\n clearInterval(intervalRef.current);\n intervalRef.current = undefined;\n }\n if (messageHandlerRef.current) {\n window.removeEventListener(\"message\", messageHandlerRef.current);\n messageHandlerRef.current = undefined;\n }\n };\n\n messageHandlerRef.current = (event: MessageEvent) => {\n if (\n event.origin === parsedUrl.origin &&\n event.data?.redirectToken === redirectToken\n ) {\n cleanup();\n }\n };\n window.addEventListener(\"message\", messageHandlerRef.current);\n\n let attempts = 0;\n intervalRef.current = setInterval(() => {\n attempts += 1;\n\n if (attempts >= HANDOFF_MAX_ATTEMPTS) {\n cleanup();\n return;\n }\n\n if (win && !win.closed) {\n win.postMessage(payload, parsedUrl.origin);\n } else {\n cleanup();\n }\n }, HANDOFF_INTERVAL_MS);\n }\n },\n [authorizeDataIntegration, integration.slug, baseUrl],\n );\n};\n\n/**\n * Returns the provider-declared `installation`-scope config fields that the\n * integration has not pinned a value for, sorted by descriptor `order`. These\n * are the fields the connect flow must prompt for (pin / prompt-if-unset).\n */\nfunction getUnpinnedInstallationFields(\n integration: DataIntegration,\n): DataIntegrationConfigField[] {\n return (integration.configFields ?? [])\n .filter(\n (field) =>\n field.scope === \"installation\" && !integration.config?.[field.key],\n )\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\n/**\n * Seed values for the descriptors from a stored `config` object, stringifying\n * the scalar values the inputs can round-trip and skipping anything else.\n */\nfunction getInitialConfigValues(\n fields: DataIntegrationConfigField[],\n storedConfig: Record<string, unknown>,\n): Record<string, string> {\n const values: Record<string, string> = {};\n for (const field of fields) {\n const stored = storedConfig[field.key];\n if (\n typeof stored === \"string\" ||\n typeof stored === \"number\" ||\n typeof stored === \"boolean\"\n ) {\n values[field.key] = String(stored);\n }\n }\n return values;\n}\n\n/**\n * Compile a descriptor `pattern` (+ optional flags), returning undefined when\n * it isn't valid regex syntax so the server's validation remains the backstop.\n *\n * Anchored as `^(?:…)$` to match the server, so an unanchored descriptor\n * pattern surfaces the same inline error here instead of passing client\n * validation and being rejected on submit.\n */\nfunction compileConfigFieldPattern(\n pattern: string,\n flags: string | undefined,\n): RegExp | undefined {\n try {\n return new RegExp(`^(?:${pattern})$`, flags);\n } catch {\n return undefined;\n }\n}\n\n/**\n * Form state for a set of provider-declared config-field descriptors: the\n * collected values, inline validation against `required` / `pattern`, and the\n * `config` payload the connect endpoints accept. Shared by every connect\n * surface so descriptors are rendered and validated in exactly one place.\n *\n * `initialValues` prefills the inputs (e.g. from an existing installation's\n * stored config); `isDirty` reports whether the user actually changed any of\n * them, which callers use to decide whether to send `config` at all.\n */\nfunction useConfigFieldsForm(\n fields: DataIntegrationConfigField[],\n initialValues: Record<string, string> = {},\n) {\n const [values, setValues] = useState<Record<string, string>>(initialValues);\n const [errors, setErrors] = useState<Record<string, string | null>>({});\n const translate = useTranslation();\n\n const requiredMessage = translate({\n defaultMessage: \"This field is required\",\n id: \"B2HvfC\",\n description:\n \"Validation error shown when a required configuration field is left empty\",\n });\n const patternMessage = translate({\n defaultMessage: \"Enter a valid value.\",\n id: \"2XWaGz\",\n description:\n \"Validation error shown when a configuration field value does not match the expected format\",\n });\n\n const setValue = (key: string, value: string) => {\n setValues((prev) => ({ ...prev, [key]: value }));\n setErrors((prev) => (prev[key] ? { ...prev, [key]: null } : prev));\n };\n\n const reset = () => {\n setValues(initialValues);\n setErrors({});\n };\n\n const validate = () => {\n const nextErrors: Record<string, string | null> = {};\n let valid = true;\n for (const field of fields) {\n const value = (values[field.key] ?? \"\").trim();\n if (field.required && !value) {\n nextErrors[field.key] = requiredMessage;\n valid = false;\n continue;\n }\n if (value && field.pattern) {\n const patternRegExp = compileConfigFieldPattern(\n field.pattern,\n field.patternFlags,\n );\n if (patternRegExp && !patternRegExp.test(value)) {\n nextErrors[field.key] = patternMessage;\n valid = false;\n continue;\n }\n }\n nextErrors[field.key] = null;\n }\n setErrors(nextErrors);\n return valid;\n };\n\n const buildConfig = () => {\n const config: Record<string, string> = {};\n for (const field of fields) {\n const value = (values[field.key] ?? \"\").trim();\n if (value) {\n config[field.key] = value;\n }\n }\n return config;\n };\n\n /**\n * The full `config` object to write, given the config the API returned for\n * the installation. The write is a wholesale replace, so keys the widget\n * never rendered (pinned at the integration level, or unknown to these\n * descriptors) are preserved as received rather than dropped.\n */\n const buildConfigPayload = (storedConfig: Record<string, unknown>) => {\n const payload: Record<string, unknown> = { ...storedConfig };\n for (const field of fields) {\n const value = (values[field.key] ?? \"\").trim();\n if (value) {\n payload[field.key] = value;\n } else {\n delete payload[field.key];\n }\n }\n return payload;\n };\n\n const hasMissingRequired = fields.some(\n (field) => field.required && !(values[field.key] ?? \"\").trim(),\n );\n\n const isDirty = fields.some(\n (field) => (values[field.key] ?? \"\") !== (initialValues[field.key] ?? \"\"),\n );\n\n return {\n values,\n errors,\n setValue,\n reset,\n validate,\n buildConfig,\n buildConfigPayload,\n hasMissingRequired,\n isDirty,\n };\n}\n\n/**\n * Renders config-field descriptors as labelled inputs (secret descriptors get a\n * password field), with inline validation errors wired up via `aria-invalid` /\n * `aria-describedby`.\n *\n * Stacks as label → description → input → hint, so the description is read\n * before the field is filled and the `default` hint sits with the value it\n * describes. (The dashboard's config form instead merges both into one help\n * line below the input; the copy matches, the placement follows the widget's\n * existing description-above-input layout.)\n *\n * The `default` — falling back to the display-only `example` — is the\n * placeholder, and is never filled in as a value: submitting it would pin it and\n * freeze it, while leaving the field empty lets the API resolve the default on\n * read, so a later change to it reaches existing installations.\n */\nfunction ConfigFieldInputs({\n idPrefix,\n fields,\n values,\n errors,\n onChange,\n}: {\n idPrefix: string;\n fields: DataIntegrationConfigField[];\n values: Record<string, string>;\n errors: Record<string, string | null>;\n onChange: (key: string, value: string) => void;\n}) {\n return fields.map((field) => {\n const fieldId = `${idPrefix}-${field.key}`;\n const errorId = `${fieldId}-error`;\n const descriptionId = `${fieldId}-description`;\n const error = errors[field.key];\n const Control = field.secret ? PasswordField : TextField;\n const defaultHint =\n field.default !== undefined ? (\n <Translation\n defaultMessage=\"Defaults to {value} when left blank.\"\n id=\"MTNqSC\"\n description=\"Hint naming the value used when a configuration field is left blank\"\n values={{ value: field.default }}\n />\n ) : null;\n // The hint and the error share the slot under the input; the error wins.\n const hintId = `${fieldId}-hint`;\n const showHint = !error && defaultHint;\n const describedBy =\n [\n field.description ? descriptionId : null,\n showHint ? hintId : null,\n error ? errorId : null,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n return (\n <Flex key={field.key} direction=\"column\" gap=\"1\">\n <Label htmlFor={fieldId}>{field.label}</Label>\n {field.description ? (\n <Text color=\"gray\" size=\"2\" id={descriptionId} mb=\"1\">\n {field.description}\n </Text>\n ) : null}\n <Control\n id={fieldId}\n value={values[field.key] ?? \"\"}\n placeholder={field.default ?? field.example}\n autoComplete=\"off\"\n required={field.required || undefined}\n aria-invalid={!!error || undefined}\n aria-describedby={describedBy}\n onChange={(event) => onChange(field.key, event.target.value)}\n />\n {showHint ? (\n <Text color=\"gray\" size=\"2\" id={hintId}>\n {defaultHint}\n </Text>\n ) : null}\n {error ? (\n <Text color=\"red\" size=\"2\" id={errorId}>\n {error}\n </Text>\n ) : null}\n </Flex>\n );\n });\n}\n\n/** Gray dot separator shown between the logos in the connect-dialog header. */\nfunction LogoSeparator() {\n return (\n <DotsHorizontalIcon\n width=\"20\"\n height=\"20\"\n style={{ color: \"var(--gray-8)\" }}\n />\n );\n}\n\n/**\n * Shared connect-dialog header: the WorkOS → provider icon row and the\n * \"{app} uses WorkOS to connect to {provider}\" title.\n */\nfunction ConnectDialogHeader({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n const settings = useSettings();\n const logo = settings.data?.logoDarkPath ?? settings.data?.logoLightPath;\n const appName = settings.data?.teamName ?? \"This application\";\n\n return (\n <>\n <Flex justify=\"center\" align=\"center\" gap=\"2\" mt=\"2\">\n {logo && (\n <>\n <IconPanel color=\"panel\" style={{ width: \"48px\", height: \"48px\" }}>\n <ProviderIcon\n size=\"2\"\n provider=\"workos\"\n style={{ backgroundImage: `url(${logo})` }}\n />\n </IconPanel>\n <LogoSeparator />\n </>\n )}\n <IconPanel\n color=\"panel\"\n style={{\n ...(logo ? { borderWidth: 0 } : undefined),\n width: \"48px\",\n height: \"48px\",\n }}\n >\n <ProviderIcon size=\"2\" provider=\"workos\" />\n </IconPanel>\n <LogoSeparator />\n <IconPanel color=\"panel\" style={{ width: \"48px\", height: \"48px\" }}>\n <DataIntegrationIcon size=\"2\" integration={integration} />\n </IconPanel>\n </Flex>\n <Dialog.Title size=\"2\" mt=\"5\" mb=\"5\" weight={\"bold\"} align=\"center\">\n <Translation\n defaultMessage=\"{appName} uses WorkOS to connect to {integrationName}.\"\n id=\"ujRDBH\"\n description=\"Dialog title explaining the app connection flow\"\n values={{ appName, integrationName: integration.name }}\n />\n </Dialog.Title>\n </>\n );\n}\n\n/**\n * Shared connect-dialog explainer card: \"you'll be redirected to sign in\" +\n * \"your credentials remain secure\".\n */\nfunction ConnectExplainerCard({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n return (\n <Card>\n <Flex direction=\"column\" gap=\"4\">\n <Flex gap=\"2\" align=\"center\">\n <IconPanel color=\"gray\" style={{ width: \"32px\", height: \"32px\" }}>\n <GlobeIcon />\n </IconPanel>\n <Flex direction=\"column\">\n <Text size=\"1\" weight=\"bold\">\n <Translation\n defaultMessage=\"You'll be redirected to sign in with {integrationName}.\"\n id=\"g+n4aY\"\n description=\"Instruction about redirect to sign in\"\n values={{ integrationName: integration.name }}\n />\n </Text>\n <Text size=\"1\">\n <Translation\n defaultMessage=\"Authorize access to connect your account.\"\n id=\"fxVS34\"\n description=\"Instruction to authorize access\"\n />\n </Text>\n </Flex>\n </Flex>\n <Flex gap=\"2\" align=\"center\">\n <IconPanel color=\"gray\" style={{ width: \"32px\", height: \"32px\" }}>\n <LockClosedIcon />\n </IconPanel>\n <Flex direction=\"column\">\n <Text size=\"1\" weight=\"bold\">\n <Translation\n defaultMessage=\"Your credentials remain secure.\"\n id=\"gM3bot\"\n description=\"Security message about credentials\"\n />\n </Text>\n <Text size=\"1\">\n <Translation\n defaultMessage=\"WorkOS never sees your credentials.\"\n id=\"kC9Fwe\"\n description=\"Security message about WorkOS not seeing credentials\"\n />\n </Text>\n </Flex>\n </Flex>\n </Flex>\n </Card>\n );\n}\n\n/**\n * The single connect dialog for all non-API (OAuth) providers. When the\n * provider declares unpinned `installation`-scope config fields (e.g. a Zendesk\n * subdomain), it opens on a field-collection step (values validated against the\n * descriptor `required` / `pattern`) before the redirect explainer; otherwise\n * it opens directly on the explainer. Collected values are submitted as\n * `config` on the POST authorize call. Controlled so it backs the initial\n * connect flow, the dual-method OAuth option, and reauthorization.\n */\nfunction ConnectDialog({\n integration,\n fields,\n open,\n onOpenChange,\n}: {\n integration: DataIntegration;\n fields: DataIntegrationConfigField[];\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n // Providers without fields to collect skip straight to the explainer.\n const initialStep = fields.length > 0 ? \"fields\" : \"review\";\n const [step, setStep] = useState<\"fields\" | \"review\">(initialStep);\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const configForm = useConfigFieldsForm(fields);\n const eventHandler = useOpenDataIntegrationAuthorizeUrl(integration);\n const translate = useTranslation();\n\n const genericConnectError = translate({\n defaultMessage: \"We couldn't start the connection. Please try again.\",\n id: \"zGw1ma\",\n description:\n \"Fallback error shown when starting the connection fails for a non-specific reason\",\n });\n\n const reset = () => {\n setStep(initialStep);\n configForm.reset();\n setSubmitError(null);\n setIsSubmitting(false);\n };\n\n const handleConnect = async () => {\n setSubmitError(null);\n setIsSubmitting(true);\n try {\n // Opens the popup synchronously within this click before awaiting.\n await eventHandler(configForm.buildConfig());\n onOpenChange(false);\n } catch (error) {\n // Surface a message for every failure mode (ApiError, network, blocked\n // popup, etc.) so the dialog never fails silently.\n setSubmitError(\n error instanceof ApiError && error.message\n ? error.message\n : genericConnectError,\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return (\n <Dialog.Root\n open={open}\n onOpenChange={(next) => {\n onOpenChange(next);\n if (!next) {\n reset();\n }\n }}\n >\n <Dialog.Content maxWidth=\"430px\">\n <ConnectDialogHeader integration={integration} />\n\n {step === \"fields\" ? (\n <>\n <Card>\n <Flex direction=\"column\" gap=\"4\">\n <ConfigFieldInputs\n idPrefix=\"pipes-config\"\n fields={fields}\n values={configForm.values}\n errors={configForm.errors}\n onChange={configForm.setValue}\n />\n </Flex>\n </Card>\n <Flex justify=\"end\" gap=\"3\" mt=\"5\">\n <Dialog.Close>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <Button\n type=\"button\"\n disabled={configForm.hasMissingRequired}\n onClick={() => {\n if (configForm.validate()) {\n setStep(\"review\");\n }\n }}\n >\n <Translation\n defaultMessage=\"Next\"\n id=\"L2fmxK\"\n description=\"Button to advance to the next step of the connect flow\"\n />\n </Button>\n </Flex>\n </>\n ) : (\n <>\n {submitError && (\n <Callout.Root mb=\"3\" color=\"red\" role=\"alert\">\n <Callout.Text>{submitError}</Callout.Text>\n </Callout.Root>\n )}\n <ConnectExplainerCard integration={integration} />\n <Flex justify=\"end\" gap=\"3\" mt=\"5\">\n {fields.length > 0 ? (\n <Button\n variant=\"secondary\"\n type=\"button\"\n onClick={() => setStep(\"fields\")}\n >\n <Translation\n defaultMessage=\"Back\"\n id=\"J9MvVP\"\n description=\"Button to return to the previous step of the connect flow\"\n />\n </Button>\n ) : (\n <Dialog.Close>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n )}\n <Button\n type=\"button\"\n loading={isSubmitting}\n disabled={isSubmitting}\n onClick={handleConnect}\n >\n <Translation\n defaultMessage=\"Connect\"\n id=\"16WmG0\"\n description=\"Connect button with external link\"\n trailingSpace\n />\n <ExternalLinkIcon aria-hidden />\n </Button>\n </Flex>\n </>\n )}\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\n/**\n * Connect button for a not-yet-connected OAuth provider. Opens the unified\n * {@link ConnectDialog}, which prompts for any unpinned `installation`-scope\n * config fields before the redirect explainer.\n */\nfunction ConnectIntegrationButton({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n const [open, setOpen] = useState(false);\n const fields = getUnpinnedInstallationFields(integration);\n\n return (\n <>\n <ConnectDialog\n integration={integration}\n fields={fields}\n open={open}\n onOpenChange={setOpen}\n />\n <Button variant=\"secondary\" onClick={() => setOpen(true)}>\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n </Button>\n </>\n );\n}\n\nconst API_KEY_REDACTED_PREFIX = \"••••\";\n\nfunction ApiKeyDialog({\n integration,\n open,\n onOpenChange,\n}: {\n integration: DataIntegration;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const queryClient = useQueryClient();\n const installation = integration.installation;\n const isRotation =\n installation?.auth_method === \"api_key\" &&\n installation.state === \"connected\";\n const last4 = installation?.api_key_last_4;\n const maskedKey = last4 ? `${API_KEY_REDACTED_PREFIX}${last4}` : \"\";\n\n const [secret, setSecret] = useState(\"\");\n const translate = useTranslation();\n\n const apiKeyPlaceholder = translate({\n defaultMessage: \"Enter your API key\",\n id: \"MzSxEF\",\n description: \"Placeholder for the API key input field\",\n });\n\n const {\n mutate: upsertApiKey,\n error,\n reset,\n isPending,\n } = useUpsertDataIntegrationApiKey({\n mutation: {\n onSuccess: () => {\n onOpenChange(false);\n queryClient.invalidateQueries({\n queryKey: getMyDataIntegrationsQueryKey(),\n });\n },\n },\n });\n\n // The component is only mounted while open (conditional rendering in\n // ApiKeyConnectButton / ProviderStatus), so state resets on mount.\n // We only need to reset the mutation state when the dialog opens in\n // case the same instance was reused.\n useEffect(() => {\n reset();\n }, [reset]);\n\n const errorMessage = (() => {\n if (!error) return null;\n if (error instanceof ApiError && error.message) {\n return error.message;\n }\n return null;\n })();\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Content maxWidth=\"430px\">\n <Dialog.Title size=\"3\" weight=\"bold\">\n {isRotation ? (\n <Translation\n defaultMessage=\"Rotate API key for {integrationName}\"\n id=\"8+NN3t\"\n description=\"Dialog title for rotating an API key\"\n values={{ integrationName: integration.name }}\n />\n ) : (\n <Translation\n defaultMessage=\"Connect {integrationName} with API key\"\n id=\"EyItbA\"\n description=\"Dialog title for connecting with an API key\"\n values={{ integrationName: integration.name }}\n />\n )}\n </Dialog.Title>\n\n {/*\n * The provider's own description. Built-in providers are self-evident,\n * but a custom provider's definition copy is the only thing telling the\n * tenant which key to paste and where to mint it. Rendered as the\n * dialog's description so it's announced with the dialog rather than\n * being an unassociated paragraph.\n */}\n {integration.description && (\n <Dialog.Description color=\"gray\" mt=\"1\">\n {integration.description}\n </Dialog.Description>\n )}\n\n {error && (\n <Callout.Root my=\"3\" color=\"red\" role=\"alert\">\n <Callout.Text>\n {errorMessage ?? (\n <Translation\n defaultMessage=\"An error occurred. Please check the value and try again.\"\n id=\"bYLbLL\"\n description=\"Generic error message for API key submission failure\"\n />\n )}\n </Callout.Text>\n </Callout.Root>\n )}\n\n <Flex direction=\"column\" gap=\"4\" mt=\"2\">\n {isRotation && last4 && (\n <Flex direction=\"column\" gap=\"1\">\n <Label>\n <Translation\n defaultMessage=\"Current API key\"\n id=\"+odk8g\"\n description=\"Label for the current masked API key\"\n />\n </Label>\n <Text size=\"2\" color=\"gray\">\n {maskedKey}\n </Text>\n </Flex>\n )}\n\n <Flex direction=\"column\" gap=\"1\">\n <Label>\n {isRotation ? (\n <Translation\n defaultMessage=\"New API key\"\n id=\"L3AmMK\"\n description=\"Label for the new API key input when rotating\"\n />\n ) : (\n <Translation\n defaultMessage=\"API key\"\n id=\"Xnkv+J\"\n description=\"Label for the API key input\"\n />\n )}\n </Label>\n <PasswordField\n value={secret}\n autoComplete=\"off\"\n placeholder={apiKeyPlaceholder}\n onChange={(event) => setSecret(event.target.value)}\n />\n </Flex>\n </Flex>\n\n <Flex justify=\"end\" gap=\"3\" mt=\"5\">\n <Dialog.Close>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <Button\n type=\"button\"\n disabled={isPending || !secret.trim()}\n loading={isPending}\n onClick={() =>\n upsertApiKey({\n slug: integration.slug,\n data: { secret: secret.trim() },\n })\n }\n >\n {isRotation ? (\n <Translation\n defaultMessage=\"Rotate\"\n id=\"LAh+p5\"\n description=\"Button to rotate an API key\"\n />\n ) : (\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n )}\n </Button>\n </Flex>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\nfunction ApiKeyConnectButton({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n const [open, setOpen] = useState(false);\n\n return (\n <>\n {open && (\n <ApiKeyDialog\n integration={integration}\n open={open}\n onOpenChange={setOpen}\n />\n )}\n <Button variant=\"secondary\" onClick={() => setOpen(true)}>\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n </Button>\n </>\n );\n}\n\n/**\n * Connect form for the `client_credentials` auth method: the provider's client\n * id and secret plus any unpinned `installation`-scope config fields, rendered\n * generically from the descriptors via {@link ConfigFieldInputs}. Submits to\n * PUT `/DataIntegrations/:slug/client-credentials`, which also handles\n * replacing the credentials of an existing client-credentials installation.\n *\n * For an existing installation the form is prefilled from it: the client id as\n * received, the stored secret as a redacted mask that clears on focus (the\n * real value is never sent to the widget, so a new secret must be re-entered\n * to save), and the config fields from `installation.config`. `config` is only\n * included in the payload when the user edits a config field, since the API\n * keeps the stored config when the key is absent; when it is included it is\n * the full round-tripped object, because the write replaces config wholesale.\n */\nfunction ClientCredentialsDialog({\n integration,\n fields,\n open,\n onOpenChange,\n}: {\n integration: DataIntegration;\n fields: DataIntegrationConfigField[];\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const queryClient = useQueryClient();\n const installation = integration.installation;\n const isUpdate = installation?.auth_method === \"client_credentials\";\n const storedConfig = useMemo(\n () => (isUpdate ? (installation?.config ?? {}) : {}),\n [isUpdate, installation?.config],\n );\n const initialConfigValues = useMemo(\n () => getInitialConfigValues(fields, storedConfig),\n [fields, storedConfig],\n );\n const redactedSecret = buildRedactedSecret(\n isUpdate ? installation?.client_secret_last_4 : null,\n );\n\n const [clientId, setClientId] = useState(\n (isUpdate ? installation?.client_id : null) ?? \"\",\n );\n const [clientSecret, setClientSecret] = useState(redactedSecret);\n const configForm = useConfigFieldsForm(fields, initialConfigValues);\n const translate = useTranslation();\n\n const clientIdPlaceholder = translate({\n defaultMessage: \"Enter your client ID\",\n id: \"5YTAFo\",\n description: \"Placeholder for the client credentials client ID input\",\n });\n const clientSecretPlaceholder = translate({\n defaultMessage: \"Enter your client secret\",\n id: \"53f0B7\",\n description: \"Placeholder for the client credentials client secret input\",\n });\n\n // The widget never holds the real secret, so the prefilled mask can't be\n // submitted: the PUT requires a client secret and re-entry is the only way\n // to supply one.\n const secretMissing = !clientSecret.trim() || isRedactedSecret(clientSecret);\n\n const {\n mutate: upsertClientCredentials,\n error,\n isPending,\n } = useUpsertDataIntegrationClientCredentials({\n mutation: {\n onSuccess: () => {\n onOpenChange(false);\n queryClient.invalidateQueries({\n queryKey: getMyDataIntegrationsQueryKey(),\n });\n },\n },\n });\n\n // Server errors — including the 409 raised when an installation already\n // exists with a different auth method — are surfaced in the banner.\n const errorMessage =\n error instanceof ApiError && error.message ? error.message : null;\n\n const handleSubmit = () => {\n if (!configForm.validate()) {\n return;\n }\n // Untouched config fields mean no `config` key at all: the API preserves\n // the stored config when it's absent, and sending the prefilled object\n // back would make every credential update a config write too.\n const config = configForm.isDirty\n ? configForm.buildConfigPayload(storedConfig)\n : undefined;\n upsertClientCredentials({\n slug: integration.slug,\n data: {\n client_id: clientId.trim(),\n client_secret: clientSecret.trim(),\n ...(config ? { config } : {}),\n },\n });\n };\n\n return (\n <Dialog.Root open={open} onOpenChange={onOpenChange}>\n <Dialog.Content maxWidth=\"430px\">\n <Dialog.Title size=\"3\" weight=\"bold\">\n {isUpdate ? (\n <Translation\n defaultMessage=\"Update client credentials for {integrationName}\"\n id=\"/D85zF\"\n description=\"Dialog title for updating stored client credentials\"\n values={{ integrationName: integration.name }}\n />\n ) : (\n <Translation\n defaultMessage=\"Connect {integrationName} with client credentials\"\n id=\"x+7tw3\"\n description=\"Dialog title for connecting with client credentials\"\n values={{ integrationName: integration.name }}\n />\n )}\n </Dialog.Title>\n\n {error && (\n <Callout.Root my=\"3\" color=\"red\" role=\"alert\">\n <Callout.Text>\n {errorMessage ?? (\n <Translation\n defaultMessage=\"An error occurred. Please check the value and try again.\"\n id=\"bYLbLL\"\n description=\"Generic error message for API key submission failure\"\n />\n )}\n </Callout.Text>\n </Callout.Root>\n )}\n\n <Flex direction=\"column\" gap=\"4\" mt=\"2\">\n <Flex direction=\"column\" gap=\"1\">\n <Label htmlFor=\"pipes-client-credentials-client-id\">\n <Translation\n defaultMessage=\"Client ID\"\n id=\"/Cv5P1\"\n description=\"Label for the client credentials client ID input\"\n />\n </Label>\n <TextField\n id=\"pipes-client-credentials-client-id\"\n value={clientId}\n autoComplete=\"off\"\n placeholder={clientIdPlaceholder}\n onChange={(event) => setClientId(event.target.value)}\n />\n </Flex>\n\n <Flex direction=\"column\" gap=\"1\">\n <Label htmlFor=\"pipes-client-credentials-client-secret\">\n <Translation\n defaultMessage=\"Client secret\"\n id=\"uScBDj\"\n description=\"Label for the client credentials client secret input\"\n />\n </Label>\n {isUpdate && (\n <Text\n color=\"gray\"\n size=\"2\"\n id=\"pipes-client-credentials-client-secret-description\"\n mb=\"1\"\n >\n <Translation\n defaultMessage=\"Enter the client secret again to save any changes.\"\n id=\"ZrNPCF\"\n description=\"Help text explaining the client secret must be re-entered to save an update\"\n />\n </Text>\n )}\n <PasswordField\n id=\"pipes-client-credentials-client-secret\"\n value={clientSecret}\n autoComplete=\"off\"\n // The mask is what's shown, so render it as text: a password\n // input would re-bullet its last four digits away.\n type={isRedactedSecret(clientSecret) ? \"text\" : undefined}\n placeholder={clientSecretPlaceholder}\n aria-describedby={\n isUpdate\n ? \"pipes-client-credentials-client-secret-description\"\n : undefined\n }\n onChange={(event) => setClientSecret(event.target.value)}\n onFocus={() => {\n if (isRedactedSecret(clientSecret)) {\n setClientSecret(\"\");\n }\n }}\n onBlur={() => {\n if (clientSecret === \"\") {\n setClientSecret(redactedSecret);\n }\n }}\n />\n </Flex>\n\n <ConfigFieldInputs\n idPrefix=\"pipes-client-credentials-config\"\n fields={fields}\n values={configForm.values}\n errors={configForm.errors}\n onChange={configForm.setValue}\n />\n </Flex>\n\n <Flex justify=\"end\" gap=\"3\" mt=\"5\">\n <Dialog.Close>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </Dialog.Close>\n <Button\n type=\"button\"\n disabled={\n isPending ||\n !clientId.trim() ||\n secretMissing ||\n configForm.hasMissingRequired\n }\n loading={isPending}\n onClick={handleSubmit}\n >\n {isUpdate ? (\n <Translation\n defaultMessage=\"Save\"\n id=\"RT8KNi\"\n description=\"Save button text\"\n />\n ) : (\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n )}\n </Button>\n </Flex>\n </Dialog.Content>\n </Dialog.Root>\n );\n}\n\nfunction ClientCredentialsConnectButton({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n const [open, setOpen] = useState(false);\n const fields = getUnpinnedInstallationFields(integration);\n\n return (\n <>\n {open && (\n <ClientCredentialsDialog\n integration={integration}\n fields={fields}\n open={open}\n onOpenChange={setOpen}\n />\n )}\n <Button variant=\"secondary\" onClick={() => setOpen(true)}>\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n </Button>\n </>\n );\n}\n\n/**\n * Connect entry point for a provider that supports more than one auth method:\n * a menu with one item per method, each opening that method's dialog.\n */\nfunction MultiMethodConnectButton({\n integration,\n methods,\n}: {\n integration: DataIntegration;\n methods: DataIntegrationAuthMethod[];\n}) {\n const [apiKeyOpen, setApiKeyOpen] = useState(false);\n const [oauthOpen, setOauthOpen] = useState(false);\n const [clientCredentialsOpen, setClientCredentialsOpen] = useState(false);\n const fields = getUnpinnedInstallationFields(integration);\n\n return (\n <>\n {apiKeyOpen && (\n <ApiKeyDialog\n integration={integration}\n open={apiKeyOpen}\n onOpenChange={setApiKeyOpen}\n />\n )}\n {clientCredentialsOpen && (\n <ClientCredentialsDialog\n integration={integration}\n fields={fields}\n open={clientCredentialsOpen}\n onOpenChange={setClientCredentialsOpen}\n />\n )}\n {methods.includes(\"oauth\") && (\n <ConnectDialog\n integration={integration}\n fields={fields}\n open={oauthOpen}\n onOpenChange={setOauthOpen}\n />\n )}\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Connect\"\n id=\"quvdFp\"\n description=\"Button to connect an integration\"\n />\n </Button>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n {methods.includes(\"oauth\") && (\n <DropdownMenu.Item onClick={() => setOauthOpen(true)}>\n <Flex gap=\"4\" width=\"100%\" justify=\"between\" align=\"center\">\n <Translation\n defaultMessage=\"Sign in with OAuth\"\n id=\"ssNz+0\"\n description=\"Menu option to connect via OAuth\"\n trailingSpace\n />\n <ExternalLinkIcon aria-hidden />\n </Flex>\n </DropdownMenu.Item>\n )}\n {methods.includes(\"client_credentials\") && (\n <DropdownMenu.Item onClick={() => setClientCredentialsOpen(true)}>\n <Translation\n defaultMessage=\"Enter client credentials\"\n id=\"Y/87Vt\"\n description=\"Menu option to connect via client credentials\"\n />\n </DropdownMenu.Item>\n )}\n {methods.includes(\"api_key\") && (\n <DropdownMenu.Item onClick={() => setApiKeyOpen(true)}>\n <Translation\n defaultMessage=\"Enter API key\"\n id=\"8mq2DA\"\n description=\"Menu option to connect via API key\"\n />\n </DropdownMenu.Item>\n )}\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n </>\n );\n}\n\nfunction ProviderStatus({ integration }: { integration: DataIntegration }) {\n const [disconnectOpen, setDisconnectOpen] = useState(false);\n const [apiKeyOpen, setApiKeyOpen] = useState(false);\n const [clientCredentialsOpen, setClientCredentialsOpen] = useState(false);\n const [reauthConfigOpen, setReauthConfigOpen] = useState(false);\n const authorizeEventHandler = useOpenDataIntegrationAuthorizeUrl(integration);\n const translate = useTranslation();\n\n const pipeActionsTitle = translate({\n defaultMessage: \"Pipe actions\",\n id: \"1uF9ve\",\n description: \"Title for pipe actions dropdown button\",\n });\n\n // Unpinned installation fields must be re-collected on reauthorization too;\n // the authorize endpoint rejects them as missing otherwise.\n const unpinnedFields = getUnpinnedInstallationFields(integration);\n\n if (integration.installation) {\n const connected = integration.installation.state === \"connected\";\n const isApiKeyInstallation =\n integration.installation.auth_method === \"api_key\";\n const isClientCredentialsInstallation =\n integration.installation.auth_method === \"client_credentials\";\n\n return (\n <>\n <DisconnectAccountDialog\n integrationName={integration.name}\n installationId={integration.installation.id}\n open={disconnectOpen}\n onOpenChange={setDisconnectOpen}\n />\n {apiKeyOpen && (\n <ApiKeyDialog\n integration={integration}\n open={apiKeyOpen}\n onOpenChange={setApiKeyOpen}\n />\n )}\n {clientCredentialsOpen && (\n <ClientCredentialsDialog\n integration={integration}\n fields={unpinnedFields}\n open={clientCredentialsOpen}\n onOpenChange={setClientCredentialsOpen}\n />\n )}\n {unpinnedFields.length > 0 && !isClientCredentialsInstallation && (\n <ConnectDialog\n integration={integration}\n fields={unpinnedFields}\n open={reauthConfigOpen}\n onOpenChange={setReauthConfigOpen}\n />\n )}\n <Flex align=\"center\" gap=\"4\">\n <Status state={connected ? \"success\" : \"error\"}>\n {connected ? (\n <Translation\n defaultMessage=\"Connected\"\n id=\"i6Hxoz\"\n description=\"Status text for connected integration\"\n />\n ) : (\n <Translation\n defaultMessage=\"Requires reauthorization\"\n id=\"dqczQS\"\n description=\"Status text for integration needing reauthorization\"\n />\n )}\n </Status>\n {isClientCredentialsInstallation ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton title={pipeActionsTitle}>\n <DotsHorizontalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item\n onClick={() => setClientCredentialsOpen(true)}\n >\n <Translation\n defaultMessage=\"Update client credentials\"\n id=\"daHKWE\"\n description=\"Menu option to update stored client credentials\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Item\n variant=\"destructive\"\n onClick={() => setDisconnectOpen(true)}\n >\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"esZQrd\"\n description=\"Menu option to disconnect an account\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : connected && isApiKeyInstallation ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton title={pipeActionsTitle}>\n <DotsHorizontalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item onClick={() => setApiKeyOpen(true)}>\n <Translation\n defaultMessage=\"Rotate API key\"\n id=\"GML+c8\"\n description=\"Menu option to rotate the API key\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Item\n variant=\"destructive\"\n onClick={() => setDisconnectOpen(true)}\n >\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"esZQrd\"\n description=\"Menu option to disconnect an account\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : connected ? (\n <Button variant=\"secondary\" onClick={() => setDisconnectOpen(true)}>\n <Translation\n defaultMessage=\"Disconnect\"\n id=\"vMVXQh\"\n description=\"Button to disconnect an account\"\n />\n </Button>\n ) : isApiKeyInstallation ? (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton title={pipeActionsTitle}>\n <DotsHorizontalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item onClick={() => setApiKeyOpen(true)}>\n <Translation\n defaultMessage=\"Update API key\"\n id=\"E7pMj/\"\n description=\"Menu option to update the API key for a needs-reauthorization installation\"\n />\n </DropdownMenu.Item>\n <DropdownMenu.Item\n variant=\"destructive\"\n onClick={() => setDisconnectOpen(true)}\n >\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"esZQrd\"\n description=\"Menu option to disconnect an account\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n ) : (\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton title={pipeActionsTitle}>\n <DotsHorizontalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n <DropdownMenu.Item\n onClick={async () => {\n if (unpinnedFields.length > 0) {\n setReauthConfigOpen(true);\n return;\n }\n try {\n await authorizeEventHandler();\n } catch {\n // pass - error displayed in new tab\n }\n }}\n >\n <Flex gap=\"4\" width=\"100%\" justify=\"between\" align=\"center\">\n <Translation\n defaultMessage=\"Reauthorize\"\n id=\"0E29F1\"\n description=\"Menu option to reauthorize an integration\"\n trailingSpace\n />\n <ExternalLinkIcon aria-hidden />\n </Flex>\n </DropdownMenu.Item>\n <DropdownMenu.Item\n variant=\"destructive\"\n onClick={() => setDisconnectOpen(true)}\n >\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"esZQrd\"\n description=\"Menu option to disconnect an account\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n )}\n </Flex>\n </>\n );\n }\n\n // Not connected: choose the connect entry point from the supported methods.\n // More than one: a menu of methods; otherwise that method's own button, with\n // OAuth as the default for a provider that declares nothing.\n const authMethods = integration.authMethods ?? [];\n const methods = CONNECT_AUTH_METHODS.filter((method) =>\n authMethods.includes(method),\n );\n\n return (\n <Flex align=\"center\" gap=\"4\">\n <Status state=\"neutral\">\n <Translation\n defaultMessage=\"Not connected\"\n id=\"J7bTZa\"\n description=\"Status text for an integration that is not connected\"\n />\n </Status>\n {methods.length > 1 ? (\n <MultiMethodConnectButton integration={integration} methods={methods} />\n ) : methods.length === 1 && methods[0] === \"api_key\" ? (\n <ApiKeyConnectButton integration={integration} />\n ) : methods.length === 1 && methods[0] === \"client_credentials\" ? (\n <ClientCredentialsConnectButton integration={integration} />\n ) : (\n <ConnectIntegrationButton integration={integration} />\n )}\n </Flex>\n );\n}\n\nfunction DisconnectAccountDialog({\n integrationName,\n installationId,\n open,\n onOpenChange,\n}: {\n integrationName: string;\n installationId: string;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const queryClient = useQueryClient();\n const {\n mutate: deleteDataInstallation,\n error,\n reset,\n isPending,\n } = useDeleteDataInstallation({\n mutation: {\n onSuccess: () => {\n onOpenChange(false);\n queryClient.invalidateQueries({\n queryKey: getMyDataIntegrationsQueryKey(),\n });\n },\n },\n });\n\n useEffect(() => {\n if (open) {\n reset();\n }\n }, [open, reset]);\n\n return (\n <AlertDialog.Root open={open} onOpenChange={onOpenChange}>\n <AlertDialog.Content style={{ width: \"80vw\", maxWidth: \"520px\" }}>\n <AlertDialog.Title>\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"9ABlCr\"\n description=\"Dialog title for disconnecting an account\"\n />\n </AlertDialog.Title>\n {error && (\n <Callout.Root my=\"5\" color=\"red\" role=\"alert\">\n <Callout.Text>\n <Translation\n defaultMessage=\"An error occurred while disconnecting your account. Please refresh the page and try again.\"\n id=\"qKBKF7\"\n description=\"Error message when disconnecting an account fails\"\n />\n </Callout.Text>\n </Callout.Root>\n )}\n <AlertDialog.Description>\n <Translation\n defaultMessage=\"Are you sure you want to disconnect your {integrationName} account?\"\n id=\"eEXeqP\"\n description=\"Confirmation message for disconnecting an account\"\n values={{\n integrationName: (\n <Text as=\"span\" weight=\"bold\">\n {integrationName}\n </Text>\n ),\n }}\n />\n </AlertDialog.Description>\n <Flex gap=\"3\" justify=\"end\" mt=\"5\">\n <AlertDialog.Cancel>\n <Button variant=\"secondary\">\n <Translation\n defaultMessage=\"Cancel\"\n id=\"hHNj31\"\n description=\"Cancel button text\"\n />\n </Button>\n </AlertDialog.Cancel>\n <Button\n variant=\"destructive\"\n disabled={isPending}\n loading={isPending}\n onClick={() => deleteDataInstallation({ installationId })}\n >\n <Translation\n defaultMessage=\"Disconnect\"\n id=\"vMVXQh\"\n description=\"Button to disconnect an account\"\n />\n </Button>\n </Flex>\n </AlertDialog.Content>\n </AlertDialog.Root>\n );\n}\n\ninterface PipesLoadingProps extends WidgetRootDomProps {\n count: number;\n}\n\n/** The skeleton rows shared by the whole-widget and shared-section loaders. */\nfunction PipesSkeletonItems({ count }: { count: number }) {\n return Array.from({ length: count }).map((_, index) => (\n <CardList.Item key={index}>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <Skeleton>\n <IconPanel>\n <ProviderIcon provider=\"google\" size=\"2\" />\n </IconPanel>\n </Skeleton>\n <Skeleton>\n <Text size=\"2\" weight=\"bold\">\n <Translation\n defaultMessage=\"Google Drive\"\n id=\"g11OOu\"\n description=\"Placeholder text for loading state\"\n />\n </Text>\n </Skeleton>\n </Flex>\n <Skeleton>\n <Button variant=\"secondary\" disabled>\n <Translation\n defaultMessage=\"Connect\"\n id=\"8TuDfA\"\n description=\"Placeholder button text for loading state\"\n />\n </Button>\n </Skeleton>\n </Flex>\n </CardList.Item>\n ));\n}\n\nconst PipesLoading: React.FC<PipesLoadingProps> = ({ count, ...domProps }) => {\n return (\n <CardList.Root {...getWidgetRootDomProps(\"loading\", domProps)}>\n <PipesSkeletonItems count={count} />\n </CardList.Root>\n );\n};\n\n/** The member's own connections, each with its credential-management actions. */\nfunction PipesItems({ integrations }: { integrations: DataIntegration[] }) {\n return integrations.map((integration) => (\n <CardList.Item key={integration.id}>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"2\">\n <Flex gap=\"4\" align=\"center\">\n <IconPanel color=\"panel\">\n <DataIntegrationIcon integration={integration} size=\"2\" />\n </IconPanel>\n <Text size=\"2\" weight=\"bold\">\n {integration.name}\n </Text>\n </Flex>\n <ProviderStatus integration={integration} />\n </Flex>\n </CardList.Item>\n ));\n}\n\n/**\n * Stands in for the rows a list has none of. Filtering is client-side, so an\n * empty list can say whether nothing is enabled yet or a `filter` emptied it.\n */\nfunction PipesEmptyItem({ isFiltered }: { isFiltered: boolean }) {\n return (\n <CardList.Item>\n <Text size=\"2\" color=\"gray\">\n {isFiltered ? (\n <Translation\n defaultMessage=\"No integrations to show.\"\n id=\"cAs7JC\"\n description=\"Empty state shown when the host's filter leaves no integrations to list\"\n />\n ) : (\n <Translation\n defaultMessage=\"No integrations are available yet.\"\n id=\"oK0Rjh\"\n description=\"Empty state shown when no integrations are enabled at all\"\n />\n )}\n </Text>\n </CardList.Item>\n );\n}\n\nconst Pipes: React.FC<PipesProps> = ({\n integrations,\n hasUnfilteredIntegrations,\n ...domProps\n}) => {\n return (\n <CardList.Root {...getWidgetRootDomProps(\"resolved\", domProps)}>\n {integrations.length > 0 ? (\n <PipesItems integrations={integrations} />\n ) : (\n <PipesEmptyItem isFiltered={hasUnfilteredIntegrations ?? false} />\n )}\n </CardList.Root>\n );\n};\n\n/**\n * A member's view of an organization-owned connection: usable as soon as one of\n * the organization's accounts is available, otherwise waiting on an\n * administrator. Members have no actions either way, so this is text only.\n */\nfunction SharedConnectionStatus({\n connection,\n}: {\n connection: SharedDataConnection;\n}) {\n const isAvailable = connection.connected_accounts.some(\n (account) => account.availability === \"available\",\n );\n\n return isAvailable ? (\n <Status state=\"success\">\n <Translation\n defaultMessage=\"Available\"\n id=\"_jQjSu\"\n description=\"Status text for a shared connection the member can use\"\n />\n </Status>\n ) : (\n <Status state=\"warning\">\n <Translation\n defaultMessage=\"Needs admin attention\"\n id=\"K5YoFj\"\n description=\"Status text for a shared connection an administrator must repair\"\n />\n </Status>\n );\n}\n\n/**\n * The sectioned row shell: the provider name with its state inline, the\n * connector description underneath, and actions confined to the right slot.\n */\nfunction SectionedItem({\n icon,\n name,\n status,\n description,\n actions,\n}: {\n icon: React.ReactNode;\n name: string;\n status?: React.ReactNode;\n description?: string | null;\n actions?: React.ReactNode;\n}) {\n return (\n <CardList.Item>\n <Flex direction=\"row\" justify=\"between\" align=\"center\" gap=\"4\">\n <Flex gap=\"4\" align=\"center\">\n <IconPanel color=\"panel\">{icon}</IconPanel>\n <Flex direction=\"column\" gap=\"1\">\n <Flex align=\"center\" gap=\"2\" wrap=\"wrap\">\n <Text size=\"2\" weight=\"bold\">\n {name}\n </Text>\n {status}\n </Flex>\n {description && (\n <Text size=\"2\" color=\"gray\">\n {description}\n </Text>\n )}\n </Flex>\n </Flex>\n {actions}\n </Flex>\n </CardList.Item>\n );\n}\n\n/**\n * A read-only row for an organization-owned connection. Shared connections\n * carry no `integrationType`, so the provider slug drives the icon fallbacks.\n */\nfunction SharedConnectionItem({\n connection,\n}: {\n connection: SharedDataConnection;\n}) {\n return (\n <SectionedItem\n icon={\n <DataIntegrationIcon\n integration={{\n integrationType: connection.slug,\n iconSlug: connection.iconSlug,\n iconUrl: connection.iconUrl,\n iconDarkUrl: connection.iconDarkUrl,\n }}\n size=\"2\"\n />\n }\n name={connection.name}\n status={<SharedConnectionStatus connection={connection} />}\n description={connection.description}\n />\n );\n}\n\n/**\n * The member's own connection state, inline beside the provider name. An\n * integration the member has not connected has no state to report — its row\n * says everything with the connect action.\n */\nfunction MemberConnectionStatus({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n const installation = integration.installation;\n\n if (!installation) {\n return null;\n }\n\n if (installation.state === \"connected\") {\n return (\n <Status state=\"success\">\n {installation.auth_method === \"api_key\" ? (\n <Translation\n defaultMessage=\"Connected via API key\"\n id=\"jQLTNe\"\n description=\"Status text for a connection established with an API key\"\n />\n ) : installation.auth_method === \"client_credentials\" ? (\n <Translation\n defaultMessage=\"Connected via client credentials\"\n id=\"hQKIrx\"\n description=\"Status text for a connection established with client credentials\"\n />\n ) : (\n <Translation\n defaultMessage=\"Connected via OAuth\"\n id=\"pJcK_M\"\n description=\"Status text for a connection established with OAuth\"\n />\n )}\n </Status>\n );\n }\n\n return (\n <Status state=\"warning\">\n {installation.auth_method === \"api_key\" ? (\n <Translation\n defaultMessage=\"Update your API key\"\n id=\"-YLPTk\"\n description=\"Status text for a connection whose API key stopped working\"\n />\n ) : (\n <Translation\n defaultMessage=\"Requires reauthorization\"\n id=\"dqczQS\"\n description=\"Status text for integration needing reauthorization\"\n />\n )}\n </Status>\n );\n}\n\n/**\n * The right slot of a member's row: the repair the state calls for, promoted to\n * a button, plus the credential management the connection supports. The state\n * itself lives beside the provider name, never here.\n */\nfunction MemberConnectionActions({\n integration,\n}: {\n integration: DataIntegration;\n}) {\n const [disconnectOpen, setDisconnectOpen] = useState(false);\n const [apiKeyOpen, setApiKeyOpen] = useState(false);\n const [clientCredentialsOpen, setClientCredentialsOpen] = useState(false);\n const [reauthConfigOpen, setReauthConfigOpen] = useState(false);\n const authorizeEventHandler = useOpenDataIntegrationAuthorizeUrl(integration);\n const translate = useTranslation();\n\n const pipeActionsTitle = translate({\n defaultMessage: \"Pipe actions\",\n id: \"1uF9ve\",\n description: \"Title for pipe actions dropdown button\",\n });\n\n // Unpinned installation fields must be re-collected on reauthorization too;\n // the authorize endpoint rejects them as missing otherwise.\n const unpinnedFields = getUnpinnedInstallationFields(integration);\n\n if (!integration.installation) {\n const authMethods = integration.authMethods ?? [];\n const methods = CONNECT_AUTH_METHODS.filter((method) =>\n authMethods.includes(method),\n );\n\n return methods.length > 1 ? (\n <MultiMethodConnectButton integration={integration} methods={methods} />\n ) : methods.length === 1 && methods[0] === \"api_key\" ? (\n <ApiKeyConnectButton integration={integration} />\n ) : methods.length === 1 && methods[0] === \"client_credentials\" ? (\n <ClientCredentialsConnectButton integration={integration} />\n ) : (\n <ConnectIntegrationButton integration={integration} />\n );\n }\n\n const connected = integration.installation.state === \"connected\";\n const isApiKeyInstallation =\n integration.installation.auth_method === \"api_key\";\n const isClientCredentialsInstallation =\n integration.installation.auth_method === \"client_credentials\";\n\n return (\n <>\n <DisconnectAccountDialog\n integrationName={integration.name}\n installationId={integration.installation.id}\n open={disconnectOpen}\n onOpenChange={setDisconnectOpen}\n />\n {apiKeyOpen && (\n <ApiKeyDialog\n integration={integration}\n open={apiKeyOpen}\n onOpenChange={setApiKeyOpen}\n />\n )}\n {clientCredentialsOpen && (\n <ClientCredentialsDialog\n integration={integration}\n fields={unpinnedFields}\n open={clientCredentialsOpen}\n onOpenChange={setClientCredentialsOpen}\n />\n )}\n {unpinnedFields.length > 0 && !isClientCredentialsInstallation && (\n <ConnectDialog\n integration={integration}\n fields={unpinnedFields}\n open={reauthConfigOpen}\n onOpenChange={setReauthConfigOpen}\n />\n )}\n <Flex align=\"center\" gap=\"4\">\n {!connected &&\n (isApiKeyInstallation ? (\n <Button variant=\"secondary\" onClick={() => setApiKeyOpen(true)}>\n <Translation\n defaultMessage=\"Update key\"\n id=\"MP-aOE\"\n description=\"Button to replace the API key of a connection that stopped working\"\n />\n </Button>\n ) : isClientCredentialsInstallation ? (\n <Button\n variant=\"secondary\"\n onClick={() => setClientCredentialsOpen(true)}\n >\n <Translation\n defaultMessage=\"Update credentials\"\n id=\"1inB3Y\"\n description=\"Button to update the client credentials of a connection that stopped working\"\n />\n </Button>\n ) : (\n <Button\n variant=\"secondary\"\n onClick={async () => {\n if (unpinnedFields.length > 0) {\n setReauthConfigOpen(true);\n return;\n }\n try {\n await authorizeEventHandler();\n } catch {\n // pass - error displayed in new tab\n }\n }}\n >\n <Translation\n defaultMessage=\"Reauthorize\"\n id=\"3IbiTG\"\n description=\"Button to reauthorize a connection that stopped working\"\n />\n </Button>\n ))}\n <DropdownMenu.Root>\n <DropdownMenu.Trigger>\n <IconButton title={pipeActionsTitle}>\n <DotsHorizontalIcon />\n </IconButton>\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">\n {connected && isApiKeyInstallation && (\n <DropdownMenu.Item onClick={() => setApiKeyOpen(true)}>\n <Translation\n defaultMessage=\"Rotate API key\"\n id=\"GML+c8\"\n description=\"Menu option to rotate the API key\"\n />\n </DropdownMenu.Item>\n )}\n {connected && isClientCredentialsInstallation && (\n <DropdownMenu.Item onClick={() => setClientCredentialsOpen(true)}>\n <Translation\n defaultMessage=\"Update client credentials\"\n id=\"daHKWE\"\n description=\"Menu option to update stored client credentials\"\n />\n </DropdownMenu.Item>\n )}\n <DropdownMenu.Item\n variant=\"destructive\"\n onClick={() => setDisconnectOpen(true)}\n >\n <Translation\n defaultMessage=\"Disconnect account\"\n id=\"esZQrd\"\n description=\"Menu option to disconnect an account\"\n />\n </DropdownMenu.Item>\n </DropdownMenu.Content>\n </DropdownMenu.Root>\n </Flex>\n </>\n );\n}\n\n/** The member's own connections in the sectioned experience. */\nfunction MemberConnectionItems({\n integrations,\n}: {\n integrations: DataIntegration[];\n}) {\n return integrations.map((integration) => (\n <SectionedItem\n key={integration.id}\n icon={<DataIntegrationIcon integration={integration} size=\"2\" />}\n name={integration.name}\n status={<MemberConnectionStatus integration={integration} />}\n description={integration.description}\n actions={<MemberConnectionActions integration={integration} />}\n />\n ));\n}\n\nfunction PipesSection({\n title,\n description,\n children,\n}: {\n title: React.ReactNode;\n description: React.ReactNode;\n children: React.ReactNode;\n}) {\n return (\n <Flex direction=\"column\" gap=\"3\">\n <Flex direction=\"column\" gap=\"1\">\n <Text size=\"3\" weight=\"bold\">\n {title}\n </Text>\n <Text size=\"2\" color=\"gray\">\n {description}\n </Text>\n </Flex>\n {children}\n </Flex>\n );\n}\n\n/**\n * The sectioned member experience: the connections the organization shares,\n * then the member's own. The two lanes come from different endpoints and are\n * never merged — the same provider can legitimately appear in both, once as an\n * organization-owned connection and once as the member's own account.\n *\n * The shared section is omitted entirely when the organization shares nothing\n * (or the request failed), leaving the member's own section usable on its own.\n */\nconst PipesSections: React.FC<PipesSectionsProps> = ({\n integrations,\n hasUnfilteredIntegrations,\n sharedConnections,\n hasUnfilteredSharedConnections,\n isSharedLoading,\n organizationName,\n ...domProps\n}) => {\n return (\n <Flex\n direction=\"column\"\n gap=\"5\"\n {...getWidgetRootDomProps(\"resolved\", domProps)}\n >\n {(isSharedLoading ||\n sharedConnections.length > 0 ||\n hasUnfilteredSharedConnections) && (\n <PipesSection\n title={\n <Translation\n defaultMessage=\"Shared connections\"\n id=\"Fcd-bK\"\n description=\"Heading for the section listing connections the organization owns\"\n />\n }\n description={\n organizationName ? (\n <Translation\n defaultMessage=\"Accounts {organizationName} owns and shares with everyone.\"\n id=\"7U8P0v\"\n description=\"Description of the shared connections section, naming the organization\"\n values={{ organizationName }}\n />\n ) : (\n <Translation\n defaultMessage=\"Accounts your organization owns and shares with everyone.\"\n id=\"72FEZi\"\n description=\"Description of the shared connections section when the organization name is unknown\"\n />\n )\n }\n >\n <CardList.Root>\n {isSharedLoading ? (\n <PipesSkeletonItems count={2} />\n ) : sharedConnections.length > 0 ? (\n sharedConnections.map((connection) => (\n <SharedConnectionItem\n key={connection.id}\n connection={connection}\n />\n ))\n ) : (\n <PipesEmptyItem isFiltered />\n )}\n </CardList.Root>\n </PipesSection>\n )}\n <PipesSection\n title={\n <Translation\n defaultMessage=\"Your connections\"\n id=\"-VDI3G\"\n description=\"Heading for the section listing the member's own connections\"\n />\n }\n description={\n <Translation\n defaultMessage=\"Connect your account to access these connections.\"\n id=\"ObXqUu\"\n description=\"Description of the personal connections section\"\n />\n }\n >\n <CardList.Root>\n {integrations.length > 0 ? (\n <MemberConnectionItems integrations={integrations} />\n ) : (\n <PipesEmptyItem isFiltered={hasUnfilteredIntegrations ?? false} />\n )}\n </CardList.Root>\n </PipesSection>\n </Flex>\n );\n};\n\ninterface PipesErrorProps extends WidgetRootDomProps {\n error: unknown;\n}\n\nconst PipesError: React.FC<PipesErrorProps> = ({ error, ...domProps }) => {\n return (\n <Card size=\"2\" {...getWidgetRootDomProps(\"error\", domProps)}>\n <GenericError error={error} />\n </Card>\n );\n};\n\nfunction getWidgetRootDomProps(\n state: WidgetRootState,\n domProps: WidgetRootDomProps,\n) {\n return getDomProps({\n ...domProps,\n isWidgetRoot: true,\n widgetId: \"pipes\",\n widgetState: state,\n });\n}\n\nexport type {\n PipesProps,\n PipesSectionsProps,\n PipesLoadingProps,\n PipesErrorProps,\n};\nexport { Pipes, PipesSections, PipesLoading, PipesError };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoZQ;AAnZR,oBAA0C;AAC1C,mBAAkE;AAClE,eAA0B;AAC1B,mCAAoC;AACpC,2BAA6B;AAC7B,yBAKO;AACP,sBAUO;AACP,wBAA0B;AAC1B,oBAAuB;AACvB,sBAUO;AACP,yBAA+B;AAC/B,2BAA6B;AAC7B,mBAAiE;AACjE,yBAA4B;AAC5B,6BAA+B;AAC/B,oBAAyB;AACzB,6BAAsD;AAgCtD,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAO7B,MAAM,uBAAoD;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,qCAAqC,CAAC,gBAAiC;AAC3E,QAAM,+BAA2B,iDAAgC;AACjE,QAAM,eAAW,6BAAY;AAC7B,QAAM,UAAU,SAAS,MAAM,iBAAiB;AAChD,QAAM,kBAAc;AAAA,IAClB;AAAA,EACF;AACA,QAAM,wBAAoB;AAAA,IACxB;AAAA,EACF;AAEA,8BAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,YAAY,SAAS;AACvB,sBAAc,YAAY,OAAO;AAAA,MACnC;AACA,UAAI,kBAAkB,SAAS;AAC7B,eAAO,oBAAoB,WAAW,kBAAkB,OAAO;AAAA,MACjE;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,aAAO;AAAA,IACL,OAAO,WAAoC;AAEzC,UAAI,YAAY,SAAS;AACvB,sBAAc,YAAY,OAAO;AACjC,oBAAY,UAAU;AAAA,MACxB;AAEA,UAAI,kBAAkB,SAAS;AAC7B,eAAO,oBAAoB,WAAW,kBAAkB,OAAO;AAC/D,0BAAkB,UAAU;AAAA,MAC9B;AAGA,YAAM,MAAM,OAAO,KAAK,GAAG,OAAO,sBAAsB,QAAQ;AAGhE,UAAI,CAAC,KAAK;AACR,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC5D;AAIA,UAAI;AACJ,UAAI;AACF,wBAAgB,MAAM,yBAAyB,YAAY,MAAM;AAAA,UAC/D,gBAAgB;AAAA,UAChB;AAAA,QACF,CAAC;AAAA,MACH,SAAS,OAAO;AACd,YAAI,MAAM;AACV,cAAM;AAAA,MACR;AACA,YAAM,EAAE,KAAK,cAAc,cAAc,IAAI;AAC7C,UAAI,KAAK;AACP,YAAI,WAAW;AACf,cAAM,YAAY,IAAI,IAAI,GAAG;AAC7B,cAAM,UAAU,EAAE,cAAc,cAAc;AAE9C,cAAM,UAAU,MAAM;AACpB,cAAI,YAAY,SAAS;AACvB,0BAAc,YAAY,OAAO;AACjC,wBAAY,UAAU;AAAA,UACxB;AACA,cAAI,kBAAkB,SAAS;AAC7B,mBAAO,oBAAoB,WAAW,kBAAkB,OAAO;AAC/D,8BAAkB,UAAU;AAAA,UAC9B;AAAA,QACF;AAEA,0BAAkB,UAAU,CAAC,UAAwB;AACnD,cACE,MAAM,WAAW,UAAU,UAC3B,MAAM,MAAM,kBAAkB,eAC9B;AACA,oBAAQ;AAAA,UACV;AAAA,QACF;AACA,eAAO,iBAAiB,WAAW,kBAAkB,OAAO;AAE5D,YAAI,WAAW;AACf,oBAAY,UAAU,YAAY,MAAM;AACtC,sBAAY;AAEZ,cAAI,YAAY,sBAAsB;AACpC,oBAAQ;AACR;AAAA,UACF;AAEA,cAAI,OAAO,CAAC,IAAI,QAAQ;AACtB,gBAAI,YAAY,SAAS,UAAU,MAAM;AAAA,UAC3C,OAAO;AACL,oBAAQ;AAAA,UACV;AAAA,QACF,GAAG,mBAAmB;AAAA,MACxB;AAAA,IACF;AAAA,IACA,CAAC,0BAA0B,YAAY,MAAM,OAAO;AAAA,EACtD;AACF;AAOA,SAAS,8BACP,aAC8B;AAC9B,UAAQ,YAAY,gBAAgB,CAAC,GAClC;AAAA,IACC,CAAC,UACC,MAAM,UAAU,kBAAkB,CAAC,YAAY,SAAS,MAAM,GAAG;AAAA,EACrE,EACC,KAAK,CAAC,GAAG,OAAO,EAAE,SAAS,MAAM,EAAE,SAAS,EAAE;AACnD;AAMA,SAAS,uBACP,QACA,cACwB;AACxB,QAAM,SAAiC,CAAC;AACxC,aAAW,SAAS,QAAQ;AAC1B,UAAM,SAAS,aAAa,MAAM,GAAG;AACrC,QACE,OAAO,WAAW,YAClB,OAAO,WAAW,YAClB,OAAO,WAAW,WAClB;AACA,aAAO,MAAM,GAAG,IAAI,OAAO,MAAM;AAAA,IACnC;AAAA,EACF;AACA,SAAO;AACT;AAUA,SAAS,0BACP,SACA,OACoB;AACpB,MAAI;AACF,WAAO,IAAI,OAAO,OAAO,OAAO,MAAM,KAAK;AAAA,EAC7C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAYA,SAAS,oBACP,QACA,gBAAwC,CAAC,GACzC;AACA,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAiC,aAAa;AAC1E,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAwC,CAAC,CAAC;AACtE,QAAM,gBAAY,uCAAe;AAEjC,QAAM,kBAAkB,UAAU;AAAA,IAChC,gBAAgB;AAAA,IAChB,IAAI;AAAA,IACJ,aACE;AAAA,EACJ,CAAC;AACD,QAAM,iBAAiB,UAAU;AAAA,IAC/B,gBAAgB;AAAA,IAChB,IAAI;AAAA,IACJ,aACE;AAAA,EACJ,CAAC;AAED,QAAM,WAAW,CAAC,KAAa,UAAkB;AAC/C,cAAU,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,GAAG,GAAG,MAAM,EAAE;AAC/C,cAAU,CAAC,SAAU,KAAK,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,GAAG,KAAK,IAAI,IAAK;AAAA,EACnE;AAEA,QAAM,QAAQ,MAAM;AAClB,cAAU,aAAa;AACvB,cAAU,CAAC,CAAC;AAAA,EACd;AAEA,QAAM,WAAW,MAAM;AACrB,UAAM,aAA4C,CAAC;AACnD,QAAI,QAAQ;AACZ,eAAW,SAAS,QAAQ;AAC1B,YAAM,SAAS,OAAO,MAAM,GAAG,KAAK,IAAI,KAAK;AAC7C,UAAI,MAAM,YAAY,CAAC,OAAO;AAC5B,mBAAW,MAAM,GAAG,IAAI;AACxB,gBAAQ;AACR;AAAA,MACF;AACA,UAAI,SAAS,MAAM,SAAS;AAC1B,cAAM,gBAAgB;AAAA,UACpB,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AACA,YAAI,iBAAiB,CAAC,cAAc,KAAK,KAAK,GAAG;AAC/C,qBAAW,MAAM,GAAG,IAAI;AACxB,kBAAQ;AACR;AAAA,QACF;AAAA,MACF;AACA,iBAAW,MAAM,GAAG,IAAI;AAAA,IAC1B;AACA,cAAU,UAAU;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,MAAM;AACxB,UAAM,SAAiC,CAAC;AACxC,eAAW,SAAS,QAAQ;AAC1B,YAAM,SAAS,OAAO,MAAM,GAAG,KAAK,IAAI,KAAK;AAC7C,UAAI,OAAO;AACT,eAAO,MAAM,GAAG,IAAI;AAAA,MACtB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAQA,QAAM,qBAAqB,CAAC,iBAA0C;AACpE,UAAM,UAAmC,EAAE,GAAG,aAAa;AAC3D,eAAW,SAAS,QAAQ;AAC1B,YAAM,SAAS,OAAO,MAAM,GAAG,KAAK,IAAI,KAAK;AAC7C,UAAI,OAAO;AACT,gBAAQ,MAAM,GAAG,IAAI;AAAA,MACvB,OAAO;AACL,eAAO,QAAQ,MAAM,GAAG;AAAA,MAC1B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,qBAAqB,OAAO;AAAA,IAChC,CAAC,UAAU,MAAM,YAAY,EAAE,OAAO,MAAM,GAAG,KAAK,IAAI,KAAK;AAAA,EAC/D;AAEA,QAAM,UAAU,OAAO;AAAA,IACrB,CAAC,WAAW,OAAO,MAAM,GAAG,KAAK,SAAS,cAAc,MAAM,GAAG,KAAK;AAAA,EACxE;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAkBA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SAAO,OAAO,IAAI,CAAC,UAAU;AAC3B,UAAM,UAAU,GAAG,QAAQ,IAAI,MAAM,GAAG;AACxC,UAAM,UAAU,GAAG,OAAO;AAC1B,UAAM,gBAAgB,GAAG,OAAO;AAChC,UAAM,QAAQ,OAAO,MAAM,GAAG;AAC9B,UAAM,UAAU,MAAM,SAAS,gCAAgB;AAC/C,UAAM,cACJ,MAAM,YAAY,SAChB;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA,QACZ,QAAQ,EAAE,OAAO,MAAM,QAAQ;AAAA;AAAA,IACjC,IACE;AAEN,UAAM,SAAS,GAAG,OAAO;AACzB,UAAM,WAAW,CAAC,SAAS;AAC3B,UAAM,cACJ;AAAA,MACE,MAAM,cAAc,gBAAgB;AAAA,MACpC,WAAW,SAAS;AAAA,MACpB,QAAQ,UAAU;AAAA,IACpB,EACG,OAAO,OAAO,EACd,KAAK,GAAG,KAAK;AAClB,WACE,6CAAC,sBAAqB,WAAU,UAAS,KAAI,KAC3C;AAAA,kDAAC,yBAAM,SAAS,SAAU,gBAAM,OAAM;AAAA,MACrC,MAAM,cACL,4CAAC,sBAAK,OAAM,QAAO,MAAK,KAAI,IAAI,eAAe,IAAG,KAC/C,gBAAM,aACT,IACE;AAAA,MACJ;AAAA,QAAC;AAAA;AAAA,UACC,IAAI;AAAA,UACJ,OAAO,OAAO,MAAM,GAAG,KAAK;AAAA,UAC5B,aAAa,MAAM,WAAW,MAAM;AAAA,UACpC,cAAa;AAAA,UACb,UAAU,MAAM,YAAY;AAAA,UAC5B,gBAAc,CAAC,CAAC,SAAS;AAAA,UACzB,oBAAkB;AAAA,UAClB,UAAU,CAAC,UAAU,SAAS,MAAM,KAAK,MAAM,OAAO,KAAK;AAAA;AAAA,MAC7D;AAAA,MACC,WACC,4CAAC,sBAAK,OAAM,QAAO,MAAK,KAAI,IAAI,QAC7B,uBACH,IACE;AAAA,MACH,QACC,4CAAC,sBAAK,OAAM,OAAM,MAAK,KAAI,IAAI,SAC5B,iBACH,IACE;AAAA,SA1BK,MAAM,GA2BjB;AAAA,EAEJ,CAAC;AACH;AAGA,SAAS,gBAAgB;AACvB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,OAAO,EAAE,OAAO,gBAAgB;AAAA;AAAA,EAClC;AAEJ;AAMA,SAAS,oBAAoB;AAAA,EAC3B;AACF,GAEG;AACD,QAAM,eAAW,6BAAY;AAC7B,QAAM,OAAO,SAAS,MAAM,gBAAgB,SAAS,MAAM;AAC3D,QAAM,UAAU,SAAS,MAAM,YAAY;AAE3C,SACE,4EACE;AAAA,iDAAC,sBAAK,SAAQ,UAAS,OAAM,UAAS,KAAI,KAAI,IAAG,KAC9C;AAAA,cACC,4EACE;AAAA,oDAAC,+BAAU,OAAM,SAAQ,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAO,GAC9D;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,UAAS;AAAA,YACT,OAAO,EAAE,iBAAiB,OAAO,IAAI,IAAI;AAAA;AAAA,QAC3C,GACF;AAAA,QACA,4CAAC,iBAAc;AAAA,SACjB;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,OAAO;AAAA,YACL,GAAI,OAAO,EAAE,aAAa,EAAE,IAAI;AAAA,YAChC,OAAO;AAAA,YACP,QAAQ;AAAA,UACV;AAAA,UAEA,sDAAC,qCAAa,MAAK,KAAI,UAAS,UAAS;AAAA;AAAA,MAC3C;AAAA,MACA,4CAAC,iBAAc;AAAA,MACf,4CAAC,+BAAU,OAAM,SAAQ,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAO,GAC9D,sDAAC,oDAAoB,MAAK,KAAI,aAA0B,GAC1D;AAAA,OACF;AAAA,IACA,4CAAC,uBAAO,OAAP,EAAa,MAAK,KAAI,IAAG,KAAI,IAAG,KAAI,QAAQ,QAAQ,OAAM,UACzD;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA,QACZ,QAAQ,EAAE,SAAS,iBAAiB,YAAY,KAAK;AAAA;AAAA,IACvD,GACF;AAAA,KACF;AAEJ;AAMA,SAAS,qBAAqB;AAAA,EAC5B;AACF,GAEG;AACD,SACE,4CAAC,sBACC,uDAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,iDAAC,sBAAK,KAAI,KAAI,OAAM,UAClB;AAAA,kDAAC,+BAAU,OAAM,QAAO,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAO,GAC7D,sDAAC,gCAAU,GACb;AAAA,MACA,6CAAC,sBAAK,WAAU,UACd;AAAA,oDAAC,sBAAK,MAAK,KAAI,QAAO,QACpB;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA,YACZ,QAAQ,EAAE,iBAAiB,YAAY,KAAK;AAAA;AAAA,QAC9C,GACF;AAAA,QACA,4CAAC,sBAAK,MAAK,KACT;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF;AAAA,SACF;AAAA,OACF;AAAA,IACA,6CAAC,sBAAK,KAAI,KAAI,OAAM,UAClB;AAAA,kDAAC,+BAAU,OAAM,QAAO,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAO,GAC7D,sDAAC,qCAAe,GAClB;AAAA,MACA,6CAAC,sBAAK,WAAU,UACd;AAAA,oDAAC,sBAAK,MAAK,KAAI,QAAO,QACpB;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF;AAAA,QACA,4CAAC,sBAAK,MAAK,KACT;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF;AAAA,SACF;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAWA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AAED,QAAM,cAAc,OAAO,SAAS,IAAI,WAAW;AACnD,QAAM,CAAC,MAAM,OAAO,QAAI,uBAA8B,WAAW;AACjE,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAwB,IAAI;AAClE,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,KAAK;AACtD,QAAM,aAAa,oBAAoB,MAAM;AAC7C,QAAM,eAAe,mCAAmC,WAAW;AACnE,QAAM,gBAAY,uCAAe;AAEjC,QAAM,sBAAsB,UAAU;AAAA,IACpC,gBAAgB;AAAA,IAChB,IAAI;AAAA,IACJ,aACE;AAAA,EACJ,CAAC;AAED,QAAM,QAAQ,MAAM;AAClB,YAAQ,WAAW;AACnB,eAAW,MAAM;AACjB,mBAAe,IAAI;AACnB,oBAAgB,KAAK;AAAA,EACvB;AAEA,QAAM,gBAAgB,YAAY;AAChC,mBAAe,IAAI;AACnB,oBAAgB,IAAI;AACpB,QAAI;AAEF,YAAM,aAAa,WAAW,YAAY,CAAC;AAC3C,mBAAa,KAAK;AAAA,IACpB,SAAS,OAAO;AAGd;AAAA,QACE,iBAAiB,0BAAY,MAAM,UAC/B,MAAM,UACN;AAAA,MACN;AAAA,IACF,UAAE;AACA,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF;AAEA,SACE;AAAA,IAAC,uBAAO;AAAA,IAAP;AAAA,MACC;AAAA,MACA,cAAc,CAAC,SAAS;AACtB,qBAAa,IAAI;AACjB,YAAI,CAAC,MAAM;AACT,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,MAEA,uDAAC,uBAAO,SAAP,EAAe,UAAS,SACvB;AAAA,oDAAC,uBAAoB,aAA0B;AAAA,QAE9C,SAAS,WACR,4EACE;AAAA,sDAAC,sBACC,sDAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,YAAC;AAAA;AAAA,cACC,UAAS;AAAA,cACT;AAAA,cACA,QAAQ,WAAW;AAAA,cACnB,QAAQ,WAAW;AAAA,cACnB,UAAU,WAAW;AAAA;AAAA,UACvB,GACF,GACF;AAAA,UACA,6CAAC,sBAAK,SAAQ,OAAM,KAAI,KAAI,IAAG,KAC7B;AAAA,wDAAC,uBAAO,OAAP,EACC,sDAAC,0BAAO,SAAQ,aACd;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd,GACF,GACF;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,UAAU,WAAW;AAAA,gBACrB,SAAS,MAAM;AACb,sBAAI,WAAW,SAAS,GAAG;AACzB,4BAAQ,QAAQ;AAAA,kBAClB;AAAA,gBACF;AAAA,gBAEA;AAAA,kBAAC;AAAA;AAAA,oBACC,gBAAe;AAAA,oBACf,IAAG;AAAA,oBACH,aAAY;AAAA;AAAA,gBACd;AAAA;AAAA,YACF;AAAA,aACF;AAAA,WACF,IAEA,4EACG;AAAA,yBACC,4CAAC,sBAAQ,MAAR,EAAa,IAAG,KAAI,OAAM,OAAM,MAAK,SACpC,sDAAC,sBAAQ,MAAR,EAAc,uBAAY,GAC7B;AAAA,UAEF,4CAAC,wBAAqB,aAA0B;AAAA,UAChD,6CAAC,sBAAK,SAAQ,OAAM,KAAI,KAAI,IAAG,KAC5B;AAAA,mBAAO,SAAS,IACf;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,SAAS,MAAM,QAAQ,QAAQ;AAAA,gBAE/B;AAAA,kBAAC;AAAA;AAAA,oBACC,gBAAe;AAAA,oBACf,IAAG;AAAA,oBACH,aAAY;AAAA;AAAA,gBACd;AAAA;AAAA,YACF,IAEA,4CAAC,uBAAO,OAAP,EACC,sDAAC,0BAAO,SAAQ,aACd;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd,GACF,GACF;AAAA,YAEF;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,SAAS;AAAA,gBAET;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,gBAAe;AAAA,sBACf,IAAG;AAAA,sBACH,aAAY;AAAA,sBACZ,eAAa;AAAA;AAAA,kBACf;AAAA,kBACA,4CAAC,uCAAiB,eAAW,MAAC;AAAA;AAAA;AAAA,YAChC;AAAA,aACF;AAAA,WACF;AAAA,SAEJ;AAAA;AAAA,EACF;AAEJ;AAOA,SAAS,yBAAyB;AAAA,EAChC;AACF,GAEG;AACD,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AACtC,QAAM,SAAS,8BAA8B,WAAW;AAExD,SACE,4EACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA,cAAc;AAAA;AAAA,IAChB;AAAA,IACA,4CAAC,0BAAO,SAAQ,aAAY,SAAS,MAAM,QAAQ,IAAI,GACrD;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,KACF;AAEJ;AAEA,MAAM,0BAA0B;AAEhC,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,kBAAc,mCAAe;AACnC,QAAM,eAAe,YAAY;AACjC,QAAM,aACJ,cAAc,gBAAgB,aAC9B,aAAa,UAAU;AACzB,QAAM,QAAQ,cAAc;AAC5B,QAAM,YAAY,QAAQ,GAAG,uBAAuB,GAAG,KAAK,KAAK;AAEjE,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,EAAE;AACvC,QAAM,gBAAY,uCAAe;AAEjC,QAAM,oBAAoB,UAAU;AAAA,IAClC,gBAAgB;AAAA,IAChB,IAAI;AAAA,IACJ,aAAa;AAAA,EACf,CAAC;AAED,QAAM;AAAA,IACJ,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF,QAAI,gDAA+B;AAAA,IACjC,UAAU;AAAA,MACR,WAAW,MAAM;AACf,qBAAa,KAAK;AAClB,oBAAY,kBAAkB;AAAA,UAC5B,cAAU,+CAA8B;AAAA,QAC1C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AAMD,8BAAU,MAAM;AACd,UAAM;AAAA,EACR,GAAG,CAAC,KAAK,CAAC;AAEV,QAAM,gBAAgB,MAAM;AAC1B,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,iBAAiB,0BAAY,MAAM,SAAS;AAC9C,aAAO,MAAM;AAAA,IACf;AACA,WAAO;AAAA,EACT,GAAG;AAEH,SACE,4CAAC,uBAAO,MAAP,EAAY,MAAY,cACvB,uDAAC,uBAAO,SAAP,EAAe,UAAS,SACvB;AAAA,gDAAC,uBAAO,OAAP,EAAa,MAAK,KAAI,QAAO,QAC3B,uBACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA,QACZ,QAAQ,EAAE,iBAAiB,YAAY,KAAK;AAAA;AAAA,IAC9C,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA,QACZ,QAAQ,EAAE,iBAAiB,YAAY,KAAK;AAAA;AAAA,IAC9C,GAEJ;AAAA,IASC,YAAY,eACX,4CAAC,uBAAO,aAAP,EAAmB,OAAM,QAAO,IAAG,KACjC,sBAAY,aACf;AAAA,IAGD,SACC,4CAAC,sBAAQ,MAAR,EAAa,IAAG,KAAI,OAAM,OAAM,MAAK,SACpC,sDAAC,sBAAQ,MAAR,EACE,0BACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GAEJ,GACF;AAAA,IAGF,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAAI,IAAG,KACjC;AAAA,oBAAc,SACb,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,oDAAC,yBACC;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF;AAAA,QACA,4CAAC,sBAAK,MAAK,KAAI,OAAM,QAClB,qBACH;AAAA,SACF;AAAA,MAGF,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,oDAAC,yBACE,uBACC;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,IAEA;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GAEJ;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,cAAa;AAAA,YACb,aAAa;AAAA,YACb,UAAU,CAAC,UAAU,UAAU,MAAM,OAAO,KAAK;AAAA;AAAA,QACnD;AAAA,SACF;AAAA,OACF;AAAA,IAEA,6CAAC,sBAAK,SAAQ,OAAM,KAAI,KAAI,IAAG,KAC7B;AAAA,kDAAC,uBAAO,OAAP,EACC,sDAAC,0BAAO,SAAQ,aACd;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,GACF,GACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UAAU,aAAa,CAAC,OAAO,KAAK;AAAA,UACpC,SAAS;AAAA,UACT,SAAS,MACP,aAAa;AAAA,YACX,MAAM,YAAY;AAAA,YAClB,MAAM,EAAE,QAAQ,OAAO,KAAK,EAAE;AAAA,UAChC,CAAC;AAAA,UAGF,uBACC;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd,IAEA;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd;AAAA;AAAA,MAEJ;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAEA,SAAS,oBAAoB;AAAA,EAC3B;AACF,GAEG;AACD,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AAEtC,SACE,4EACG;AAAA,YACC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,cAAc;AAAA;AAAA,IAChB;AAAA,IAEF,4CAAC,0BAAO,SAAQ,aAAY,SAAS,MAAM,QAAQ,IAAI,GACrD;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,KACF;AAEJ;AAiBA,SAAS,wBAAwB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,kBAAc,mCAAe;AACnC,QAAM,eAAe,YAAY;AACjC,QAAM,WAAW,cAAc,gBAAgB;AAC/C,QAAM,mBAAe;AAAA,IACnB,MAAO,WAAY,cAAc,UAAU,CAAC,IAAK,CAAC;AAAA,IAClD,CAAC,UAAU,cAAc,MAAM;AAAA,EACjC;AACA,QAAM,0BAAsB;AAAA,IAC1B,MAAM,uBAAuB,QAAQ,YAAY;AAAA,IACjD,CAAC,QAAQ,YAAY;AAAA,EACvB;AACA,QAAM,qBAAiB;AAAA,IACrB,WAAW,cAAc,uBAAuB;AAAA,EAClD;AAEA,QAAM,CAAC,UAAU,WAAW,QAAI;AAAA,KAC7B,WAAW,cAAc,YAAY,SAAS;AAAA,EACjD;AACA,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,cAAc;AAC/D,QAAM,aAAa,oBAAoB,QAAQ,mBAAmB;AAClE,QAAM,gBAAY,uCAAe;AAEjC,QAAM,sBAAsB,UAAU;AAAA,IACpC,gBAAgB;AAAA,IAChB,IAAI;AAAA,IACJ,aAAa;AAAA,EACf,CAAC;AACD,QAAM,0BAA0B,UAAU;AAAA,IACxC,gBAAgB;AAAA,IAChB,IAAI;AAAA,IACJ,aAAa;AAAA,EACf,CAAC;AAKD,QAAM,gBAAgB,CAAC,aAAa,KAAK,SAAK,yCAAiB,YAAY;AAE3E,QAAM;AAAA,IACJ,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,EACF,QAAI,2DAA0C;AAAA,IAC5C,UAAU;AAAA,MACR,WAAW,MAAM;AACf,qBAAa,KAAK;AAClB,oBAAY,kBAAkB;AAAA,UAC5B,cAAU,+CAA8B;AAAA,QAC1C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AAID,QAAM,eACJ,iBAAiB,0BAAY,MAAM,UAAU,MAAM,UAAU;AAE/D,QAAM,eAAe,MAAM;AACzB,QAAI,CAAC,WAAW,SAAS,GAAG;AAC1B;AAAA,IACF;AAIA,UAAM,SAAS,WAAW,UACtB,WAAW,mBAAmB,YAAY,IAC1C;AACJ,4BAAwB;AAAA,MACtB,MAAM,YAAY;AAAA,MAClB,MAAM;AAAA,QACJ,WAAW,SAAS,KAAK;AAAA,QACzB,eAAe,aAAa,KAAK;AAAA,QACjC,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,MAC7B;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SACE,4CAAC,uBAAO,MAAP,EAAY,MAAY,cACvB,uDAAC,uBAAO,SAAP,EAAe,UAAS,SACvB;AAAA,gDAAC,uBAAO,OAAP,EAAa,MAAK,KAAI,QAAO,QAC3B,qBACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA,QACZ,QAAQ,EAAE,iBAAiB,YAAY,KAAK;AAAA;AAAA,IAC9C,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA,QACZ,QAAQ,EAAE,iBAAiB,YAAY,KAAK;AAAA;AAAA,IAC9C,GAEJ;AAAA,IAEC,SACC,4CAAC,sBAAQ,MAAR,EAAa,IAAG,KAAI,OAAM,OAAM,MAAK,SACpC,sDAAC,sBAAQ,MAAR,EACE,0BACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GAEJ,GACF;AAAA,IAGF,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAAI,IAAG,KAClC;AAAA,mDAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,oDAAC,yBAAM,SAAQ,sCACb;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,OAAO;AAAA,YACP,cAAa;AAAA,YACb,aAAa;AAAA,YACb,UAAU,CAAC,UAAU,YAAY,MAAM,OAAO,KAAK;AAAA;AAAA,QACrD;AAAA,SACF;AAAA,MAEA,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,oDAAC,yBAAM,SAAQ,0CACb;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF;AAAA,QACC,YACC;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN,MAAK;AAAA,YACL,IAAG;AAAA,YACH,IAAG;AAAA,YAEH;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd;AAAA;AAAA,QACF;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,OAAO;AAAA,YACP,cAAa;AAAA,YAGb,UAAM,yCAAiB,YAAY,IAAI,SAAS;AAAA,YAChD,aAAa;AAAA,YACb,oBACE,WACI,uDACA;AAAA,YAEN,UAAU,CAAC,UAAU,gBAAgB,MAAM,OAAO,KAAK;AAAA,YACvD,SAAS,MAAM;AACb,sBAAI,yCAAiB,YAAY,GAAG;AAClC,gCAAgB,EAAE;AAAA,cACpB;AAAA,YACF;AAAA,YACA,QAAQ,MAAM;AACZ,kBAAI,iBAAiB,IAAI;AACvB,gCAAgB,cAAc;AAAA,cAChC;AAAA,YACF;AAAA;AAAA,QACF;AAAA,SACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,UAAS;AAAA,UACT;AAAA,UACA,QAAQ,WAAW;AAAA,UACnB,QAAQ,WAAW;AAAA,UACnB,UAAU,WAAW;AAAA;AAAA,MACvB;AAAA,OACF;AAAA,IAEA,6CAAC,sBAAK,SAAQ,OAAM,KAAI,KAAI,IAAG,KAC7B;AAAA,kDAAC,uBAAO,OAAP,EACC,sDAAC,0BAAO,SAAQ,aACd;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,GACF,GACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,UACE,aACA,CAAC,SAAS,KAAK,KACf,iBACA,WAAW;AAAA,UAEb,SAAS;AAAA,UACT,SAAS;AAAA,UAER,qBACC;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd,IAEA;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd;AAAA;AAAA,MAEJ;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAEA,SAAS,+BAA+B;AAAA,EACtC;AACF,GAEG;AACD,QAAM,CAAC,MAAM,OAAO,QAAI,uBAAS,KAAK;AACtC,QAAM,SAAS,8BAA8B,WAAW;AAExD,SACE,4EACG;AAAA,YACC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA,QACA,cAAc;AAAA;AAAA,IAChB;AAAA,IAEF,4CAAC,0BAAO,SAAQ,aAAY,SAAS,MAAM,QAAQ,IAAI,GACrD;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,KACF;AAEJ;AAMA,SAAS,yBAAyB;AAAA,EAChC;AAAA,EACA;AACF,GAGG;AACD,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAS,KAAK;AAClD,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAChD,QAAM,CAAC,uBAAuB,wBAAwB,QAAI,uBAAS,KAAK;AACxE,QAAM,SAAS,8BAA8B,WAAW;AAExD,SACE,4EACG;AAAA,kBACC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAM;AAAA,QACN,cAAc;AAAA;AAAA,IAChB;AAAA,IAED,yBACC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,cAAc;AAAA;AAAA,IAChB;AAAA,IAED,QAAQ,SAAS,OAAO,KACvB;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN,cAAc;AAAA;AAAA,IAChB;AAAA,IAEF,6CAAC,6BAAa,MAAb,EACC;AAAA,kDAAC,6BAAa,SAAb,EACC,sDAAC,0BAAO,SAAQ,aACd;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,GACF,GACF;AAAA,MACA,6CAAC,6BAAa,SAAb,EAAqB,OAAM,OACzB;AAAA,gBAAQ,SAAS,OAAO,KACvB,4CAAC,6BAAa,MAAb,EAAkB,SAAS,MAAM,aAAa,IAAI,GACjD,uDAAC,sBAAK,KAAI,KAAI,OAAM,QAAO,SAAQ,WAAU,OAAM,UACjD;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA,cACZ,eAAa;AAAA;AAAA,UACf;AAAA,UACA,4CAAC,uCAAiB,eAAW,MAAC;AAAA,WAChC,GACF;AAAA,QAED,QAAQ,SAAS,oBAAoB,KACpC,4CAAC,6BAAa,MAAb,EAAkB,SAAS,MAAM,yBAAyB,IAAI,GAC7D;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF;AAAA,QAED,QAAQ,SAAS,SAAS,KACzB,4CAAC,6BAAa,MAAb,EAAkB,SAAS,MAAM,cAAc,IAAI,GAClD;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF;AAAA,SAEJ;AAAA,OACF;AAAA,KACF;AAEJ;AAEA,SAAS,eAAe,EAAE,YAAY,GAAqC;AACzE,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,uBAAS,KAAK;AAC1D,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAS,KAAK;AAClD,QAAM,CAAC,uBAAuB,wBAAwB,QAAI,uBAAS,KAAK;AACxE,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,uBAAS,KAAK;AAC9D,QAAM,wBAAwB,mCAAmC,WAAW;AAC5E,QAAM,gBAAY,uCAAe;AAEjC,QAAM,mBAAmB,UAAU;AAAA,IACjC,gBAAgB;AAAA,IAChB,IAAI;AAAA,IACJ,aAAa;AAAA,EACf,CAAC;AAID,QAAM,iBAAiB,8BAA8B,WAAW;AAEhE,MAAI,YAAY,cAAc;AAC5B,UAAM,YAAY,YAAY,aAAa,UAAU;AACrD,UAAM,uBACJ,YAAY,aAAa,gBAAgB;AAC3C,UAAM,kCACJ,YAAY,aAAa,gBAAgB;AAE3C,WACE,4EACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,iBAAiB,YAAY;AAAA,UAC7B,gBAAgB,YAAY,aAAa;AAAA,UACzC,MAAM;AAAA,UACN,cAAc;AAAA;AAAA,MAChB;AAAA,MACC,cACC;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,MAAM;AAAA,UACN,cAAc;AAAA;AAAA,MAChB;AAAA,MAED,yBACC;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,cAAc;AAAA;AAAA,MAChB;AAAA,MAED,eAAe,SAAS,KAAK,CAAC,mCAC7B;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,cAAc;AAAA;AAAA,MAChB;AAAA,MAEF,6CAAC,sBAAK,OAAM,UAAS,KAAI,KACvB;AAAA,oDAAC,wBAAO,OAAO,YAAY,YAAY,SACpC,sBACC;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,IAEA;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GAEJ;AAAA,QACC,kCACC,6CAAC,6BAAa,MAAb,EACC;AAAA,sDAAC,6BAAa,SAAb,EACC,sDAAC,8BAAW,OAAO,kBACjB,sDAAC,yCAAmB,GACtB,GACF;AAAA,UACA,6CAAC,6BAAa,SAAb,EAAqB,OAAM,OAC1B;AAAA;AAAA,cAAC,6BAAa;AAAA,cAAb;AAAA,gBACC,SAAS,MAAM,yBAAyB,IAAI;AAAA,gBAE5C;AAAA,kBAAC;AAAA;AAAA,oBACC,gBAAe;AAAA,oBACf,IAAG;AAAA,oBACH,aAAY;AAAA;AAAA,gBACd;AAAA;AAAA,YACF;AAAA,YACA;AAAA,cAAC,6BAAa;AAAA,cAAb;AAAA,gBACC,SAAQ;AAAA,gBACR,SAAS,MAAM,kBAAkB,IAAI;AAAA,gBAErC;AAAA,kBAAC;AAAA;AAAA,oBACC,gBAAe;AAAA,oBACf,IAAG;AAAA,oBACH,aAAY;AAAA;AAAA,gBACd;AAAA;AAAA,YACF;AAAA,aACF;AAAA,WACF,IACE,aAAa,uBACf,6CAAC,6BAAa,MAAb,EACC;AAAA,sDAAC,6BAAa,SAAb,EACC,sDAAC,8BAAW,OAAO,kBACjB,sDAAC,yCAAmB,GACtB,GACF;AAAA,UACA,6CAAC,6BAAa,SAAb,EAAqB,OAAM,OAC1B;AAAA,wDAAC,6BAAa,MAAb,EAAkB,SAAS,MAAM,cAAc,IAAI,GAClD;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd,GACF;AAAA,YACA;AAAA,cAAC,6BAAa;AAAA,cAAb;AAAA,gBACC,SAAQ;AAAA,gBACR,SAAS,MAAM,kBAAkB,IAAI;AAAA,gBAErC;AAAA,kBAAC;AAAA;AAAA,oBACC,gBAAe;AAAA,oBACf,IAAG;AAAA,oBACH,aAAY;AAAA;AAAA,gBACd;AAAA;AAAA,YACF;AAAA,aACF;AAAA,WACF,IACE,YACF,4CAAC,0BAAO,SAAQ,aAAY,SAAS,MAAM,kBAAkB,IAAI,GAC/D;AAAA,UAAC;AAAA;AAAA,YACC,gBAAe;AAAA,YACf,IAAG;AAAA,YACH,aAAY;AAAA;AAAA,QACd,GACF,IACE,uBACF,6CAAC,6BAAa,MAAb,EACC;AAAA,sDAAC,6BAAa,SAAb,EACC,sDAAC,8BAAW,OAAO,kBACjB,sDAAC,yCAAmB,GACtB,GACF;AAAA,UACA,6CAAC,6BAAa,SAAb,EAAqB,OAAM,OAC1B;AAAA,wDAAC,6BAAa,MAAb,EAAkB,SAAS,MAAM,cAAc,IAAI,GAClD;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd,GACF;AAAA,YACA;AAAA,cAAC,6BAAa;AAAA,cAAb;AAAA,gBACC,SAAQ;AAAA,gBACR,SAAS,MAAM,kBAAkB,IAAI;AAAA,gBAErC;AAAA,kBAAC;AAAA;AAAA,oBACC,gBAAe;AAAA,oBACf,IAAG;AAAA,oBACH,aAAY;AAAA;AAAA,gBACd;AAAA;AAAA,YACF;AAAA,aACF;AAAA,WACF,IAEA,6CAAC,6BAAa,MAAb,EACC;AAAA,sDAAC,6BAAa,SAAb,EACC,sDAAC,8BAAW,OAAO,kBACjB,sDAAC,yCAAmB,GACtB,GACF;AAAA,UACA,6CAAC,6BAAa,SAAb,EAAqB,OAAM,OAC1B;AAAA;AAAA,cAAC,6BAAa;AAAA,cAAb;AAAA,gBACC,SAAS,YAAY;AACnB,sBAAI,eAAe,SAAS,GAAG;AAC7B,wCAAoB,IAAI;AACxB;AAAA,kBACF;AACA,sBAAI;AACF,0BAAM,sBAAsB;AAAA,kBAC9B,QAAQ;AAAA,kBAER;AAAA,gBACF;AAAA,gBAEA,uDAAC,sBAAK,KAAI,KAAI,OAAM,QAAO,SAAQ,WAAU,OAAM,UACjD;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,gBAAe;AAAA,sBACf,IAAG;AAAA,sBACH,aAAY;AAAA,sBACZ,eAAa;AAAA;AAAA,kBACf;AAAA,kBACA,4CAAC,uCAAiB,eAAW,MAAC;AAAA,mBAChC;AAAA;AAAA,YACF;AAAA,YACA;AAAA,cAAC,6BAAa;AAAA,cAAb;AAAA,gBACC,SAAQ;AAAA,gBACR,SAAS,MAAM,kBAAkB,IAAI;AAAA,gBAErC;AAAA,kBAAC;AAAA;AAAA,oBACC,gBAAe;AAAA,oBACf,IAAG;AAAA,oBACH,aAAY;AAAA;AAAA,gBACd;AAAA;AAAA,YACF;AAAA,aACF;AAAA,WACF;AAAA,SAEJ;AAAA,OACF;AAAA,EAEJ;AAKA,QAAM,cAAc,YAAY,eAAe,CAAC;AAChD,QAAM,UAAU,qBAAqB;AAAA,IAAO,CAAC,WAC3C,YAAY,SAAS,MAAM;AAAA,EAC7B;AAEA,SACE,6CAAC,sBAAK,OAAM,UAAS,KAAI,KACvB;AAAA,gDAAC,wBAAO,OAAM,WACZ;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,IACC,QAAQ,SAAS,IAChB,4CAAC,4BAAyB,aAA0B,SAAkB,IACpE,QAAQ,WAAW,KAAK,QAAQ,CAAC,MAAM,YACzC,4CAAC,uBAAoB,aAA0B,IAC7C,QAAQ,WAAW,KAAK,QAAQ,CAAC,MAAM,uBACzC,4CAAC,kCAA+B,aAA0B,IAE1D,4CAAC,4BAAyB,aAA0B;AAAA,KAExD;AAEJ;AAEA,SAAS,wBAAwB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,kBAAc,mCAAe;AACnC,QAAM;AAAA,IACJ,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF,QAAI,2CAA0B;AAAA,IAC5B,UAAU;AAAA,MACR,WAAW,MAAM;AACf,qBAAa,KAAK;AAClB,oBAAY,kBAAkB;AAAA,UAC5B,cAAU,+CAA8B;AAAA,QAC1C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AAED,8BAAU,MAAM;AACd,QAAI,MAAM;AACR,YAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,MAAM,KAAK,CAAC;AAEhB,SACE,4CAAC,4BAAY,MAAZ,EAAiB,MAAY,cAC5B,uDAAC,4BAAY,SAAZ,EAAoB,OAAO,EAAE,OAAO,QAAQ,UAAU,QAAQ,GAC7D;AAAA,gDAAC,4BAAY,OAAZ,EACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF;AAAA,IACC,SACC,4CAAC,sBAAQ,MAAR,EAAa,IAAG,KAAI,OAAM,OAAM,MAAK,SACpC,sDAAC,sBAAQ,MAAR,EACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF,GACF;AAAA,IAEF,4CAAC,4BAAY,aAAZ,EACC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA,QACZ,QAAQ;AAAA,UACN,iBACE,4CAAC,sBAAK,IAAG,QAAO,QAAO,QACpB,2BACH;AAAA,QAEJ;AAAA;AAAA,IACF,GACF;AAAA,IACA,6CAAC,sBAAK,KAAI,KAAI,SAAQ,OAAM,IAAG,KAC7B;AAAA,kDAAC,4BAAY,QAAZ,EACC,sDAAC,0BAAO,SAAQ,aACd;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,GACF,GACF;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,UAAU;AAAA,UACV,SAAS;AAAA,UACT,SAAS,MAAM,uBAAuB,EAAE,eAAe,CAAC;AAAA,UAExD;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd;AAAA;AAAA,MACF;AAAA,OACF;AAAA,KACF,GACF;AAEJ;AAOA,SAAS,mBAAmB,EAAE,MAAM,GAAsB;AACxD,SAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,CAAC,EAAE,IAAI,CAAC,GAAG,UAC3C,4CAAC,SAAS,MAAT,EACC,uDAAC,sBAAK,WAAU,OAAM,SAAQ,WAAU,OAAM,UAAS,KAAI,KACzD;AAAA,iDAAC,sBAAK,KAAI,KAAI,OAAM,UAClB;AAAA,kDAAC,4BACC,sDAAC,+BACC,sDAAC,qCAAa,UAAS,UAAS,MAAK,KAAI,GAC3C,GACF;AAAA,MACA,4CAAC,4BACC,sDAAC,sBAAK,MAAK,KAAI,QAAO,QACpB;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,GACF,GACF;AAAA,OACF;AAAA,IACA,4CAAC,4BACC,sDAAC,0BAAO,SAAQ,aAAY,UAAQ,MAClC;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GACF,GACF;AAAA,KACF,KA3BkB,KA4BpB,CACD;AACH;AAEA,MAAM,eAA4C,CAAC,EAAE,OAAO,GAAG,SAAS,MAAM;AAC5E,SACE,4CAAC,SAAS,MAAT,EAAe,GAAG,sBAAsB,WAAW,QAAQ,GAC1D,sDAAC,sBAAmB,OAAc,GACpC;AAEJ;AAGA,SAAS,WAAW,EAAE,aAAa,GAAwC;AACzE,SAAO,aAAa,IAAI,CAAC,gBACvB,4CAAC,SAAS,MAAT,EACC,uDAAC,sBAAK,WAAU,OAAM,SAAQ,WAAU,OAAM,UAAS,KAAI,KACzD;AAAA,iDAAC,sBAAK,KAAI,KAAI,OAAM,UAClB;AAAA,kDAAC,+BAAU,OAAM,SACf,sDAAC,oDAAoB,aAA0B,MAAK,KAAI,GAC1D;AAAA,MACA,4CAAC,sBAAK,MAAK,KAAI,QAAO,QACnB,sBAAY,MACf;AAAA,OACF;AAAA,IACA,4CAAC,kBAAe,aAA0B;AAAA,KAC5C,KAXkB,YAAY,EAYhC,CACD;AACH;AAMA,SAAS,eAAe,EAAE,WAAW,GAA4B;AAC/D,SACE,4CAAC,SAAS,MAAT,EACC,sDAAC,sBAAK,MAAK,KAAI,OAAM,QAClB,uBACC;AAAA,IAAC;AAAA;AAAA,MACC,gBAAe;AAAA,MACf,IAAG;AAAA,MACH,aAAY;AAAA;AAAA,EACd,IAEA;AAAA,IAAC;AAAA;AAAA,MACC,gBAAe;AAAA,MACf,IAAG;AAAA,MACH,aAAY;AAAA;AAAA,EACd,GAEJ,GACF;AAEJ;AAEA,MAAM,QAA8B,CAAC;AAAA,EACnC;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,SACE,4CAAC,SAAS,MAAT,EAAe,GAAG,sBAAsB,YAAY,QAAQ,GAC1D,uBAAa,SAAS,IACrB,4CAAC,cAAW,cAA4B,IAExC,4CAAC,kBAAe,YAAY,6BAA6B,OAAO,GAEpE;AAEJ;AAOA,SAAS,uBAAuB;AAAA,EAC9B;AACF,GAEG;AACD,QAAM,cAAc,WAAW,mBAAmB;AAAA,IAChD,CAAC,YAAY,QAAQ,iBAAiB;AAAA,EACxC;AAEA,SAAO,cACL,4CAAC,wBAAO,OAAM,WACZ;AAAA,IAAC;AAAA;AAAA,MACC,gBAAe;AAAA,MACf,IAAG;AAAA,MACH,aAAY;AAAA;AAAA,EACd,GACF,IAEA,4CAAC,wBAAO,OAAM,WACZ;AAAA,IAAC;AAAA;AAAA,MACC,gBAAe;AAAA,MACf,IAAG;AAAA,MACH,aAAY;AAAA;AAAA,EACd,GACF;AAEJ;AAMA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAMG;AACD,SACE,4CAAC,SAAS,MAAT,EACC,uDAAC,sBAAK,WAAU,OAAM,SAAQ,WAAU,OAAM,UAAS,KAAI,KACzD;AAAA,iDAAC,sBAAK,KAAI,KAAI,OAAM,UAClB;AAAA,kDAAC,+BAAU,OAAM,SAAS,gBAAK;AAAA,MAC/B,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,qDAAC,sBAAK,OAAM,UAAS,KAAI,KAAI,MAAK,QAChC;AAAA,sDAAC,sBAAK,MAAK,KAAI,QAAO,QACnB,gBACH;AAAA,UACC;AAAA,WACH;AAAA,QACC,eACC,4CAAC,sBAAK,MAAK,KAAI,OAAM,QAClB,uBACH;AAAA,SAEJ;AAAA,OACF;AAAA,IACC;AAAA,KACH,GACF;AAEJ;AAMA,SAAS,qBAAqB;AAAA,EAC5B;AACF,GAEG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MACE;AAAA,QAAC;AAAA;AAAA,UACC,aAAa;AAAA,YACX,iBAAiB,WAAW;AAAA,YAC5B,UAAU,WAAW;AAAA,YACrB,SAAS,WAAW;AAAA,YACpB,aAAa,WAAW;AAAA,UAC1B;AAAA,UACA,MAAK;AAAA;AAAA,MACP;AAAA,MAEF,MAAM,WAAW;AAAA,MACjB,QAAQ,4CAAC,0BAAuB,YAAwB;AAAA,MACxD,aAAa,WAAW;AAAA;AAAA,EAC1B;AAEJ;AAOA,SAAS,uBAAuB;AAAA,EAC9B;AACF,GAEG;AACD,QAAM,eAAe,YAAY;AAEjC,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,EACT;AAEA,MAAI,aAAa,UAAU,aAAa;AACtC,WACE,4CAAC,wBAAO,OAAM,WACX,uBAAa,gBAAgB,YAC5B;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,IACE,aAAa,gBAAgB,uBAC/B;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,gBAAe;AAAA,QACf,IAAG;AAAA,QACH,aAAY;AAAA;AAAA,IACd,GAEJ;AAAA,EAEJ;AAEA,SACE,4CAAC,wBAAO,OAAM,WACX,uBAAa,gBAAgB,YAC5B;AAAA,IAAC;AAAA;AAAA,MACC,gBAAe;AAAA,MACf,IAAG;AAAA,MACH,aAAY;AAAA;AAAA,EACd,IAEA;AAAA,IAAC;AAAA;AAAA,MACC,gBAAe;AAAA,MACf,IAAG;AAAA,MACH,aAAY;AAAA;AAAA,EACd,GAEJ;AAEJ;AAOA,SAAS,wBAAwB;AAAA,EAC/B;AACF,GAEG;AACD,QAAM,CAAC,gBAAgB,iBAAiB,QAAI,uBAAS,KAAK;AAC1D,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAS,KAAK;AAClD,QAAM,CAAC,uBAAuB,wBAAwB,QAAI,uBAAS,KAAK;AACxE,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,uBAAS,KAAK;AAC9D,QAAM,wBAAwB,mCAAmC,WAAW;AAC5E,QAAM,gBAAY,uCAAe;AAEjC,QAAM,mBAAmB,UAAU;AAAA,IACjC,gBAAgB;AAAA,IAChB,IAAI;AAAA,IACJ,aAAa;AAAA,EACf,CAAC;AAID,QAAM,iBAAiB,8BAA8B,WAAW;AAEhE,MAAI,CAAC,YAAY,cAAc;AAC7B,UAAM,cAAc,YAAY,eAAe,CAAC;AAChD,UAAM,UAAU,qBAAqB;AAAA,MAAO,CAAC,WAC3C,YAAY,SAAS,MAAM;AAAA,IAC7B;AAEA,WAAO,QAAQ,SAAS,IACtB,4CAAC,4BAAyB,aAA0B,SAAkB,IACpE,QAAQ,WAAW,KAAK,QAAQ,CAAC,MAAM,YACzC,4CAAC,uBAAoB,aAA0B,IAC7C,QAAQ,WAAW,KAAK,QAAQ,CAAC,MAAM,uBACzC,4CAAC,kCAA+B,aAA0B,IAE1D,4CAAC,4BAAyB,aAA0B;AAAA,EAExD;AAEA,QAAM,YAAY,YAAY,aAAa,UAAU;AACrD,QAAM,uBACJ,YAAY,aAAa,gBAAgB;AAC3C,QAAM,kCACJ,YAAY,aAAa,gBAAgB;AAE3C,SACE,4EACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,iBAAiB,YAAY;AAAA,QAC7B,gBAAgB,YAAY,aAAa;AAAA,QACzC,MAAM;AAAA,QACN,cAAc;AAAA;AAAA,IAChB;AAAA,IACC,cACC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,MAAM;AAAA,QACN,cAAc;AAAA;AAAA,IAChB;AAAA,IAED,yBACC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,cAAc;AAAA;AAAA,IAChB;AAAA,IAED,eAAe,SAAS,KAAK,CAAC,mCAC7B;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,cAAc;AAAA;AAAA,IAChB;AAAA,IAEF,6CAAC,sBAAK,OAAM,UAAS,KAAI,KACtB;AAAA,OAAC,cACC,uBACC,4CAAC,0BAAO,SAAQ,aAAY,SAAS,MAAM,cAAc,IAAI,GAC3D;AAAA,QAAC;AAAA;AAAA,UACC,gBAAe;AAAA,UACf,IAAG;AAAA,UACH,aAAY;AAAA;AAAA,MACd,GACF,IACE,kCACF;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAS,MAAM,yBAAyB,IAAI;AAAA,UAE5C;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd;AAAA;AAAA,MACF,IAEA;AAAA,QAAC;AAAA;AAAA,UACC,SAAQ;AAAA,UACR,SAAS,YAAY;AACnB,gBAAI,eAAe,SAAS,GAAG;AAC7B,kCAAoB,IAAI;AACxB;AAAA,YACF;AACA,gBAAI;AACF,oBAAM,sBAAsB;AAAA,YAC9B,QAAQ;AAAA,YAER;AAAA,UACF;AAAA,UAEA;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd;AAAA;AAAA,MACF;AAAA,MAEJ,6CAAC,6BAAa,MAAb,EACC;AAAA,oDAAC,6BAAa,SAAb,EACC,sDAAC,8BAAW,OAAO,kBACjB,sDAAC,yCAAmB,GACtB,GACF;AAAA,QACA,6CAAC,6BAAa,SAAb,EAAqB,OAAM,OACzB;AAAA,uBAAa,wBACZ,4CAAC,6BAAa,MAAb,EAAkB,SAAS,MAAM,cAAc,IAAI,GAClD;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd,GACF;AAAA,UAED,aAAa,mCACZ,4CAAC,6BAAa,MAAb,EAAkB,SAAS,MAAM,yBAAyB,IAAI,GAC7D;AAAA,YAAC;AAAA;AAAA,cACC,gBAAe;AAAA,cACf,IAAG;AAAA,cACH,aAAY;AAAA;AAAA,UACd,GACF;AAAA,UAEF;AAAA,YAAC,6BAAa;AAAA,YAAb;AAAA,cACC,SAAQ;AAAA,cACR,SAAS,MAAM,kBAAkB,IAAI;AAAA,cAErC;AAAA,gBAAC;AAAA;AAAA,kBACC,gBAAe;AAAA,kBACf,IAAG;AAAA,kBACH,aAAY;AAAA;AAAA,cACd;AAAA;AAAA,UACF;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;AAGA,SAAS,sBAAsB;AAAA,EAC7B;AACF,GAEG;AACD,SAAO,aAAa,IAAI,CAAC,gBACvB;AAAA,IAAC;AAAA;AAAA,MAEC,MAAM,4CAAC,oDAAoB,aAA0B,MAAK,KAAI;AAAA,MAC9D,MAAM,YAAY;AAAA,MAClB,QAAQ,4CAAC,0BAAuB,aAA0B;AAAA,MAC1D,aAAa,YAAY;AAAA,MACzB,SAAS,4CAAC,2BAAwB,aAA0B;AAAA;AAAA,IALvD,YAAY;AAAA,EAMnB,CACD;AACH;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,6CAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,iDAAC,sBAAK,WAAU,UAAS,KAAI,KAC3B;AAAA,kDAAC,sBAAK,MAAK,KAAI,QAAO,QACnB,iBACH;AAAA,MACA,4CAAC,sBAAK,MAAK,KAAI,OAAM,QAClB,uBACH;AAAA,OACF;AAAA,IACC;AAAA,KACH;AAEJ;AAWA,MAAM,gBAA8C,CAAC;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MAAM;AACJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,KAAI;AAAA,MACH,GAAG,sBAAsB,YAAY,QAAQ;AAAA,MAE5C;AAAA,4BACA,kBAAkB,SAAS,KAC3B,mCACA;AAAA,UAAC;AAAA;AAAA,YACC,OACE;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd;AAAA,YAEF,aACE,mBACE;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA,gBACZ,QAAQ,EAAE,iBAAiB;AAAA;AAAA,YAC7B,IAEA;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd;AAAA,YAIJ,sDAAC,SAAS,MAAT,EACE,4BACC,4CAAC,sBAAmB,OAAO,GAAG,IAC5B,kBAAkB,SAAS,IAC7B,kBAAkB,IAAI,CAAC,eACrB;AAAA,cAAC;AAAA;AAAA,gBAEC;AAAA;AAAA,cADK,WAAW;AAAA,YAElB,CACD,IAED,4CAAC,kBAAe,YAAU,MAAC,GAE/B;AAAA;AAAA,QACF;AAAA,QAEF;AAAA,UAAC;AAAA;AAAA,YACC,OACE;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd;AAAA,YAEF,aACE;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAe;AAAA,gBACf,IAAG;AAAA,gBACH,aAAY;AAAA;AAAA,YACd;AAAA,YAGF,sDAAC,SAAS,MAAT,EACE,uBAAa,SAAS,IACrB,4CAAC,yBAAsB,cAA4B,IAEnD,4CAAC,kBAAe,YAAY,6BAA6B,OAAO,GAEpE;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAMA,MAAM,aAAwC,CAAC,EAAE,OAAO,GAAG,SAAS,MAAM;AACxE,SACE,4CAAC,sBAAK,MAAK,KAAK,GAAG,sBAAsB,SAAS,QAAQ,GACxD,sDAAC,qCAAa,OAAc,GAC9B;AAEJ;AAEA,SAAS,sBACP,OACA,UACA;AACA,aAAO,0BAAY;AAAA,IACjB,GAAG;AAAA,IACH,cAAc;AAAA,IACd,UAAU;AAAA,IACV,aAAa;AAAA,EACf,CAAC;AACH;","names":[]}
@@ -1,4 +1,4 @@
1
- import { DataIntegration } from '../api/endpoint.cjs';
1
+ import { DataIntegration, SharedDataConnection } from '../api/endpoint.cjs';
2
2
  import { WidgetRootDomProps } from './utils.cjs';
3
3
  import '@tanstack/react-query';
4
4
  import '../api/widgets-api-client.cjs';
@@ -17,15 +17,50 @@ import '@radix-ui/themes/components/select';
17
17
 
18
18
  interface PipesProps extends WidgetRootDomProps {
19
19
  integrations: DataIntegration[];
20
+ /**
21
+ * Whether the endpoint returned any connections before the host's `filter`
22
+ * ran, which is what tells an organization with nothing enabled yet apart
23
+ * from a filter that matched nothing. Defaults to whatever survived, the
24
+ * reading for an unfiltered list.
25
+ */
26
+ hasUnfilteredIntegrations?: boolean;
27
+ }
28
+ interface PipesSectionsProps extends PipesProps {
29
+ /**
30
+ * Organization-owned connections, as returned by the shared-connections
31
+ * endpoint. Empty both when the organization shares nothing and when the
32
+ * request failed, since neither is something a member can act on.
33
+ */
34
+ sharedConnections: SharedDataConnection[];
35
+ /**
36
+ * {@link PipesProps.hasUnfilteredIntegrations} for the shared section. The
37
+ * section is dropped entirely unless the organization shares something, so
38
+ * this only ever decides whether a filtered-out lane says so.
39
+ */
40
+ hasUnfilteredSharedConnections?: boolean;
41
+ /** Renders the shared section as skeleton rows while it resolves. */
42
+ isSharedLoading?: boolean;
43
+ /** Names the owning organization in the shared section's description. */
44
+ organizationName?: string;
20
45
  }
21
46
  interface PipesLoadingProps extends WidgetRootDomProps {
22
47
  count: number;
23
48
  }
24
49
  declare const PipesLoading: React.FC<PipesLoadingProps>;
25
50
  declare const Pipes: React.FC<PipesProps>;
51
+ /**
52
+ * The sectioned member experience: the connections the organization shares,
53
+ * then the member's own. The two lanes come from different endpoints and are
54
+ * never merged — the same provider can legitimately appear in both, once as an
55
+ * organization-owned connection and once as the member's own account.
56
+ *
57
+ * The shared section is omitted entirely when the organization shares nothing
58
+ * (or the request failed), leaving the member's own section usable on its own.
59
+ */
60
+ declare const PipesSections: React.FC<PipesSectionsProps>;
26
61
  interface PipesErrorProps extends WidgetRootDomProps {
27
62
  error: unknown;
28
63
  }
29
64
  declare const PipesError: React.FC<PipesErrorProps>;
30
65
 
31
- export { Pipes, PipesError, type PipesErrorProps, PipesLoading, type PipesLoadingProps, type PipesProps };
66
+ export { Pipes, PipesError, type PipesErrorProps, PipesLoading, type PipesLoadingProps, type PipesProps, PipesSections, type PipesSectionsProps };
@@ -43,6 +43,8 @@ const getStatusColor = (state) => {
43
43
  case "waiting":
44
44
  case "neutral":
45
45
  return "gray";
46
+ case "warning":
47
+ return "amber";
46
48
  case "error":
47
49
  return "red";
48
50
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/lib/status.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport * as React from \"react\";\nimport { MarginProps } from \"@radix-ui/themes/props\";\nimport { Spinner, Text } from \"@radix-ui/themes\";\n\nexport const getStatusColor = (\n state: \"success\" | \"waiting\" | \"error\" | \"neutral\",\n): \"green\" | \"gray\" | \"red\" => {\n switch (state) {\n case \"success\":\n return \"green\";\n case \"waiting\":\n case \"neutral\":\n return \"gray\";\n case \"error\":\n return \"red\";\n }\n};\n\nexport interface StatusProps\n extends Omit<React.ComponentPropsWithoutRef<\"span\">, \"color\">, MarginProps {\n children?: React.ReactNode;\n state: \"success\" | \"waiting\" | \"error\" | \"neutral\";\n}\n\nconst Status = React.forwardRef<HTMLSpanElement, StatusProps>(\n ({ className, ...props }, forwardedRef) => (\n <Text\n ref={forwardedRef}\n className={clsx(className, \"woswidgets-status\")}\n data-state={props.state}\n {...props}\n size=\"2\"\n color={getStatusColor(props.state)}\n >\n {props.state === \"waiting\" && <Spinner />}\n {props.children}\n </Text>\n ),\n);\n\nStatus.displayName = \"Status\";\n\nexport { Status };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BI;AA3BJ,kBAAiB;AACjB,YAAuB;AAEvB,oBAA8B;AAEvB,MAAM,iBAAiB,CAC5B,UAC6B;AAC7B,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAQA,MAAM,SAAS,MAAM;AAAA,EACnB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,iBACxB;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,eAAW,YAAAA,SAAK,WAAW,mBAAmB;AAAA,MAC9C,cAAY,MAAM;AAAA,MACjB,GAAG;AAAA,MACJ,MAAK;AAAA,MACL,OAAO,eAAe,MAAM,KAAK;AAAA,MAEhC;AAAA,cAAM,UAAU,aAAa,4CAAC,yBAAQ;AAAA,QACtC,MAAM;AAAA;AAAA;AAAA,EACT;AAEJ;AAEA,OAAO,cAAc;","names":["clsx"]}
1
+ {"version":3,"sources":["../../../src/lib/status.tsx"],"sourcesContent":["import clsx from \"clsx\";\nimport * as React from \"react\";\nimport { MarginProps } from \"@radix-ui/themes/props\";\nimport { Spinner, Text } from \"@radix-ui/themes\";\n\nexport const getStatusColor = (\n state: \"success\" | \"waiting\" | \"warning\" | \"error\" | \"neutral\",\n): \"green\" | \"gray\" | \"amber\" | \"red\" => {\n switch (state) {\n case \"success\":\n return \"green\";\n case \"waiting\":\n case \"neutral\":\n return \"gray\";\n case \"warning\":\n return \"amber\";\n case \"error\":\n return \"red\";\n }\n};\n\nexport interface StatusProps\n extends Omit<React.ComponentPropsWithoutRef<\"span\">, \"color\">, MarginProps {\n children?: React.ReactNode;\n state: \"success\" | \"waiting\" | \"warning\" | \"error\" | \"neutral\";\n}\n\nconst Status = React.forwardRef<HTMLSpanElement, StatusProps>(\n ({ className, ...props }, forwardedRef) => (\n <Text\n ref={forwardedRef}\n className={clsx(className, \"woswidgets-status\")}\n data-state={props.state}\n {...props}\n size=\"2\"\n color={getStatusColor(props.state)}\n >\n {props.state === \"waiting\" && <Spinner />}\n {props.children}\n </Text>\n ),\n);\n\nStatus.displayName = \"Status\";\n\nexport { Status };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BI;AA7BJ,kBAAiB;AACjB,YAAuB;AAEvB,oBAA8B;AAEvB,MAAM,iBAAiB,CAC5B,UACuC;AACvC,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACF;AAQA,MAAM,SAAS,MAAM;AAAA,EACnB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,iBACxB;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACL,eAAW,YAAAA,SAAK,WAAW,mBAAmB;AAAA,MAC9C,cAAY,MAAM;AAAA,MACjB,GAAG;AAAA,MACJ,MAAK;AAAA,MACL,OAAO,eAAe,MAAM,KAAK;AAAA,MAEhC;AAAA,cAAM,UAAU,aAAa,4CAAC,yBAAQ;AAAA,QACtC,MAAM;AAAA;AAAA;AAAA,EACT;AAEJ;AAEA,OAAO,cAAc;","names":["clsx"]}
@@ -1,10 +1,10 @@
1
1
  import * as React from 'react';
2
2
  import { MarginProps } from '@radix-ui/themes/props';
3
3
 
4
- declare const getStatusColor: (state: "success" | "waiting" | "error" | "neutral") => "green" | "gray" | "red";
4
+ declare const getStatusColor: (state: "success" | "waiting" | "warning" | "error" | "neutral") => "green" | "gray" | "amber" | "red";
5
5
  interface StatusProps extends Omit<React.ComponentPropsWithoutRef<"span">, "color">, MarginProps {
6
6
  children?: React.ReactNode;
7
- state: "success" | "waiting" | "error" | "neutral";
7
+ state: "success" | "waiting" | "warning" | "error" | "neutral";
8
8
  }
9
9
  declare const Status: React.ForwardRefExoticComponent<StatusProps & React.RefAttributes<HTMLSpanElement>>;
10
10