mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-11 01:36:37 +08:00
chore: format
This commit is contained in:
@@ -66,22 +66,25 @@ export function CacheManager({ refreshTrigger }: CacheManagerProps) {
|
||||
const [lruEnabled, setLruEnabled] = useState<boolean>(true);
|
||||
|
||||
// 获取磁盘缓存状态
|
||||
const fetchCacheStatus = useCallback(async (isSilent = false) => {
|
||||
if (!isSilent) setLoadingCache(true);
|
||||
try {
|
||||
const data = await services.adminCache.getCacheStatus();
|
||||
setCacheStatus(data);
|
||||
setMaxSizeMB(data.max_size_mb.toString());
|
||||
setTtlMinutes(data.ttl_minutes.toString());
|
||||
setLruEnabled(data.lru_enabled);
|
||||
} catch (err) {
|
||||
toast.error(t('fetchCacheStatusFailed'), {
|
||||
description: err instanceof Error ? err.message : t('unknownError'),
|
||||
});
|
||||
} finally {
|
||||
setLoadingCache(false);
|
||||
}
|
||||
}, [t]);
|
||||
const fetchCacheStatus = useCallback(
|
||||
async (isSilent = false) => {
|
||||
if (!isSilent) setLoadingCache(true);
|
||||
try {
|
||||
const data = await services.adminCache.getCacheStatus();
|
||||
setCacheStatus(data);
|
||||
setMaxSizeMB(data.max_size_mb.toString());
|
||||
setTtlMinutes(data.ttl_minutes.toString());
|
||||
setLruEnabled(data.lru_enabled);
|
||||
} catch (err) {
|
||||
toast.error(t('fetchCacheStatusFailed'), {
|
||||
description: err instanceof Error ? err.message : t('unknownError'),
|
||||
});
|
||||
} finally {
|
||||
setLoadingCache(false);
|
||||
}
|
||||
},
|
||||
[t],
|
||||
);
|
||||
|
||||
// 保存配置
|
||||
const handleSaveConfig = async (e: React.FormEvent) => {
|
||||
|
||||
@@ -349,9 +349,7 @@ export function SQLConsole({ dbType, onClose }: SQLConsoleProps) {
|
||||
{!executingSQL && !sqlResult && !sqlError && (
|
||||
<div className='flex flex-col items-center justify-center h-full py-10 text-muted-foreground opacity-60'>
|
||||
<Terminal className='size-8 mb-2' />
|
||||
<span className='text-xs'>
|
||||
{t('editorReady')}
|
||||
</span>
|
||||
<span className='text-xs'>{t('editorReady')}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -71,19 +71,22 @@ export function DatabasePageClient() {
|
||||
const [refreshTrigger, setRefreshTrigger] = useState<number>(0);
|
||||
|
||||
// 1. 获取运行概览
|
||||
const fetchOverview = useCallback(async (isSilent = false) => {
|
||||
if (!isSilent) setLoadingOverview(true);
|
||||
try {
|
||||
const data = await services.dbManage.getOverview();
|
||||
setOverview(data);
|
||||
} catch (err) {
|
||||
toast.error(t('fetchOverviewFailed'), {
|
||||
description: err instanceof Error ? err.message : t('unknownError'),
|
||||
});
|
||||
} finally {
|
||||
setLoadingOverview(false);
|
||||
}
|
||||
}, [t]);
|
||||
const fetchOverview = useCallback(
|
||||
async (isSilent = false) => {
|
||||
if (!isSilent) setLoadingOverview(true);
|
||||
try {
|
||||
const data = await services.dbManage.getOverview();
|
||||
setOverview(data);
|
||||
} catch (err) {
|
||||
toast.error(t('fetchOverviewFailed'), {
|
||||
description: err instanceof Error ? err.message : t('unknownError'),
|
||||
});
|
||||
} finally {
|
||||
setLoadingOverview(false);
|
||||
}
|
||||
},
|
||||
[t],
|
||||
);
|
||||
|
||||
// 2. 获取表列表
|
||||
const fetchTables = useCallback(async () => {
|
||||
|
||||
@@ -77,9 +77,7 @@ export function DashboardTab() {
|
||||
<span className='font-semibold text-foreground'>34</span>
|
||||
</div>
|
||||
</div>
|
||||
<p className='text-[10px] text-muted-foreground'>
|
||||
{t('dbStatus')}
|
||||
</p>
|
||||
<p className='text-[10px] text-muted-foreground'>{t('dbStatus')}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
@@ -478,9 +478,7 @@ export function FileList() {
|
||||
<SheetContent className='w-full sm:max-w-md overflow-y-auto p-6'>
|
||||
<SheetHeader className='border-b pb-4 px-0'>
|
||||
<SheetTitle>{t('list.detailTitle')}</SheetTitle>
|
||||
<SheetDescription>
|
||||
{t('list.detailDesc')}
|
||||
</SheetDescription>
|
||||
<SheetDescription>{t('list.detailDesc')}</SheetDescription>
|
||||
</SheetHeader>
|
||||
|
||||
{detailTarget && (
|
||||
@@ -542,8 +540,7 @@ export function FileList() {
|
||||
</span>
|
||||
<span className='col-span-2 text-foreground/90'>
|
||||
{formatFileSize(detailTarget.file_size)} (
|
||||
{detailTarget.file_size.toLocaleString()} {t('list.bytes')}
|
||||
)
|
||||
{detailTarget.file_size.toLocaleString()} {t('list.bytes')})
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -397,8 +397,7 @@ export function AccessAnalytics() {
|
||||
{user.nickname
|
||||
? `(${user.nickname})`
|
||||
: t('noNickname')}{' '}
|
||||
|
|
||||
ID: {user.user_id}
|
||||
| ID: {user.user_id}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -174,13 +174,16 @@ export function AppLogs() {
|
||||
}, [logs, autoScroll]);
|
||||
|
||||
// ---- Data fetching ---------------------------------------------------
|
||||
const fetchLogs = useCallback(async (cursor: number = 0) => {
|
||||
try {
|
||||
return await services.adminLog.getLogs(cursor);
|
||||
} catch (err) {
|
||||
throw err instanceof Error ? err : new Error(t('fetchFailed'));
|
||||
}
|
||||
}, [t]);
|
||||
const fetchLogs = useCallback(
|
||||
async (cursor: number = 0) => {
|
||||
try {
|
||||
return await services.adminLog.getLogs(cursor);
|
||||
} catch (err) {
|
||||
throw err instanceof Error ? err : new Error(t('fetchFailed'));
|
||||
}
|
||||
},
|
||||
[t],
|
||||
);
|
||||
|
||||
const loadHistory = useCallback(
|
||||
async (cursor: number = 0) => {
|
||||
|
||||
@@ -315,7 +315,10 @@ export function EventsTab() {
|
||||
</Button>
|
||||
</div>
|
||||
{eventsQuery.isLoading ? (
|
||||
<LoadingStateWithBorder icon={Layers} description={t('loadingEvents')} />
|
||||
<LoadingStateWithBorder
|
||||
icon={Layers}
|
||||
description={t('loadingEvents')}
|
||||
/>
|
||||
) : eventsQuery.isError ? (
|
||||
<div className='p-8 border border-dashed rounded-xl bg-card'>
|
||||
<ErrorInline
|
||||
@@ -325,10 +328,7 @@ export function EventsTab() {
|
||||
/>
|
||||
</div>
|
||||
) : (eventsQuery.data ?? []).length === 0 ? (
|
||||
<EmptyStateWithBorder
|
||||
icon={Layers}
|
||||
description={t('noEvents')}
|
||||
/>
|
||||
<EmptyStateWithBorder icon={Layers} description={t('noEvents')} />
|
||||
) : (
|
||||
<div className='border border-dashed shadow-none rounded-lg overflow-hidden'>
|
||||
<Table className='w-full caption-bottom text-sm min-w-full'>
|
||||
@@ -492,9 +492,7 @@ export function EventsTab() {
|
||||
<DialogContent className='sm:max-w-[550px] max-h-[85vh] overflow-y-auto'>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('addEventDialogTitle')}</DialogTitle>
|
||||
<DialogDescription>
|
||||
{t('addEventDialogDesc')}
|
||||
</DialogDescription>
|
||||
<DialogDescription>{t('addEventDialogDesc')}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className='space-y-4 py-4'>
|
||||
@@ -534,7 +532,9 @@ export function EventsTab() {
|
||||
|
||||
{newEventType === 'builtin' ? (
|
||||
<div className='space-y-1.5'>
|
||||
<Label className='text-xs font-semibold'>{t('systemEvent')}</Label>
|
||||
<Label className='text-xs font-semibold'>
|
||||
{t('systemEvent')}
|
||||
</Label>
|
||||
{builtInEventsQuery.isLoading ? (
|
||||
<div className='flex items-center gap-2 text-xs text-muted-foreground'>
|
||||
<Loader2 className='size-3.5 animate-spin' />
|
||||
@@ -724,7 +724,9 @@ export function EventsTab() {
|
||||
|
||||
<div className='flex items-center justify-between p-3 border rounded-lg bg-muted/10'>
|
||||
<div className='space-y-0.5'>
|
||||
<Label className='text-xs font-semibold'>{t('enableStatus')}</Label>
|
||||
<Label className='text-xs font-semibold'>
|
||||
{t('enableStatus')}
|
||||
</Label>
|
||||
<div className='text-[10px] text-muted-foreground'>
|
||||
{t('enableStatusDesc')}
|
||||
</div>
|
||||
@@ -770,9 +772,7 @@ export function EventsTab() {
|
||||
<DialogContent className='sm:max-w-[550px] max-h-[85vh] overflow-y-auto'>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('editEventDialogTitle')}</DialogTitle>
|
||||
<DialogDescription>
|
||||
{t('editEventDialogDesc')}
|
||||
</DialogDescription>
|
||||
<DialogDescription>{t('editEventDialogDesc')}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
{selectedEvent && (
|
||||
|
||||
@@ -271,9 +271,7 @@ export function HistoriesTab() {
|
||||
|
||||
{historiesQuery.data && historiesQuery.data.total > 0 && (
|
||||
<div className='flex justify-between items-center text-xs text-muted-foreground'>
|
||||
<span>
|
||||
{t('totalRecords', { total: historiesQuery.data.total })}
|
||||
</span>
|
||||
<span>{t('totalRecords', { total: historiesQuery.data.total })}</span>
|
||||
<div className='flex items-center gap-1.5'>
|
||||
<Button
|
||||
variant='outline'
|
||||
|
||||
@@ -335,9 +335,7 @@ export function SettingsTab() {
|
||||
className='size-8 mb-2 opacity-30 animate-spin'
|
||||
style={{ animationDuration: '3s' }}
|
||||
/>
|
||||
<span className='text-xs font-medium'>
|
||||
{t('noCustomChannels')}
|
||||
</span>
|
||||
<span className='text-xs font-medium'>{t('noCustomChannels')}</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className='border border-dashed shadow-none rounded-lg overflow-hidden'>
|
||||
@@ -464,7 +462,9 @@ export function SettingsTab() {
|
||||
|
||||
<div className='space-y-4 py-4'>
|
||||
<div className='space-y-1.5'>
|
||||
<Label className='text-xs font-semibold'>{t('channelName')}</Label>
|
||||
<Label className='text-xs font-semibold'>
|
||||
{t('channelName')}
|
||||
</Label>
|
||||
<Input
|
||||
type='text'
|
||||
placeholder={t('channelNamePlaceholder')}
|
||||
@@ -479,7 +479,9 @@ export function SettingsTab() {
|
||||
</div>
|
||||
|
||||
<div className='space-y-1.5'>
|
||||
<Label className='text-xs font-semibold'>{t('channelRemark')}</Label>
|
||||
<Label className='text-xs font-semibold'>
|
||||
{t('channelRemark')}
|
||||
</Label>
|
||||
<Input
|
||||
type='text'
|
||||
placeholder={t('channelRemarkPlaceholder')}
|
||||
@@ -490,7 +492,9 @@ export function SettingsTab() {
|
||||
</div>
|
||||
|
||||
<div className='space-y-1.5'>
|
||||
<Label className='text-xs font-semibold'>{t('channelType')}</Label>
|
||||
<Label className='text-xs font-semibold'>
|
||||
{t('channelType')}
|
||||
</Label>
|
||||
<Select
|
||||
value={channelType}
|
||||
onValueChange={handleChannelTypeChange}
|
||||
|
||||
@@ -201,9 +201,7 @@ export function OpenFlareOpsSettings() {
|
||||
};
|
||||
|
||||
if (optionsQuery.isLoading) {
|
||||
return (
|
||||
<LoadingStateWithBorder icon={Server} description={t('loading')} />
|
||||
);
|
||||
return <LoadingStateWithBorder icon={Server} description={t('loading')} />;
|
||||
}
|
||||
|
||||
if (optionsQuery.isError) {
|
||||
@@ -406,9 +404,7 @@ export function OpenFlareOpsSettings() {
|
||||
<Card className='border-dashed shadow-none'>
|
||||
<CardHeader className='flex flex-row items-center justify-between gap-4'>
|
||||
<div>
|
||||
<CardTitle className='text-base'>
|
||||
{t('discovery.title')}
|
||||
</CardTitle>
|
||||
<CardTitle className='text-base'>{t('discovery.title')}</CardTitle>
|
||||
<CardDescription>{t('discovery.description')}</CardDescription>
|
||||
</div>
|
||||
<div className='flex flex-wrap gap-2'>
|
||||
|
||||
@@ -60,38 +60,41 @@ export function SystemStatusManager() {
|
||||
);
|
||||
|
||||
// 获取状态数据
|
||||
const fetchStatus = useCallback(async (isSilent = false) => {
|
||||
if (!isSilent) setWavelet(true);
|
||||
try {
|
||||
const data = await services.adminStatus.getSystemStatus();
|
||||
const fetchStatus = useCallback(
|
||||
async (isSilent = false) => {
|
||||
if (!isSilent) setWavelet(true);
|
||||
try {
|
||||
const data = await services.adminStatus.getSystemStatus();
|
||||
|
||||
// 检测变化的字段用于微动画效果
|
||||
if (prevStatusRef.current) {
|
||||
const changes: Record<string, boolean> = {};
|
||||
Object.keys(data).forEach((key) => {
|
||||
const k = key as keyof SystemStatus;
|
||||
if (prevStatusRef.current && prevStatusRef.current[k] !== data[k]) {
|
||||
changes[k] = true;
|
||||
}
|
||||
// 检测变化的字段用于微动画效果
|
||||
if (prevStatusRef.current) {
|
||||
const changes: Record<string, boolean> = {};
|
||||
Object.keys(data).forEach((key) => {
|
||||
const k = key as keyof SystemStatus;
|
||||
if (prevStatusRef.current && prevStatusRef.current[k] !== data[k]) {
|
||||
changes[k] = true;
|
||||
}
|
||||
});
|
||||
setChangedFields(changes);
|
||||
// 1秒后清除变化状态
|
||||
setTimeout(() => {
|
||||
setChangedFields({});
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
setStatus(data);
|
||||
prevStatusRef.current = data;
|
||||
} catch (err) {
|
||||
toast.error(t('loadFailed'), {
|
||||
description: err instanceof Error ? err.message : t('unknownError'),
|
||||
});
|
||||
setChangedFields(changes);
|
||||
// 1秒后清除变化状态
|
||||
setTimeout(() => {
|
||||
setChangedFields({});
|
||||
}, 1000);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setWavelet(false);
|
||||
}
|
||||
|
||||
setStatus(data);
|
||||
prevStatusRef.current = data;
|
||||
} catch (err) {
|
||||
toast.error(t('loadFailed'), {
|
||||
description: err instanceof Error ? err.message : t('unknownError'),
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setWavelet(false);
|
||||
}
|
||||
}, [t]);
|
||||
},
|
||||
[t],
|
||||
);
|
||||
|
||||
// 轮询逻辑
|
||||
useEffect(() => {
|
||||
|
||||
@@ -256,7 +256,9 @@ export function TaskExecutionsManager() {
|
||||
<TableHead className='w-[110px]'>{t('colTrigger')}</TableHead>
|
||||
<TableHead className='w-[120px]'>{t('colRetry')}</TableHead>
|
||||
<TableHead className='w-[120px]'>{t('colDuration')}</TableHead>
|
||||
<TableHead className='min-w-[220px]'>{t('colResult')}</TableHead>
|
||||
<TableHead className='min-w-[220px]'>
|
||||
{t('colResult')}
|
||||
</TableHead>
|
||||
<TableHead className='w-[170px]'>{t('colCreatedAt')}</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
@@ -376,9 +378,8 @@ export function TaskExecutionsManager() {
|
||||
{t('detailTrigger')}
|
||||
</div>
|
||||
<div className='mt-2 text-sm font-medium'>
|
||||
{t(
|
||||
TRIGGER_LABELS_KEYS[selectedExecution.triggered_by],
|
||||
) || selectedExecution.triggered_by}
|
||||
{t(TRIGGER_LABELS_KEYS[selectedExecution.triggered_by]) ||
|
||||
selectedExecution.triggered_by}
|
||||
</div>
|
||||
</div>
|
||||
<div className='rounded-lg border p-3'>
|
||||
|
||||
@@ -165,7 +165,11 @@ function DatePickerWithTime({
|
||||
)}
|
||||
>
|
||||
<CalendarIcon className='mr-1 size-3' />
|
||||
{date ? format(date, 'yyyy-MM-dd') : <span>{t('selectDate')}</span>}
|
||||
{date ? (
|
||||
format(date, 'yyyy-MM-dd')
|
||||
) : (
|
||||
<span>{t('selectDate')}</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className='w-auto p-0' align='start'>
|
||||
@@ -213,7 +217,9 @@ export function TaskManager() {
|
||||
const data = await services.adminTask.getTaskTypes();
|
||||
setTaskTypes(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err : new Error(t('loadTaskTypesFailed')));
|
||||
setError(
|
||||
err instanceof Error ? err : new Error(t('loadTaskTypesFailed')),
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,9 @@ export function TaskSchedulesManager() {
|
||||
setSchedules(schedulesData || []);
|
||||
setTaskTypes(taskTypesData || []);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err : new Error(t('loadSchedulesFailed')));
|
||||
setError(
|
||||
err instanceof Error ? err : new Error(t('loadSchedulesFailed')),
|
||||
);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -304,10 +306,7 @@ export function TaskSchedulesManager() {
|
||||
description={t('loadingSchedules')}
|
||||
/>
|
||||
) : schedules.length === 0 ? (
|
||||
<EmptyStateWithBorder
|
||||
icon={Clock}
|
||||
description={t('noSchedules')}
|
||||
/>
|
||||
<EmptyStateWithBorder icon={Clock} description={t('noSchedules')} />
|
||||
) : (
|
||||
<div className='rounded-lg border bg-card'>
|
||||
<Table className='min-w-[800px]'>
|
||||
@@ -395,9 +394,7 @@ export function TaskSchedulesManager() {
|
||||
<DialogTitle>
|
||||
{editingSchedule ? t('editSchedule') : t('addSchedule')}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
{t('scheduleDialogDesc')}
|
||||
</DialogDescription>
|
||||
<DialogDescription>{t('scheduleDialogDesc')}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className='grid gap-4 py-4'>
|
||||
@@ -574,9 +571,7 @@ export function TaskSchedulesManager() {
|
||||
<DialogContent className='sm:max-w-[400px]'>
|
||||
<DialogHeader>
|
||||
<DialogTitle>{t('deleteScheduleTitle')}</DialogTitle>
|
||||
<DialogDescription>
|
||||
{t('deleteScheduleDesc')}
|
||||
</DialogDescription>
|
||||
<DialogDescription>{t('deleteScheduleDesc')}</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter className='gap-2 sm:gap-0'>
|
||||
<Button
|
||||
|
||||
@@ -218,7 +218,9 @@ export function EditUserModal({
|
||||
|
||||
<div className='flex items-center justify-between rounded-lg border border-dashed p-3 bg-muted/10'>
|
||||
<div>
|
||||
<div className='font-medium text-sm'>{t('adminPermission')}</div>
|
||||
<div className='font-medium text-sm'>
|
||||
{t('adminPermission')}
|
||||
</div>
|
||||
<div className='text-xs text-muted-foreground'>
|
||||
{isSelf
|
||||
? t('cannotRevokeSelfAdmin')
|
||||
@@ -288,7 +290,9 @@ export function EditUserModal({
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel disabled={saving}>{t('cancel')}</AlertDialogCancel>
|
||||
<AlertDialogCancel disabled={saving}>
|
||||
{t('cancel')}
|
||||
</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -172,7 +172,9 @@ export function UserDetailSheet({
|
||||
</h4>
|
||||
<div className='rounded-lg border divide-y bg-background/50'>
|
||||
<div className='flex items-center justify-between p-3.5 text-sm'>
|
||||
<span className='text-[10px]'>{t('accountStatus')}</span>
|
||||
<span className='text-[10px]'>
|
||||
{t('accountStatus')}
|
||||
</span>
|
||||
<Badge
|
||||
variant={
|
||||
selectedUser.is_active ? 'secondary' : 'outline'
|
||||
|
||||
Reference in New Issue
Block a user