Add panel feature updates across API, daemon, and web

This commit is contained in:
2026-03-02 21:53:54 +00:00
parent 6b463c2b1a
commit afc64b83c1
49 changed files with 7040 additions and 305 deletions
+28 -20
View File
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { Settings2, FileText, Save } from 'lucide-react';
@@ -30,6 +30,24 @@ interface ConfigDetail {
raw: string;
}
function mergeConfigEntries(
entries: ConfigEntry[],
editableKeys: string[] | null,
): ConfigEntry[] {
if (!editableKeys || editableKeys.length === 0) return entries;
const existing = new Map(entries.map((entry) => [entry.key, entry]));
const merged = [...entries];
for (const key of editableKeys) {
if (!existing.has(key)) {
merged.push({ key, value: '' });
}
}
return merged;
}
export function ConfigPage() {
const { orgId, serverId } = useParams();
const queryClient = useQueryClient();
@@ -102,13 +120,11 @@ function ConfigEditor({
});
const [entries, setEntries] = useState<ConfigEntry[]>([]);
const [initialized, setInitialized] = useState(false);
// Initialize entries from server data
if (detail && !initialized) {
setEntries(detail.entries);
setInitialized(true);
}
useEffect(() => {
if (!detail) return;
setEntries(mergeConfigEntries(detail.entries, configFile.editableKeys));
}, [detail, configFile.editableKeys]);
const saveMutation = useMutation({
mutationFn: (data: { entries: ConfigEntry[] }) =>
@@ -129,14 +145,6 @@ function ConfigEditor({
);
};
const displayEntries = configFile.editableKeys
? entries.filter((e) => configFile.editableKeys!.includes(e.key))
: entries;
const entriesToSave = configFile.editableKeys
? entries.filter((e) => configFile.editableKeys!.includes(e.key))
: entries;
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between">
@@ -147,13 +155,13 @@ function ConfigEditor({
</CardTitle>
<CardDescription>
{configFile.editableKeys
? `${configFile.editableKeys.length} editable keys`
: 'All keys editable'}
? `${configFile.editableKeys.length} allowed additions, plus existing keys`
: 'All detected keys editable'}
</CardDescription>
</div>
<Button
size="sm"
onClick={() => saveMutation.mutate({ entries: entriesToSave })}
onClick={() => saveMutation.mutate({ entries })}
disabled={saveMutation.isPending}
>
<Save className="h-4 w-4" />
@@ -161,13 +169,13 @@ function ConfigEditor({
</Button>
</CardHeader>
<CardContent>
{displayEntries.length === 0 ? (
{entries.length === 0 ? (
<p className="py-8 text-center text-sm text-muted-foreground">
{detail ? 'No entries found. The server may need to be started first to generate config files.' : 'Loading...'}
</p>
) : (
<div className="space-y-3">
{displayEntries.map((entry) => (
{entries.map((entry) => (
<div key={entry.key} className="grid gap-1.5">
<Label className="font-mono text-xs text-muted-foreground">
{entry.key}