From 52c5be4fa473f777a5f99f7ef098782ee9d07338 Mon Sep 17 00:00:00 2001 From: "glm5.2 agent 180" Date: Sat, 20 Jun 2026 13:52:26 +0300 Subject: [PATCH] feat(ai-settings): put Clear inside the API key field, drop the eye The PasswordInput for each endpoint API key (Chat / LLM, Embeddings, Voice / STT) used to show Mantine's built-in visibility toggle (the 'eye') plus a separate 'Clear' link below the field. The eye is useless here: the key field is a write-only buffer, the stored key never loads back (the server only returns hasApiKey), so clicking the eye reveals an empty buffer. Replace it with a Clear ActionIcon in the field's right section. Passing a custom rightSection suppresses the built-in eye (Mantine). The Clear action appears ONLY when a key is stored AND the buffer is empty (has*ApiKey && form.values.*ApiKey.length === 0); as soon as the user starts typing a new key, the rightSection falls back to undefined and the default eye returns - now it is useful (verify what was typed). After Clear, the handler sets has*ApiKey=false, so the rightSection flips back too. Self-consistent. The old Stack wrapper and Anchor 'Clear' link are gone; Anchor is removed from the @mantine/core import (no remaining usages). The Clear icon-only button carries type='button' (never submits) and an aria-label. The two-column 'Model | API key' layout and the write-only buffer/handler semantics are unchanged. --- .../components/ai-provider-settings.tsx | 156 +++++++++++------- 1 file changed, 95 insertions(+), 61 deletions(-) diff --git a/apps/client/src/features/workspace/components/settings/components/ai-provider-settings.tsx b/apps/client/src/features/workspace/components/settings/components/ai-provider-settings.tsx index 78727bda..360dc6db 100644 --- a/apps/client/src/features/workspace/components/settings/components/ai-provider-settings.tsx +++ b/apps/client/src/features/workspace/components/settings/components/ai-provider-settings.tsx @@ -1,7 +1,7 @@ import { useEffect, useState } from "react"; import { z } from "zod/v4"; import { - Anchor, + ActionIcon, Badge, Box, Button, @@ -15,12 +15,13 @@ import { Text, Textarea, TextInput, + Tooltip, useMantineTheme, } from "@mantine/core"; import { useForm } from "@mantine/form"; import { useDisclosure } from "@mantine/hooks"; import { zod4Resolver } from "mantine-form-zod-resolver"; -import { IconPencil } from "@tabler/icons-react"; +import { IconPencil, IconX } from "@tabler/icons-react"; import { useAtom } from "jotai"; import { notifications } from "@mantine/notifications"; import { useTranslation } from "react-i18next"; @@ -430,19 +431,34 @@ export default function AiProviderSettings() { disabled={isLoading} {...form.getInputProps("chatModel")} /> - - - {hasApiKey && ( - - {t("Clear")} - - )} - + {/* The key field is write-only: the stored key never loads back, so the + built-in visibility toggle reveals nothing. Replace it with a Clear + action in the right section. Passing rightSection suppresses the eye + (Mantine). While typing a new key (buffer non-empty) fall back to + the default eye so the user can verify what they typed. */} + + + + + + ) : undefined + } + rightSectionPointerEvents="all" + {...form.getInputProps("apiKey")} + /> - - - {hasEmbeddingApiKey && ( - - {t("Clear")} - - )} - + {/* The key field is write-only: the stored key never loads back, so the + built-in visibility toggle reveals nothing. Replace it with a Clear + action in the right section. Passing rightSection suppresses the eye + (Mantine). While typing a new key (buffer non-empty) fall back to + the default eye so the user can verify what they typed. */} + + + + + + ) : undefined + } + rightSectionPointerEvents="all" + {...form.getInputProps("embeddingApiKey")} + /> - - - {hasSttApiKey && ( - - {t("Clear")} - - )} - + {/* The key field is write-only: the stored key never loads back, so the + built-in visibility toggle reveals nothing. Replace it with a Clear + action in the right section. Passing rightSection suppresses the eye + (Mantine). While typing a new key (buffer non-empty) fall back to + the default eye so the user can verify what they typed. */} + + + + + + ) : undefined + } + rightSectionPointerEvents="all" + {...form.getInputProps("sttApiKey")} + />