mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-05 00:03:08 +00:00
fix: improve input history
This commit is contained in:
@@ -7666,6 +7666,14 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: input
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
- name: allow_large
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
responses:
|
||||
"200":
|
||||
description: args
|
||||
@@ -9147,8 +9155,6 @@ components:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
args:
|
||||
type: object
|
||||
created_by:
|
||||
type: string
|
||||
created_at:
|
||||
|
||||
@@ -127,7 +127,7 @@ async fn get_input_history(
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
|
||||
let sql = &format!(
|
||||
"select id, created_at, created_by, CASE WHEN args is null or pg_column_size(args) < 40000 THEN args ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as args, success from completed_job \
|
||||
"select id, created_at, created_by, 'null'::jsonb as args, success from completed_job \
|
||||
where {} = $1 and job_kind = $2 and workspace_id = $3 \
|
||||
order by created_at desc limit $4 offset $5",
|
||||
r.runnable_type.column_name()
|
||||
@@ -173,19 +173,48 @@ async fn get_input_history(
|
||||
Ok(Json(inputs))
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct GetArgs {
|
||||
input: Option<bool>,
|
||||
allow_large: Option<bool>,
|
||||
}
|
||||
async fn get_args_from_history_or_saved_input(
|
||||
authed: ApiAuthed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
Query(g): Query<GetArgs>,
|
||||
Path((w_id, job_or_input_id)): Path<(String, Uuid)>,
|
||||
) -> JsonResult<Option<Value>> {
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
let result_o = sqlx::query_scalar!(
|
||||
"SELECT args FROM completed_job WHERE id = $1 AND workspace_id = $2 UNION ALL SELECT args FROM input WHERE id = $1 AND workspace_id = $2",
|
||||
let result_o = if let Some(input) = g.input {
|
||||
if input {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT CASE WHEN pg_column_size(args) < 40000 OR $3 THEN args ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as args FROM input WHERE id = $1 AND workspace_id = $2",
|
||||
job_or_input_id,
|
||||
w_id,
|
||||
g.allow_large.unwrap_or(true)
|
||||
)
|
||||
.fetch_optional(&mut *tx)
|
||||
.await?
|
||||
} else {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT CASE WHEN pg_column_size(args) < 40000 OR $3 THEN args ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as args FROM completed_job WHERE id = $1 AND workspace_id = $2",
|
||||
job_or_input_id,
|
||||
w_id,
|
||||
g.allow_large.unwrap_or(true)
|
||||
)
|
||||
.fetch_optional(&mut *tx)
|
||||
.await?
|
||||
}
|
||||
} else {
|
||||
sqlx::query_scalar!(
|
||||
"SELECT CASE WHEN pg_column_size(args) < 40000 OR $3 THEN args ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as args FROM completed_job WHERE id = $1 AND workspace_id = $2 UNION ALL SELECT CASE WHEN pg_column_size(args) < 40000 OR $3 THEN args ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as args FROM input WHERE id = $1 AND workspace_id = $2",
|
||||
job_or_input_id,
|
||||
w_id
|
||||
w_id,
|
||||
g.allow_large.unwrap_or(true)
|
||||
)
|
||||
.fetch_optional(&mut *tx)
|
||||
.await?;
|
||||
.await?
|
||||
};
|
||||
|
||||
tx.commit().await?;
|
||||
|
||||
@@ -206,7 +235,7 @@ async fn list_saved_inputs(
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
|
||||
let rows = sqlx::query_as::<_, InputRow>(
|
||||
"select id, workspace_id, runnable_id, runnable_type, name, CASE WHEN pg_column_size(args) < 40000 THEN args ELSE '\"WINDMILL_TOO_BIG\"'::jsonb END as args, created_at, created_by, is_public from input \
|
||||
"select id, workspace_id, runnable_id, runnable_type, name, 'null'::jsonb as args, created_at, created_by, is_public from input \
|
||||
where runnable_id = $1 and runnable_type = $2 and workspace_id = $3 \
|
||||
and (is_public IS true OR created_by = $4) \
|
||||
order by created_at desc limit $5 offset $6",
|
||||
|
||||
@@ -1466,7 +1466,7 @@ async fn list_jobs(
|
||||
};
|
||||
|
||||
let sql = if lq.success.is_none() && lq.label.is_none() {
|
||||
let sqlq = list_queue_jobs_query(
|
||||
let mut sqlq = list_queue_jobs_query(
|
||||
&w_id,
|
||||
&ListQueueQuery { order_desc: Some(true), ..lq.into() },
|
||||
UnifiedJob::queued_job_fields(),
|
||||
@@ -1482,10 +1482,10 @@ async fn list_jobs(
|
||||
offset
|
||||
)
|
||||
} else {
|
||||
sqlq.query()?
|
||||
sqlq.limit(per_page).offset(offset).query()?
|
||||
}
|
||||
} else {
|
||||
sqlc.unwrap().query()?
|
||||
sqlc.unwrap().limit(per_page).offset(offset).query()?
|
||||
};
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
|
||||
|
||||
@@ -52,13 +52,21 @@
|
||||
? 'FlowPath'
|
||||
: undefined
|
||||
|
||||
let hasAlreadyFailed = false
|
||||
async function loadInputHistory() {
|
||||
previousInputs = await InputService.getInputHistory({
|
||||
workspace: $workspaceStore!,
|
||||
runnableId,
|
||||
runnableType,
|
||||
perPage: 10
|
||||
})
|
||||
try {
|
||||
previousInputs = await InputService.getInputHistory({
|
||||
workspace: $workspaceStore!,
|
||||
runnableId,
|
||||
runnableType,
|
||||
perPage: 10
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
if (hasAlreadyFailed) return
|
||||
hasAlreadyFailed = true
|
||||
sendUserToast(`Failed to load input history: ${e}`, true)
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSavedInputs() {
|
||||
@@ -139,30 +147,31 @@
|
||||
}
|
||||
|
||||
$: {
|
||||
if ($workspaceStore && jobs && (scriptHash || scriptPath || flowPath)) {
|
||||
console.log('loading inputs')
|
||||
if ($workspaceStore && (scriptHash || scriptPath || flowPath)) {
|
||||
loadInputHistory()
|
||||
loadSavedInputs()
|
||||
}
|
||||
}
|
||||
|
||||
let previewArgs: any = undefined
|
||||
|
||||
function selectArgs(selected_args: any) {
|
||||
dispatch('selected_args', selected_args)
|
||||
previewArgs = selected_args
|
||||
}
|
||||
|
||||
async function loadLargeArgs(id: string | undefined) {
|
||||
async function loadLargeArgs(
|
||||
id: string | undefined,
|
||||
input: boolean | undefined,
|
||||
allowLarge: boolean
|
||||
): Promise<any> {
|
||||
if (!id) return
|
||||
largeArgs = await InputService.getArgsFromHistoryOrSavedInput({
|
||||
return await InputService.getArgsFromHistoryOrSavedInput({
|
||||
jobOrInputId: id,
|
||||
workspace: $workspaceStore!
|
||||
workspace: $workspaceStore!,
|
||||
input,
|
||||
allowLarge
|
||||
})
|
||||
}
|
||||
|
||||
let hasLargeArgs = false
|
||||
$: hasLargeArgs =
|
||||
typeof selectedInput?.args === 'string' && selectedInput?.args === 'WINDMILL_TOO_BIG'
|
||||
let largeArgs: any = undefined
|
||||
$: hasLargeArgs && loadLargeArgs(selectedInput?.id)
|
||||
</script>
|
||||
|
||||
<JobLoader
|
||||
@@ -181,6 +190,7 @@
|
||||
syncQueuedRunsCount={false}
|
||||
refreshRate={10000}
|
||||
computeMinAndMax={undefined}
|
||||
perPage={5}
|
||||
/>
|
||||
|
||||
<div class="min-w-[300px] h-full">
|
||||
@@ -207,17 +217,17 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="w-full flex flex-col gap-2 h-full overflow-y-auto p">
|
||||
<div class="w-full flex flex-col gap-1 h-full overflow-y-auto p">
|
||||
{#if savedInputs === undefined}
|
||||
<Skeleton layout={[[8]]} />
|
||||
{:else if savedInputs.length > 0}
|
||||
{#each savedInputs as i}
|
||||
<button
|
||||
class={classNames(
|
||||
`w-full flex items-center group justify-between gap-4 py-2 px-4 text-left border rounded-md hover:bg-surface-hover transition-all`,
|
||||
`w-full flex items-center text-sm group justify-between gap-4 py-1.5 px-4 text-left border rounded-sm hover:bg-surface-hover transition-all`,
|
||||
selectedInput === i ? 'border-blue-500 bg-blue-50 dark:bg-blue-900' : ''
|
||||
)}
|
||||
on:click={() => {
|
||||
on:click={async () => {
|
||||
if (!i.isEditing) {
|
||||
if (selectedInput === i) {
|
||||
selectedInput = null
|
||||
@@ -225,6 +235,7 @@
|
||||
selectedInput = i
|
||||
}
|
||||
}
|
||||
selectArgs(await loadLargeArgs(i.id, true, false))
|
||||
}}
|
||||
>
|
||||
<div class="w-full h-full items-center justify-between flex gap-1 min-w-0">
|
||||
@@ -308,8 +319,8 @@
|
||||
<span class="text-sm font-semibold">Previous runs</span>
|
||||
|
||||
<div class="w-full flex flex-col gap-1 p-0 h-full overflow-y-auto">
|
||||
{#if loading}
|
||||
<Skeleton layout={[[2]]} />
|
||||
{#if loading && (jobs == undefined || jobs?.length == 0)}
|
||||
<div class="text-left text-tertiary text-xs">Loading current runs...</div>
|
||||
{:else if jobs.length > 0}
|
||||
{#each jobs as i (i.id)}
|
||||
<button
|
||||
@@ -324,7 +335,7 @@
|
||||
<div class="">
|
||||
<div class="rounded-full w-2 h-2 bg-orange-400 animate-pulse" />
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<div class="col-span-2 truncate">
|
||||
{i.created_by}
|
||||
</div>
|
||||
<div
|
||||
@@ -345,6 +356,11 @@
|
||||
</div>
|
||||
</button>
|
||||
{/each}
|
||||
{#if jobs.length == 5}
|
||||
<div class="text-left text-tertiary text-xs"
|
||||
>... there may be more runs not displayed here as the limit is 5</div
|
||||
>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="text-left text-tertiary text-xs">No running runs</div>
|
||||
{/if}
|
||||
@@ -360,12 +376,13 @@
|
||||
`w-full flex items-center justify-between gap-4 py-2 px-4 text-left border rounded-sm hover:bg-surface-hover transition-a`,
|
||||
selectedInput === i ? 'border-blue-500 bg-blue-50 dark:bg-blue-900' : ''
|
||||
)}
|
||||
on:click={() => {
|
||||
on:click={async () => {
|
||||
if (selectedInput === i) {
|
||||
selectedInput = null
|
||||
} else {
|
||||
selectedInput = i
|
||||
}
|
||||
selectArgs(await loadLargeArgs(i.id, false, false))
|
||||
}}
|
||||
>
|
||||
<div
|
||||
@@ -374,7 +391,7 @@
|
||||
<div class="">
|
||||
<div class="rounded-full w-2 h-2 {i.success ? 'bg-green-400' : 'bg-red-400'}" />
|
||||
</div>
|
||||
<div class="col-span-2">
|
||||
<div class="col-span-2 truncate" title={i.created_by}>
|
||||
{i.created_by}
|
||||
</div>
|
||||
<div
|
||||
@@ -410,33 +427,29 @@
|
||||
<Pane>
|
||||
<div class="h-full overflow-hidden min-h-0 flex flex-col justify-between">
|
||||
<div class="w-full flex flex-col min-h-0 gap-2 px-2 py-2 grow">
|
||||
<div class="text-sm font-semibold">Preview</div>
|
||||
<div class="w-full flex flex-col">
|
||||
<Button
|
||||
color="blue"
|
||||
btnClasses="w-full"
|
||||
size="sm"
|
||||
spacingSize="xl"
|
||||
on:click={() => selectArgs(hasLargeArgs ? largeArgs : selectedInput?.args)}
|
||||
disabled={Object.keys(selectedInput?.args || {}).length === 0 ||
|
||||
(hasLargeArgs && Object.keys(largeArgs || {}).length === 0)}
|
||||
on:click={async () => {
|
||||
dispatch('selected_args', await loadLargeArgs(selectedInput?.id, undefined, false))
|
||||
}}
|
||||
disabled={!selectedInput}
|
||||
>
|
||||
<ArrowLeftIcon class="w-4 h-4 mr-2" />
|
||||
Use Input
|
||||
</Button>
|
||||
</div>
|
||||
<div class="w-full min-h-0 grow overflow-auto">
|
||||
{#if hasLargeArgs}
|
||||
{#if largeArgs}
|
||||
<div class=" overflow-auto h-full p-2">
|
||||
<ObjectViewer json={largeArgs} />
|
||||
</div>
|
||||
{:else}
|
||||
<Skeleton layout={[[8]]} />
|
||||
{/if}
|
||||
{:else if Object.keys(selectedInput?.args || {}).length > 0}
|
||||
{#if typeof previewArgs == 'string' && previewArgs == 'WINDMILL_TOO_BIG'}
|
||||
<div class="text-secondary mt-2">
|
||||
Payload too big to preview but can still be loaded</div
|
||||
>
|
||||
{:else if Object.keys(previewArgs || {}).length > 0}
|
||||
<div class=" overflow-auto h-full p-2">
|
||||
<ObjectViewer json={selectedInput?.args} />
|
||||
<ObjectViewer json={previewArgs} />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-center text-tertiary">
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
export let allWorkspaces: boolean = false
|
||||
export let computeMinAndMax: (() => { minTs: string; maxTs: string } | undefined) | undefined
|
||||
export let lookback: number = 0
|
||||
export let perPage: number | undefined = undefined
|
||||
|
||||
let intervalId: NodeJS.Timeout | undefined
|
||||
let sync = true
|
||||
@@ -135,7 +136,8 @@
|
||||
resultFilter && resultFilter != '{}' && resultFilter != '' && resultError == ''
|
||||
? resultFilter
|
||||
: undefined,
|
||||
allWorkspaces: allWorkspaces ? true : undefined
|
||||
allWorkspaces: allWorkspaces ? true : undefined,
|
||||
perPage
|
||||
})
|
||||
}
|
||||
|
||||
@@ -170,7 +172,8 @@
|
||||
resultFilter && resultFilter != '{}' && resultFilter != '' && resultError == ''
|
||||
? resultFilter
|
||||
: undefined,
|
||||
allWorkspaces: allWorkspaces ? true : undefined
|
||||
allWorkspaces: allWorkspaces ? true : undefined,
|
||||
perPage
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user