diff --git a/frontend/src/lib/actions/triggerableByAI.ts b/frontend/src/lib/actions/triggerableByAI.svelte.ts similarity index 86% rename from frontend/src/lib/actions/triggerableByAI.ts rename to frontend/src/lib/actions/triggerableByAI.svelte.ts index 09b4d9ce9e..5fd9950067 100644 --- a/frontend/src/lib/actions/triggerableByAI.ts +++ b/frontend/src/lib/actions/triggerableByAI.svelte.ts @@ -1,4 +1,4 @@ -import { aiChatManager } from '$lib/components/copilot/chat/AIChatManager.svelte' +import { triggerablesByAi } from '$lib/components/copilot/chat/sharedChatState.svelte' export interface TriggerableByAIOptions { id?: string @@ -60,15 +60,15 @@ export function triggerableByAI(element: HTMLElement, options: TriggerableByAIOp // register the triggerable const currentData = { description, onTrigger: handleTrigger } - aiChatManager.triggerablesByAI[id] = currentData + triggerablesByAi[id] = currentData } function unregister() { if (isDisabled || !id) return // unregister the triggerable - if (aiChatManager.triggerablesByAI[id]) { - delete aiChatManager.triggerablesByAI[id] + if (triggerablesByAi[id]) { + delete triggerablesByAi[id] } } @@ -77,7 +77,7 @@ export function triggerableByAI(element: HTMLElement, options: TriggerableByAIOp return { update(newOptions: TriggerableByAIOptions) { - ;({ id, description, callback, showAnimation = true } = newOptions) + ; ({ id, description, callback, showAnimation = true } = newOptions) register() }, destroy() { diff --git a/frontend/src/lib/components/ArgTest.svelte b/frontend/src/lib/components/ArgTest.svelte new file mode 100644 index 0000000000..7025dd50ab --- /dev/null +++ b/frontend/src/lib/components/ArgTest.svelte @@ -0,0 +1,8 @@ + diff --git a/frontend/src/lib/components/DisplayResult.svelte b/frontend/src/lib/components/DisplayResult.svelte index 5df3253b0a..ae6bab9fce 100644 --- a/frontend/src/lib/components/DisplayResult.svelte +++ b/frontend/src/lib/components/DisplayResult.svelte @@ -13,7 +13,8 @@ Table2, Braces, Highlighter, - ArrowDownFromLine + ArrowDownFromLine, + Loader2 } from 'lucide-svelte' import Portal from '$lib/components/Portal.svelte' import DisplayResultControlBar from './DisplayResultControlBar.svelte' @@ -34,7 +35,6 @@ import { convertJsonToCsv } from './table/tableUtils' import Tooltip from './Tooltip.svelte' import HighlightTheme from './HighlightTheme.svelte' - import PdfViewer from './display/PdfViewer.svelte' import type { DisplayResultUi } from './custom_ui' import { getContext, hasContext, createEventDispatcher, onDestroy } from 'svelte' import { toJsonStr } from '$lib/utils' @@ -634,10 +634,14 @@ {:else if !forceJson && resultKind === 'pdf'}
- + {#await import('$lib/components/display/PdfViewer.svelte')} + + {:then Module} + + {/await}
{:else if !forceJson && resultKind === 'plain'}
 							{:else if result?.s3?.endsWith('.pdf')}
 								
- + {#await import('$lib/components/display/PdfViewer.svelte')} + + {:then Module} + + {/await}
{/if} {/if} @@ -893,12 +901,16 @@ {/if} {:else if s3object?.s3?.endsWith('.pdf')}
- + {#await import('$lib/components/display/PdfViewer.svelte')} + + {:then Module} + + {/await}
{/if} {/each} diff --git a/frontend/src/lib/components/DropdownV2.svelte b/frontend/src/lib/components/DropdownV2.svelte index a0ffa86fcb..9415635bab 100644 --- a/frontend/src/lib/components/DropdownV2.svelte +++ b/frontend/src/lib/components/DropdownV2.svelte @@ -16,7 +16,7 @@ import ResolveOpen from '$lib/components/common/menu/ResolveOpen.svelte' import Button from '$lib/components/common/button/Button.svelte' import { twMerge } from 'tailwind-merge' - import { triggerableByAI } from '$lib/actions/triggerableByAI' + import { triggerableByAI } from '$lib/actions/triggerableByAI.svelte' import { untrack } from 'svelte' interface Props { diff --git a/frontend/src/lib/components/DropdownV2Inner.svelte b/frontend/src/lib/components/DropdownV2Inner.svelte index b11c9623ab..c8236eed5f 100644 --- a/frontend/src/lib/components/DropdownV2Inner.svelte +++ b/frontend/src/lib/components/DropdownV2Inner.svelte @@ -1,5 +1,5 @@ @@ -13,24 +27,24 @@ class={'bg-surface py-3 ' + (stickToTop ? 'lg:sticky lg:top-0 z-[500] border-b border-gray-200 border-opacity-0 duration-300 ' + - (scrollY >= 30 ? 'border-opacity-100 ' : '') + (scrollY >= 30 ? 'border-opacity-100 ' : '') : '') + - ($$props.class || '')} + (clazz || '')} >
- {#if $$slots.left} - + {#if left} + {@render left?.()} {/if}
- {#if $$slots.middle} - + {#if middle} + {@render middle?.()} {/if}
- {#if $$slots.right} - + {#if right} + {@render right?.()} {/if}
diff --git a/frontend/src/lib/components/common/button/Button.svelte b/frontend/src/lib/components/common/button/Button.svelte index 0a0940bc4b..4d861be88f 100644 --- a/frontend/src/lib/components/common/button/Button.svelte +++ b/frontend/src/lib/components/common/button/Button.svelte @@ -12,7 +12,7 @@ import type { Placement } from '@floating-ui/core' import { conditionalMelt } from '$lib/utils' import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted' - import { triggerableByAI } from '$lib/actions/triggerableByAI' + import { triggerableByAI } from '$lib/actions/triggerableByAI.svelte' type MenuItem = { label: string diff --git a/frontend/src/lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte b/frontend/src/lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte index c8d73358bb..67e5701317 100644 --- a/frontend/src/lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte +++ b/frontend/src/lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte @@ -12,7 +12,7 @@ } from '$lib/utils' import { page } from '$app/stores' import type { GetInitialAndModifiedValues } from './unsavedTypes' - import { triggerableByAI } from '$lib/actions/triggerableByAI' + import { triggerableByAI } from '$lib/actions/triggerableByAI.svelte' export let getInitialAndModifiedValues: GetInitialAndModifiedValues = undefined export let diffDrawer: DiffDrawer | undefined = undefined @@ -69,7 +69,13 @@ {#if open} -
+
{/if} + } - let disposable: Disposable | undefined = undefined + let { + open = $bindable(false), + duration = 0.3, + placement = 'right', + size = '600px', + alwaysOpen = false, + shouldUsePortal = true, + offset = 0, + preventEscape = false, + disableChatOffset = false, + class: clazz = '', + positionClass = undefined, + children + }: Props = $props() - $: durationMs = duration * 1000 + let disposable: Disposable | undefined = $state(undefined) + + let durationMs = $derived(duration * 1000) export function toggleDrawer() { disposable?.toggleDrawer() @@ -42,7 +62,7 @@ let mounted = false const dispatch = createEventDispatcher() - $: style = `--duration: ${duration}s; --size: ${size};` + let style = $derived(`--duration: ${duration}s; --size: ${size};`) function scrollLock(open: boolean) { if (BROWSER) { @@ -54,45 +74,55 @@ } } - $: scrollLock(open) + $effect(() => { + scrollLock(open) + }) - $: open ? openDrawer() : closeDrawer() + $effect(() => { + open ? openDrawer() : closeDrawer() + }) - let timeout = true - $: !open ? setTimeout(() => (timeout = true), durationMs) : (timeout = false) + let timeout = $state(true) + $effect(() => { + !open ? setTimeout(() => (timeout = true), durationMs) : (timeout = false) + }) onMount(() => { mounted = true }) + + const children_render = $derived(children) + const aiChatOpen = $derived(chatState.size > 0) - + {#snippet children({ handleClickAway, zIndex })} + + {/snippet} diff --git a/frontend/src/lib/components/common/drawer/DrawerContent.svelte b/frontend/src/lib/components/common/drawer/DrawerContent.svelte index 38826e8515..f3c05b08c9 100644 --- a/frontend/src/lib/components/common/drawer/DrawerContent.svelte +++ b/frontend/src/lib/components/common/drawer/DrawerContent.svelte @@ -2,7 +2,7 @@ import Tooltip from '$lib/components/Tooltip.svelte' import { classNames } from '$lib/utils' import CloseButton from '../CloseButton.svelte' - import { triggerableByAI } from '$lib/actions/triggerableByAI' + import { triggerableByAI } from '$lib/actions/triggerableByAI.svelte' import { createEventDispatcher } from 'svelte' interface Props { diff --git a/frontend/src/lib/components/common/table/Row.svelte b/frontend/src/lib/components/common/table/Row.svelte index 293f3ff65f..43b51917a3 100644 --- a/frontend/src/lib/components/common/table/Row.svelte +++ b/frontend/src/lib/components/common/table/Row.svelte @@ -5,7 +5,7 @@ import { BellOff } from 'lucide-svelte' import { twMerge } from 'tailwind-merge' import { goto } from '$lib/navigation' - import { triggerableByAI } from '$lib/actions/triggerableByAI' + import { triggerableByAI } from '$lib/actions/triggerableByAI.svelte' const dispatch = createEventDispatcher() diff --git a/frontend/src/lib/components/common/tabs/Tab.svelte b/frontend/src/lib/components/common/tabs/Tab.svelte index 8d433f7ea1..30b22abeb9 100644 --- a/frontend/src/lib/components/common/tabs/Tab.svelte +++ b/frontend/src/lib/components/common/tabs/Tab.svelte @@ -2,7 +2,7 @@ import type { TabsContext } from '$lib/components/apps/editor/settingsPanel/inputEditor/tabs.svelte' import { createEventDispatcher, getContext } from 'svelte' import { twMerge } from 'tailwind-merge' - import { triggerableByAI } from '$lib/actions/triggerableByAI' + import { triggerableByAI } from '$lib/actions/triggerableByAI.svelte' const dispatch = createEventDispatcher<{ onpointerdown: any }>() diff --git a/frontend/src/lib/components/copilot/MetadataGen.svelte b/frontend/src/lib/components/copilot/MetadataGen.svelte index a68fdc494d..bd47e28e0c 100644 --- a/frontend/src/lib/components/copilot/MetadataGen.svelte +++ b/frontend/src/lib/components/copilot/MetadataGen.svelte @@ -11,7 +11,7 @@ import { yamlStringifyExceptKeys } from './utils' import type { ChatCompletionMessageParam } from 'openai/resources/index.mjs' import { createDispatcherIfMounted } from '$lib/createDispatcherIfMounted' - import { triggerableByAI } from '$lib/actions/triggerableByAI' + import { triggerableByAI } from '$lib/actions/triggerableByAI.svelte' type PromptConfig = { system: string @@ -234,72 +234,70 @@ Generate a description for the flow below: } }} > -
- {#if active} - 0 - ? 'bg-green-100 text-green-800 dark:text-green-400 dark:bg-green-700' - : '' - )} - > - - {#if loading} - ESC - {:else} - TAB - {/if} - {#if loading} - - {:else if generatedContent} - - {:else} - - {/if} - +
+ {#if active} + 0 + ? 'bg-green-100 text-green-800 dark:text-green-400 dark:bg-green-700' + : '' + )} + > + + {#if loading} + ESC + {:else} + TAB + {/if} + {#if loading} + + {:else if generatedContent} + + {:else} + + {/if} -
- {generatedContent} -
- {/if} -
- {#if elementType === 'textarea'} -
-
GH Markdown
- + +
+ {generatedContent}
- {:else} - + {#if elementType === 'textarea'} +
+
GH Markdown
+ +
+ {:else} + (focused = true)} + on:blur={() => (focused = false)} + /> + {/if}
diff --git a/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts b/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts index 23e978896b..2480304522 100644 --- a/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts +++ b/frontend/src/lib/components/copilot/chat/AIChatManager.svelte.ts @@ -30,14 +30,8 @@ import type { CurrentEditor, ExtendedOpenFlow } from '$lib/components/flows/type import { untrack } from 'svelte' import type { DBSchemas } from '$lib/stores' import { askTools, prepareAskSystemMessage } from './ask/core' +import { chatState, DEFAULT_SIZE, triggerablesByAi } from './sharedChatState.svelte' -type TriggerablesMap = Record< - string, - { - description: string - onTrigger: ((value?: string) => void) | undefined - } -> export enum AIMode { SCRIPT = 'script', @@ -47,7 +41,6 @@ export enum AIMode { } class AIChatManager { - DEFAULT_SIZE = 22 NAVIGATION_SYSTEM_PROMPT = ` CONSIDERATIONS: - You are provided with a tool to switch to navigation mode, only use it when you are sure that the user is asking you to navigate the application, help them find something or fetch data from the API. Do not use it otherwise. @@ -57,8 +50,7 @@ class AIChatManager { abortController: AbortController | undefined = undefined mode = $state(AIMode.NAVIGATOR) - size = $state(localStorage.getItem('ai-chat-open') === 'true' ? this.DEFAULT_SIZE : 0) - readonly isOpen = $derived(this.size > 0) + readonly isOpen = $derived(chatState.size > 0) savedSize = $state(0) instructions = $state('') pendingPrompt = $state('') @@ -74,7 +66,6 @@ class AIChatManager { tools = $state[]>([]) helpers = $state(undefined) - triggerablesByAI = $state({}) scriptEditorOptions = $state(undefined) scriptEditorApplyCode = $state<((code: string) => void) | undefined>(undefined) scriptEditorShowDiffMode = $state<(() => void) | undefined>(undefined) @@ -89,7 +80,7 @@ class AIChatManager { ask: true }) - open = $derived(this.size > 0) + open = $derived(chatState.size > 0) async loadApiTools() { if (this.apiTools.length === 0) { @@ -129,7 +120,7 @@ class AIChatManager { getLang: () => lang } if (options?.closeScriptSettings) { - const closeComponent = this.triggerablesByAI['close-script-builder-settings'] + const closeComponent = triggerablesByAi['close-script-builder-settings'] if (closeComponent) { closeComponent.onTrigger?.() } @@ -188,22 +179,22 @@ class AIChatManager { } openChat = () => { - this.size = this.savedSize > 0 ? this.savedSize : this.DEFAULT_SIZE + chatState.size = this.savedSize > 0 ? this.savedSize : DEFAULT_SIZE localStorage.setItem('ai-chat-open', 'true') } closeChat = () => { - this.savedSize = this.size - this.size = 0 + this.savedSize = chatState.size + chatState.size = 0 localStorage.setItem('ai-chat-open', 'false') } toggleOpen = () => { - if (this.size > 0) { - this.savedSize = this.size + if (chatState.size > 0) { + this.savedSize = chatState.size } - this.size = this.size === 0 ? (this.savedSize > 0 ? this.savedSize : this.DEFAULT_SIZE) : 0 - localStorage.setItem('ai-chat-open', this.size === 0 ? 'false' : 'true') + chatState.size = chatState.size === 0 ? (this.savedSize > 0 ? this.savedSize : DEFAULT_SIZE) : 0 + localStorage.setItem('ai-chat-open', chatState.size === 0 ? 'false' : 'true') } askAi = ( @@ -432,8 +423,8 @@ class AIChatManager { : this.mode === AIMode.NAVIGATOR ? prepareNavigatorUserMessage(oldInstructions) : await prepareScriptUserMessage(oldInstructions, lang, oldSelectedContext, { - isPreprocessor - }) + isPreprocessor + }) this.messages.push(userMessage) await this.historyManager.saveChat(this.displayMessages, this.messages) @@ -503,7 +494,7 @@ class AIChatManager { restartLastGeneration = (displayMessageIndex: number) => { const userMessage = this.displayMessages[displayMessageIndex] - + if (!userMessage || userMessage.role !== 'user') { throw new Error('No user message found at the specified index') } @@ -657,15 +648,15 @@ class AIChatManager { const editorRelated = currentEditor && currentEditor.type === 'script' && currentEditor.stepId === module.id ? { - diffMode: currentEditor.diffMode, - lastDeployedCode: currentEditor.lastDeployedCode, - lastSavedCode: undefined - } + diffMode: currentEditor.diffMode, + lastDeployedCode: currentEditor.lastDeployedCode, + lastSavedCode: undefined + } : { - diffMode: false, - lastDeployedCode: undefined, - lastSavedCode: undefined - } + diffMode: false, + lastDeployedCode: undefined, + lastSavedCode: undefined + } return { args: moduleState?.previewArgs ?? {}, diff --git a/frontend/src/lib/components/copilot/chat/ContextManager.svelte.ts b/frontend/src/lib/components/copilot/chat/ContextManager.svelte.ts index ad89b9b672..a7eb958fca 100644 --- a/frontend/src/lib/components/copilot/chat/ContextManager.svelte.ts +++ b/frontend/src/lib/components/copilot/chat/ContextManager.svelte.ts @@ -1,4 +1,3 @@ -import { langToExt } from '$lib/editorUtils' import { ResourceService, type ListResourceResponse, type ScriptLang } from '$lib/gen' import { scriptLangToEditorLang } from '$lib/scripts' import { SQLSchemaLanguages, type DBSchemas } from '$lib/stores' @@ -6,6 +5,7 @@ import { diffLines } from 'diff' import type { ContextElement } from './context' import type { DisplayMessage } from './shared' +import { langToExt } from '$lib/editorLangUtils' export interface ScriptOptions { lang: ScriptLang | 'bunnative' @@ -160,15 +160,15 @@ export default class ContextManager { .map((c) => c.type === 'code' ? { - ...c, - content: scriptOptions.code, - title: this.getContextCodePath(scriptOptions) - } + ...c, + content: scriptOptions.code, + title: this.getContextCodePath(scriptOptions) + } : c.type === 'db' && dbSchemas[c.title] ? { - ...c, - schema: dbSchemas[c.title] - } + ...c, + schema: dbSchemas[c.title] + } : c ) @@ -234,14 +234,14 @@ export default class ContextManager { ...(options.withCode === false ? [] : [codeContext]), ...(options.withDiff ? [ - { - type: 'diff' as const, - title: 'diff_with_last_deployed_version', - content: this.scriptOptions.lastDeployedCode ?? '', - diff: diffLines(this.scriptOptions.lastDeployedCode ?? '', this.scriptOptions.code), - lang: this.scriptOptions.lang - } - ] + { + type: 'diff' as const, + title: 'diff_with_last_deployed_version', + content: this.scriptOptions.lastDeployedCode ?? '', + diff: diffLines(this.scriptOptions.lastDeployedCode ?? '', this.scriptOptions.code), + lang: this.scriptOptions.lang + } + ] : []) ] } @@ -268,14 +268,14 @@ export default class ContextManager { contextElements: m.role !== 'tool' && m.contextElements ? m.contextElements.map((c) => - c.type === 'db' - ? { - type: 'db', - title: c.title, - schema: dbSchemas[c.title] - } - : c - ) + c.type === 'db' + ? { + type: 'db', + title: c.title, + schema: dbSchemas[c.title] + } + : c + ) : undefined })) } diff --git a/frontend/src/lib/components/copilot/chat/HistoryManager.svelte.ts b/frontend/src/lib/components/copilot/chat/HistoryManager.svelte.ts index da08cd4ae9..d4396e0ea6 100644 --- a/frontend/src/lib/components/copilot/chat/HistoryManager.svelte.ts +++ b/frontend/src/lib/components/copilot/chat/HistoryManager.svelte.ts @@ -1,6 +1,6 @@ import { openDB, type DBSchema as IDBSchema, type IDBPDatabase } from 'idb' import type { DisplayMessage } from './shared' -import { createLongHash } from '$lib/editorUtils' +import { createLongHash } from '$lib/editorLangUtils' import type { ChatCompletionMessageParam } from 'openai/resources/index.mjs' interface ChatSchema extends IDBSchema { chats: { diff --git a/frontend/src/lib/components/copilot/chat/flow/ModuleAcceptReject.svelte b/frontend/src/lib/components/copilot/chat/flow/ModuleAcceptReject.svelte index 3bc0c4dc88..0f92e60da1 100644 --- a/frontend/src/lib/components/copilot/chat/flow/ModuleAcceptReject.svelte +++ b/frontend/src/lib/components/copilot/chat/flow/ModuleAcceptReject.svelte @@ -3,19 +3,6 @@ if (!id) return undefined return aiChatManager.flowAiChatHelpers?.getModuleAction(id) } - - export function aiModuleActionToBgColor(action: AIModuleAction | undefined) { - switch (action) { - case 'modified': - return '!bg-orange-200 dark:!bg-orange-800' - case 'added': - return '!bg-green-200 dark:!bg-green-800' - case 'removed': - return '!bg-red-200/50 dark:!bg-red-800/50' - default: - return '' - } - }