oxios 1.5.2

Oxios Agent OS — Agent Operating System powered by oxi-sdk
import { AlertCircle, Eye, EyeOff, Key, Shield, Terminal } from 'lucide-react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { cn } from '@/lib/utils'
import type { ApiKeySource } from '@/types/engine'

// ─── API key source config ───────────────────────────────────

const SOURCE_CONFIG: Record<
  ApiKeySource,
  { labelKey: string; icon: React.ReactNode; color: string }
> = {
  env: {
    labelKey: 'engine.apiKeyEnv',
    icon: <Terminal className="h-3.5 w-3.5" />,
    color: 'text-success',
  },
  auth_store: {
    labelKey: 'engine.apiKeyAuthStore',
    icon: <Shield className="h-3.5 w-3.5" />,
    color: 'text-info',
  },
  config: {
    labelKey: 'engine.apiKeyConfig',
    icon: <Key className="h-3.5 w-3.5" />,
    color: 'text-warning',
  },
  none: {
    labelKey: 'engine.apiKeyNone',
    icon: <AlertCircle className="h-3.5 w-3.5" />,
    color: 'text-muted-foreground',
  },
}

// ─── Component ───────────────────────────────────────────────

interface ApiKeyInputProps {
  /** Whether an API key is currently configured */
  hasKey: boolean
  /** Source of the existing key */
  source?: ApiKeySource
  /** Provider name for display */
  providerName: string
  /** Called when user submits a new key */
  onSubmit: (apiKey: string) => void
  /** Whether the mutation is pending */
  isPending?: boolean
  className?: string
}

export function ApiKeyInput({
  hasKey,
  source = 'none',
  providerName,
  onSubmit,
  isPending,
  className,
}: ApiKeyInputProps) {
  const { t } = useTranslation()
  const [inputValue, setInputValue] = useState('')
  const [visible, setVisible] = useState(false)

  const sourceInfo = SOURCE_CONFIG[source]

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault()
    if (inputValue.trim()) {
      onSubmit(inputValue.trim())
      setInputValue('')
    }
  }

  return (
    <div className={cn('space-y-3', className)}>
      {/* Current status */}
      <div className="flex items-center gap-2 text-sm">
        <span className={cn('flex items-center gap-1.5', sourceInfo.color)}>
          {sourceInfo.icon}
          <span>{t(sourceInfo.labelKey)}</span>
        </span>
      </div>

      {/* Input form */}
      <form onSubmit={handleSubmit} className="flex items-center gap-2">
        <div className="relative flex-1">
          <Input
            type={visible ? 'text' : 'password'}
            value={inputValue}
            onChange={(e) => setInputValue(e.target.value)}
            placeholder={
              hasKey
                ? t('engine.apiKeyOverrideHint')
                : t('engine.apiKeyPlaceholder', 'Enter {{provider}} API key', {
                    provider: providerName,
                  })
            }
            className="pr-9 font-mono text-sm"
          />
          <button
            type="button"
            onClick={() => setVisible(!visible)}
            className="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
          >
            {visible ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
          </button>
        </div>
        <Button type="submit" size="sm" disabled={!inputValue.trim() || isPending}>
          {isPending
            ? t('engine.apiKeySaving')
            : hasKey
              ? t('engine.apiKeyUpdate')
              : t('engine.apiKeySetNew')}
        </Button>
      </form>

      {/* Hint */}
      {hasKey && <p className="text-xs text-muted-foreground">{t('engine.apiKeyOverrideHint')}</p>}
    </div>
  )
}