mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-25 08:00:59 +00:00
feat: runs page have sharable args in hash of links
This commit is contained in:
@@ -1,16 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { defaultIfEmptyString, emptyString, truncateHash } from '$lib/utils'
|
||||
import {
|
||||
computeSharableHash as computeSharableHash,
|
||||
defaultIfEmptyString,
|
||||
emptyString,
|
||||
truncateHash
|
||||
} from '$lib/utils'
|
||||
|
||||
import type { Schema } from '$lib/common'
|
||||
import CliHelpBox from './CliHelpBox.svelte'
|
||||
import { Badge, Button } from './common'
|
||||
import SchemaForm from './SchemaForm.svelte'
|
||||
import SharedBadge from './SharedBadge.svelte'
|
||||
|
||||
import CollapseLink from './CollapseLink.svelte'
|
||||
import { SCRIPT_VIEW_SHOW_RUN_FROM_CLI } from '$lib/consts'
|
||||
import TimeAgo from './TimeAgo.svelte'
|
||||
import ClipboardPanel from './details/ClipboardPanel.svelte'
|
||||
import Popup from './common/popup/Popup.svelte'
|
||||
import { autoPlacement } from '@floating-ui/core'
|
||||
import { Calendar, CornerDownLeft } from 'lucide-svelte'
|
||||
@@ -44,8 +45,6 @@
|
||||
export let topButton = false
|
||||
export let loading = false
|
||||
export let noVariablePicker = false
|
||||
export let viewCliRun = false
|
||||
export let isFlow: boolean
|
||||
export let viewKeybinding = false
|
||||
|
||||
export let scheduledForStr: string | undefined
|
||||
@@ -68,9 +67,7 @@
|
||||
|
||||
export let isValid = true
|
||||
|
||||
$: cliCommand = `wmill ${isFlow ? 'flow' : 'script'} run ${runnable?.path} -d '${JSON.stringify(
|
||||
args
|
||||
)}'`
|
||||
$: window.location.hash = computeSharableHash(args)
|
||||
</script>
|
||||
|
||||
<div class="max-w-3xl">
|
||||
@@ -213,18 +210,4 @@
|
||||
{buttonText}
|
||||
</Button>
|
||||
{/if}
|
||||
|
||||
{#if viewCliRun}
|
||||
<div>
|
||||
<div class="mt-4" />
|
||||
{#if SCRIPT_VIEW_SHOW_RUN_FROM_CLI}
|
||||
<CollapseLink small text="Run it from CLI">
|
||||
<div class="mt-2" />
|
||||
<ClipboardPanel content={cliCommand} />
|
||||
<CliHelpBox />
|
||||
</CollapseLink>
|
||||
{/if}
|
||||
<div class="mb-20" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
export let scheduledForStr: string | undefined
|
||||
export let invisible_to_owner: boolean | undefined
|
||||
export let overrideTag: string | undefined
|
||||
|
||||
loadWorkerGroups()
|
||||
|
||||
async function loadWorkerGroups() {
|
||||
|
||||
@@ -21,7 +21,14 @@
|
||||
|
||||
let userSettings: UserSettings
|
||||
|
||||
export let webhooks: {
|
||||
export let token: string
|
||||
export let args: any
|
||||
export let scopes: string[] = []
|
||||
export let isFlow: boolean = false
|
||||
export let hash: string | undefined = undefined
|
||||
export let path: string
|
||||
|
||||
let webhooks: {
|
||||
async: {
|
||||
hash?: string
|
||||
path: string
|
||||
@@ -32,10 +39,39 @@
|
||||
get_path?: string
|
||||
}
|
||||
}
|
||||
export let token: string
|
||||
export let args: any
|
||||
export let scopes: string[] = []
|
||||
export let isFlow: boolean = false
|
||||
|
||||
$: webhooks = isFlow ? computeFlowWebhooks(path) : computeScriptWebhooks(hash, path)
|
||||
|
||||
function computeScriptWebhooks(hash: string | undefined, path: string) {
|
||||
let base = `${$page.url.origin}/api/w/${$workspaceStore}/jobs/`
|
||||
return {
|
||||
async: {
|
||||
hash: `${base}run/h/${hash}`,
|
||||
path: `${base}run/p/${path}`
|
||||
},
|
||||
sync: {
|
||||
hash: `${base}run_wait_result/h/${hash}`,
|
||||
path: `${base}run_wait_result/p/${path}`,
|
||||
get_path: `${base}run_wait_result/p/${path}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function computeFlowWebhooks(path: string) {
|
||||
let base = `${$page.url.origin}/api/w/${$workspaceStore}/jobs/`
|
||||
|
||||
let urlAsync = `${base}run/f/${path}`
|
||||
let urlSync = `${base}run_wait_result/f/${path}`
|
||||
return {
|
||||
async: {
|
||||
path: urlAsync
|
||||
},
|
||||
sync: {
|
||||
path: urlSync,
|
||||
get_path: urlSync
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let webhookType: 'async' | 'sync' = DEFAULT_WEBHOOK_TYPE
|
||||
let requestType: 'hash' | 'path' | 'get_path' = isFlow ? 'path' : 'path'
|
||||
|
||||
@@ -110,9 +110,8 @@
|
||||
async function fetchJobs(
|
||||
startedBefore: string | undefined,
|
||||
startedAfter: string | undefined,
|
||||
startedAfterCompletedJobs: string | undefined,
|
||||
startedAfterCompletedJobs: string | undefined
|
||||
): Promise<Job[]> {
|
||||
console.log('fetching jobs', startedAfter, startedBefore)
|
||||
return JobService.listJobs({
|
||||
workspace: $workspaceStore!,
|
||||
createdOrStartedBefore: startedBefore,
|
||||
|
||||
@@ -33,7 +33,6 @@ export const enterpriseLicense = writable<string | undefined>(undefined)
|
||||
export const workerTags = writable<string[] | undefined>(undefined)
|
||||
export const usageStore = writable<number>(0)
|
||||
export const workspaceUsageStore = writable<number>(0)
|
||||
export const runFormStore = writable<any>()
|
||||
export const oauthStore = writable<TokenResponse | undefined>(undefined)
|
||||
export const userStore = writable<UserExt | undefined>(undefined)
|
||||
export const workspaceStore = writable<string | undefined>(
|
||||
|
||||
@@ -49,14 +49,16 @@ export function displayDateOnly(dateString: string | Date | undefined): string {
|
||||
}
|
||||
}
|
||||
|
||||
export function subtractDaysFromDateString(dateString: string | undefined, days: number): string | undefined {
|
||||
export function subtractDaysFromDateString(
|
||||
dateString: string | undefined,
|
||||
days: number
|
||||
): string | undefined {
|
||||
if (dateString == undefined) {
|
||||
return undefined
|
||||
}
|
||||
let date = new Date(dateString)
|
||||
date.setDate(date.getDate() - days)
|
||||
return date.toISOString()
|
||||
|
||||
}
|
||||
|
||||
export function displayDate(
|
||||
@@ -507,7 +509,7 @@ export function isObject(obj: any) {
|
||||
|
||||
export function debounce(func: (...args: any[]) => any, wait: number) {
|
||||
let timeout: any
|
||||
return function(...args: any[]) {
|
||||
return function (...args: any[]) {
|
||||
// @ts-ignore
|
||||
const context = this
|
||||
clearTimeout(timeout)
|
||||
@@ -517,7 +519,7 @@ export function debounce(func: (...args: any[]) => any, wait: number) {
|
||||
|
||||
export function throttle<T>(func: (...args: any[]) => T, wait: number) {
|
||||
let timeout: any
|
||||
return function(...args: any[]) {
|
||||
return function (...args: any[]) {
|
||||
if (!timeout) {
|
||||
timeout = setTimeout(() => {
|
||||
timeout = null
|
||||
@@ -666,6 +668,17 @@ export function extractCustomProperties(styleStr: string): string {
|
||||
return customStyleStr
|
||||
}
|
||||
|
||||
export function computeSharableHash(args: any) {
|
||||
let nargs = {}
|
||||
Object.entries(args).forEach(([k, v]) => {
|
||||
if (v !== undefined) {
|
||||
// if
|
||||
nargs[k] = JSON.stringify(v)
|
||||
}
|
||||
})
|
||||
return new URLSearchParams(nargs).toString()
|
||||
}
|
||||
|
||||
export function toCamel(s: string) {
|
||||
return s.replace(/([-_][a-z])/gi, ($1) => {
|
||||
return $1.toUpperCase().replace('-', '').replace('_', '')
|
||||
@@ -711,7 +724,7 @@ export async function tryEvery({
|
||||
try {
|
||||
await tryCode()
|
||||
break
|
||||
} catch (err) { }
|
||||
} catch (err) {}
|
||||
i++
|
||||
}
|
||||
if (i >= times) {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import MoveDrawer from '$lib/components/MoveDrawer.svelte'
|
||||
import RunForm from '$lib/components/RunForm.svelte'
|
||||
import ShareModal from '$lib/components/ShareModal.svelte'
|
||||
import { runFormStore, userStore, workspaceStore } from '$lib/stores'
|
||||
import { userStore, workspaceStore } from '$lib/stores'
|
||||
import { sendUserToast } from '$lib/toast'
|
||||
import DeployWorkspaceDrawer from '$lib/components/DeployWorkspaceDrawer.svelte'
|
||||
import SavedInputs from '$lib/components/SavedInputs.svelte'
|
||||
@@ -55,9 +55,13 @@
|
||||
|
||||
$: cliCommand = `wmill flow run ${flow?.path} -d '${JSON.stringify(args)}'`
|
||||
|
||||
let previousPath: string | undefined = undefined
|
||||
$: {
|
||||
if ($workspaceStore && $userStore && $page.params.path) {
|
||||
loadFlow()
|
||||
if (previousPath !== path) {
|
||||
previousPath = path
|
||||
loadFlow()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,9 +92,6 @@
|
||||
} catch {}
|
||||
}
|
||||
|
||||
$: urlAsync = `${$page.url.origin}/api/w/${$workspaceStore}/jobs/run/f/${flow?.path}`
|
||||
$: urlSync = `${$page.url.origin}/api/w/${$workspaceStore}/jobs/run_wait_result/f/${flow?.path}`
|
||||
|
||||
let isValid = true
|
||||
let loading = false
|
||||
|
||||
@@ -113,11 +114,18 @@
|
||||
await goto('/run/' + run + '?workspace=' + $workspaceStore)
|
||||
}
|
||||
|
||||
let args = undefined
|
||||
let args: Record<string, any> | undefined = undefined
|
||||
|
||||
if ($runFormStore) {
|
||||
args = $runFormStore
|
||||
$runFormStore = undefined
|
||||
let hash = window.location.hash
|
||||
if (hash.length > 1) {
|
||||
console.log(hash)
|
||||
try {
|
||||
let searchParams = new URLSearchParams(hash.slice(1))
|
||||
let params = [...searchParams.entries()].map(([k, v]) => [k, JSON.parse(v)])
|
||||
args = Object.fromEntries(params)
|
||||
} catch (e) {
|
||||
console.error('Was not able to transform hash as args', e)
|
||||
}
|
||||
}
|
||||
|
||||
let moveDrawer: MoveDrawer
|
||||
@@ -359,7 +367,6 @@
|
||||
runnable={flow}
|
||||
runAction={runFlow}
|
||||
bind:args
|
||||
isFlow
|
||||
bind:this={runForm}
|
||||
/>
|
||||
<div class="py-10" />
|
||||
@@ -418,15 +425,7 @@
|
||||
<WebhooksPanel
|
||||
bind:token
|
||||
scopes={[`run:flow/${flow?.path}`]}
|
||||
webhooks={{
|
||||
async: {
|
||||
path: urlAsync
|
||||
},
|
||||
sync: {
|
||||
path: urlSync,
|
||||
get_path: urlSync
|
||||
}
|
||||
}}
|
||||
path={flow?.path}
|
||||
isFlow={true}
|
||||
{args}
|
||||
/>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
} from '$lib/gen'
|
||||
import {
|
||||
canWrite,
|
||||
computeSharableHash,
|
||||
copyToClipboard,
|
||||
displayDate,
|
||||
emptyString,
|
||||
@@ -43,7 +44,6 @@
|
||||
import DisplayResult from '$lib/components/DisplayResult.svelte'
|
||||
import {
|
||||
enterpriseLicense,
|
||||
runFormStore,
|
||||
superadmin,
|
||||
userStore,
|
||||
userWorkspaces,
|
||||
@@ -564,8 +564,7 @@
|
||||
{#if job?.job_kind === 'script' || job?.job_kind === 'flow'}
|
||||
<Button
|
||||
on:click|once={() => {
|
||||
$runFormStore = job?.args
|
||||
goto(viewHref)
|
||||
goto(viewHref + `#${computeSharableHash(job?.args)}`)
|
||||
}}
|
||||
color="blue"
|
||||
size="sm"
|
||||
@@ -577,7 +576,6 @@
|
||||
{#if canWrite(job?.script_path ?? '', {}, $userStore)}
|
||||
<Button
|
||||
on:click|once={() => {
|
||||
$runFormStore = job?.args
|
||||
goto(`${stem}/edit/${job?.script_path}${isScript ? `` : `?nodraft=true`}`)
|
||||
}}
|
||||
color="blue"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { ScriptService, type NewScript, type NewScriptWithDraft, DraftService } from '$lib/gen'
|
||||
|
||||
import { page } from '$app/stores'
|
||||
import { runFormStore, workspaceStore } from '$lib/stores'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import ScriptBuilder from '$lib/components/ScriptBuilder.svelte'
|
||||
import { decodeState, cleanValueProperties, orderedJsonStringify } from '$lib/utils'
|
||||
import { goto } from '$app/navigation'
|
||||
@@ -12,10 +12,6 @@
|
||||
|
||||
const initialState = $page.url.hash != '' ? $page.url.hash.slice(1) : undefined
|
||||
let initialArgs = {}
|
||||
if ($runFormStore) {
|
||||
initialArgs = $runFormStore
|
||||
$runFormStore = undefined
|
||||
}
|
||||
let topHash = $page.url.searchParams.get('topHash') ?? undefined
|
||||
|
||||
let hash = $page.url.searchParams.get('hash') ?? undefined
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
} from '$lib/utils'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import ShareModal from '$lib/components/ShareModal.svelte'
|
||||
import { hubBaseUrlStore, runFormStore, userStore, workspaceStore } from '$lib/stores'
|
||||
import { hubBaseUrlStore, userStore, workspaceStore } from '$lib/stores'
|
||||
import SchemaViewer from '$lib/components/SchemaViewer.svelte'
|
||||
import { onDestroy } from 'svelte'
|
||||
import HighlightCode from '$lib/components/HighlightCode.svelte'
|
||||
@@ -83,18 +83,12 @@
|
||||
$: cliCommand = `wmill script run ${script?.path} -d '${JSON.stringify(args)}'`
|
||||
|
||||
$: loading = !script
|
||||
|
||||
let previousHash: string | undefined = undefined
|
||||
$: if ($workspaceStore) {
|
||||
loadScript($page.params.hash)
|
||||
}
|
||||
$: webhooks = {
|
||||
async: {
|
||||
hash: `${$page.url.origin}/api/w/${$workspaceStore}/jobs/run/h/${script?.hash}`,
|
||||
path: `${$page.url.origin}/api/w/${$workspaceStore}/jobs/run/p/${script?.path}`
|
||||
},
|
||||
sync: {
|
||||
hash: `${$page.url.origin}/api/w/${$workspaceStore}/jobs/run_wait_result/h/${script?.hash}`,
|
||||
path: `${$page.url.origin}/api/w/${$workspaceStore}/jobs/run_wait_result/p/${script?.path}`,
|
||||
get_path: `${$page.url.origin}/api/w/${$workspaceStore}/jobs/run_wait_result/p/${script?.path}`
|
||||
if (previousHash != $page.params.hash) {
|
||||
previousHash = $page.params.hash
|
||||
loadScript($page.params.hash)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,13 +202,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
let args = undefined
|
||||
|
||||
if ($runFormStore) {
|
||||
args = $runFormStore
|
||||
$runFormStore = undefined
|
||||
let args: Record<string, any> | undefined = undefined
|
||||
let hash = window.location.hash
|
||||
if (hash.length > 1) {
|
||||
console.log(hash)
|
||||
try {
|
||||
let searchParams = new URLSearchParams(hash.slice(1))
|
||||
let params = [...searchParams.entries()].map(([k, v]) => [k, JSON.parse(v)])
|
||||
args = Object.fromEntries(params)
|
||||
} catch (e) {
|
||||
console.error('Was not able to transform hash as args', e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let moveDrawer: MoveDrawer
|
||||
let deploymentDrawer: DeployWorkspaceDrawer
|
||||
let persistentScriptDrawer: PersistentScriptDrawer
|
||||
@@ -595,7 +596,6 @@
|
||||
runAction={runScript}
|
||||
bind:args
|
||||
schedulable={true}
|
||||
isFlow={false}
|
||||
bind:this={runForm}
|
||||
/>
|
||||
|
||||
@@ -607,7 +607,8 @@
|
||||
{/if}
|
||||
<div class="flex flex-row gap-x-2 flex-wrap items-center">
|
||||
<span class="text-sm text-tertiary">
|
||||
Edited <TimeAgo withDate date={script.created_at || ''} /> by {script.created_by || 'unknown'}
|
||||
Edited <TimeAgo withDate date={script.created_at || ''} /> by {script.created_by ||
|
||||
'unknown'}
|
||||
</span>
|
||||
<Badge small color="gray">
|
||||
{truncateHash(script?.hash ?? '')}
|
||||
@@ -641,7 +642,13 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="webhooks">
|
||||
<WebhooksPanel bind:token scopes={[`run:script/${script?.path}`]} {webhooks} {args} />
|
||||
<WebhooksPanel
|
||||
bind:token
|
||||
scopes={[`run:script/${script?.path}`]}
|
||||
hash={script.hash}
|
||||
path={script.path}
|
||||
{args}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="schedule">
|
||||
<RunPageSchedules isFlow={false} path={script.path ?? ''} {can_write} />
|
||||
|
||||
Reference in New Issue
Block a user