import { useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { CompanySecret } from "@paperclipai/shared"; import { AlertCircle, KeyRound, Trash2, UserRound } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { EmptyState } from "../../components/EmptyState"; import { secretsApi, type MyUserSecretEntry } from "../../api/secrets"; import { queryKeys } from "../../lib/queryKeys"; import { cn } from "../../lib/utils"; import { useToastActions } from "../../context/ToastContext"; import { SetMyUserSecretDialog } from "./SetMyUserSecretDialog"; import { SecretPathName } from "./SecretPathName"; import { myValueLabel, myValueState, myValueTone, } from "./my-value-state"; /** * Secrets → My secrets tab. Lists every company user-secret definition paired * with the current user's own value state, and lets the user set / update / * clear their value. This is the owner-facing counterpart to the admin * "User secret definitions" tab. */ export function MyUserSecretsTab({ companyId }: { companyId: string }) { const queryClient = useQueryClient(); const { pushToast } = useToastActions(); const [dialogFor, setDialogFor] = useState(null); const mySecretsQuery = useQuery({ queryKey: queryKeys.secrets.myUserSecrets(companyId), queryFn: () => secretsApi.listMyUserSecrets(companyId), }); const entries = mySecretsQuery.data ?? []; const clear = useMutation({ mutationFn: (secret: CompanySecret) => secretsApi.removeMyUserSecret(companyId, secret.id), onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.secrets.myUserSecrets(companyId) }); pushToast({ title: "Value cleared", tone: "info" }); }, onError: (err) => pushToast({ title: "Could not clear value", body: err instanceof Error ? err.message : undefined, tone: "error", }), }); const missingCount = entries.filter( (entry) => entry.definition.status === "active" && !entry.secret, ).length; return (

These are credentials only you provide. Each value is yours alone — used when you are the user responsible for a run — and is never shown back to anyone, including admins. {missingCount > 0 ? ( {" "} {missingCount} required secret{missingCount === 1 ? " still needs" : "s still need"} your value. ) : null}

{mySecretsQuery.isError ? (
Failed to load your secrets:{" "} {(mySecretsQuery.error as Error).message}
) : entries.length === 0 && !mySecretsQuery.isPending ? ( ) : (
    {entries.map((entry) => ( setDialogFor(entry)} onClear={() => entry.secret && clear.mutate(entry.secret)} clearing={clear.isPending} /> ))}
)}
{ if (!open) setDialogFor(null); }} />
); } function MyUserSecretRow({ entry, onSet, onClear, clearing, }: { entry: MyUserSecretEntry; onSet: () => void; onClear: () => void; clearing: boolean; }) { const { definition, secret } = entry; const state = myValueState(definition, secret); const disabledDefinition = definition.status !== "active"; return (
  • {definition.key} {disabledDefinition ? ( {definition.status} ) : null}
    {definition.description ? (

    {definition.description}

    ) : null} {definition.usageGuidance ? (

    {definition.usageGuidance}

    ) : null}
    {myValueLabel(state)} {!disabledDefinition ? ( ) : null} {secret ? ( ) : null}
  • ); }