ui: Sidebar Conversations Bulk Action + Improved Settings logic/UI (#25815)
* feat: WIP * feat: Replace conversation rename flow with unified AlertDialog component * feat: Add radio group component and consolidate title generation settings * refactor: Remove JS Sandbox global toggle and migrate legacy user state * chore: Formatting * refactor: Cleanup Co-authored-by: Aleksander Grygier <aleksander.grygier@gmail.com> * refactor: Cleanup * refactor: Marquee selection hook * feat: UI improvements * refactor: Bulk db operations * fix: optimize bulk conversation deletion to handle ancestor chains * refactor: remove pairedKey mechanism from settings system * fix: remove redundant onclick handler from dialog cancel button * chore: pin @lucide/svelte to exact version * feat: Run JavaScript tool disabled by default * fix: correct active conversation deletion tracking in bulk delete * feat: improve shift-key multi-selection support in sidebar via keyboard * refactor: Retrieve JS Tool enabling via Developer Settings * nits: sync, dialog wording, cycle guard, and lockfile follow-ups - Restore titleGenerationUseLLM registry entry so it syncs across devices again - Mention fork cascade in the bulk delete confirmation dialog - Clear newParent on cycle guard break so children never point at a deleted conversation - Align @lucide/svelte in package-lock.json with the exact pin in package.json --------- Co-authored-by: Pascal <admin@serveurperso.com>
This commit is contained in:
co-authored by
Pascal
parent
91d2fc3875
commit
2beefef688
@@ -54,6 +54,34 @@ const COLOR_MODE_OPTIONS: Array<{ value: string; label: string; icon: Component
|
||||
{ value: ColorMode.DARK, label: 'Dark', icon: Moon }
|
||||
];
|
||||
|
||||
// Shared options for the title-generation radio group. Both paired registry entries
|
||||
// (USE_FIRST_LINE, USE_LLM) reference this list so labels stay in lockstep.
|
||||
const TITLE_GENERATION_RADIO_OPTIONS: Array<{
|
||||
value: string;
|
||||
label: string;
|
||||
key: string;
|
||||
isExperimental?: boolean;
|
||||
}> = [
|
||||
{
|
||||
value: 'firstLine',
|
||||
label: 'Use first non-empty line for the conversation title',
|
||||
key: SETTINGS_KEYS.TITLE_GENERATION_USE_FIRST_LINE
|
||||
},
|
||||
{
|
||||
value: 'llm',
|
||||
label: 'Generate title with LLM',
|
||||
key: SETTINGS_KEYS.TITLE_GENERATION_USE_LLM,
|
||||
isExperimental: true
|
||||
}
|
||||
];
|
||||
|
||||
// Common shape for the conversation title radio entry.
|
||||
const TITLE_GENERATION_BASE = {
|
||||
type: SettingsFieldType.RADIO,
|
||||
section: SETTINGS_SECTION_SLUGS.GENERAL,
|
||||
radioOptions: TITLE_GENERATION_RADIO_OPTIONS
|
||||
} as const;
|
||||
|
||||
const SETTINGS_REGISTRY: Record<string, SettingsSectionEntry> = {
|
||||
[SETTINGS_SECTION_SLUGS.GENERAL]: {
|
||||
title: SETTINGS_SECTION_TITLES.GENERAL,
|
||||
@@ -115,14 +143,15 @@ const SETTINGS_REGISTRY: Record<string, SettingsSectionEntry> = {
|
||||
}
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.COPY_TEXT_ATTACHMENTS_AS_PLAIN_TEXT,
|
||||
label: 'Copy text attachments as plain text',
|
||||
help: 'When copying a message with text attachments, combine them into a single plain text string instead of a special format that can be pasted back as attachments.',
|
||||
key: SETTINGS_KEYS.AUTO_MIC_ON_EMPTY,
|
||||
label: 'Show microphone on empty input',
|
||||
help: 'Automatically show microphone button instead of send button when textarea is empty for models with audio modality support.',
|
||||
defaultValue: false,
|
||||
type: SettingsFieldType.CHECKBOX,
|
||||
section: SETTINGS_SECTION_SLUGS.GENERAL,
|
||||
isExperimental: true,
|
||||
sync: {
|
||||
serverKey: SETTINGS_KEYS.COPY_TEXT_ATTACHMENTS_AS_PLAIN_TEXT,
|
||||
serverKey: SETTINGS_KEYS.AUTO_MIC_ON_EMPTY,
|
||||
paramType: SyncableParameterType.BOOLEAN
|
||||
}
|
||||
},
|
||||
@@ -140,54 +169,16 @@ const SETTINGS_REGISTRY: Record<string, SettingsSectionEntry> = {
|
||||
}
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.PDF_AS_IMAGE,
|
||||
label: 'Parse PDF as image',
|
||||
help: 'Parse PDF as image instead of text. Automatically falls back to text processing for non-vision models.',
|
||||
defaultValue: false,
|
||||
type: SettingsFieldType.CHECKBOX,
|
||||
section: SETTINGS_SECTION_SLUGS.GENERAL,
|
||||
sync: {
|
||||
serverKey: SETTINGS_KEYS.PDF_AS_IMAGE,
|
||||
paramType: SyncableParameterType.BOOLEAN
|
||||
}
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.ASK_FOR_TITLE_CONFIRMATION,
|
||||
label: 'Ask for confirmation before changing conversation title',
|
||||
help: 'Ask for confirmation before automatically changing conversation title when editing the first message.',
|
||||
defaultValue: false,
|
||||
type: SettingsFieldType.CHECKBOX,
|
||||
section: SETTINGS_SECTION_SLUGS.GENERAL,
|
||||
sync: {
|
||||
serverKey: SETTINGS_KEYS.ASK_FOR_TITLE_CONFIRMATION,
|
||||
paramType: SyncableParameterType.BOOLEAN
|
||||
}
|
||||
},
|
||||
{
|
||||
...TITLE_GENERATION_BASE,
|
||||
key: SETTINGS_KEYS.TITLE_GENERATION_USE_FIRST_LINE,
|
||||
label: 'Use first non-empty line for conversation title',
|
||||
help: 'Use only the first non-empty line of the prompt to generate the conversation title.',
|
||||
defaultValue: false,
|
||||
type: SettingsFieldType.CHECKBOX,
|
||||
section: SETTINGS_SECTION_SLUGS.GENERAL,
|
||||
label: 'Conversation title',
|
||||
help: 'Choose how conversation titles are generated. The first non-empty line uses a fast deterministic rule; the LLM option uses a model-generated title from the first message exchange.',
|
||||
defaultValue: true,
|
||||
sync: {
|
||||
serverKey: SETTINGS_KEYS.TITLE_GENERATION_USE_FIRST_LINE,
|
||||
paramType: SyncableParameterType.BOOLEAN
|
||||
}
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.TITLE_GENERATION_USE_LLM,
|
||||
label: 'Use LLM to generate conversation title',
|
||||
help: 'Use the LLM to automatically generate conversation titles based on the first message exchange.',
|
||||
defaultValue: false,
|
||||
type: SettingsFieldType.CHECKBOX,
|
||||
section: SETTINGS_SECTION_SLUGS.GENERAL,
|
||||
isExperimental: true,
|
||||
sync: {
|
||||
serverKey: SETTINGS_KEYS.TITLE_GENERATION_USE_LLM,
|
||||
paramType: SyncableParameterType.BOOLEAN
|
||||
}
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.TITLE_GENERATION_PROMPT,
|
||||
label: 'LLM title generation prompt',
|
||||
@@ -195,11 +186,36 @@ const SETTINGS_REGISTRY: Record<string, SettingsSectionEntry> = {
|
||||
defaultValue: TITLE_GENERATION.DEFAULT_PROMPT,
|
||||
type: SettingsFieldType.TEXTAREA,
|
||||
section: SETTINGS_SECTION_SLUGS.GENERAL,
|
||||
dependsOn: SETTINGS_KEYS.TITLE_GENERATION_USE_LLM,
|
||||
sync: {
|
||||
serverKey: SETTINGS_KEYS.TITLE_GENERATION_PROMPT,
|
||||
paramType: SyncableParameterType.STRING
|
||||
}
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.COPY_TEXT_ATTACHMENTS_AS_PLAIN_TEXT,
|
||||
label: 'Copy text attachments as plain text',
|
||||
help: 'When copying a message with text attachments, combine them into a single plain text string instead of a special format that can be pasted back as attachments.',
|
||||
defaultValue: false,
|
||||
type: SettingsFieldType.CHECKBOX,
|
||||
section: SETTINGS_SECTION_SLUGS.GENERAL,
|
||||
sync: {
|
||||
serverKey: SETTINGS_KEYS.COPY_TEXT_ATTACHMENTS_AS_PLAIN_TEXT,
|
||||
paramType: SyncableParameterType.BOOLEAN
|
||||
}
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.PDF_AS_IMAGE,
|
||||
label: 'Parse PDF as image',
|
||||
help: 'Parse PDF as image instead of text. Automatically falls back to text processing for non-vision models.',
|
||||
defaultValue: false,
|
||||
type: SettingsFieldType.CHECKBOX,
|
||||
section: SETTINGS_SECTION_SLUGS.GENERAL,
|
||||
sync: {
|
||||
serverKey: SETTINGS_KEYS.PDF_AS_IMAGE,
|
||||
paramType: SyncableParameterType.BOOLEAN
|
||||
}
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.MAX_IMAGE_RESOLUTION,
|
||||
label: 'Maximum image resolution (megapixels)',
|
||||
@@ -264,19 +280,6 @@ const SETTINGS_REGISTRY: Record<string, SettingsSectionEntry> = {
|
||||
paramType: SyncableParameterType.BOOLEAN
|
||||
}
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.AUTO_MIC_ON_EMPTY,
|
||||
label: 'Show microphone on empty input',
|
||||
help: 'Automatically show microphone button instead of send button when textarea is empty for models with audio modality support.',
|
||||
defaultValue: false,
|
||||
type: SettingsFieldType.CHECKBOX,
|
||||
section: SETTINGS_SECTION_SLUGS.DISPLAY,
|
||||
isExperimental: true,
|
||||
sync: {
|
||||
serverKey: SETTINGS_KEYS.AUTO_MIC_ON_EMPTY,
|
||||
paramType: SyncableParameterType.BOOLEAN
|
||||
}
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.RENDER_USER_CONTENT_AS_MARKDOWN,
|
||||
label: 'Render user content as Markdown',
|
||||
@@ -764,6 +767,17 @@ const NON_UI_SETTINGS: SettingsEntry[] = [
|
||||
defaultValue: '[]',
|
||||
type: SettingsFieldType.INPUT,
|
||||
sync: { serverKey: SETTINGS_KEYS.MCP_SERVERS, paramType: SyncableParameterType.STRING }
|
||||
},
|
||||
{
|
||||
key: SETTINGS_KEYS.TITLE_GENERATION_USE_LLM,
|
||||
label: 'Generate title with LLM',
|
||||
help: 'Counterpart of the conversation title radio; stored and synced without a dedicated UI field.',
|
||||
defaultValue: false,
|
||||
type: SettingsFieldType.CHECKBOX,
|
||||
sync: {
|
||||
serverKey: SETTINGS_KEYS.TITLE_GENERATION_USE_LLM,
|
||||
paramType: SyncableParameterType.BOOLEAN
|
||||
}
|
||||
}
|
||||
// {
|
||||
// key: SETTINGS_KEYS.PY_INTERPRETER_ENABLED,
|
||||
@@ -812,7 +826,8 @@ export const SETTINGS_CHAT_SECTIONS: SettingsSection[] = [
|
||||
isPositiveInteger: s.isPositiveInteger,
|
||||
dependsOn: s.dependsOn,
|
||||
help: s.help,
|
||||
options: s.options
|
||||
options: s.options,
|
||||
radioOptions: s.radioOptions
|
||||
}))
|
||||
})),
|
||||
...STANDALONE_SECTIONS
|
||||
|
||||
Reference in New Issue
Block a user