mirror of
https://github.com/jeffusion/gitea-ai-assistant.git
synced 2026-03-27 10:05:50 +00:00
feat(frontend): update config UI for DB-first config architecture
- ConfigSource type: 'default' | 'db' (removed 'env') - Badge: 'db' shows '已配置', 'default' shows '默认值' - Removed readonly field lock icon and env-var-only warning message - Updated 'override' → 'db' references in ConfigGroupCard and ConfigManager - Removed readonly/readonlyWarning from ConfigFieldDto interface
This commit is contained in:
@@ -6,7 +6,6 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Lock } from 'lucide-react';
|
||||
|
||||
interface ConfigFieldInputProps {
|
||||
field: ConfigFieldDto;
|
||||
@@ -15,18 +14,15 @@ interface ConfigFieldInputProps {
|
||||
}
|
||||
|
||||
export function ConfigFieldInput({ field, value, onChange }: ConfigFieldInputProps) {
|
||||
const isReadonly = !!field.readonly;
|
||||
|
||||
const renderInput = () => {
|
||||
const baseInputClasses = "bg-zinc-900/50 border-white/10 focus-visible:ring-primary focus-visible:border-primary transition-all duration-200" + (isReadonly ? " opacity-50 cursor-not-allowed" : "");
|
||||
const baseInputClasses = "bg-zinc-900/50 border-white/10 focus-visible:ring-primary focus-visible:border-primary transition-all duration-200";
|
||||
switch (field.type) {
|
||||
case 'boolean':
|
||||
return (
|
||||
<Switch
|
||||
checked={Boolean(value)}
|
||||
onCheckedChange={onChange}
|
||||
disabled={isReadonly}
|
||||
className={`data-[state=checked]:bg-primary ${isReadonly ? 'opacity-50 cursor-not-allowed' : ''}`}
|
||||
className="data-[state=checked]:bg-primary"
|
||||
/>
|
||||
);
|
||||
case 'enum':
|
||||
@@ -34,7 +30,6 @@ export function ConfigFieldInput({ field, value, onChange }: ConfigFieldInputPro
|
||||
<Select
|
||||
value={value !== undefined && value !== null ? String(value) : ''}
|
||||
onValueChange={onChange}
|
||||
disabled={isReadonly}
|
||||
>
|
||||
<SelectTrigger className={`w-full ${baseInputClasses}`}>
|
||||
<SelectValue placeholder="请选择..." />
|
||||
@@ -55,7 +50,6 @@ export function ConfigFieldInput({ field, value, onChange }: ConfigFieldInputPro
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={field.sensitive && field.hasValue ? '••••••••' : ''}
|
||||
className={`min-h-[100px] ${baseInputClasses}`}
|
||||
disabled={isReadonly}
|
||||
/>
|
||||
);
|
||||
case 'number':
|
||||
@@ -67,7 +61,6 @@ export function ConfigFieldInput({ field, value, onChange }: ConfigFieldInputPro
|
||||
placeholder={field.sensitive && field.hasValue ? '••••••••' : ''}
|
||||
min={field.min}
|
||||
max={field.max}
|
||||
disabled={isReadonly}
|
||||
className={baseInputClasses}
|
||||
/>
|
||||
);
|
||||
@@ -80,7 +73,6 @@ export function ConfigFieldInput({ field, value, onChange }: ConfigFieldInputPro
|
||||
value={value !== undefined && value !== null ? String(value) : ''}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
placeholder={field.sensitive && field.hasValue ? '••••••••' : ''}
|
||||
disabled={isReadonly}
|
||||
className={baseInputClasses}
|
||||
/>
|
||||
);
|
||||
@@ -89,10 +81,8 @@ export function ConfigFieldInput({ field, value, onChange }: ConfigFieldInputPro
|
||||
|
||||
const getSourceBadge = () => {
|
||||
switch (field.source) {
|
||||
case 'override':
|
||||
return <Badge className="ml-2 bg-primary/20 text-primary border-primary/30 tech-glow hover:bg-primary/30 transition-colors">覆盖值</Badge>;
|
||||
case 'env':
|
||||
return <Badge variant="secondary" className="ml-2 bg-amber-500/20 text-amber-500 border-amber-500/30 hover:bg-amber-500/30">环境变量</Badge>;
|
||||
case 'db':
|
||||
return <Badge className="ml-2 bg-primary/20 text-primary border-primary/30 tech-glow hover:bg-primary/30 transition-colors">已配置</Badge>;
|
||||
case 'default':
|
||||
default:
|
||||
return <Badge variant="outline" className="ml-2 border-zinc-600 text-zinc-400">默认值</Badge>;
|
||||
@@ -112,27 +102,13 @@ export function ConfigFieldInput({ field, value, onChange }: ConfigFieldInputPro
|
||||
</div>
|
||||
<div className="pt-1">
|
||||
<span className="font-mono text-xs px-2 py-0.5 rounded-md bg-primary/10 text-primary border border-primary/20 inline-flex items-center">
|
||||
$ {field.envKey}
|
||||
{field.envKey}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 w-full max-w-xl flex flex-col gap-2">
|
||||
{renderInput()}
|
||||
|
||||
{isReadonly && (
|
||||
<div className="text-xs text-zinc-500 flex items-center gap-1.5 pt-1">
|
||||
<Lock className="w-3.5 h-3.5" />
|
||||
只读配置,请通过环境变量文件修改
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isReadonly && field.readonlyWarning && (
|
||||
<div className="text-xs text-amber-500 flex items-center gap-1.5 pt-1">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-amber-500 animate-pulse" />
|
||||
{field.readonlyWarning}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -33,12 +33,12 @@ export function ConfigGroupCard({
|
||||
onReset,
|
||||
isResetting,
|
||||
}: ConfigGroupCardProps) {
|
||||
const hasOverride = group.fields.some((f) => f.source === 'override');
|
||||
const hasOverride = group.fields.some((f) => f.source === 'db');
|
||||
|
||||
const handleReset = () => {
|
||||
// Only reset fields that actually have overrides
|
||||
// Only reset fields that have been stored in DB
|
||||
const keysToReset = group.fields
|
||||
.filter((f) => f.source === 'override')
|
||||
.filter((f) => f.source === 'db')
|
||||
.map((f) => f.envKey);
|
||||
|
||||
if (keysToReset.length > 0) {
|
||||
|
||||
@@ -97,7 +97,7 @@ export function ConfigManager() {
|
||||
if (!data) return;
|
||||
const allOverrideKeys = data.groups
|
||||
.flatMap((g) => g.fields)
|
||||
.filter((f) => f.source === 'override')
|
||||
.filter((f) => f.source === 'db')
|
||||
.map((f) => f.envKey);
|
||||
if (allOverrideKeys.length === 0) return;
|
||||
if (confirm('确定要重置所有配置到默认值吗?这将立即生效。')) {
|
||||
@@ -106,7 +106,7 @@ export function ConfigManager() {
|
||||
};
|
||||
|
||||
const hasOverrides = data?.groups.some((g) =>
|
||||
g.fields.some((f) => f.source === 'override')
|
||||
g.fields.some((f) => f.source === 'db')
|
||||
) ?? false;
|
||||
|
||||
if (isLoading) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import api from '@/lib/api';
|
||||
|
||||
export type ConfigSource = 'default' | 'env' | 'override';
|
||||
export type ConfigSource = 'default' | 'db';
|
||||
export type ConfigFieldType = 'string' | 'number' | 'boolean' | 'url' | 'text' | 'enum';
|
||||
|
||||
export interface ConfigFieldDto {
|
||||
@@ -9,8 +9,6 @@ export interface ConfigFieldDto {
|
||||
description: string;
|
||||
type: ConfigFieldType;
|
||||
sensitive: boolean;
|
||||
readonly?: boolean;
|
||||
readonlyWarning?: string;
|
||||
enumValues?: string[];
|
||||
min?: number;
|
||||
max?: number;
|
||||
|
||||
Reference in New Issue
Block a user