Release v0.1.5
This commit is contained in:
85
webui/src/features/admin/TenantSettingsPanel.tsx
Normal file
85
webui/src/features/admin/TenantSettingsPanel.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import type { ApiSettings } from "@govoplan/core-webui";
|
||||
import { Button } from "@govoplan/core-webui";
|
||||
import { Card } from "@govoplan/core-webui";
|
||||
import { FormField } from "@govoplan/core-webui";
|
||||
import { fetchTenantSettings, updateTenantSettings, type TenantSettingsItem } from "../../api/admin";
|
||||
import { AdminPageLayout, adminErrorMessage } from "@govoplan/core-webui";
|
||||
|
||||
const fallback: TenantSettingsItem = {
|
||||
id: "",
|
||||
slug: "",
|
||||
name: "",
|
||||
default_locale: "en",
|
||||
settings: {}
|
||||
};
|
||||
|
||||
export default function TenantSettingsPanel({
|
||||
settings,
|
||||
canWrite,
|
||||
onAuthRefresh
|
||||
}: {
|
||||
settings: ApiSettings;
|
||||
canWrite: boolean;
|
||||
onAuthRefresh: () => Promise<void>;
|
||||
}) {
|
||||
const [draft, setDraft] = useState<TenantSettingsItem>(fallback);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [success, setSuccess] = useState("");
|
||||
|
||||
async function load() {
|
||||
setLoading(true);
|
||||
setError("");
|
||||
setSuccess("");
|
||||
try {
|
||||
setDraft(await fetchTenantSettings(settings));
|
||||
} catch (err) {
|
||||
setError(adminErrorMessage(err));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => { void load(); }, [settings.accessToken, settings.apiBaseUrl]);
|
||||
|
||||
async function save() {
|
||||
setBusy(true);
|
||||
setError("");
|
||||
setSuccess("");
|
||||
try {
|
||||
const saved = await updateTenantSettings(settings, { default_locale: draft.default_locale });
|
||||
setDraft(saved);
|
||||
setSuccess("Tenant general settings saved.");
|
||||
await onAuthRefresh();
|
||||
} catch (err) {
|
||||
setError(adminErrorMessage(err));
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<AdminPageLayout
|
||||
title="Tenant general settings"
|
||||
description="Settings for the active tenant context."
|
||||
loading={loading}
|
||||
error={error}
|
||||
success={success}
|
||||
actions={<><Button onClick={() => void load()} disabled={loading}>Reload</Button><Button variant="primary" onClick={() => void save()} disabled={!canWrite || busy || !draft.default_locale.trim()}>{busy ? "Saving..." : "Save general settings"}</Button></>}
|
||||
>
|
||||
<div className="admin-settings-form">
|
||||
<Card title="Locale">
|
||||
<FormField label="Tenant locale" help="Used as this tenant's locale default for tenant-aware views and future formatting defaults.">
|
||||
<input value={draft.default_locale} disabled={!canWrite || busy} onChange={(event) => setDraft({ ...draft, default_locale: event.target.value })} />
|
||||
</FormField>
|
||||
<dl className="detail-list">
|
||||
<div><dt>Tenant</dt><dd>{draft.name || "-"}</dd></div>
|
||||
<div><dt>Slug</dt><dd>{draft.slug || "-"}</dd></div>
|
||||
</dl>
|
||||
</Card>
|
||||
</div>
|
||||
</AdminPageLayout>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user