Threema Gateway
All checks were successful
Build and Push / build (push) Successful in 1m30s

This commit is contained in:
2026-05-16 22:00:27 +02:00
parent 726151d90b
commit 85c4302f7a
8 changed files with 914 additions and 8 deletions

View File

@@ -30,6 +30,26 @@ export function PackageCard({
const [error, setError] = useState<string | null>(null);
async function handleEnable() {
if (pkg.customProvisioning) {
// Platform-side provisioning, then add to packages list.
setSaving(true);
setError(null);
try {
const provRes = await fetch(`/api/tenants/${tenantName}/${pkg.id}`, {
method: "POST",
});
if (!provRes.ok) {
const err = await provRes.json().catch(() => ({}));
throw new Error(err.error || `Provisioning failed (HTTP ${provRes.status})`);
}
await togglePackage(true);
} catch (e: any) {
setError(e.message);
} finally {
setSaving(false);
}
return;
}
if (pkg.requiresSecrets) {
setShowModal(true);
setSecrets({});
@@ -40,6 +60,34 @@ export function PackageCard({
await togglePackage(true);
}
async function handleDisable() {
setSaving(true);
setError(null);
try {
if (pkg.customProvisioning) {
// Revoke platform-side credentials FIRST so the relay drops
// routes before the operator removes the channel from the
// OpenClaw config. Partial-success (token revoked, OpenBao
// delete failed) returns 503 with partial=true and we surface
// the error rather than continuing — the secret may still be
// valid in OpenBao and rolling back the relay revoke isn't
// possible (it cascaded to routes).
const deprovRes = await fetch(`/api/tenants/${tenantName}/${pkg.id}`, {
method: "DELETE",
});
if (!deprovRes.ok) {
const err = await deprovRes.json().catch(() => ({}));
throw new Error(err.error || `Deprovisioning failed (HTTP ${deprovRes.status})`);
}
}
await togglePackage(false);
} catch (e: any) {
setError(e.message);
} finally {
setSaving(false);
}
}
async function togglePackage(enable: boolean) {
setSaving(true);
try {
@@ -124,7 +172,7 @@ export function PackageCard({
)}
{canEdit ? (
<button
onClick={enabled ? () => togglePackage(false) : handleEnable}
onClick={enabled ? handleDisable : handleEnable}
disabled={saving}
className={`ml-auto rounded-lg px-3 py-1.5 text-xs font-medium transition-all cursor-pointer ${
enabled