import { useId } from "react" import { Controller, useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { z } from "zod" import { ExternalLink, Inbox, KeyRound, Loader2, Plus, Trash2 } from "lucide-react" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldSet, } from "@/components/ui/field" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table" import { useAccounts, useCreateAccount, useDeleteAccount } from "@/hooks/useApi" const createAccountSchema = z.object({ provider: z.literal("selectel"), username: z.string().trim().min(1, "Укажите имя сервисного пользователя"), password: z.string().min(1, "Укажите пароль"), accountId: z.string().trim().min(1, "Укажите номер аккаунта"), projectName: z.string().trim().min(1, "Укажите имя проекта"), comment: z.string(), }) type CreateAccountForm = z.infer // API возвращает generic "invalid provider credentials" (нарочно, чтобы не // палить детали) — переводим в понятную пользователю формулировку. function createAccountErrorMessage(message: string): string { if (message.toLowerCase().includes("invalid provider credentials")) { return "Selectel отклонил учётные данные — проверьте логин, пароль, номер аккаунта и имя проекта." } return message } const EMPTY_FORM: CreateAccountForm = { provider: "selectel", username: "", password: "", accountId: "", projectName: "", comment: "", } export function AccountsPage() { const accounts = useAccounts() const createAccount = useCreateAccount() const deleteAccount = useDeleteAccount() const usernameFieldId = useId() const passwordFieldId = useId() const accountIdFieldId = useId() const projectNameFieldId = useId() const commentFieldId = useId() const accountList = accounts.data ?? [] const { control, handleSubmit, reset, formState: { errors }, } = useForm({ resolver: zodResolver(createAccountSchema), defaultValues: EMPTY_FORM, }) function onSubmit(values: CreateAccountForm) { createAccount.mutate( { provider: "selectel", comment: values.comment, secret: { username: values.username.trim(), password: values.password, account_id: values.accountId.trim(), project_name: values.projectName.trim(), }, }, { onSuccess: () => reset(EMPTY_FORM) }, ) } function onDelete(id: string, comment: string) { if (window.confirm(`Удалить учётную запись «${comment}»? Действие необратимо.`)) { deleteAccount.mutate(id) } } return (
providers

Учётные записи

Имя сервисного пользователя ( )} /> Пароль ( )} /> Номер аккаунта ( )} /> Имя проекта ( )} /> Комментарий ( )} /> Провайдер: selectel. Создайте сервисного пользователя в панели управления Selectel, выдайте ему роль на нужный проект и укажите здесь его логин, пароль, номер аккаунта и имя проекта. Пароль хранится в зашифрованном виде.{" "} Пользователи и роли на my.selectel.ru
{createAccount.isError && ( {createAccountErrorMessage(createAccount.error.message)} )}
{deleteAccount.isError && ( {deleteAccount.error.message} )} {accountList.length === 0 ? (
Учётных записей пока нет — добавьте первую выше.
) : ( Провайдер Комментарий Действия {accountList.map((a) => ( {a.provider} {a.comment} ))}
)}
) }