ui: ESLint config updates (#27700)

* chore: Spacing between sibling elements in html markup

* chore: Formatting and linting rules
This commit is contained in:
Aleksander Grygier
2026-08-25 14:34:34 +02:00
committed by GitHub
parent 3737e41370
commit f1357e4998
267 changed files with 1706 additions and 1344 deletions
@@ -123,21 +123,21 @@
}
</script>
<div class="mx-auto flex h-full w-full flex-col md:pl-8" in:fade={{ duration: 150 }}>
<div in:fade={{ duration: 150 }} class="mx-auto flex h-full w-full flex-col md:pl-8">
<div class="flex flex-1 flex-col gap-4 md:flex-row">
<SettingsChatDesktopSidebar
sections={SETTINGS_CHAT_SECTIONS}
isActive={(section: SettingsSection) => section.slug === activeSlug}
getHref={getSectionHref ??
((section: SettingsSection) => RouterService.settings(section.slug))}
isActive={(section: SettingsSection) => section.slug === activeSlug}
sections={SETTINGS_CHAT_SECTIONS}
/>
<SettingsChatMobileHeader
sections={SETTINGS_CHAT_SECTIONS}
isActive={(section: SettingsSection) => section.slug === activeSlug}
bind:this={mobileHeader}
getHref={getSectionHref ??
((section: SettingsSection) => RouterService.settings(section.slug))}
bind:this={mobileHeader}
isActive={(section: SettingsSection) => section.slug === activeSlug}
sections={SETTINGS_CHAT_SECTIONS}
/>
<div class="mx-auto max-w-3xl flex-1">
@@ -145,6 +145,7 @@
<div class="grid">
<div class="mb-6 flex items-center gap-2 border-b border-border/30 pb-6 md:flex">
<currentSection.icon class="h-5 w-5" />
<h3 class="text-lg font-semibold">{currentSection.title}</h3>
</div>
@@ -163,7 +164,7 @@
{#if currentSection.slug === SETTINGS_SECTION_SLUGS.GENERAL}
<div class="flex justify-end">
<Button variant="outline" onclick={() => window.location.reload()}>
<Button onclick={() => window.location.reload()} variant="outline">
<RefreshCw class="h-3 w-3" />
Reload app
</Button>
@@ -66,13 +66,14 @@
})()}
<div class="flex items-center gap-2">
<Label for={field.key} class="flex items-center gap-1.5 text-sm font-medium">
<Label class="flex items-center gap-1.5 text-sm font-medium" for={field.key}>
{field.label}
{#if field.isExperimental}
<FlaskConical class="h-3.5 w-3.5 text-muted-foreground" />
{/if}
</Label>
{#if isCustomRealTime}
<SettingsChatParameterSourceIndicator />
{/if}
@@ -80,9 +81,9 @@
<div class="relative w-full">
<Input
autocomplete={field.isPrivate ? 'new-password' : undefined}
id={field.key}
type={field.isPrivate ? 'password' : field.isPositiveInteger ? 'number' : 'text'}
autocomplete={field.isPrivate ? 'new-password' : undefined}
{...field.isPositiveInteger
? {
min: String(field.min ?? 1),
@@ -90,28 +91,30 @@
...(field.max != null ? { max: String(field.max) } : {})
}
: {}}
value={currentValue}
class="w-full {isCustomRealTime ? 'pr-8' : ''}"
oninput={(e) => onConfigChange(field.key, e.currentTarget.value)}
placeholder={currentModelParams[field.key] != null
? `Default: ${normalizeFloatingPoint(currentModelParams[field.key])}`
: (field.placeholder ?? '')}
class="w-full {isCustomRealTime ? 'pr-8' : ''}"
value={currentValue}
/>
{#if isCustomRealTime}
<button
type="button"
aria-label="Reset to default"
class="absolute top-1/2 right-2 inline-flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded transition-colors hover:bg-muted"
onclick={() => {
settingsStore.resetParameterToServerDefault(field.key);
onConfigChange(field.key, '');
}}
class="absolute top-1/2 right-2 inline-flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded transition-colors hover:bg-muted"
aria-label="Reset to default"
title="Reset to default"
type="button"
>
<RotateCcw class="h-3 w-3" />
</button>
{/if}
</div>
{#if field.help || SETTING_CONFIG_INFO[field.key]}
<p class="mt-1 text-xs text-muted-foreground">
{@html field.help || SETTING_CONFIG_INFO[field.key]}
@@ -119,7 +122,7 @@
{/if}
{:else if field.type === SettingsFieldType.TEXTAREA}
{#if field.label}
<Label for={field.key} class="block flex items-center gap-1.5 text-sm font-medium">
<Label class="block flex items-center gap-1.5 text-sm font-medium" for={field.key}>
{field.label}
{#if field.isExperimental}
@@ -129,11 +132,11 @@
{/if}
<Textarea
class="min-h-[10rem] w-full md:max-w-3xl"
id={field.key}
value={String(localConfig[field.key] ?? '')}
onchange={(e) => onConfigChange(field.key, e.currentTarget.value)}
placeholder=""
class="min-h-[10rem] w-full md:max-w-3xl"
value={String(localConfig[field.key] ?? '')}
/>
{#if field.help || SETTING_CONFIG_INFO[field.key]}
@@ -145,13 +148,13 @@
{#if field.key === SETTINGS_KEYS.SYSTEM_MESSAGE}
<div class="mt-3 flex items-center gap-2">
<Checkbox
id="showSystemMessage"
checked={Boolean(localConfig.showSystemMessage ?? true)}
id="showSystemMessage"
onCheckedChange={(checked) =>
onConfigChange(SETTINGS_KEYS.SHOW_SYSTEM_MESSAGE, Boolean(checked))}
/>
<Label for="showSystemMessage" class="cursor-pointer text-sm font-normal">
<Label class="cursor-pointer text-sm font-normal" for="showSystemMessage">
Show system message in conversations
</Label>
</div>
@@ -172,21 +175,20 @@
})()}
<div class="flex items-center gap-2">
<Label for={field.key} class="flex items-center gap-1.5 text-sm font-medium">
<Label class="flex items-center gap-1.5 text-sm font-medium" for={field.key}>
{field.label}
{#if field.isExperimental}
<FlaskConical class="h-3.5 w-3.5 text-muted-foreground" />
{/if}
</Label>
{#if isCustomRealTime}
<SettingsChatParameterSourceIndicator />
{/if}
</div>
<Select.Root
type="single"
value={currentValue}
onValueChange={(value) => {
if (field.key === SETTINGS_KEYS.THEME && value && onThemeChange) {
onThemeChange(value);
@@ -194,6 +196,8 @@
onConfigChange(field.key, value);
}
}}
type="single"
value={currentValue}
>
<div class="relative w-full md:w-auto">
<Select.Trigger class="w-full">
@@ -206,25 +210,27 @@
{selectedOption?.label || `Select ${field.label.toLowerCase()}`}
</div>
</Select.Trigger>
{#if isCustomRealTime}
<button
type="button"
aria-label="Reset to default"
class="absolute top-1/2 right-8 inline-flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded transition-colors hover:bg-muted"
onclick={() => {
settingsStore.resetParameterToServerDefault(field.key);
onConfigChange(field.key, '');
}}
class="absolute top-1/2 right-8 inline-flex h-5 w-5 -translate-y-1/2 items-center justify-center rounded transition-colors hover:bg-muted"
aria-label="Reset to default"
title="Reset to default"
type="button"
>
<RotateCcw class="h-3 w-3" />
</button>
{/if}
</div>
<Select.Content>
{#if field.options}
{#each field.options as option (option.value)}
<Select.Item value={option.value} label={option.label}>
<Select.Item label={option.label} value={option.value}>
<div class="flex items-center gap-2">
{#if option.icon}
{@const IconComponent = option.icon}
@@ -237,6 +243,7 @@
{/if}
</Select.Content>
</Select.Root>
{#if field.help || SETTING_CONFIG_INFO[field.key]}
<p class="mt-1 text-xs text-muted-foreground">
{field.help || SETTING_CONFIG_INFO[field.key]}
@@ -258,20 +265,21 @@
<RadioGroup.Root
class="gap-4"
value={currentMode}
onValueChange={(value) => {
for (const opt of radioOptions) {
onConfigChange(opt.key, opt.value === value);
}
}}
value={currentMode}
>
{#each radioOptions as opt (opt.value)}
{@const itemId = `${field.key}-${opt.value}`}
<div class="flex items-center gap-2">
<RadioGroup.Item value={opt.value} id={itemId} />
<RadioGroup.Item id={itemId} value={opt.value} />
<Label
for={itemId}
class="flex cursor-pointer items-center gap-1.5 text-sm font-normal"
for={itemId}
>
{opt.label}
@@ -291,16 +299,16 @@
{:else if field.type === SettingsFieldType.CHECKBOX}
<div class="flex items-start space-x-3">
<Checkbox
id={field.key}
checked={Boolean(localConfig[field.key])}
onCheckedChange={(checked) => onConfigChange(field.key, checked)}
class="mt-1"
id={field.key}
onCheckedChange={(checked) => onConfigChange(field.key, checked)}
/>
<div class="space-y-1">
<label
for={field.key}
class="flex cursor-pointer items-center gap-1.5 pt-1 pb-0.5 text-sm leading-none font-medium"
for={field.key}
>
{field.label}
@@ -261,92 +261,92 @@
}
</script>
<div class="space-y-12" in:fade={{ duration: 150 }}>
<div in:fade={{ duration: 150 }} class="space-y-12">
<SettingsGroup title="Conversations">
<SettingsChatImportExportSection
title="Export"
description="Download your conversations as a ZIP of JSONL files. This includes all messages, attachments, and conversation history."
IconComponent={Download}
buttonText="Export conversations"
description="Download your conversations as a ZIP of JSONL files. This includes all messages, attachments, and conversation history."
onclick={handleExportClick}
summary={{ items: exportedConversations, show: showExportSummary, verb: 'Exported' }}
title="Export"
/>
<SettingsChatImportExportSection
title="Import"
description="Import one or more conversations from a previously exported ZIP or JSONL file. This will merge with your existing conversations."
IconComponent={Upload}
buttonText="Import conversations"
description="Import one or more conversations from a previously exported ZIP or JSONL file. This will merge with your existing conversations."
onclick={handleImportClick}
summary={{ items: importedConversations, show: showImportSummary, verb: 'Imported' }}
title="Import"
/>
<SettingsChatImportExportSection
title="Delete All"
description="Permanently delete all conversations and their messages. This action cannot be undone. Consider exporting your conversations first if you want to keep a backup."
IconComponent={Trash2}
buttonText="Delete all conversations"
onclick={handleDeleteAllClick}
titleClass="text-destructive"
buttonVariant="destructive"
buttonClass="text-destructive-foreground justify-start justify-self-start bg-destructive hover:bg-destructive/80 md:w-auto"
buttonText="Delete all conversations"
buttonVariant="destructive"
description="Permanently delete all conversations and their messages. This action cannot be undone. Consider exporting your conversations first if you want to keep a backup."
onclick={handleDeleteAllClick}
title="Delete All"
titleClass="text-destructive"
/>
</SettingsGroup>
<SettingsGroup title="Settings">
<SettingsChatImportExportSection
title="Export"
description="Export your chat settings and preferences as a JSON file."
IconComponent={Download}
buttonText="Export settings"
description="Export your chat settings and preferences as a JSON file."
onclick={handleSettingsExport}
summary={{ items: [], show: showSettingsExportSummary, verb: 'Exported' }}
title="Export"
/>
<SettingsChatImportExportSection
title="Import"
description="Import chat settings from a previously exported JSON file. This will merge with your existing settings."
IconComponent={Upload}
buttonText="Import settings"
description="Import chat settings from a previously exported JSON file. This will merge with your existing settings."
onclick={handleSettingsImport}
summary={{ items: [], show: showSettingsImportSummary, verb: 'Imported' }}
title="Import"
/>
</SettingsGroup>
</div>
<DialogExportSettings
bind:open={showSettingsExportDialog}
bind:includeSensitiveData
onConfirm={handleSettingsExportConfirm}
bind:open={showSettingsExportDialog}
onCancel={handleSettingsExportCancel}
onConfirm={handleSettingsExportConfirm}
/>
<DialogConversationSelection
bind:open={showExportDialog}
conversations={availableConversations}
{messageCountMap}
mode={ConversationSelectionMode.EXPORT}
bind:open={showExportDialog}
onCancel={() => (showExportDialog = false)}
onConfirm={handleExportConfirm}
/>
<DialogConversationSelection
bind:open={showImportDialog}
conversations={availableConversations}
{messageCountMap}
mode={ConversationSelectionMode.IMPORT}
bind:open={showImportDialog}
onCancel={() => (showImportDialog = false)}
onConfirm={handleImportConfirm}
/>
<DialogConfirmation
bind:open={showDeleteDialog}
title="Delete all conversations"
description="Are you sure you want to delete all conversations? This action cannot be undone and will permanently remove all your conversations and messages."
confirmText="Delete All"
cancelText="Cancel"
variant="destructive"
confirmText="Delete All"
description="Are you sure you want to delete all conversations? This action cannot be undone and will permanently remove all your conversations and messages."
icon={Trash2}
onConfirm={handleDeleteAllConfirm}
onCancel={handleDeleteAllCancel}
onConfirm={handleDeleteAllConfirm}
title="Delete all conversations"
variant="destructive"
/>
@@ -10,8 +10,8 @@
</script>
<Badge
variant="secondary"
class="h-5 bg-orange-100 px-1.5 py-0.5 text-xs text-orange-800 dark:bg-orange-900 dark:text-orange-200 {className}"
variant="secondary"
>
<Wrench class="mr-1 h-3 w-3" />
@@ -27,7 +27,7 @@
<div class="space-y-2">
{#each groups as group (group.key)}
{@const isExpanded = expandedGroups.has(group.key)}
<Collapsible.Root open={isExpanded} onOpenChange={() => toggleExpanded(group.key)}>
<Collapsible.Root onOpenChange={() => toggleExpanded(group.key)} open={isExpanded}>
<Collapsible.Trigger
class="flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm hover:bg-muted/50"
>
@@ -42,14 +42,14 @@
<span class="inline-flex min-w-0 items-center gap-1.5 font-medium">
{#if group.source === 'mcp'}
<McpServerIdentity
displayName={group.label}
{faviconUrl}
iconClass={ICON_CLASS_DEFAULT}
iconRounded="rounded-sm"
showVersion={false}
displayName={group.label}
{faviconUrl}
/>
{:else}
<TruncatedText text={group.label} class="font-medium" />
<TruncatedText class="font-medium" text={group.label} />
{/if}
</span>
@@ -63,7 +63,9 @@
<!-- Header row -->
<div class="flex items-center gap-2 px-2 py-1 text-xs text-muted-foreground">
<span class="min-w-0 flex-1">Tool</span>
<span class="w-16 shrink-0 text-center">Enabled</span>
<span class="w-20 shrink-0 text-center">Always allow</span>
</div>
@@ -84,20 +86,22 @@
{#if IconComponent}
<IconComponent class={ICON_CLASS_DEFAULT} />
{/if}
<TruncatedText text={displayLabel} class="min-w-0" showTooltip={true} />
<TruncatedText class="min-w-0" showTooltip={true} text={displayLabel} />
</span>
<div class="flex w-16 shrink-0 justify-center">
<Checkbox
checked={isEnabled}
onCheckedChange={() => toolsStore.toggleTool(entry.key)}
class={ICON_CLASS_DEFAULT}
onCheckedChange={() => toolsStore.toggleTool(entry.key)}
/>
</div>
<div class="flex w-20 shrink-0 justify-center">
<Checkbox
checked={isAlwaysAllowed}
class={ICON_CLASS_DEFAULT}
onCheckedChange={() => {
if (isAlwaysAllowed) {
permissionsStore.revokeTool(permissionKey);
@@ -105,7 +109,6 @@
permissionsStore.allowTool(permissionKey);
}
}}
class={ICON_CLASS_DEFAULT}
/>
</div>
</div>
@@ -32,6 +32,7 @@
href={getHref(section)}
>
<section.icon class={ICON_CLASS_DEFAULT} />
<span class="ml-2">{section.title}</span>
</a>
{:else}
@@ -44,6 +45,7 @@
onclick={() => onSectionChange?.(section.title)}
>
<section.icon class={ICON_CLASS_DEFAULT} />
<span class="ml-2">{section.title}</span>
</button>
{/if}
@@ -45,7 +45,7 @@
</div>
<div class="border-b border-border/30 py-2">
<ScrollCarousel {carousel} alwaysShowArrows containerClass="py-2" innerClass="gap-2">
<ScrollCarousel alwaysShowArrows {carousel} containerClass="py-2" innerClass="gap-2">
{#each sections as section (section.title)}
{#if getHref}
<a
@@ -61,6 +61,7 @@
}}
>
<section.icon class="{ICON_CLASS_DEFAULT} flex-shrink-0" />
<span>{section.title}</span>
</a>
{:else}
@@ -77,6 +78,7 @@
}}
>
<section.icon class="{ICON_CLASS_DEFAULT} flex-shrink-0" />
<span>{section.title}</span>
</button>
{/if}
@@ -31,7 +31,7 @@
<div class="sticky bottom-0 mx-auto mt-4 flex w-full justify-between p-6">
<div class="flex gap-2">
<Button variant="outline" onclick={handleResetClick}>
<Button onclick={handleResetClick} variant="outline">
<RotateCcw class="h-3 w-3" />
Reset to default
@@ -45,14 +45,17 @@
<AlertDialog.Content>
<AlertDialog.Header>
<AlertDialog.Title>Reset Settings to Default</AlertDialog.Title>
<AlertDialog.Description>
Are you sure you want to reset all settings to their default values? This will reset all
parameters to the values provided by the server's /props endpoint and remove all your custom
configurations.
</AlertDialog.Description>
</AlertDialog.Header>
<AlertDialog.Footer>
<AlertDialog.Cancel>Cancel</AlertDialog.Cancel>
<AlertDialog.Action onclick={handleConfirmReset}>Reset to Default</AlertDialog.Action>
</AlertDialog.Footer>
</AlertDialog.Content>
@@ -73,7 +73,7 @@
<div in:fade={{ duration: 150 }} class="flex min-h-[calc(100dvh-4rem)] flex-col">
<div class="fixed top-4.5 right-4 z-50 md:hidden">
<ActionIcon icon={X} tooltip="Close" onclick={handleClose} />
<ActionIcon icon={X} onclick={handleClose} tooltip="Close" />
</div>
<div
@@ -102,7 +102,7 @@
</Empty.Header>
<Empty.Content>
<Button size="sm" onclick={() => (isAddingServer = true)}>
<Button onclick={() => (isAddingServer = true)} size="sm">
<Plus />
Add New Server
@@ -120,8 +120,8 @@
<McpServerCardSkeleton />
{:else}
<McpServerCard
{server}
enabled={conversationsStore.preferences.isMcpServerEnabledForChat(server.id)}
onDelete={() => mcpStore.removeServer(server.id)}
onToggle={async () => {
const wasEnabled = conversationsStore.preferences.isMcpServerEnabledForChat(
server.id
@@ -137,7 +137,7 @@
}
}}
onUpdate={(updates) => mcpStore.updateServer(server.id, updates)}
onDelete={() => mcpStore.removeServer(server.id)}
{server}
/>
{/if}
{/each}
@@ -155,7 +155,7 @@
</Empty.Header>
<Empty.Content>
<Button size="sm" onclick={() => (isAddingServer = true)}>
<Button onclick={() => (isAddingServer = true)} size="sm">
<Plus />
Add New Server