feat:启动时检查webui版本并尝试自动更新
This commit is contained in:
@@ -84,7 +84,7 @@ function DynamicConfigSection({
|
||||
values: Record<string, unknown>
|
||||
}) {
|
||||
return (
|
||||
<Card>
|
||||
<Card className="min-w-0">
|
||||
<CardHeader className="border-b border-border/50 pb-4">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="space-y-1">
|
||||
@@ -296,15 +296,15 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
|
||||
row.length > 1 ? (
|
||||
<div
|
||||
key={row.map((field) => field.name).join('|')}
|
||||
className="grid gap-4 py-1 md:grid-cols-[repeat(var(--field-row-count),minmax(0,1fr))]"
|
||||
className="grid min-w-0 gap-4 py-1 md:grid-cols-[repeat(var(--field-row-count),minmax(0,1fr))]"
|
||||
style={{ '--field-row-count': row.length } as React.CSSProperties}
|
||||
>
|
||||
{row.map((field) => (
|
||||
<div key={field.name}>{renderField(field)}</div>
|
||||
<div key={field.name} className="min-w-0">{renderField(field)}</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div key={row[0].name} className="py-1">{renderField(row[0])}</div>
|
||||
<div key={row[0].name} className="min-w-0 py-1">{renderField(row[0])}</div>
|
||||
)
|
||||
))}
|
||||
</>
|
||||
@@ -322,7 +322,7 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="min-w-0 space-y-6">
|
||||
{visibleFields.length > 0 && (
|
||||
<div>
|
||||
{renderFieldList(visibleFields)}
|
||||
@@ -353,7 +353,7 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
|
||||
const HookComponent = hookEntry.component
|
||||
if (hookEntry.type === 'replace') {
|
||||
return (
|
||||
<div key={key}>
|
||||
<div key={key} className="min-w-0">
|
||||
<HookComponent
|
||||
fieldPath={nestedFieldPath}
|
||||
value={values[key]}
|
||||
@@ -368,7 +368,7 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={key}>
|
||||
<div key={key} className="min-w-0">
|
||||
<HookComponent
|
||||
fieldPath={nestedFieldPath}
|
||||
value={values[key]}
|
||||
@@ -416,7 +416,7 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<Card key={key} className="border-border/70 bg-muted/20 shadow-none">
|
||||
<Card key={key} className="min-w-0 border-border/70 bg-muted/20 shadow-none">
|
||||
<CardHeader className="border-b border-border/50 px-4 py-3">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="space-y-1">
|
||||
@@ -449,7 +449,7 @@ export const DynamicConfigForm: React.FC<DynamicConfigFormProps> = ({
|
||||
|
||||
if (level === 0 && sectionColumns === 2 && visibleNestedSections.length > 1) {
|
||||
return (
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<div className="grid min-w-0 gap-4 md:grid-cols-2">
|
||||
{visibleNestedSections}
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -158,7 +158,7 @@ export const DynamicField: React.FC<DynamicFieldProps> = ({
|
||||
const label = (
|
||||
<Label
|
||||
className={cn(
|
||||
"inline-flex shrink-0 items-center gap-1.5 whitespace-nowrap text-[15px] leading-6",
|
||||
"inline-flex min-w-0 items-center gap-1.5 text-[15px] leading-6",
|
||||
descriptionDisplay === 'label-hover' && fieldDescription && "cursor-help",
|
||||
schema.advanced
|
||||
? "text-sky-700 dark:text-sky-300"
|
||||
@@ -166,7 +166,7 @@ export const DynamicField: React.FC<DynamicFieldProps> = ({
|
||||
)}
|
||||
>
|
||||
{renderIcon()}
|
||||
<span>{fieldLabel}</span>
|
||||
<span className="break-words">{fieldLabel}</span>
|
||||
{schema.required && <span className="text-destructive">*</span>}
|
||||
</Label>
|
||||
)
|
||||
@@ -281,8 +281,8 @@ export const DynamicField: React.FC<DynamicFieldProps> = ({
|
||||
const renderSwitch = () => {
|
||||
const checked = Boolean(value)
|
||||
return (
|
||||
<div className="flex items-center justify-between gap-4 py-2">
|
||||
<div className="pr-4">
|
||||
<div className="flex min-w-0 items-center justify-between gap-4 py-2">
|
||||
<div className="min-w-0 pr-4">
|
||||
{renderFieldHeader()}
|
||||
</div>
|
||||
<Switch
|
||||
@@ -303,7 +303,7 @@ export const DynamicField: React.FC<DynamicFieldProps> = ({
|
||||
const step = schema.step ?? 1
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className="min-w-0 space-y-2">
|
||||
<Slider
|
||||
value={[numValue]}
|
||||
onValueChange={(values) => onChange(values[0])}
|
||||
@@ -466,7 +466,7 @@ export const DynamicField: React.FC<DynamicFieldProps> = ({
|
||||
className="flex flex-col gap-2 py-2 sm:flex-row sm:items-center"
|
||||
style={{ '--field-input-width': schema['x-input-width'] ?? '12rem' } as React.CSSProperties}
|
||||
>
|
||||
<div className="shrink-0">
|
||||
<div className="min-w-0 sm:shrink-0">
|
||||
{renderFieldHeader()}
|
||||
</div>
|
||||
<div className="min-w-20 flex-1 sm:ml-auto sm:max-w-[var(--field-input-width)]">
|
||||
@@ -477,7 +477,7 @@ export const DynamicField: React.FC<DynamicFieldProps> = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<div className="min-w-0 space-y-2">
|
||||
{renderFieldHeader()}
|
||||
|
||||
{/* Input component */}
|
||||
|
||||
@@ -87,12 +87,12 @@ export function Header({
|
||||
return (
|
||||
<header
|
||||
className={cn(
|
||||
'sticky top-0 isolate z-10 flex h-16 items-center justify-between border-b px-4 backdrop-blur-md',
|
||||
'sticky top-0 isolate z-10 flex h-16 min-w-0 items-center justify-between gap-2 border-b px-3 backdrop-blur-md sm:px-4',
|
||||
inheritsPageBackground ? 'bg-transparent' : 'bg-card/80'
|
||||
)}
|
||||
>
|
||||
{!inheritsPageBackground && <BackgroundLayer config={headerBg} layerId="header" />}
|
||||
<div className="relative z-10 flex items-center gap-4">
|
||||
<div className="relative z-10 flex min-w-0 shrink-0 items-center gap-2 sm:gap-4">
|
||||
{/* 移动端菜单按钮 */}
|
||||
<button
|
||||
onClick={onMobileMenuToggle}
|
||||
@@ -122,7 +122,7 @@ export function Header({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="relative z-10 flex items-center gap-2">
|
||||
<div className="relative z-10 flex min-w-0 flex-1 items-center justify-end gap-1 sm:gap-2">
|
||||
{/* 工作区切换:复用 Tabs 组件 + Motion 动画指示器 */}
|
||||
<LayoutGroup id="workspace-switcher">
|
||||
<Tabs value={workspaceMode} aria-label={t('workspace.switcherLabel')}>
|
||||
@@ -165,7 +165,7 @@ export function Header({
|
||||
</Tabs>
|
||||
</LayoutGroup>
|
||||
|
||||
<div className="bg-border h-6 w-px" />
|
||||
<div className="bg-border hidden h-6 w-px sm:block" />
|
||||
{/* 后端切换按钮(仅 Electron) */}
|
||||
{isElectron() && (
|
||||
<>
|
||||
@@ -211,7 +211,7 @@ export function Header({
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => window.open('https://docs.mai-mai.org', '_blank')}
|
||||
className="gap-2"
|
||||
className="hidden gap-2 sm:inline-flex"
|
||||
title={t('header.viewDocs')}
|
||||
>
|
||||
<BookOpen className="h-4 w-4" />
|
||||
@@ -221,7 +221,7 @@ export function Header({
|
||||
{/* 语言切换 */}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="sm" className="gap-2">
|
||||
<Button variant="ghost" size="sm" className="gap-2 px-2 sm:px-3">
|
||||
<Globe className="h-4 w-4" />
|
||||
<span className="hidden text-xs sm:inline">
|
||||
{LANGUAGE_NAMES[currentLang.split('-')[0] as 'zh' | 'en' | 'ja' | 'ko'] ??
|
||||
@@ -259,14 +259,14 @@ export function Header({
|
||||
</button>
|
||||
|
||||
{/* 分隔线 */}
|
||||
<div className="bg-border h-6 w-px" />
|
||||
<div className="bg-border hidden h-6 w-px sm:block" />
|
||||
|
||||
{/* 登出按钮 */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={handleLogout}
|
||||
className="gap-2"
|
||||
className="gap-2 px-2 sm:px-3"
|
||||
title={t('header.logout')}
|
||||
>
|
||||
<LogOut className="h-4 w-4" />
|
||||
|
||||
@@ -178,7 +178,7 @@ export function Layout({ children }: LayoutProps) {
|
||||
)}
|
||||
</AnimatePresence>
|
||||
{/* Main content */}
|
||||
<div className="flex flex-1 flex-col overflow-hidden">
|
||||
<div className="flex min-w-0 flex-1 flex-col overflow-hidden">
|
||||
{/* HTTP 安全警告横幅 */}
|
||||
<HttpWarningBanner />
|
||||
|
||||
@@ -211,7 +211,7 @@ export function Layout({ children }: LayoutProps) {
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
<motion.div
|
||||
key={workspaceMode}
|
||||
className="relative z-10 h-full"
|
||||
className="relative z-10 h-full min-w-0"
|
||||
initial={{ opacity: 0, x: isChatWorkspace ? 32 : -32, filter: 'blur(6px)' }}
|
||||
animate={{ opacity: 1, x: 0, filter: 'blur(0px)' }}
|
||||
exit={{ opacity: 0, x: isChatWorkspace ? -32 : 32, filter: 'blur(6px)' }}
|
||||
|
||||
Reference in New Issue
Block a user