ui: Constants refactor (#26908)

* refactor: Constants

* refactor: Constants/Enums cleanup

* refactor: Constant objects instead of multiple single value constants

* refactor: Cleanup constants
This commit is contained in:
Aleksander Grygier
2026-08-13 06:53:56 +02:00
committed by GitHub
parent 8e7f22b67e
commit e21152dc96
209 changed files with 1101 additions and 1137 deletions
@@ -1,7 +1,7 @@
<script lang="ts">
import ActionIcon from './ActionIcon.svelte';
import { Copy } from '@lucide/svelte';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { copyToClipboard } from '$lib/utils';
export let ariaLabel: string = 'Copy to clipboard';
@@ -1,7 +1,7 @@
<script lang="ts">
import { Music, Video, X } from '@lucide/svelte';
import { ActionIcon } from '$lib/components/app';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { AttachmentType } from '$lib/enums';
import {
formatFileSize,
@@ -3,7 +3,7 @@
import { SyntaxHighlightedCode } from '$lib/components/app';
import * as Alert from '$lib/components/ui/alert';
import { Button } from '$lib/components/ui/button';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { PdfViewMode } from '$lib/enums';
import type { ChatAttachmentDisplayItem } from '$lib/types';
import { getLanguageFromFilename } from '$lib/utils';
@@ -1,7 +1,7 @@
<script lang="ts">
import { FileText, Music, Video } from '@lucide/svelte';
import { HorizontalScrollCarousel } from '$lib/components/app/misc';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
interface PreviewItem {
id: string;
@@ -2,8 +2,7 @@
import { Plus } from '@lucide/svelte';
import { Button } from '$lib/components/ui/button';
import * as Tooltip from '$lib/components/ui/tooltip';
import { ATTACHMENT_TOOLTIP_TEXT } from '$lib/constants';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ATTACHMENT_TOOLTIP_TEXT, ICON_CLASS_DEFAULT } from '$lib/constants';
interface Props {
disabled?: boolean;
@@ -12,9 +12,9 @@
import {
ATTACHMENT_FILE_ITEMS,
ATTACHMENT_TOOLTIP_TEXT,
ICON_CLASS_DEFAULT,
TOOLTIP_DELAY_DURATION
} from '$lib/constants';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { useAttachmentMenu } from '$lib/hooks/use-attachment-menu.svelte';
interface Props {
@@ -4,8 +4,7 @@
import { DropdownMenuSearchable, McpLogo, McpServerIdentity } from '$lib/components/app';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
import { Switch } from '$lib/components/ui/switch';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ROUTES } from '$lib/constants/routes';
import { ICON_CLASS_DEFAULT, ROUTES } from '$lib/constants';
import { HealthCheckStatus } from '$lib/enums';
import { conversationsStore } from '$lib/stores/conversations.svelte';
import { mcpStore } from '$lib/stores/mcp.svelte';
@@ -2,7 +2,7 @@
import { Check, Info, Lightbulb, LightbulbOff } from '@lucide/svelte';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
import * as Tooltip from '$lib/components/ui/tooltip';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { useReasoningMenu } from '$lib/hooks/use-reasoning-menu.svelte';
const reasoning = useReasoningMenu();
@@ -14,9 +14,11 @@
import * as Sheet from '$lib/components/ui/sheet';
import { Switch } from '$lib/components/ui/switch';
import * as Tooltip from '$lib/components/ui/tooltip';
import { TOOLTIP_DELAY_DURATION } from '$lib/constants';
import { ATTACHMENT_FILE_ITEMS } from '$lib/constants/attachment-menu';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import {
ATTACHMENT_FILE_ITEMS,
ICON_CLASS_DEFAULT,
TOOLTIP_DELAY_DURATION
} from '$lib/constants';
import { HealthCheckStatus } from '$lib/enums';
import { AttachmentAction } from '$lib/enums/attachment.enums';
import { useAttachmentMenu } from '$lib/hooks/use-attachment-menu.svelte';
@@ -4,8 +4,7 @@
import * as Collapsible from '$lib/components/ui/collapsible';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
import * as Tooltip from '$lib/components/ui/tooltip';
import { CLI_FLAGS } from '$lib/constants';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { CLI_FLAGS, ICON_CLASS_DEFAULT } from '$lib/constants';
import { useToolsPanel } from '$lib/hooks/use-tools-panel.svelte';
import { mcpStore } from '$lib/stores/mcp.svelte';
import { toolsStore } from '$lib/stores/tools.svelte';
@@ -2,7 +2,7 @@
import { Mic, Square } from '@lucide/svelte';
import { Button } from '$lib/components/ui/button';
import * as Tooltip from '$lib/components/ui/tooltip';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
interface Props {
class?: string;
@@ -10,8 +10,7 @@
ChatFormContextGauge
} from '$lib/components/app';
import { Button } from '$lib/components/ui/button';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ROUTES } from '$lib/constants/routes';
import { ICON_CLASS_DEFAULT, ROUTES } from '$lib/constants';
import { FileTypeCategory, MessageRole } from '$lib/enums';
import { ChatService } from '$lib/services';
import {
@@ -1,5 +1,5 @@
<script lang="ts">
import { TRIM_LEADING_PADDING_REGEX, TRIM_TRAILING_PADDING_REGEX } from '$lib/constants';
import { CODE_BLOCK } from '$lib/constants';
import { ColorMode } from '$lib/enums';
import { isMobile } from '$lib/stores/viewport.svelte';
import type { ContentToken, SourceHistoryEntry } from '$lib/utils';
@@ -105,8 +105,8 @@
const prefix = open[0];
const language = open[1].trim().split(/\s+/)[0] ?? '';
const content = segment.slice(prefix.length, -3);
const leading = content.match(TRIM_LEADING_PADDING_REGEX)?.[0] ?? '';
const trailing = content.match(TRIM_TRAILING_PADDING_REGEX)?.[0] ?? '';
const leading = content.match(CODE_BLOCK.TRIM_LEADING_PADDING_REGEX)?.[0] ?? '';
const trailing = content.match(CODE_BLOCK.TRIM_TRAILING_PADDING_REGEX)?.[0] ?? '';
const core = content.slice(leading.length, content.length - trailing.length);
// autoDetect off: re-guessing the language on every keystroke
// costs ~38ms a call and flickers while typing
@@ -4,11 +4,7 @@
import HighlightedMatch from '$lib/components/app/forms/HighlightedMatch.svelte';
import * as Popover from '$lib/components/ui/popover';
import * as Tooltip from '$lib/components/ui/tooltip';
import {
FILE_GLOB_SEARCH_PICKERS_DEFAULT_SEARCH_DEPTH,
HOME_TILDE,
SEARCH_DEBOUNCE_MS
} from '$lib/constants';
import { FILE_GLOB_SEARCH_PICKERS, HOME_TILDE, SEARCH } from '$lib/constants';
import { BuiltInTool, FileMentionEntryType, GlobSearchType, KeyboardKey } from '$lib/enums';
import { useDebouncedSearch } from '$lib/hooks/use-debounced-search.svelte';
import { usePickerNavigation } from '$lib/hooks/use-picker-navigation.svelte';
@@ -70,7 +66,7 @@
const searchDepth = $derived.by(() => {
const n = Number(config().mentionSearchMaxDepth);
return Number.isInteger(n) && n > 0 ? n : FILE_GLOB_SEARCH_PICKERS_DEFAULT_SEARCH_DEPTH;
return Number.isInteger(n) && n > 0 ? n : FILE_GLOB_SEARCH_PICKERS.DEFAULT_SEARCH_DEPTH;
});
const home = $derived(toolsStore.serverHome);
@@ -80,7 +76,7 @@
const search = useDebouncedSearch({
canRun: () => isOpen && fileSearchEnabled,
debounceMs: SEARCH_DEBOUNCE_MS,
debounceMs: SEARCH.DEBOUNCE_MS,
getQuery: () => trimmedQuery,
run: async (query, signal, isCurrent) => {
try {
@@ -4,16 +4,7 @@
import { FolderOpen } from '@lucide/svelte';
import SearchInput from '$lib/components/app/forms/SearchInput.svelte';
import * as Popover from '$lib/components/ui/popover';
import {
DEFAULT_MOBILE_BREAKPOINT,
HOME_TILDE,
MAX_RESULTS_SHOWN,
NATIVE_LIMIT,
NATIVE_MAX_DEPTH,
SEARCH_DEBOUNCE_MS,
SEARCH_LIMIT,
SEARCH_MAX_DEPTH
} from '$lib/constants';
import { DEFAULT_MOBILE_BREAKPOINT, HOME_TILDE, SEARCH } from '$lib/constants';
import { BuiltInTool, GlobSearchType, KeyboardKey } from '$lib/enums';
import { useDebouncedSearch } from '$lib/hooks/use-debounced-search.svelte';
import { usePickerNavigation } from '$lib/hooks/use-picker-navigation.svelte';
@@ -142,7 +133,7 @@
// children too, so path navigation does not require a trailing slash.
const search = useDebouncedSearch({
canRun: () => isOpen && fileSearchEnabled,
debounceMs: SEARCH_DEBOUNCE_MS,
debounceMs: SEARCH.DEBOUNCE_MS,
getQuery: () => query.trim(),
run: async (q, signal, isCurrent) => {
const trimmed = q.trim();
@@ -162,8 +153,8 @@
const res = await runGlobSearchWithChildren(
trimmed,
homeBase ?? HOME_TILDE,
SEARCH_MAX_DEPTH,
SEARCH_LIMIT,
SEARCH.MAX_DEPTH,
SEARCH.LIMIT,
signal,
{ type: GlobSearchType.DIR }
);
@@ -179,7 +170,7 @@
}
searchScope = res.exactDir ?? res.args.path;
queryResults = res.entries.map((e) => e.path).slice(0, MAX_RESULTS_SHOWN);
queryResults = res.entries.map((e) => e.path).slice(0, SEARCH.MAX_RESULTS_SHOWN);
if (queryResults.length > 0) {
nav.reset(0);
@@ -223,8 +214,8 @@
try {
const res = await ToolsService.executeToolRaw(BuiltInTool.FILE_GLOB_SEARCH, {
include: buildCaseInsensitiveGlob(name),
limit: NATIVE_LIMIT,
max_depth: NATIVE_MAX_DEPTH,
limit: SEARCH.NATIVE_LIMIT,
max_depth: SEARCH.NATIVE_MAX_DEPTH,
path: homeBase ?? HOME_TILDE,
type: GlobSearchType.DIR
});
@@ -7,9 +7,7 @@
ChatMessageSystem,
ChatMessageUser
} from '$lib/components/app/chat';
import { SYSTEM_MESSAGE_PLACEHOLDER } from '$lib/constants';
import { REASONING_TAGS } from '$lib/constants/agentic';
import { ROUTES } from '$lib/constants/routes';
import { REASONING_TAGS, ROUTES, SYSTEM_MESSAGE_PLACEHOLDER } from '$lib/constants';
import { getChatActionsContext, setMessageEditContext } from '$lib/contexts';
import { AgenticSectionType, AttachmentType, MessageRole } from '$lib/enums';
import { DatabaseService } from '$lib/services/database.service';
@@ -7,13 +7,13 @@
import { Loader2 } from '@lucide/svelte';
import { MarkdownContent, SyntaxHighlightedCode } from '$lib/components/app';
import { MAX_HEIGHT_CODE_BLOCK } from '$lib/constants';
import { getBuiltinToolUi } from '$lib/constants/built-in-tools';
import { AttachmentType, FileTypeText, MimeTypeAudio, ToolResultKind } from '$lib/enums';
import type { DatabaseMessageExtra } from '$lib/types';
import {
type AgenticSection,
classifyToolResult,
formatJsonPretty,
getBuiltinToolUi,
parseToolResultWithMedia,
type ToolResultLine
} from '$lib/utils';
@@ -10,8 +10,7 @@
import ToolCallBlock from './ToolCallBlock.svelte';
import { AlertTriangle, Check, Loader2, XCircle } from '@lucide/svelte';
import { CollapsibleTerminalBlock } from '$lib/components/app';
import { SETTINGS_KEYS } from '$lib/constants';
import { TOOL_RUNTIME_SCROLL_AT_BOTTOM_THRESHOLD_PX } from '$lib/constants/auto-scroll';
import { SETTINGS_KEYS, TOOL_RUNTIME_SCROLL_AT_BOTTOM_THRESHOLD_PX } from '$lib/constants';
import { config } from '$lib/stores/settings.svelte';
import { toolsStore } from '$lib/stores/tools.svelte';
import type { DatabaseMessageExtra } from '$lib/types';
@@ -2,7 +2,7 @@
import { parseReadFileMeta } from './parsers/read-file';
import ToolCallBlock from './ToolCallBlock.svelte';
import { SyntaxHighlightedCode } from '$lib/components/app';
import { DEFAULT_LANGUAGE, MAX_HEIGHT_CODE_BLOCK } from '$lib/constants';
import { CODE_BLOCK, MAX_HEIGHT_CODE_BLOCK } from '$lib/constants';
import { type AgenticSection } from '$lib/utils';
interface Props {
@@ -32,7 +32,7 @@
{#if section.toolResult}
<SyntaxHighlightedCode
code={section.toolResult}
language={readFileMeta?.language ?? DEFAULT_LANGUAGE}
language={readFileMeta?.language ?? CODE_BLOCK.DEFAULT_LANGUAGE}
maxHeight={MAX_HEIGHT_CODE_BLOCK}
/>
{:else}
@@ -1,7 +1,7 @@
<script lang="ts">
import { parseReadMediaMeta } from './parsers/read-media';
import ToolCallBlock from './ToolCallBlock.svelte';
import { ATTACHMENT_SAVED_REGEX } from '$lib/constants/agentic';
import { ATTACHMENT_SAVED_REGEX } from '$lib/constants/agentic.constants';
import { AttachmentType, MimeTypeAudio } from '$lib/enums';
import type { DatabaseMessageExtraAudioFile, DatabaseMessageExtraImageFile } from '$lib/types';
import { type AgenticSection } from '$lib/utils';
@@ -2,7 +2,7 @@
import { Globe, Loader2 } from '@lucide/svelte';
import { CollapsibleContentBlock } from '$lib/components/app';
import * as HoverCard from '$lib/components/ui/hover-card';
import { ICON_CLASS_DEFAULT, ICON_CLASS_SPIN } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT, ICON_CLASS_SPIN } from '$lib/constants';
import { AgenticSectionType } from '$lib/enums';
import { mcpStore } from '$lib/stores/mcp.svelte';
import {
@@ -11,11 +11,10 @@
import { Loader2, Wrench } from '@lucide/svelte';
import { CollapsibleContentBlock } from '$lib/components/app';
import { getBuiltinToolUi } from '$lib/constants/built-in-tools';
import { ICON_CLASS_DEFAULT, ICON_CLASS_SPIN } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT, ICON_CLASS_SPIN } from '$lib/constants';
import { AgenticSectionType } from '$lib/enums';
import { mcpStore } from '$lib/stores/mcp.svelte';
import type { AgenticSection, BuiltinToolUiEntry } from '$lib/utils';
import { type AgenticSection, type BuiltinToolUiEntry, getBuiltinToolUi } from '$lib/utils';
import type { Component, Snippet } from 'svelte';
type ToolCallBlockMetaWithError = TMeta & { errorMessage?: string };
@@ -4,11 +4,7 @@
// can render incrementally as the file path streams in.
import { parseToolArgs } from './_shared';
import {
DEFAULT_LANGUAGE,
FILE_PATH_SEPARATOR_REGEX,
TEXT_LANGUAGE_PREFIX_REGEX
} from '$lib/constants';
import { CODE_BLOCK, FILE_PATH_SEPARATOR_REGEX } from '$lib/constants';
import { BuiltInTool } from '$lib/enums';
import { type AgenticSection, getFileTypeByExtension } from '$lib/utils';
@@ -50,7 +46,9 @@ export function parseReadFileMeta(section: AgenticSection): ReadFileMeta | null
}
const fileType = getFileTypeByExtension(fileName);
const language = fileType ? fileType.replace(TEXT_LANGUAGE_PREFIX_REGEX, '') : DEFAULT_LANGUAGE;
const language = fileType
? fileType.replace(CODE_BLOCK.TEXT_LANGUAGE_PREFIX_REGEX, '')
: CODE_BLOCK.DEFAULT_LANGUAGE;
return { fileName, language, lineRange };
}
@@ -1,4 +1,4 @@
import { FILE_PATH_SEPARATOR_REGEX, NEWLINE } from '$lib/constants/code';
import { FILE_PATH_SEPARATOR_REGEX, NEWLINE } from '$lib/constants';
import {
PREFIX_FILE,
PREFIX_MIME,
@@ -4,11 +4,7 @@
// result blob.
import { parseToolArgs } from './_shared';
import {
DEFAULT_LANGUAGE,
FILE_PATH_SEPARATOR_REGEX,
TEXT_LANGUAGE_PREFIX_REGEX
} from '$lib/constants';
import { CODE_BLOCK, FILE_PATH_SEPARATOR_REGEX } from '$lib/constants';
import { BuiltInTool } from '$lib/enums';
import { type AgenticSection, getFileTypeByExtension, tryParseToolResultObject } from '$lib/utils';
@@ -36,7 +32,8 @@ export function parseWriteFileMeta(section: AgenticSection): WriteFileMeta | nul
const fileName = rawPath.split(FILE_PATH_SEPARATOR_REGEX).pop() || rawPath;
const content = typeof args.content === 'string' ? args.content : '';
const language =
getFileTypeByExtension(rawPath)?.replace(TEXT_LANGUAGE_PREFIX_REGEX, '') ?? DEFAULT_LANGUAGE;
getFileTypeByExtension(rawPath)?.replace(CODE_BLOCK.TEXT_LANGUAGE_PREFIX_REGEX, '') ??
CODE_BLOCK.DEFAULT_LANGUAGE;
const resultObj = tryParseToolResultObject(section.toolResult);
const bytesWritten =
resultObj && Number.isFinite(Number(resultObj.bytes)) ? Number(resultObj.bytes) : undefined;
@@ -1,5 +1,5 @@
<script lang="ts">
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import type { Component, Snippet } from 'svelte';
interface Props {
@@ -1,7 +1,7 @@
<script lang="ts">
import { Lightbulb } from '@lucide/svelte';
import { CollapsibleContentBlock, MarkdownContent } from '$lib/components/app';
import { REASONING_SCROLL_AT_BOTTOM_THRESHOLD_PX } from '$lib/constants/auto-scroll';
import { REASONING_SCROLL_AT_BOTTOM_THRESHOLD_PX } from '$lib/constants';
import { AgenticSectionType } from '$lib/enums';
import { config } from '$lib/stores/settings.svelte';
import type { DatabaseMessageExtra } from '$lib/types';
@@ -1,7 +1,7 @@
<script lang="ts">
import { ArrowDown } from '@lucide/svelte';
import ActionIcon from '$lib/components/app/actions/ActionIcon.svelte';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
let { onclick }: { onclick: (e?: MouseEvent) => void } = $props();
</script>
@@ -1,7 +1,7 @@
<script lang="ts">
import { AlertTriangle, Loader2, RefreshCw } from '@lucide/svelte';
import * as Alert from '$lib/components/ui/alert';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { serverError, serverLoading, serverStatus, serverStore } from '$lib/stores/server.svelte';
let hasError = $derived(!!serverError());
@@ -2,7 +2,7 @@
import ChevronDown from '@lucide/svelte/icons/chevron-down';
import * as Collapsible from '$lib/components/ui/collapsible/index.js';
import { cn } from '$lib/components/ui/utils';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import type { Snippet } from 'svelte';
import type { Component } from 'svelte';
@@ -26,7 +26,7 @@
} from '$lib/components/app';
import {
BOOL_TRUE_STRING,
CODE_BLOCK_HEADER_CLASS,
CODE_BLOCK_CLASS,
DATA_ERROR_BOUND_ATTR,
DATA_ERROR_HANDLED_ATTR,
DIAGRAM_VIEW_MODE_ATTR,
@@ -39,15 +39,8 @@
MERMAID_SYNTAX_ATTR,
MERMAID_WRAPPER_CLASS,
SETTINGS_KEYS,
SVG_BLOCK_CLASS,
SVG_INLINE_SHADOW_STYLE,
SVG_LANGUAGE,
SVG_RENDERED_ATTR,
SVG_SOURCE_ATTR,
SVG_TAG_PREFIX,
SVG_WRAPPER_CLASS,
TOGGLE_SOURCE_BTN_CLASS,
XML_LANGUAGE
SVG,
TOGGLE_SOURCE_BTN_CLASS
} from '$lib/constants';
import { ColorMode, UrlProtocol } from '$lib/enums';
import { FileTypeText } from '$lib/enums/files.enums';
@@ -105,9 +98,9 @@
if (!block) return null;
if (block.language === SVG_LANGUAGE) return block.code;
if (block.language === SVG.LANGUAGE) return block.code;
if (block.language === XML_LANGUAGE && block.code.trimStart().startsWith(SVG_TAG_PREFIX))
if (block.language === SVG.XML_LANGUAGE && block.code.trimStart().startsWith(SVG.TAG_PREFIX))
return block.code;
return null;
@@ -137,7 +130,7 @@
// Mount the streaming svg into its shadow host on every chunk so it renders live
$effect(() => {
if (streamingSvgHost) mountSvgShadow(streamingSvgHost, liveSvgHtml, SVG_INLINE_SHADOW_STYLE);
if (streamingSvgHost) mountSvgShadow(streamingSvgHost, liveSvgHtml, SVG.INLINE_SHADOW_STYLE);
});
let streamingCodeScrollContainer = $state<HTMLDivElement>();
@@ -535,7 +528,7 @@
event.preventDefault();
event.stopPropagation();
const wrapper = toggleBtn.closest(`.${MERMAID_WRAPPER_CLASS}, .${SVG_WRAPPER_CLASS}`);
const wrapper = toggleBtn.closest(`.${MERMAID_WRAPPER_CLASS}, .${SVG.WRAPPER_CLASS}`);
if (!wrapper) return;
@@ -593,16 +586,16 @@
}
// Check if clicking on copy or preview button in svg block
const svgCopyBtn = target.closest(`.${SVG_WRAPPER_CLASS} .copy-code-btn`);
const svgPreviewBtn = target.closest(`.${SVG_WRAPPER_CLASS} .preview-code-btn`);
const svgCopyBtn = target.closest(`.${SVG.WRAPPER_CLASS} .copy-code-btn`);
const svgPreviewBtn = target.closest(`.${SVG.WRAPPER_CLASS} .preview-code-btn`);
if (svgCopyBtn || svgPreviewBtn) {
const wrapper = target.closest(`.${SVG_WRAPPER_CLASS}`);
const wrapper = target.closest(`.${SVG.WRAPPER_CLASS}`);
if (!wrapper) return;
const preElement = wrapper.querySelector<HTMLElement>(
`pre.${SVG_BLOCK_CLASS}[${SVG_SOURCE_ATTR}]`
`pre.${SVG.BLOCK_CLASS}[${SVG.SOURCE_ATTR}]`
);
if (!preElement) return;
@@ -611,7 +604,7 @@
event.preventDefault();
event.stopPropagation();
try {
await copyToClipboard(preElement.getAttribute(SVG_SOURCE_ATTR) ?? '');
await copyToClipboard(preElement.getAttribute(SVG.SOURCE_ATTR) ?? '');
} catch (error) {
console.error('Failed to copy svg source:', error);
}
@@ -622,7 +615,7 @@
if (svgPreviewBtn) {
event.preventDefault();
event.stopPropagation();
mermaidPreviewSvgHtml = sanitizeSvg(preElement.getAttribute(SVG_SOURCE_ATTR) ?? '');
mermaidPreviewSvgHtml = sanitizeSvg(preElement.getAttribute(SVG.SOURCE_ATTR) ?? '');
svgPreviewLive = false;
mermaidPreviewOpen = true;
@@ -633,14 +626,14 @@
// A click on the header chrome targets the action buttons, never the
// diagram. Guard so a header click can not fall through to the click to
// zoom branches below, whatever the scroll position or stacking.
if (target.closest(`.${CODE_BLOCK_HEADER_CLASS}`)) return;
if (target.closest(`.${CODE_BLOCK_CLASS.HEADER}`)) return;
// Open preview when clicking the svg block itself. A final block carries its
// source, a streaming block does not and is mirrored live into the dialog.
const svgEl = target.closest(`.${SVG_BLOCK_CLASS}`);
const svgEl = target.closest(`.${SVG.BLOCK_CLASS}`);
if (svgEl) {
const source = svgEl.getAttribute(SVG_SOURCE_ATTR);
const source = svgEl.getAttribute(SVG.SOURCE_ATTR);
if (source !== null) {
mermaidPreviewSvgHtml = sanitizeSvg(source);
@@ -739,15 +732,15 @@
if (!containerRef) return;
const nodes = containerRef.querySelectorAll<HTMLElement>(
`pre.${SVG_BLOCK_CLASS}:not([${SVG_RENDERED_ATTR}])`
`pre.${SVG.BLOCK_CLASS}:not([${SVG.RENDERED_ATTR}])`
);
if (nodes.length === 0) return;
nodes.forEach((node) => {
node.setAttribute(SVG_RENDERED_ATTR, 'true');
node.setAttribute(SVG.RENDERED_ATTR, 'true');
const source = node.getAttribute(SVG_SOURCE_ATTR) ?? node.textContent ?? '';
const source = node.getAttribute(SVG.SOURCE_ATTR) ?? node.textContent ?? '';
const clean = sanitizeSvg(source);
if (clean) {
@@ -755,7 +748,7 @@
const host = document.createElement('div');
node.appendChild(host);
mountSvgShadow(host, clean, SVG_INLINE_SHADOW_STYLE);
mountSvgShadow(host, clean, SVG.INLINE_SHADOW_STYLE);
}
});
}
@@ -919,7 +912,7 @@
</div>
{#if liveSvgHtml}
<div class="svg-scroll-container">
<div class={SVG_BLOCK_CLASS}>
<div class={SVG.BLOCK_CLASS}>
<div bind:this={streamingSvgHost}></div>
</div>
</div>
@@ -4,17 +4,11 @@
*/
import {
CODE_BLOCK_ACTIONS_CLASS,
CODE_BLOCK_HEADER_CLASS,
CODE_BLOCK_SCROLL_CONTAINER_CLASS,
CODE_BLOCK_CLASS,
CODE_ICON_SVG,
CODE_LANGUAGE_CLASS,
COPY_CODE_BTN_CLASS,
COPY_ICON_SVG,
DIAGRAM_SOURCE_CLASS,
PREVIEW_CODE_BTN_CLASS,
PREVIEW_ICON_SVG,
RELATIVE_CLASS,
TOGGLE_SOURCE_BTN_CLASS
} from '$lib/constants';
import type { Element, ElementContent } from 'hast';
@@ -65,7 +59,7 @@ export function createButton(
* Creates a copy button element.
*/
export function createCopyButton(id: string, idAttribute: string, title: string = 'Copy'): Element {
return createButton(COPY_CODE_BTN_CLASS, title, COPY_ICON_SVG, id, idAttribute);
return createButton(CODE_BLOCK_CLASS.COPY_BTN, title, COPY_ICON_SVG, id, idAttribute);
}
/**
@@ -76,7 +70,7 @@ export function createPreviewButton(
idAttribute: string,
title: string = 'Preview'
): Element {
return createButton(PREVIEW_CODE_BTN_CLASS, title, PREVIEW_ICON_SVG, id, idAttribute);
return createButton(CODE_BLOCK_CLASS.PREVIEW_BTN, title, PREVIEW_ICON_SVG, id, idAttribute);
}
/**
@@ -120,7 +114,7 @@ export function createSourceView(
type: 'element'
}
],
properties: { className: [DIAGRAM_SOURCE_CLASS, CODE_BLOCK_SCROLL_CONTAINER_CLASS] },
properties: { className: [DIAGRAM_SOURCE_CLASS, CODE_BLOCK_CLASS.SCROLL_CONTAINER] },
tagName: 'div',
type: 'element'
};
@@ -134,7 +128,7 @@ export function createBlockHeader(
id: string,
idAttribute: string,
actions: Element[],
languageClassName: string = CODE_LANGUAGE_CLASS
languageClassName: string = CODE_BLOCK_CLASS.LANGUAGE
): Element {
return {
children: [
@@ -146,12 +140,12 @@ export function createBlockHeader(
},
{
children: actions,
properties: { className: [CODE_BLOCK_ACTIONS_CLASS] },
properties: { className: [CODE_BLOCK_CLASS.ACTIONS] },
tagName: 'div',
type: 'element'
}
],
properties: { className: [CODE_BLOCK_HEADER_CLASS] },
properties: { className: [CODE_BLOCK_CLASS.HEADER] },
tagName: 'div',
type: 'element'
};
@@ -185,7 +179,7 @@ export function createWrapper(
return {
children: [header, createScrollContainer(preElement, scrollContainerClass), ...extraChildren],
properties: {
className: [wrapperClass, RELATIVE_CLASS],
className: [wrapperClass, CODE_BLOCK_CLASS.RELATIVE],
...additionalAttributes
} as Element['properties'],
tagName: 'div',
@@ -17,7 +17,7 @@ import {
createWrapper,
generateBlockId
} from './code-block-utils';
import { CODE_BLOCK_SCROLL_CONTAINER_CLASS, CODE_BLOCK_WRAPPER_CLASS } from '$lib/constants';
import { CODE_BLOCK_CLASS } from '$lib/constants';
import type { Element, ElementContent, Root } from 'hast';
import type { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
@@ -78,8 +78,8 @@ export const rehypeEnhanceCodeBlocks: Plugin<[], Root> = () => {
const wrapper = createWrapper(
header,
node,
CODE_BLOCK_WRAPPER_CLASS,
CODE_BLOCK_SCROLL_CONTAINER_CLASS
CODE_BLOCK_CLASS.WRAPPER,
CODE_BLOCK_CLASS.SCROLL_CONTAINER
);
// Replace pre with wrapper in parent
@@ -19,16 +19,7 @@ import {
generateBlockId
} from './code-block-utils';
import type { DiagramPreData } from './pre-transform';
import {
DIAGRAM_VIEW_MODE_ATTR,
DIAGRAM_VIEW_RENDERED,
SVG_BLOCK_CLASS,
SVG_ID_ATTR,
SVG_LANGUAGE,
SVG_SCROLL_CONTAINER_CLASS,
SVG_SOURCE_ATTR,
SVG_WRAPPER_CLASS
} from '$lib/constants';
import { DIAGRAM_VIEW_MODE_ATTR, DIAGRAM_VIEW_RENDERED, SVG } from '$lib/constants';
import type { Element, ElementContent, Root } from 'hast';
import type { Plugin } from 'unified';
import { visit } from 'unist-util-visit';
@@ -48,11 +39,11 @@ export const rehypeEnhanceSvgBlocks: Plugin<[], Root> = () => {
if (!Array.isArray(className)) return;
const isSvg = className.some((cls) => typeof cls === 'string' && cls === SVG_BLOCK_CLASS);
const isSvg = className.some((cls) => typeof cls === 'string' && cls === SVG.BLOCK_CLASS);
if (!isSvg) return;
const svgId = generateBlockId(SVG_LANGUAGE, 'idxSvgBlock');
const svgId = generateBlockId(SVG.LANGUAGE, 'idxSvgBlock');
// Extract the svg source (text content of the pre element)
const svgSource = node.children
.map((child) => {
@@ -65,26 +56,26 @@ export const rehypeEnhanceSvgBlocks: Plugin<[], Root> = () => {
// Store the svg source in data attribute for copy and render
node.properties = {
...node.properties,
[SVG_ID_ATTR]: svgId,
[SVG_SOURCE_ATTR]: svgSource
[SVG.ID_ATTR]: svgId,
[SVG.SOURCE_ATTR]: svgSource
};
const actions = [
createCopyButton(svgId, SVG_ID_ATTR, 'Copy svg source'),
createToggleSourceButton(svgId, SVG_ID_ATTR, 'Toggle svg source'),
createPreviewButton(svgId, SVG_ID_ATTR, 'Preview svg')
createCopyButton(svgId, SVG.ID_ATTR, 'Copy svg source'),
createToggleSourceButton(svgId, SVG.ID_ATTR, 'Toggle svg source'),
createPreviewButton(svgId, SVG.ID_ATTR, 'Preview svg')
];
const header = createBlockHeader(SVG_LANGUAGE, svgId, SVG_ID_ATTR, actions);
const header = createBlockHeader(SVG.LANGUAGE, svgId, SVG.ID_ATTR, actions);
const preservedCode = (node.data as DiagramPreData | undefined)?.sourceCode;
const sourceView = createSourceView(preservedCode, svgSource, SVG_LANGUAGE);
const sourceView = createSourceView(preservedCode, svgSource, SVG.LANGUAGE);
const wrapper = createWrapper(
header,
node,
SVG_WRAPPER_CLASS,
SVG_SCROLL_CONTAINER_CLASS,
SVG.WRAPPER_CLASS,
SVG.SCROLL_CONTAINER_CLASS,
{
[DIAGRAM_VIEW_MODE_ATTR]: DIAGRAM_VIEW_RENDERED,
[SVG_ID_ATTR]: svgId
[SVG.ID_ATTR]: svgId
},
[sourceView]
);
@@ -1,7 +1,7 @@
/**
* Rehype plugin that rewrites `file://` markdown anchors into the inline
* mention chip, sharing the class string with the contenteditable
* tokenizer via `$lib/constants/mention-badge`.
* tokenizer via `$lib/constants`.
*
* The chip is presentational: `file://` navigation is blocked from
* http(s) pages, so the anchor becomes a plain `<span>` (no link role,
@@ -1,5 +1,5 @@
import { createPreTransform } from './pre-transform';
import { SVG_BLOCK_CLASS, SVG_LANGUAGE, SVG_TAG_PREFIX, XML_LANGUAGE } from '$lib/constants';
import { SVG } from '$lib/constants';
/**
* Converts svg code blocks to <pre class="svg-block"> for client-side rendering.
@@ -7,7 +7,7 @@ import { SVG_BLOCK_CLASS, SVG_LANGUAGE, SVG_TAG_PREFIX, XML_LANGUAGE } from '$li
* svg inside an xml fence.
*/
export const rehypeSvgPre = createPreTransform(
[SVG_LANGUAGE, XML_LANGUAGE],
SVG_BLOCK_CLASS,
(text) => text.startsWith(SVG_TAG_PREFIX)
[SVG.LANGUAGE, SVG.XML_LANGUAGE],
SVG.BLOCK_CLASS,
(text) => text.startsWith(SVG.TAG_PREFIX)
);
@@ -1,6 +1,6 @@
<script lang="ts">
import MermaidPreviewControls from './MermaidPreviewControls.svelte';
import { SVG_DIALOG_SHADOW_STYLE } from '$lib/constants';
import { SVG } from '$lib/constants';
import { mountSvgShadow } from '$lib/utils/svg-shadow';
interface Props {
@@ -13,7 +13,7 @@
// Re-mount on every svgHtml change so a live streaming svg keeps rendering while zoomed
$effect(() => {
if (svgHost) mountSvgShadow(svgHost, svgHtml, SVG_DIALOG_SHADOW_STYLE);
if (svgHost) mountSvgShadow(svgHost, svgHtml, SVG.DIALOG_SHADOW_STYLE);
});
// Zoom and pan state
@@ -3,7 +3,7 @@
import RotateCcwIcon from '@lucide/svelte/icons/rotate-ccw';
import ZoomInIcon from '@lucide/svelte/icons/zoom-in';
import ZoomOutIcon from '@lucide/svelte/icons/zoom-out';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
interface Props {
scale: number;
@@ -1,6 +1,6 @@
<script lang="ts">
import { browser } from '$app/environment';
import { SYNTAX_CODE_SCROLL_AT_BOTTOM_THRESHOLD_PX } from '$lib/constants/auto-scroll';
import { SYNTAX_CODE_SCROLL_AT_BOTTOM_THRESHOLD_PX } from '$lib/constants';
import { ColorMode } from '$lib/enums';
import { highlightCode } from '$lib/utils';
import githubLightCss from 'highlight.js/styles/github.css?inline';
@@ -3,8 +3,8 @@
import { ActionIconCopyToClipboard, SyntaxHighlightedCode } from '$lib/components/app';
import { Button } from '$lib/components/ui/button';
import * as Dialog from '$lib/components/ui/dialog';
import { DEFAULT_RESOURCE_FILENAME } from '$lib/constants';
import { MimeTypeIncludes, MimeTypeText } from '$lib/enums';
import { DEFAULT_RESOURCE_FILENAME, MIME_TYPE_SUBSTRINGS } from '$lib/constants';
import { MimeTypeText } from '$lib/enums';
import { mcpStore } from '$lib/stores/mcp.svelte';
import type { DatabaseMessageExtraMcpResource } from '$lib/types';
import {
@@ -26,11 +26,13 @@
const favicon = $derived(mcpStore.getServerFavicon(extra.serverName));
function getLanguage(): string {
if (extra.mimeType?.includes(MimeTypeIncludes.JSON)) return MimeTypeIncludes.JSON;
if (extra.mimeType?.includes(MIME_TYPE_SUBSTRINGS.JSON)) return MIME_TYPE_SUBSTRINGS.JSON;
if (extra.mimeType?.includes(MimeTypeIncludes.JAVASCRIPT)) return MimeTypeIncludes.JAVASCRIPT;
if (extra.mimeType?.includes(MIME_TYPE_SUBSTRINGS.JAVASCRIPT))
return MIME_TYPE_SUBSTRINGS.JAVASCRIPT;
if (extra.mimeType?.includes(MimeTypeIncludes.TYPESCRIPT)) return MimeTypeIncludes.TYPESCRIPT;
if (extra.mimeType?.includes(MIME_TYPE_SUBSTRINGS.TYPESCRIPT))
return MIME_TYPE_SUBSTRINGS.TYPESCRIPT;
const name = extra.name || extra.uri || '';
@@ -7,7 +7,7 @@
} from '$lib/components/app';
import { Button } from '$lib/components/ui/button';
import * as Dialog from '$lib/components/ui/dialog';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { conversationsStore } from '$lib/stores/conversations.svelte';
import { mcpStore } from '$lib/stores/mcp.svelte';
import {
@@ -4,13 +4,12 @@
import { Button } from '$lib/components/ui/button';
import * as Dialog from '$lib/components/ui/dialog';
import {
BEARER_PREFIX,
BOOL_FALSE_STRING,
BOOL_TRUE_STRING,
DISMISSED_RECOMMENDED_MCP_SERVERS_LOCALSTORAGE_KEY,
HEADERS,
MCP_SERVER_ID_PREFIX,
RECOMMENDED_MCP_SERVERS,
REDACTED_HEADERS
RECOMMENDED_MCP_SERVERS
} from '$lib/constants';
import { HealthCheckStatus } from '$lib/enums';
import { conversationsStore } from '$lib/stores/conversations.svelte';
@@ -61,10 +60,10 @@
let bearerTokenFilled = $derived.by(() => {
const pairs = parseHeadersToArray(newServerHeaders);
const bearerPrefix = BEARER_PREFIX.toLowerCase();
const bearerPrefix = HEADERS.BEARER.toLowerCase();
const bearer = pairs.find(
(p) =>
REDACTED_HEADERS.has(p.key.trim().toLowerCase()) &&
HEADERS.REDACTED.has(p.key.trim().toLowerCase()) &&
p.value.trim().toLowerCase().startsWith(bearerPrefix)
);
@@ -3,8 +3,7 @@
import { goto } from '$app/navigation';
import { page } from '$app/state';
import * as AlertDialog from '$lib/components/ui/alert-dialog';
import { URL_PARAMS } from '$lib/constants';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT, URL_PARAMS } from '$lib/constants';
interface Props {
open: boolean;
@@ -1,7 +1,7 @@
<script lang="ts">
import { Search, X } from '@lucide/svelte';
import { Input } from '$lib/components/ui/input';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
interface Props {
autofocus?: boolean;
@@ -1,8 +1,7 @@
<script lang="ts">
import McpLogo from './McpLogo.svelte';
import * as Tooltip from '$lib/components/ui/tooltip';
import { MAX_DISPLAYED_MCP_AVATARS } from '$lib/constants';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT, MAX_DISPLAYED_MCP_AVATARS } from '$lib/constants';
import { HealthCheckStatus } from '$lib/enums';
import { conversationsStore } from '$lib/stores/conversations.svelte';
import { mcpStore } from '$lib/stores/mcp.svelte';
@@ -2,7 +2,7 @@
import { AlertCircle, Download, FileText, Loader2 } from '@lucide/svelte';
import { ActionIconCopyToClipboard } from '$lib/components/app';
import { Button } from '$lib/components/ui/button';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { MimeTypeApplication, MimeTypeText } from '$lib/enums';
import { mcpStore } from '$lib/stores/mcp.svelte';
import type { MCPResourceContent, MCPResourceInfo } from '$lib/types';
@@ -2,7 +2,7 @@
import { Loader2, RefreshCw } from '@lucide/svelte';
import { SearchInput } from '$lib/components/app/forms';
import { Button } from '$lib/components/ui/button';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
interface Props {
isLoading: boolean;
@@ -9,7 +9,7 @@
import { McpServerIdentity } from '$lib/components/app/mcp';
import { Checkbox } from '$lib/components/ui/checkbox';
import * as Collapsible from '$lib/components/ui/collapsible';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { mcpStore } from '$lib/stores/mcp.svelte';
import type { MCPResourceInfo, MCPResourceTemplateInfo, MCPServerResources } from '$lib/types';
import { getDisplayName, getResourceIcon } from '$lib/utils';
@@ -10,7 +10,7 @@
} from '$lib/components/app/mcp';
import * as Card from '$lib/components/ui/card';
import { Skeleton } from '$lib/components/ui/skeleton';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { HealthCheckStatus } from '$lib/enums';
import { mcpStore } from '$lib/stores/mcp.svelte';
import type { HealthCheckState, MCPServerSettingsEntry } from '$lib/types';
@@ -2,13 +2,7 @@
import { KeyValuePairs } from '$lib/components/app';
import { Input } from '$lib/components/ui/input';
import { Switch } from '$lib/components/ui/switch';
import {
AUTHORIZATION_HEADER,
BEARER_PREFIX,
CLI_FLAGS,
MCP_SERVER_URL_PLACEHOLDER,
REDACTED_HEADERS
} from '$lib/constants';
import { CLI_FLAGS, HEADERS, MCP_SERVER_URL_PLACEHOLDER } from '$lib/constants';
import { UrlProtocol } from '$lib/enums';
import { mcpStore } from '$lib/stores/mcp.svelte';
import type { KeyValuePair } from '$lib/types';
@@ -72,10 +66,10 @@
// carry a Bearer scheme. Anything else (e.g. Basic, raw tokens) stays in the
// KV section so the user can still edit those values verbatim.
const matchesAuthorizationKey = (key: string): boolean =>
REDACTED_HEADERS.has(key.trim().toLowerCase());
HEADERS.REDACTED.has(key.trim().toLowerCase());
const isBearerScheme = (value: string): boolean =>
value.trim().toLowerCase().startsWith(BEARER_PREFIX.toLowerCase());
value.trim().toLowerCase().startsWith(HEADERS.BEARER.toLowerCase());
const ownedByBearerUi = (p: KeyValuePair): boolean =>
matchesAuthorizationKey(p.key) && isBearerScheme(p.value);
@@ -102,7 +96,7 @@
if (!auth) return '';
return auth.value.trim().slice(BEARER_PREFIX.length).trim();
return auth.value.trim().slice(HEADERS.BEARER.length).trim();
});
$effect(() => {
@@ -125,7 +119,7 @@
const trimmed = token.trim();
if (trimmed) {
filtered.push({ key: AUTHORIZATION_HEADER, value: `${BEARER_PREFIX}${trimmed}` });
filtered.push({ key: HEADERS.AUTHORIZATION, value: `${HEADERS.BEARER}${trimmed}` });
}
updateHeaderPairs(filtered);
@@ -1,6 +1,6 @@
<script lang="ts">
import { ChevronLeft, ChevronRight } from '@lucide/svelte';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import type { Snippet } from 'svelte';
interface Props {
@@ -11,7 +11,7 @@
RotateCw
} from '@lucide/svelte';
import { ActionIcon, ModelId } from '$lib/components/app';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { ServerModelStatus } from '$lib/enums';
import { modelsStore, routerModels } from '$lib/stores/models.svelte';
import type { ModelOption } from '$lib/types/models';
@@ -5,12 +5,12 @@
import { ActionIcon, KeyboardShortcutInfo, SearchInput } from '$lib/components/app';
import { Button } from '$lib/components/ui/button';
import {
ICON_CLASS_DEFAULT,
ICON_STRIP_TRANSITION_DELAY_MULTIPLIER,
ICON_STRIP_TRANSITION_DURATION,
ROUTES,
SIDEBAR_ACTIONS_ITEMS
} from '$lib/constants';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { TooltipSide } from '$lib/enums';
import { isMobile } from '$lib/stores/viewport.svelte';
import type { Component } from 'svelte';
@@ -15,8 +15,7 @@
import { TruncatedText } from '$lib/components/app';
import { Checkbox } from '$lib/components/ui/checkbox';
import * as Tooltip from '$lib/components/ui/tooltip';
import { FORK_TREE_DEPTH_PADDING } from '$lib/constants';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { FORK_TREE_DEPTH_PADDING, ICON_CLASS_DEFAULT } from '$lib/constants';
import { RouterService } from '$lib/services/router.service';
import { getAllLoadingChats } from '$lib/stores/chat.svelte';
import { conversationsStore } from '$lib/stores/conversations.svelte';
@@ -5,9 +5,7 @@
import { Button } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import Label from '$lib/components/ui/label/label.svelte';
import { AUTHORIZATION_HEADER, BEARER_PREFIX, SETTINGS_KEYS } from '$lib/constants';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ROUTES } from '$lib/constants/routes';
import { HEADERS, ICON_CLASS_DEFAULT, ROUTES, SETTINGS_KEYS } from '$lib/constants';
import { KeyboardKey } from '$lib/enums';
import { serverLoading, serverStore } from '$lib/stores/server.svelte';
import { config, settingsStore } from '$lib/stores/settings.svelte';
@@ -72,8 +70,8 @@
// Test the API key by making a real request to the server
const response = await fetch(`${base}/props`, {
headers: {
[AUTHORIZATION_HEADER]: `${BEARER_PREFIX}${apiKeyInput.trim()}`,
'Content-Type': 'application/json'
'Content-Type': 'application/json',
[HEADERS.AUTHORIZATION]: `${HEADERS.BEARER}${apiKeyInput.trim()}`
}
});
@@ -2,7 +2,7 @@
import { AlertTriangle, Server } from '@lucide/svelte';
import { Badge } from '$lib/components/ui/badge';
import { Button } from '$lib/components/ui/button';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { singleModelName } from '$lib/stores/models.svelte';
import { serverError, serverLoading, serverProps } from '$lib/stores/server.svelte';
@@ -7,8 +7,7 @@
import * as RadioGroup from '$lib/components/ui/radio-group';
import * as Select from '$lib/components/ui/select';
import { Textarea } from '$lib/components/ui/textarea';
import { SETTING_CONFIG_INFO, SETTINGS_KEYS } from '$lib/constants';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT, SETTING_CONFIG_INFO, SETTINGS_KEYS } from '$lib/constants';
import { SettingsFieldType } from '$lib/enums/settings.enums';
import { modelsStore, propsCacheVersion, selectedModelName } from '$lib/stores/models.svelte';
import { serverStore } from '$lib/stores/server.svelte';
@@ -1,6 +1,6 @@
<script lang="ts">
import { Button, type ButtonVariant } from '$lib/components/ui/button';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import type { Component } from 'svelte';
let {
@@ -3,12 +3,12 @@
import { McpServerIdentity, TruncatedText } from '$lib/components/app';
import { Checkbox } from '$lib/components/ui/checkbox';
import * as Collapsible from '$lib/components/ui/collapsible';
import { getBuiltinToolUi } from '$lib/constants/built-in-tools';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { ToolSource } from '$lib/enums/tools.enums';
import { mcpStore } from '$lib/stores/mcp.svelte';
import { permissionsStore } from '$lib/stores/permissions.svelte';
import { toolsStore } from '$lib/stores/tools.svelte';
import { getBuiltinToolUi } from '$lib/utils';
import { SvelteSet } from 'svelte/reactivity';
let expandedGroups = new SvelteSet<string>();
@@ -1,6 +1,6 @@
<script lang="ts">
import { Settings } from '@lucide/svelte';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import type { SettingsSection, SettingsSectionTitle } from '$lib/types';
interface Props {
@@ -1,6 +1,6 @@
<script lang="ts">
import { ChevronLeft, ChevronRight, Settings } from '@lucide/svelte';
import { ICON_CLASS_DEFAULT } from '$lib/constants/css-classes';
import { ICON_CLASS_DEFAULT } from '$lib/constants';
import { useScrollCarousel } from '$lib/hooks/use-scroll-carousel.svelte';
import type { SettingsSection, SettingsSectionTitle } from '$lib/types';
import { onMount, tick } from 'svelte';