66 lines
3.2 KiB
TypeScript
66 lines
3.2 KiB
TypeScript
'use client'
|
|
|
|
import React, { useState } from 'react'
|
|
import { ModalBase } from './ModalBase'
|
|
import { apiFetch } from '../_api'
|
|
|
|
export function CreateNamespaceModal({ tenantId, onClose, onCreated }: { tenantId: string; onClose: () => void; onCreated: () => void }) {
|
|
const [form, setForm] = useState({ name: '', slug: '', isolation_level: 'shared', classification: 'internal' })
|
|
const [saving, setSaving] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
const handleSubmit = async () => {
|
|
if (!form.name) { setError('Name ist Pflichtfeld'); return }
|
|
setSaving(true)
|
|
try {
|
|
await apiFetch(`tenants/${tenantId}/namespaces`, { method: 'POST', body: JSON.stringify(form) })
|
|
onCreated()
|
|
} catch (e) { setError(e instanceof Error ? e.message : 'Fehler') }
|
|
finally { setSaving(false) }
|
|
}
|
|
|
|
return (
|
|
<ModalBase title="Namespace erstellen" onClose={onClose}>
|
|
{error && <div className="mb-3 p-2 bg-red-50 text-red-700 rounded text-sm">{error}</div>}
|
|
<div className="space-y-3">
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Name</label>
|
|
<input type="text" value={form.name} onChange={e => setForm(f => ({ ...f, name: e.target.value }))}
|
|
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm" />
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Slug</label>
|
|
<input type="text" value={form.slug} onChange={e => setForm(f => ({ ...f, slug: e.target.value }))}
|
|
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm font-mono" />
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Isolation</label>
|
|
<select value={form.isolation_level} onChange={e => setForm(f => ({ ...f, isolation_level: e.target.value }))}
|
|
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm">
|
|
<option value="shared">Shared</option>
|
|
<option value="isolated">Isolated</option>
|
|
<option value="strict">Strict</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">Klassifikation</label>
|
|
<select value={form.classification} onChange={e => setForm(f => ({ ...f, classification: e.target.value }))}
|
|
className="w-full border border-gray-300 rounded-lg px-3 py-2 text-sm">
|
|
<option value="public">Public</option>
|
|
<option value="internal">Internal</option>
|
|
<option value="confidential">Confidential</option>
|
|
<option value="restricted">Restricted</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div className="flex justify-end gap-2 mt-5">
|
|
<button onClick={onClose} className="px-4 py-2 text-sm text-gray-600 hover:text-gray-800">Abbrechen</button>
|
|
<button onClick={handleSubmit} disabled={saving}
|
|
className="px-4 py-2 bg-purple-600 text-white rounded-lg text-sm hover:bg-purple-700 disabled:opacity-50">
|
|
{saving ? 'Speichern...' : 'Erstellen'}
|
|
</button>
|
|
</div>
|
|
</ModalBase>
|
|
)
|
|
}
|