diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index fec7d05006..4d15f57a97 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -0854c5c00f62751aa5eb44fd9e550052fdcf7884 \ No newline at end of file +bea87fa885dc041fba83b2491609a4a2cdbbfa6f diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 5020067440..9895efce7e 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -12590,6 +12590,11 @@ paths: required: true schema: type: string + - name: pagination_offset + in: query + required: false + schema: + type: integer responses: "200": description: search results @@ -12602,15 +12607,26 @@ paths: description: a list of the terms that couldn't be parsed (and thus ignored) type: array items: - type: object - properties: - dancer: - type: string + type: string hits: description: the jobs that matched the query type: array items: $ref: "#/components/schemas/JobSearchHit" + hit_count: + description: how many jobs matched in total + type: number + index_metadata: + description: Metadata about the index current state + type: object + properties: + indexed_until: + description: Datetime of the most recently indexed job + type: string + format: date-time + lost_lock_ownership: + description: Is the current indexer service being replaced + type: boolean /srch/index/search/service_logs: get: @@ -16810,4 +16826,4 @@ components: channel_name: type: string description: Microsoft Teams channel name - minLength: 1 \ No newline at end of file + minLength: 1 diff --git a/frontend/src/lib/components/search/GlobalSearchModal.svelte b/frontend/src/lib/components/search/GlobalSearchModal.svelte index 271389b007..e684ce0d89 100644 --- a/frontend/src/lib/components/search/GlobalSearchModal.svelte +++ b/frontend/src/lib/components/search/GlobalSearchModal.svelte @@ -3,7 +3,6 @@ import { AppService, FlowService, - IndexSearchService, RawAppService, ScriptService, type Flow, @@ -11,8 +10,7 @@ type ListableRawApp, type Script } from '$lib/gen' - import { clickOutside, displayDateOnly, isMac, sendUserToast } from '$lib/utils' - import TimeAgo from '../TimeAgo.svelte' + import { clickOutside, isMac } from '$lib/utils' import { AlertTriangle, BoxesIcon, @@ -22,14 +20,12 @@ DollarSignIcon, HomeIcon, LayoutDashboardIcon, - Loader2, PlayIcon, Route, Search, SearchCode, Unplug } from 'lucide-svelte' - import JobPreview from '../runs/JobPreview.svelte' import Portal from '$lib/components/Portal.svelte' import { twMerge } from 'tailwind-merge' @@ -44,6 +40,7 @@ import Popover from '../Popover.svelte' import Logs from 'lucide-svelte/icons/logs' import { AwsIcon, GoogleCloudIcon, KafkaIcon, MqttIcon, NatsIcon } from '../icons' + import RunsSearch from './RunsSearch.svelte' let open: boolean = false @@ -72,7 +69,7 @@ let switchModeItems: quickMenuItem[] = [ { search_id: 'switchto:run-search', - label: 'Search across completed runs' + ($enterpriseLicense ? '' : ' (EE)'), + label: 'Search across completed runs' + (!$enterpriseLicense ? '' : ' (EE)'), action: () => switchMode('runs'), shortcutKey: RUNS_PREFIX, icon: Search, @@ -113,28 +110,28 @@ }, { search_id: 'nav:kafka_triggers', - label: 'Go to Kafka triggers' + ($enterpriseLicense ? '' : ' (EE)'), + label: 'Go to Kafka triggers' + (!$enterpriseLicense ? '' : ' (EE)'), action: () => gotoPage('/kafka_triggers'), icon: KafkaIcon, disabled: $userStore?.operator }, { search_id: 'nav:nats_triggers', - label: 'Go to NATS triggers' + ($enterpriseLicense ? '' : ' (EE)'), + label: 'Go to NATS triggers' + (!$enterpriseLicense ? '' : ' (EE)'), action: () => gotoPage('/nats_triggers'), icon: NatsIcon, disabled: $userStore?.operator }, { search_id: 'nav:sqs_triggers', - label: 'Go to SQS triggers' + ($enterpriseLicense ? '' : ' (EE)'), + label: 'Go to SQS triggers' + (!$enterpriseLicense ? '' : ' (EE)'), action: () => gotoPage('/sqs_triggers'), icon: AwsIcon, disabled: $userStore?.operator }, { search_id: 'nav:gcp_pub_sub', - label: 'Go to GCP Pub/Sub' + ($enterpriseLicense ? '' : ' (EE)'), + label: 'Go to GCP Pub/Sub' + (!$enterpriseLicense ? '' : ' (EE)'), action: () => gotoPage('/gcp_triggers'), icon: GoogleCloudIcon, disabled: $userStore?.operator @@ -264,12 +261,8 @@ return r } - let debounceTimeout: any = undefined - const debouncePeriod: number = 1000 - let loadingCompletedRuns: boolean = false let queryParseErrors: string[] = [] - let indexMetadata: any = {} async function handleSearch() { queryParseErrors = [] @@ -314,6 +307,7 @@ ) ) } + itemMap['default'] = itemMap['default'].filter((e) => !e.disabled) } if (tab === 'switch-mode') { itemMap['switch-mode'] = fuzzyFilter( @@ -323,26 +317,8 @@ ) } if (tab === 'runs') { - const s = removePrefix(searchTerm, RUNS_PREFIX) - clearTimeout(debounceTimeout) - loadingCompletedRuns = true - debounceTimeout = setTimeout(async () => { - clearTimeout(debounceTimeout) - let searchResults - try { - searchResults = await IndexSearchService.searchJobsIndex({ - searchQuery: s, - workspace: $workspaceStore! - }) - itemMap['runs'] = searchResults.hits - queryParseErrors = searchResults.query_parse_errors - indexMetadata = searchResults.index_metadata - } catch (e) { - sendUserToast(e.body, true) - } - loadingCompletedRuns = false - selectedItem = selectItem(0) - }, debouncePeriod) + await tick() + runsSearch?.handleRunSearch(removePrefix(searchTerm, RUNS_PREFIX)) } selectedItem = selectItem(0) } @@ -594,6 +570,8 @@ return 'max-h-[60vh]' } } + + let runsSearch: RunsSearch {#if open} @@ -652,18 +630,16 @@ {#if items.length > 0}
{#each items as el} - {#if !el.disabled} - (selectedItem = el)} - id={el?.search_id} - hovered={el?.search_id === selectedItem?.search_id} - label={el?.label} - icon={el?.icon} - shortcutKey={el?.shortcutKey} - bind:mouseMoved - /> - {/if} + (selectedItem = el)} + id={el?.search_id} + hovered={el?.search_id === selectedItem?.search_id} + label={el?.label} + icon={el?.icon} + shortcutKey={el?.shortcutKey} + bind:mouseMoved + /> {/each}
{/if} @@ -729,138 +705,17 @@ {/if} {:else if tab === 'runs'} -
- {#if loadingCompletedRuns} -
-
- -
-
- {:else if itemMap['runs'] && itemMap['runs'].length > 0} -
- {#each itemMap['runs'] ?? [] as r} - { - selectedItem = r - selectedWorkspace = r?.document.workspace_id[0] - }} - on:keyboardOnlySelect={() => { - open = false - goto(`/run/${r?.document.id[0]}`) - }} - id={r?.document.id[0]} - hovered={selectedItem && r?.document.id[0] === selectedItem?.document.id[0]} - icon={r?.icon} - containerClass="rounded-md px-2 py-1 my-2" - bind:mouseMoved - > - -
-
-
-
{r?.document.script_path}
-
-
- {displayDateOnly(new Date(r?.document.created_at[0]))} -
-
- -
-
-
-
-
-
- {/each} -
-
- {#if selectedItem === undefined} - Select a result to preview - {:else} -
- -
- {/if} -
- {#if indexMetadata.indexed_until} - - Most recently indexed job was created at - - {/if} - {#if indexMetadata.lost_lock_ownership} - - - - The current indexer is no longer indexing new jobs. This is most likely - because of an ongoing deployment and indexing will resume once it's - complete. - - - {/if} -
-
- {:else} -
-
- {#if searchTerm === RUNS_PREFIX} -
Enter your search terms
-
Start typing to do full-text search across completed runs
- {:else} -
No runs found
-
There were no completed runs that match your query
- {/if} -
- Note that new runs might take a while to become searchable (by default ~5min) -
- {#if !$enterpriseLicense} -
- - - Full-text search on jobs is only available on EE. - - {/if} -
-
- {#if indexMetadata.indexed_until} - - Most recently indexed job was created at - - {/if} - {#if indexMetadata.lost_lock_ownership} - - - - The current indexer is no longer indexing new jobs. This is most likely - because of an ongoing deployment and indexing will resume once it's - complete. - - - {/if} -
-
- {/if} -
+ {/if} diff --git a/frontend/src/lib/components/search/RunsSearch.svelte b/frontend/src/lib/components/search/RunsSearch.svelte new file mode 100644 index 0000000000..e955304786 --- /dev/null +++ b/frontend/src/lib/components/search/RunsSearch.svelte @@ -0,0 +1,266 @@ + + +
+ {#if loadingCompletedRuns} +
+
+ +
+
+ {:else if loadedRuns && loadedRuns.length > 0} +
+
+ {runSearchTotalCount} jobs matched the query +
+
+ {#each loadedRuns ?? [] as r} + {#if r.search_id === 'opt:load_more_jobs'} +
+ {#if loadingMoreJobs} +
+ +
+ {:else} + { + selectedItem = r + selectedWorkspace = undefined + const paginationOffset = runSearchTotalCount! - runSearchRemainingCount! + loadMoreJobs(searchTerm, paginationOffset) + }} + id={'opt:load_more_jobs'} + hovered={selectedItem && r?.search_id === selectedItem?.search_id} + containerClass="rounded-md px-2 py-1 my-2" + bind:mouseMoved + > + +
+ Some other {runSearchRemainingCount} jobs matched the query. Click to load more. + + +
+
+
+ {/if} + {:else} + { + selectedItem = r + selectedWorkspace = r?.document.workspace_id[0] + }} + on:keyboardOnlySelect={() => { + open = false + goto(`/run/${r?.document.id[0]}`) + }} + id={r?.document.id[0]} + hovered={selectedItem && r?.search_id === selectedItem?.search_id} + icon={r?.icon} + containerClass="rounded-md px-2 py-1 my-2" + bind:mouseMoved + > + +
+
+
+
{r?.document.script_path}
+
+
+ {displayDateOnly(new Date(r?.document.created_at[0]))} +
+
+ +
+
+
+
+
+
+ {/if} + {/each} +
+
+
+ {#if selectedItem === undefined} + Select a result to preview + {:else} +
+ +
+ {/if} +
+ {#if indexMetadata.indexed_until} + + Most recently indexed job was created at + + {/if} + {#if indexMetadata.lost_lock_ownership} + + + + The current indexer is no longer indexing new jobs. This is most likely because of an + ongoing deployment and indexing will resume once it's complete. + + + {/if} +
+
+ {:else} +
+
+ {#if searchTerm === ''} +
Enter your search terms
+
Start typing to do full-text search across completed runs
+ {:else} +
No runs found
+
There were no completed runs that match your query
+ {/if} +
+ Note that new runs might take a while to become searchable (by default ~5min) +
+ {#if !$enterpriseLicense} +
+ + + Full-text search on jobs is only available on EE. + + {/if} +
+
+ {#if indexMetadata.indexed_until} + + Most recently indexed job was created at + + {/if} + {#if indexMetadata.lost_lock_ownership} + + + + The current indexer is no longer indexing new jobs. This is most likely because of an + ongoing deployment and indexing will resume once it's complete. + + + {/if} +
+
+ {/if} +