/**
* Settings — the YAML that the daemon was started from.
*
* The editor is deliberately plain: a line-numbered textarea rather than a
* YAML widget, because the operator's file already has comments and ordering
* that a form would silently destroy. Validation is server-side, so what is
* reported here is exactly what the daemon would do with the file.
*/
import { useMemo, useRef, useState } from 'react'
import type { UIEvent } from 'react'
import {
Ban,
CheckCircle2,
Database,
FileCode2,
Info,
RefreshCw,
Save,
ShieldAlert,
TriangleAlert,
} from 'lucide-react'
import {
flushCache,
getSettings,
putSettings,
refreshBlocklists,
reloadSettings,
validateSettings,
} from '../lib/api'
import type { ConfigIssue } from '../lib/types'
import { useApi, useAsyncAction } from '../hooks/useApi'
import { formatNumber } from '../lib/format'
import {
Badge,
Button,
Card,
CardBody,
ConfirmDialog,
CopyButton,
Spinner,
Textarea,
useToast,
} from '../components/ui'
import { LoadingBlock, PageError, PageHeader } from '../components/layout'
interface Report {
errors: ConfigIssue[]
warnings: ConfigIssue[]
}
/** A validation list is only usable if every entry has a message. */
function issues(list: ConfigIssue[] | undefined): ConfigIssue[] {
if (!Array.isArray(list)) return []
return list.filter((item) => item != null && typeof item.message === 'string' && item.message !== '')
}
function IssueList({ issues: list, tone }: { issues: ConfigIssue[]; tone: 'danger' | 'warn' }) {
return (
}
>
Show the effective configuration
{effective === '' ? '' : `${effective.split('\n').length} lines`}
{effective || 'The server sent no effective configuration.'}
}
>
Show defaults
read-only
{defaults || 'The server sent no defaults.'}
Both act on the running daemon; neither writes the config file.
setConfirmReload(false)}
onConfirm={() => void onReload()}
title="Reload the configuration from disk?"
message={
<>
The daemon re-reads {data?.path || 'its config'}{' '}
and applies it to the running process. In-flight queries finish on the old
configuration; the next query uses the new one.
>
}
confirmLabel="Reload"
pending={reload.pending}
/>
)
}