diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml
index 046a4122d9..ff8e9dadd7 100644
--- a/backend/windmill-api/openapi.yaml
+++ b/backend/windmill-api/openapi.yaml
@@ -5856,6 +5856,8 @@ paths:
- $ref: "#/components/parameters/ScriptExactHash"
- $ref: "#/components/parameters/StartedBefore"
- $ref: "#/components/parameters/StartedAfter"
+ - $ref: "#/components/parameters/CreatedBefore"
+ - $ref: "#/components/parameters/CreatedAfter"
- $ref: "#/components/parameters/CreatedOrStartedBefore"
- $ref: "#/components/parameters/Running"
- $ref: "#/components/parameters/ScheduledForBeforeNow"
@@ -9055,6 +9057,20 @@ components:
in: query
schema:
type: string
+ CreatedBefore:
+ name: created_before
+ description: filter on created before (inclusive) timestamp
+ in: query
+ schema:
+ type: string
+ format: date-time
+ CreatedAfter:
+ name: created_after
+ description: filter on created after (exclusive) timestamp
+ in: query
+ schema:
+ type: string
+ format: date-time
StartedBefore:
name: started_before
description: filter on started before (inclusive) timestamp
diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs
index bee997a14e..346853b101 100644
--- a/backend/windmill-api/src/jobs.rs
+++ b/backend/windmill-api/src/jobs.rs
@@ -1161,16 +1161,10 @@ pub fn filter_list_queue_query(
sqlb.and_where_eq("parent_job", "?".bind(pj));
}
if let Some(dt) = &lq.started_before {
- sqlb.and_where_le(
- "started_at",
- format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()),
- );
+ sqlb.and_where_le("started_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(dt) = &lq.started_after {
- sqlb.and_where_ge(
- "started_at",
- format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()),
- );
+ sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(fs) = &lq.is_flow_step {
sqlb.and_where_eq("is_flow_step", fs);
@@ -1182,16 +1176,10 @@ pub fn filter_list_queue_query(
}
if let Some(dt) = &lq.created_before {
- sqlb.and_where_le(
- "created_at",
- format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()),
- );
+ sqlb.and_where_le("created_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(dt) = &lq.created_after {
- sqlb.and_where_ge(
- "created_at",
- format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()),
- );
+ sqlb.and_where_ge("created_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(dt) = &lq.created_or_started_after {
@@ -4701,36 +4689,28 @@ pub fn filter_list_completed_query(
sqlb.and_where_eq("parent_job", "?".bind(pj));
}
if let Some(dt) = &lq.started_before {
- sqlb.and_where_le(
- "started_at",
- format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()),
- );
+ sqlb.and_where_le("started_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(dt) = &lq.started_after {
- sqlb.and_where_ge(
- "started_at",
- format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()),
- );
+ sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(dt) = &lq.created_or_started_before {
- sqlb.and_where_le(
- "started_at",
- format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()),
- );
+ sqlb.and_where_le("started_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(dt) = &lq.created_or_started_after {
- sqlb.and_where_ge(
- "started_at",
- format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()),
- );
+ sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339()));
+ }
+
+ if let Some(dt) = &lq.created_before {
+ sqlb.and_where_le("created_at", "?".bind(&dt.to_rfc3339()));
+ }
+ if let Some(dt) = &lq.created_after {
+ sqlb.and_where_ge("created_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(dt) = &lq.created_or_started_after_completed_jobs {
- sqlb.and_where_ge(
- "started_at",
- format!("to_timestamp({} / 1000.0)", dt.timestamp_millis()),
- );
+ sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(sk) = &lq.is_skipped {
diff --git a/frontend/src/lib/components/RunChart.svelte b/frontend/src/lib/components/RunChart.svelte
index a4c39c9da0..3898bded6d 100644
--- a/frontend/src/lib/components/RunChart.svelte
+++ b/frontend/src/lib/components/RunChart.svelte
@@ -2,6 +2,7 @@
import { Scatter } from 'svelte-chartjs'
import 'chartjs-adapter-date-fns'
import zoomPlugin from 'chartjs-plugin-zoom'
+ import Tooltip2 from '$lib/components/Tooltip.svelte'
import {
Chart as ChartJS,
Title,
@@ -17,6 +18,7 @@
import type { CompletedJob } from '$lib/gen'
import { createEventDispatcher } from 'svelte'
import { getDbClockNow } from '$lib/forLater'
+ import Button from './common/button/Button.svelte'
export let jobs: CompletedJob[] | undefined = []
export let maxIsNow: boolean = false
@@ -24,6 +26,7 @@
export let maxTimeSet: string | undefined = undefined
export let selectedIds: string[] = []
export let canSelect: boolean = true
+ export let lastFetchWentToEnd: boolean = false
const dispatch = createEventDispatcher()
const SUCCESS_COLOR = '#4ade80'
@@ -283,5 +286,18 @@
{maxTime} -->
+ {#if !lastFetchWentToEnd}
+
dispatch('loadExtra')}
+ >Load more There are more jobs to load but only the first 1000 were fetched
+ {/if}
diff --git a/frontend/src/lib/components/ScriptBuilder.svelte b/frontend/src/lib/components/ScriptBuilder.svelte
index 6f6d156f07..770e17a588 100644
--- a/frontend/src/lib/components/ScriptBuilder.svelte
+++ b/frontend/src/lib/components/ScriptBuilder.svelte
@@ -1034,6 +1034,7 @@
{
metadataOpen = true
}}
diff --git a/frontend/src/lib/components/runs/JobLoader.svelte b/frontend/src/lib/components/runs/JobLoader.svelte
index a5a083d3ec..d58a9d0af3 100644
--- a/frontend/src/lib/components/runs/JobLoader.svelte
+++ b/frontend/src/lib/components/runs/JobLoader.svelte
@@ -123,10 +123,26 @@
}
let loadingFetch = false
+
+ export async function loadExtraJobs(): Promise {
+ if (jobs && jobs.length > 0) {
+ const lastJob = jobs[jobs.length - 1]
+ // const minCreated = lastJob?.created_at
+ const minCreated = new Date(new Date(lastJob.created_at!).getTime() - 1).toISOString()
+
+ let olderJobs = await fetchJobs(undefined, minTs, undefined, minCreated)
+ jobs = jobs.concat(olderJobs)
+ computeCompletedJobs()
+ return olderJobs?.length < 1000
+ }
+ return false
+ }
+
async function fetchJobs(
startedBefore: string | undefined,
startedAfter: string | undefined,
- startedAfterCompletedJobs: string | undefined
+ startedAfterCompletedJobs: string | undefined,
+ createdBefore: string | undefined
): Promise {
loadingFetch = true
try {
@@ -139,6 +155,7 @@
createdOrStartedAfterCompletedJobs: startedAfterCompletedJobs,
schedulePath,
scriptPathExact,
+ createdBefore,
createdBy: user === null || user === '' ? undefined : user,
scriptPathStart: scriptPathStart,
jobKinds,
@@ -264,7 +281,7 @@
// lookback won't be needed anymore (just filter ended_at > minTs instead
const extendedMinTs = subtractDaysFromDateString(minTs, lookback)
if (concurrencyKey == null || concurrencyKey === '') {
- let newJobs = await fetchJobs(maxTs, undefined, extendedMinTs)
+ let newJobs = await fetchJobs(maxTs, undefined, extendedMinTs, undefined)
extendedJobs = { jobs: newJobs, obscured_jobs: [] } as ExtendedJobs
// Filter on minTs here and not in the backend
@@ -372,7 +389,7 @@
loading = true
let newJobs: Job[]
if (concurrencyKey == null || concurrencyKey === '') {
- newJobs = await fetchJobs(maxTs, minTs ?? ts, undefined)
+ newJobs = await fetchJobs(maxTs, minTs ?? ts, undefined, undefined)
} else {
// Obscured jobs have no ids, so we have to do the full request
extendedJobs = await fetchExtendedJobs(concurrencyKey, maxTs, undefined, minTs ?? ts)
diff --git a/frontend/src/lib/components/runs/RunsTable.svelte b/frontend/src/lib/components/runs/RunsTable.svelte
index e0774d78c9..e98e00d967 100644
--- a/frontend/src/lib/components/runs/RunsTable.svelte
+++ b/frontend/src/lib/components/runs/RunsTable.svelte
@@ -19,6 +19,7 @@
export let selectedWorkspace: string | undefined = undefined
export let activeLabel: string | null = null
// const loadMoreQuantity: number = 100
+ export let lastFetchWentToEnd = false
function getTime(job: Job): string | undefined {
return job['started_at'] ?? job['scheduled_for'] ?? job['created_at']
@@ -156,9 +157,12 @@
$: isSelectingJobsToCancel && (allSelected = selectedIds.length === cancelableJobCount)
$: isSelectingJobsToCancel && (cancelableJobCount = jobs?.filter(isJobCancelable).length ?? 0)
- function jobCountString(jobCount: number) {
+ function jobCountString(jobCount: number | undefined, lastFetchWentToEnd: boolean): string {
+ if (jobCount === undefined) {
+ return ''
+ }
const jc = jobCount
- const isTruncated = jc >= 1000
+ const isTruncated = jc >= 1000 && !lastFetchWentToEnd
return `${jc}${isTruncated ? '+' : ''} job${jc != 1 ? 's' : ''}`
}
@@ -201,14 +205,14 @@
{#if showExternalJobs && externalJobs.length > 0}
- {jobs && jobCountString(jobs.length + externalJobs.length)}{externalJobs.length} jobs obscured
+ {jobs
+ ? jobCountString(jobs.length + externalJobs.length, lastFetchWentToEnd)
+ : ''}{externalJobs.length} jobs obscured
{:else if $workspaceStore !== 'admins' && omittedObscuredJobs}
- {jobs && jobCountString(jobs.length)}
+ {jobs ? jobCountString(jobs.length, lastFetchWentToEnd) : ''}
@@ -218,9 +222,11 @@
{:else}
- {jobs && jobCountString(jobs.length)}
+ {jobs ? jobCountString(jobs.length, lastFetchWentToEnd) : ''}
{/if}
- Timestamp
+
Path
{#if containsLabel}
Label
@@ -297,6 +303,16 @@
{/if}
+ {#if !lastFetchWentToEnd && jobs && jobs.length >= 1000}
+ {
+ dispatch('loadExtra')
+ }}>Load next 1000 jobs
+ {/if}
{/if}
diff --git a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte
index eab0f9a6ba..59b184f755 100644
--- a/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte
+++ b/frontend/src/routes/(root)/(logged)/runs/[...path]/+page.svelte
@@ -88,6 +88,7 @@
let schedulePath = $page.url.searchParams.get('schedule_path') ?? undefined
let jobKindsCat = $page.url.searchParams.get('job_kinds') ?? 'runs'
let allWorkspaces = $page.url.searchParams.get('all_workspaces') == 'true' ?? false
+ let lastFetchWentToEnd = false
function loadFromQuery() {
path = $page.params.path
@@ -316,6 +317,7 @@
maxTs = undefined
jobs = undefined
completedJobs = undefined
+ lastFetchWentToEnd = false
selectedManualDate = 0
selectedIds = []
jobIdsToCancel = []
@@ -503,6 +505,13 @@
lookback = lookbackInDays
}
+ async function loadExtra() {
+ if (jobLoader) {
+ lastFetchWentToEnd = await jobLoader.loadExtraJobs()
+ console.log(lastFetchWentToEnd)
+ }
+ }
+
const warnJobLimitMsg =
'The exact number of concurrent jobs at the beginning of the time range may be incorrect as only the last 1000 jobs are taken into account: a job that was started earlier than this limit will not be taken into account'
@@ -739,12 +748,14 @@
{#if graph === 'RunChart'}
{
minTs = e.detail.min.toISOString()
maxTs = e.detail.max.toISOString()
@@ -904,7 +915,7 @@