Skip to content

feat: Add global chat for navigation #5820

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 42 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e68961b
feat: ai flow chat
HugoCasa May 26, 2025
9661f13
Merge remote-tracking branch 'origin/main' into hc/ai-flow-chat
HugoCasa May 27, 2025
50b9dd0
youpi
HugoCasa May 29, 2025
700c484
feat: preprocessor and error handler support
HugoCasa May 30, 2025
13de5ec
Merge remote-tracking branch 'origin/main' into hc/ai-flow-chat
HugoCasa Jun 2, 2025
38aaa44
fix: reactivity
HugoCasa Jun 2, 2025
6240ab6
Add GlobalChat component with drawer functionality
claude[bot] May 27, 2025
c2f40cb
draft
centdix May 23, 2025
7cb8f0a
use triggerable by ai compoennt
centdix May 26, 2025
db99f55
make drawer triggerable
centdix May 27, 2025
4ac46ee
implement logic
centdix May 27, 2025
2496741
add inkeep tool
centdix May 27, 2025
4da5255
cleaner code
centdix May 27, 2025
f13b8f3
make more things available
centdix May 28, 2025
86e6023
more integrations + better system prompt
centdix May 28, 2025
d6340cc
fix docs fetching
centdix May 28, 2025
fb41953
small fix
centdix May 28, 2025
a2a1df1
cleaning
centdix May 28, 2025
ffc6cda
add ask in search bar + right top icon on homepage + suggestions
centdix May 29, 2025
624e379
fix button
centdix May 29, 2025
7a0b39f
disable chat if no ai providers
centdix May 29, 2025
9c31afe
add inkeep endpoint
centdix May 29, 2025
5d14c8a
draft working stuff
centdix May 29, 2025
0217a41
cleaner code
centdix May 29, 2025
1cb8e0d
better chat
centdix May 30, 2025
dd3ff96
fix
centdix May 30, 2025
b98b451
send license and uid
centdix May 30, 2025
2a41322
better anim
centdix May 30, 2025
31f1bed
move logic
centdix May 30, 2025
a6e9ef5
parse links in chat
centdix May 30, 2025
011f881
add missing integration
centdix May 30, 2025
3aaba09
add reset button
centdix May 30, 2025
2fc4d51
fix
centdix May 31, 2025
4238173
rm file
centdix Jun 2, 2025
6e4fdd6
integrate navigator mode
centdix Jun 2, 2025
af37a93
integrate all changes
centdix Jun 2, 2025
6f5806d
add hide button
centdix Jun 2, 2025
ff3b1d1
adjust drawer size
centdix Jun 2, 2025
e331c82
add script ai chat integration
centdix Jun 2, 2025
e7f7801
fix drawer
centdix Jun 2, 2025
89934ec
small fixes
centdix Jun 2, 2025
8185a08
small fixes
centdix Jun 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add ask in search bar + right top icon on homepage + suggestions
  • Loading branch information
centdix committed Jun 2, 2025
commit ffc6cda97f3d1265646ebb44b55c314fbbd02735
29 changes: 29 additions & 0 deletions frontend/src/lib/components/AskAiButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script lang="ts">
import { Button } from '$lib/components/common'
import { WandSparkles } from 'lucide-svelte'
import { globalChatOpen, globalChatInitialInput } from '$lib/stores'

interface Props {
label?: string
initialInput?: string
onClick?: () => void
}

const { label, initialInput, onClick: onClickProp }: Props = $props()

const onClick = () => {
globalChatOpen.set(true)
if (initialInput) {
globalChatInitialInput.set(initialInput)
}
onClickProp?.()
}
</script>

<Button
size="xs2"
color="blue"
buttonType="button"
on:click={onClick}
startIcon={{ icon: WandSparkles }}>{label}</Button
>
43 changes: 43 additions & 0 deletions frontend/src/lib/components/chat/GlobalChat.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { Send, Loader2 } from 'lucide-svelte'
import { chatRequest, prepareSystemMessage } from './core'
import type { ChatCompletionMessageParam } from 'openai/resources/index.mjs'
import { globalChatInitialInput } from '$lib/stores'

let chatHistory = [
{
Expand All @@ -17,6 +18,17 @@
let currentReply = $state('')
let messages = $state(chatHistory)

// Suggested questions for the user
const suggestions = $state([
'How do I create a new workflow?',
"What's the difference between scripts and flows?",
'How can I connect to a database?',
'How do I schedule a recurring job?'
])

// Check if there are any user messages
const hasUserMessages = $derived(messages.some((msg) => msg.role === 'user'))

let abortController = new AbortController()

async function handleSubmit() {
Expand Down Expand Up @@ -45,6 +57,19 @@
inputValue = ''
isSubmitting = false
}

function submitSuggestion(suggestion: string) {
inputValue = suggestion
handleSubmit()
}

$effect(() => {
if (globalChatInitialInput) {
inputValue = $globalChatInitialInput
globalChatInitialInput.set('')
handleSubmit()
}
})
</script>

<div class="flex flex-col h-full bg-surface z-10">
Expand Down Expand Up @@ -75,6 +100,24 @@
</div>
</div>
{/if}

<!-- Suggestion buttons when no user messages yet -->
{#if !hasUserMessages && !isSubmitting}
<div class="w-full pt-4">
<div class="flex flex-wrap gap-2">
{#each suggestions as suggestion}
<Button
on:click={() => submitSuggestion(suggestion)}
size="xs2"
color="gray"
buttonType="button"
>
{suggestion}
</Button>
{/each}
</div>
</div>
{/if}
</div>

<!-- Input Area -->
Expand Down
54 changes: 31 additions & 23 deletions frontend/src/lib/components/search/GlobalSearchModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
type ListableApp,
type ListableRawApp,
type Script,

type SearchJobsIndexResponse

} from '$lib/gen'
import { clickOutside, isMac } from '$lib/utils'
import {
Expand Down Expand Up @@ -44,6 +42,7 @@
import Logs from 'lucide-svelte/icons/logs'
import { AwsIcon, GoogleCloudIcon, KafkaIcon, MqttIcon, NatsIcon } from '../icons'
import RunsSearch from './RunsSearch.svelte'
import AskAiButton from '../AskAiButton.svelte'

let open: boolean = false

Expand Down Expand Up @@ -264,7 +263,6 @@
return r
}


let queryParseErrors: string[] = []

async function handleSearch() {
Expand Down Expand Up @@ -320,8 +318,8 @@
)
}
if (tab === 'runs') {
await tick()
runsSearch?.handleRunSearch(removePrefix(searchTerm, RUNS_PREFIX))
await tick()
runsSearch?.handleRunSearch(removePrefix(searchTerm, RUNS_PREFIX))
}
selectedItem = selectItem(0)
}
Expand Down Expand Up @@ -413,7 +411,7 @@
open = false
goto(path)
} else {
window.open(path, "_blank")
window.open(path, '_blank')
}
}

Expand Down Expand Up @@ -581,8 +579,7 @@
let runsSearch: RunsSearch
let runSearchRemainingCount: number | undefined = undefined
let runSearchTotalCount: number | undefined = undefined
let indexMetadata: SearchJobsIndexResponse["index_metadata"] = undefined

let indexMetadata: SearchJobsIndexResponse['index_metadata'] = undefined
</script>

{#if open}
Expand Down Expand Up @@ -618,6 +615,15 @@
>{placeholderFromPrefix(searchTerm)}</label
>
</div>
{#if (itemMap[tab] ?? []).length === 0 && searchTerm.length > 0}
<AskAiButton
label="Ask AI"
initialInput={searchTerm}
onClick={() => {
closeModal()
}}
/>
{/if}
{#if queryParseErrors.length > 0}
<Popover notClickable placement="bottom-start">
<AlertTriangle size={16} class="text-yellow-500" />
Expand Down Expand Up @@ -682,7 +688,9 @@
{#if (itemMap[tab] ?? []).length === 0}
<div class="flex w-full justify-center items-center">
<div class="text-tertiary text-center">
<div class="text-2xl font-bold">Nothing found</div>
<div class="text-2xl font-bold"
>Nothing found, ask the AI to find what you need !</div
>
<div class="text-sm">Tip: press `esc` to quickly clear the search bar</div>
</div>
</div>
Expand Down Expand Up @@ -718,20 +726,20 @@
{/if}
</div>
{:else if tab === 'runs'}
<RunsSearch
bind:queryParseErrors
bind:this={runsSearch}
bind:selectedItem
bind:selectedWorkspace
bind:mouseMoved
bind:loadedRuns={itemMap['runs']}
bind:open
{selectItem}
searchTerm={removePrefix(searchTerm, RUNS_PREFIX)}
bind:runSearchRemainingCount
bind:runSearchTotalCount
bind:indexMetadata
/>
<RunsSearch
bind:queryParseErrors
bind:this={runsSearch}
bind:selectedItem
bind:selectedWorkspace
bind:mouseMoved
bind:loadedRuns={itemMap['runs']}
bind:open
{selectItem}
searchTerm={removePrefix(searchTerm, RUNS_PREFIX)}
bind:runSearchRemainingCount
bind:runSearchTotalCount
bind:indexMetadata
/>
{/if}
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/stores.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ export const triggerablesByAI = writable<
Record<string, { description: string; onTrigger: ((id: string) => void) | undefined }>
>({})
export const globalChatOpen = writable<boolean>(false)
export const globalChatInitialInput = writable<string>('')

type SQLBaseSchema = {
[schemaKey: string]: {
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/routes/(root)/(logged)/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@
on:click={() => openGlobalChat()}
isCollapsed={false}
icon={MessageCircle}
label="Global Chat"
label="Ask AI"
class="!text-xs"
/>
</div>
Expand Down Expand Up @@ -527,7 +527,7 @@
on:click={() => openGlobalChat()}
{isCollapsed}
icon={MessageCircle}
label="Global Chat"
label="Ask AI"
class="!text-xs"
/>
</div>
Expand Down Expand Up @@ -634,7 +634,7 @@
on:click={() => openGlobalChat()}
{isCollapsed}
icon={MessageCircle}
label="Global Chat"
label="Ask AI"
class="!text-xs"
/>
</div>
Expand Down
10 changes: 8 additions & 2 deletions frontend/src/routes/(root)/(logged)/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import { AppService, FlowService, type OpenFlow, type Script } from '$lib/gen'
import { userStore, workspaceStore } from '$lib/stores'
import { globalChatOpen, userStore, workspaceStore } from '$lib/stores'
import { Alert, Button, Drawer, DrawerContent, Tab, Tabs } from '$lib/components/common'
import PageHeader from '$lib/components/PageHeader.svelte'
import CreateActionsFlow from '$lib/components/flows/CreateActionsFlow.svelte'
Expand All @@ -23,6 +23,7 @@
import { setQuery } from '$lib/navigation'
import { page } from '$app/stores'
import { goto, replaceState } from '$app/navigation'
import AskAiButton from '$lib/components/AskAiButton.svelte'

type Tab = 'hub' | 'workspace'

Expand Down Expand Up @@ -214,7 +215,12 @@
</Drawer>

<div>
<div class="max-w-7xl mx-auto px-4 sm:px-6 md:px-8 h-fit-content">
{#if !$globalChatOpen}
<div class="fixed top-4 right-4 z-50">
<AskAiButton />
</div>
{/if}
<div class="max-w-7xl mx-auto px-4 sm:px-8 md:px-8 h-fit-content">
{#if $workspaceStore == 'admins'}
<div class="my-4"></div>

Expand Down