mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-11 08:07:15 +00:00
* add toggle option + chat interface * backend impl * draft * put info in schema * Revert "backend impl" This reverts commit c534eeb49986424e2c12e2c5642be4e17ba380d1. * chat interface in flow input * cleaning * add logic for running flow + styling * handle historic args * fix frontend changes * add tables * add conv list * add endpoints * adapt frontend * list message logic * save message in db * save response in db * cleaning * better migrations * refresh on new conv * better logic for messages * nit * genere conversation uuid from frontend * store chat mode info in flow status * better ui for chat * collapse chat * ui * infinite scroll on convs * infinite scroll on messages * fix ui * new chat entry on new * cleaning * change setting logic * fix test logic from flow input * move toggle to input * add warning modal when enabling chat mode * add summary and explanation on inline script * add hint for chat mode on user_message desc * show chat message instead of input in graph * add warning for triggers * one logo when not expanded * use infinitelist for conversations * add warning when deployment in progress * full width button * better icon for menu * better input + nits * put toggle in action * use waitjob * cleaning * cleaning * scroll on new + cleaning * use enum * fix logic * full screen * cleaning * exit on updatesqlx error * Update SQLx metadata * fix * cleaning * add for wait result endpoint * add missing drop * delete cascade * fix: use macro version of query_as in flow_conversations.rs Use sqlx::query_as! macro instead of query_as function for compile-time SQL validation and better type safety Co-authored-by: centdix <centdix@users.noreply.github.com> * fix: update comment to clarify conversation message update condition The comment now accurately reflects that the update happens when it's a flow and it's done (flow_is_done) Co-authored-by: centdix <centdix@users.noreply.github.com> * fix: only parse chat_input_enabled if conditions are met Move the parse_chat_input_enabled() call inside the condition check to avoid unnecessary parsing when the flow is not done or unsuccessful Co-authored-by: centdix <centdix@users.noreply.github.com> * fix: use the same transaction for conversation creation Pass transaction to get_or_create_conversation_with_id instead of creating a new one, ensuring all operations are atomic Co-authored-by: centdix <centdix@users.noreply.github.com> * fix: remove update trigger and handle updated_at in application code Remove the database trigger that automatically updates conversation timestamp and instead update it explicitly when creating messages. This gives better control and consistency. Co-authored-by: centdix <centdix@users.noreply.github.com> * Update SQLx metadata * cleaning * feat(aiagent): handle memory (#6719) * implement memory * s3 logic for memory * fix typo * much cleaner * cleaning * cleaning * only if chat * display nit * nit * fix stack overflow * cleaning * use len arg from input * cleaning * change order * delete memory when conv deleted * cleaning * nit * show description in expr mode * opti * opti * updatee ref * store string as simple string * use markdown * do not wait for deletion * add delete loading * fix logic * fix markdown * Update ee-repo-ref.txt * Update SQLx metadata * fix in test interface * nit * nit * fix layout * use memory_id to store memory * shorter description * rls + grant * fix text overflow * extract output from res * cleaning * handle streaming * cleaning * fix tool error * nit * update ref * fix * Update SQLx metadata * nit --------- Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com> Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: centdix <centdix@users.noreply.github.com> Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
175 lines
4.9 KiB
Svelte
175 lines
4.9 KiB
Svelte
<script lang="ts">
|
|
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
|
import FlowInputEditor from '$lib/components/flows/content/FlowInputEditor.svelte'
|
|
import HistoricInputs from '$lib/components/HistoricInputs.svelte'
|
|
import SideBarTab from '$lib/components/meltComponents/SideBarTab.svelte'
|
|
import { History, Save } from 'lucide-svelte'
|
|
import CaptureIcon from '$lib/components/triggers/CaptureIcon.svelte'
|
|
import CaptureButton from './triggers/CaptureButton.svelte'
|
|
import SavedInputsPicker from './SavedInputsPicker.svelte'
|
|
import { createEventDispatcher } from 'svelte'
|
|
import CaptureTable from './triggers/CaptureTable.svelte'
|
|
import RefreshButton from './common/button/RefreshButton.svelte'
|
|
|
|
export let runnableId: string = ''
|
|
export let stablePathForCaptures: string = ''
|
|
export let runnableType: any
|
|
export let previewArgs: any
|
|
export let isValid: boolean = true
|
|
export let jsonView: boolean = false
|
|
|
|
const dispatch = createEventDispatcher()
|
|
|
|
export function refreshHistory() {
|
|
historicInputs?.refresh()
|
|
}
|
|
|
|
export function resetSelected() {
|
|
historicInputs?.resetSelected(true)
|
|
savedInputsPicker?.resetSelected(true)
|
|
captureTable?.resetSelected(true)
|
|
}
|
|
|
|
const getDropdownItems = () => {
|
|
return [
|
|
{
|
|
label: 'History',
|
|
onClick: () => {
|
|
if (selectedTab === 'history') {
|
|
selectedTab = undefined
|
|
rightPanelOpen = false
|
|
} else {
|
|
selectedTab = 'history'
|
|
rightPanelOpen = true
|
|
}
|
|
},
|
|
icon: History,
|
|
selected: selectedTab === 'history'
|
|
},
|
|
{
|
|
label: 'Saved inputs',
|
|
onClick: () => {
|
|
if (selectedTab === 'saved_inputs') {
|
|
selectedTab = undefined
|
|
rightPanelOpen = false
|
|
} else {
|
|
selectedTab = 'saved_inputs'
|
|
rightPanelOpen = true
|
|
}
|
|
},
|
|
icon: Save,
|
|
selected: selectedTab === 'saved_inputs'
|
|
},
|
|
{
|
|
label: 'Trigger captures',
|
|
onClick: () => {
|
|
if (selectedTab === 'captures') {
|
|
selectedTab = undefined
|
|
rightPanelOpen = false
|
|
} else {
|
|
selectedTab = 'captures'
|
|
rightPanelOpen = true
|
|
}
|
|
},
|
|
icon: CaptureIcon,
|
|
selected: selectedTab === 'captures'
|
|
}
|
|
]
|
|
}
|
|
|
|
let rightHeight = 0
|
|
let selectedTab: 'history' | 'saved_inputs' | 'captures' | undefined = undefined
|
|
let dropdownItems: any
|
|
let rightPanelOpen = false
|
|
|
|
let savedInputsPicker: SavedInputsPicker | undefined = undefined
|
|
let loading = false
|
|
let captureTable: CaptureTable | undefined = undefined
|
|
let historicInputs: HistoricInputs | undefined = undefined
|
|
$: (selectedTab, (dropdownItems = getDropdownItems()))
|
|
|
|
let inputPanelSize = 70
|
|
</script>
|
|
|
|
<div class="h-fit">
|
|
<div class="relative z-[100000] w-full">
|
|
<div class="absolute" style="right: calc({100 - inputPanelSize}%); top: -1px;">
|
|
<SideBarTab {dropdownItems} fullMenu={true} noTrigger={true} />
|
|
</div>
|
|
</div>
|
|
<Splitpanes class={!rightPanelOpen ? 'splitter-hidden' : ''}>
|
|
<Pane bind:size={inputPanelSize} class="!overflow-visible" minSize={30}>
|
|
<div class="relative w-full h-fit pr-12 pb-4" bind:clientHeight={rightHeight}>
|
|
<slot />
|
|
</div>
|
|
</Pane>
|
|
|
|
<Pane minSize={rightPanelOpen ? 30 : 0}>
|
|
{#if rightPanelOpen}
|
|
<div style="height: {rightHeight}px" class="border-t border-r pb-2">
|
|
{#if selectedTab === 'history'}
|
|
<FlowInputEditor title="History">
|
|
<svelete:fragment slot="action">
|
|
<div class="center-center">
|
|
<RefreshButton {loading} on:click={() => historicInputs?.refresh()} />
|
|
</div>
|
|
</svelete:fragment>
|
|
<HistoricInputs
|
|
bind:loading
|
|
bind:this={historicInputs}
|
|
{runnableId}
|
|
{runnableType}
|
|
on:select={(e) => {
|
|
dispatch('select', { payload: e.detail?.args, type: 'history' })
|
|
}}
|
|
/>
|
|
</FlowInputEditor>
|
|
{:else if selectedTab === 'saved_inputs'}
|
|
<FlowInputEditor title="Saved inputs">
|
|
<SavedInputsPicker
|
|
{isValid}
|
|
{runnableId}
|
|
{runnableType}
|
|
{previewArgs}
|
|
bind:this={savedInputsPicker}
|
|
on:select={(e) => {
|
|
dispatch('select', { payload: e.detail, type: 'saved' })
|
|
}}
|
|
{jsonView}
|
|
/>
|
|
</FlowInputEditor>
|
|
{:else if selectedTab === 'captures'}
|
|
<FlowInputEditor title="Trigger captures">
|
|
<svelete:fragment slot="action">
|
|
<div class="center-center">
|
|
<CaptureButton on:openTriggers small={true} />
|
|
</div>
|
|
</svelete:fragment>
|
|
<div class="h-full">
|
|
<CaptureTable
|
|
path={stablePathForCaptures}
|
|
on:select={(e) => {
|
|
dispatch('select', { payload: e.detail, type: 'captures' })
|
|
}}
|
|
bind:this={captureTable}
|
|
isFlow={true}
|
|
headless={true}
|
|
addButton={false}
|
|
/>
|
|
</div>
|
|
</FlowInputEditor>
|
|
{/if}
|
|
</div>
|
|
{/if}
|
|
</Pane>
|
|
</Splitpanes>
|
|
</div>
|
|
|
|
<style>
|
|
:global(.splitter-hidden .splitpanes__splitter) {
|
|
background-color: transparent !important;
|
|
border: none !important;
|
|
opacity: 0 !important;
|
|
}
|
|
</style>
|