feat(admin): adapt new config system (#11360)

feat(server): add test mail api

feat(admin): adapt new config system
This commit is contained in:
forehalo
2025-04-01 15:00:10 +00:00
parent 8427293d36
commit dad858014f
29 changed files with 718 additions and 400 deletions
@@ -1,6 +1,5 @@
import { Button } from '@affine/admin/components/ui/button';
import { ScrollArea } from '@affine/admin/components/ui/scroll-area';
import { Separator } from '@affine/admin/components/ui/separator';
import { get } from 'lodash-es';
import { CheckIcon } from 'lucide-react';
import { useCallback, useState } from 'react';
@@ -8,17 +7,16 @@ import { useCallback, useState } from 'react';
import { Header } from '../header';
import { useNav } from '../nav/context';
import {
ALL_CONFIG,
ALL_CONFIGURABLE_MODULES,
type ConfigDescriptor,
ALL_CONFIG_DESCRIPTORS,
ALL_SETTING_GROUPS,
type AppConfig,
} from './config';
import { ConfigInput } from './config-input';
import { type ConfigInputProps, ConfigRow } from './config-input-row';
import { ConfirmChanges } from './confirm-changes';
import { RuntimeSettingRow } from './runtime-setting-row';
import { useAppConfig } from './use-app-config';
export function SettingsPage() {
const { appConfig, update, save, updates } = useAppConfig();
const { appConfig, update, save, patchedAppConfig, updates } = useAppConfig();
const [open, setOpen] = useState(false);
const onOpen = useCallback(() => setOpen(true), [setOpen]);
@@ -28,22 +26,12 @@ export function SettingsPage() {
if (disableSave) {
return;
}
save(
Object.entries(updates).map(([key, { to }]) => {
const splitAt = key.indexOf('.');
const [module, field] = [key.slice(0, splitAt), key.slice(splitAt + 1)];
return {
module,
key: field,
value: to,
};
})
);
save();
setOpen(false);
}, [save, disableSave, updates]);
}, [save, disableSave]);
return (
<div className=" h-screen flex-1 flex-col flex">
<div className="h-screen flex-1 flex-col flex">
<Header
title="Settings"
endFix={
@@ -59,7 +47,11 @@ export function SettingsPage() {
</Button>
}
/>
<AdminPanel onUpdate={update} appConfig={appConfig} />
<AdminPanel
onUpdate={update}
appConfig={appConfig}
patchedAppConfig={patchedAppConfig}
/>
<ConfirmChanges
updates={updates}
open={open}
@@ -72,58 +64,66 @@ export function SettingsPage() {
export const AdminPanel = ({
appConfig,
patchedAppConfig,
onUpdate,
}: {
appConfig: Record<string, any>;
onUpdate: (module: string, field: string, value: any) => void;
appConfig: AppConfig;
patchedAppConfig: AppConfig;
onUpdate: (path: string, value: any) => void;
}) => {
const { currentModule } = useNav();
const group = ALL_SETTING_GROUPS.find(
group => group.module === currentModule
);
if (!group) {
return null;
}
const { name, module, fields, operations } = group;
return (
<ScrollArea>
<div className="flex flex-col h-full gap-3 py-5 px-6 w-full max-w-[800px] mx-auto">
{ALL_CONFIGURABLE_MODULES.filter(
module => module === currentModule
).map(module => {
const fields = Object.keys(ALL_CONFIG[module]);
return (
<div
className="flex flex-col gap-5"
id={`config-module-${module}`}
key={module}
>
<div className="text-xl font-semibold">{module}</div>
{fields.map((field, index) => {
// @ts-expect-error allow
const { desc, type } = ALL_CONFIG[module][
field
] as ConfigDescriptor;
<ScrollArea className="h-full">
<div className="flex flex-col h-full gap-5 py-5 px-6 w-full max-w-[800px] mx-auto">
<div className="text-2xl font-semibold">{name}</div>
<div className="flex flex-col gap-10" id={`config-module-${module}`}>
{fields.map(field => {
let desc: string;
let props: ConfigInputProps;
if (typeof field === 'string') {
const descriptor = ALL_CONFIG_DESCRIPTORS[module][field];
desc = descriptor.desc;
props = {
type: descriptor.type,
defaultValue: get(appConfig[module], field),
field: `${module}/${field}`,
desc,
onChange: onUpdate,
options: [],
};
} else {
const descriptor = ALL_CONFIG_DESCRIPTORS[module][field.key];
return (
<div key={field} className="flex flex-col gap-10">
{index !== 0 && <Separator />}
<RuntimeSettingRow
key={field}
id={field}
description={desc}
orientation={
type === 'Boolean' ? 'horizontal' : 'vertical'
}
>
<ConfigInput
module={module}
field={field}
type={type}
defaultValue={get(appConfig[module], field)}
onChange={onUpdate}
/>
</RuntimeSettingRow>
</div>
);
})}
</div>
);
})}
props = {
desc: field.desc ?? descriptor.desc,
type: field.type ?? descriptor.type,
// @ts-expect-error for enum type
options: field.options,
defaultValue: get(
appConfig[module],
field.key + (field.sub ? '.' + field.sub : '')
),
field: `${module}/${field.key}${field.sub ? `/${field.sub}` : ''}`,
onChange: onUpdate,
};
}
return <ConfigRow key={props.field} {...props} />;
})}
{operations?.map(Operation => (
<Operation key={Operation.name} appConfig={patchedAppConfig} />
))}
</div>
</div>
</ScrollArea>
);