162 lines
6.5 KiB
TypeScript
162 lines
6.5 KiB
TypeScript
import { useState } from 'react'
|
|
import { useTimeout } from '../../utils/useTimeout'
|
|
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from '../ui/Card'
|
|
import { Switch } from '../ui/Switch'
|
|
import { Badge } from '../ui/Badge'
|
|
import { Alert, AlertTitle, AlertDescription } from '../ui/Alert'
|
|
import { Tooltip } from '../ui/Tooltip'
|
|
import { Kbd } from '../ui/Kbd'
|
|
import { Icon } from '../Icon'
|
|
|
|
export function SettingsPanel() {
|
|
const [apiKeyVisible, setApiKeyVisible] = useState(false)
|
|
const [copied, setCopied] = useState(false)
|
|
const [saved, setSaved] = useState(false)
|
|
|
|
// Toggles
|
|
const [canaryEnabled, setCanaryEnabled] = useState(true)
|
|
const [telemetryEnabled, setTelemetryEnabled] = useState(true)
|
|
const [autoRollback, setAutoRollback] = useState(false)
|
|
|
|
const apiKey = 'nsk_live_98a72ef01bc34d89a2'
|
|
const { schedule } = useTimeout()
|
|
|
|
const copyKey = () => {
|
|
navigator.clipboard?.writeText(apiKey)
|
|
setCopied(true)
|
|
schedule(() => setCopied(false), 2000)
|
|
}
|
|
|
|
const handleSave = () => {
|
|
setSaved(true)
|
|
schedule(() => setSaved(false), 2500)
|
|
}
|
|
|
|
return (
|
|
<div className="stack-lg">
|
|
<Card>
|
|
<CardHeader>
|
|
<div className="flex-between">
|
|
<CardTitle>Environment & Access Keys</CardTitle>
|
|
<Badge variant="primary">Production</Badge>
|
|
</div>
|
|
<CardDescription>
|
|
Manage authentication credentials and runtime ingress access.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="stack-md">
|
|
<div>
|
|
<label style={{ display: 'block', fontSize: 'var(--text-xs)', fontWeight: 600, marginBottom: 'var(--space-2)' }}>
|
|
Production Secret API Key
|
|
</label>
|
|
<div className="row-xs" style={{ alignItems: 'center' }}>
|
|
<div
|
|
style={{
|
|
flex: 1,
|
|
background: 'var(--secondary)',
|
|
border: '1px solid var(--border)',
|
|
borderRadius: 'var(--radius-md)',
|
|
padding: 'var(--space-2) var(--space-3)',
|
|
fontFamily: 'var(--font-mono)',
|
|
fontSize: 'var(--text-xs)',
|
|
color: 'var(--foreground)',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
}}
|
|
>
|
|
<span>
|
|
{apiKeyVisible ? apiKey : '••••••••••••••••••••••••••••••••'}
|
|
</span>
|
|
<button
|
|
className="icon-button"
|
|
style={{ padding: 4 }}
|
|
onClick={() => setApiKeyVisible(!apiKeyVisible)}
|
|
aria-label={apiKeyVisible ? 'Hide API key' : 'Show API key'}
|
|
>
|
|
<Icon name={apiKeyVisible ? 'eye' : 'eye'} size={14} />
|
|
</button>
|
|
</div>
|
|
<Tooltip content="Copy key to clipboard">
|
|
<button className="button secondary" onClick={copyKey}>
|
|
<Icon name={copied ? 'check' : 'copy'} size={14} />
|
|
{copied ? 'Copied' : 'Copy'}
|
|
</button>
|
|
</Tooltip>
|
|
</div>
|
|
</div>
|
|
|
|
<Alert variant="info">
|
|
<AlertTitle>Zero-Trust Rotation Enabled</AlertTitle>
|
|
<AlertDescription>
|
|
Keys are automatically renewed every 90 days. Next scheduled rotation in 14 days.
|
|
</AlertDescription>
|
|
</Alert>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>Deployment & Runtime Safeguards</CardTitle>
|
|
<CardDescription>
|
|
Fine-tune canary threshold tolerances and telemetry logging.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="stack-md">
|
|
<div className="flex-between">
|
|
<div>
|
|
<div style={{ fontSize: 'var(--text-sm)', fontWeight: 600, color: 'var(--foreground)' }}>
|
|
Automated Canary Progression
|
|
</div>
|
|
<div style={{ fontSize: 'var(--text-xs)', color: 'var(--muted-foreground)', marginTop: 2 }}>
|
|
Gradually increase traffic from 5% to 100% based on error budget.
|
|
</div>
|
|
</div>
|
|
<Switch checked={canaryEnabled} onCheckedChange={setCanaryEnabled} />
|
|
</div>
|
|
|
|
<div className="flex-between" style={{ paddingTop: 'var(--space-3)', borderTop: '1px solid var(--border)' }}>
|
|
<div>
|
|
<div style={{ fontSize: 'var(--text-sm)', fontWeight: 600, color: 'var(--foreground)' }}>
|
|
Detailed OpenTelemetry Tracing
|
|
</div>
|
|
<div style={{ fontSize: 'var(--text-xs)', color: 'var(--muted-foreground)', marginTop: 2 }}>
|
|
Emit span metrics for all inbound HTTP and gRPC remote procedure calls.
|
|
</div>
|
|
</div>
|
|
<Switch checked={telemetryEnabled} onCheckedChange={setTelemetryEnabled} />
|
|
</div>
|
|
|
|
<div className="flex-between" style={{ paddingTop: 'var(--space-3)', borderTop: '1px solid var(--border)' }}>
|
|
<div>
|
|
<div style={{ fontSize: 'var(--text-sm)', fontWeight: 600, color: 'var(--foreground)' }}>
|
|
Immediate Circuit-Breaker Rollback
|
|
</div>
|
|
<div style={{ fontSize: 'var(--text-xs)', color: 'var(--muted-foreground)', marginTop: 2 }}>
|
|
Instantly revert to prior green build if P99 latency breaches 100ms.
|
|
</div>
|
|
</div>
|
|
<Switch checked={autoRollback} onCheckedChange={setAutoRollback} />
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
<CardFooter>
|
|
<span style={{ fontSize: 'var(--text-3xs)', color: 'var(--muted-foreground)' }}>
|
|
Shortcut: <Kbd>Ctrl</Kbd> + <Kbd>S</Kbd> to persist
|
|
</span>
|
|
<div className="row-xs" style={{ marginLeft: 'auto' }}>
|
|
<button className="button ghost">Discard</button>
|
|
<button className="button primary" onClick={handleSave}>
|
|
<Icon name={saved ? 'check' : 'sparkles'} size={14} />
|
|
{saved ? 'Saved Successfully' : 'Save Changes'}
|
|
</button>
|
|
</div>
|
|
</CardFooter>
|
|
</Card>
|
|
</div>
|
|
)
|
|
}
|