mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-26 08:01:38 +00:00
improve webhooks for UX
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import Drawer from './common/drawer/Drawer.svelte'
|
||||
import { DrawerContent } from './common'
|
||||
import ObjectViewer from './propertyPicker/ObjectViewer.svelte'
|
||||
|
||||
export let value: any
|
||||
let jsonViewer: Drawer
|
||||
@@ -20,11 +21,9 @@
|
||||
jsonViewerContent = (await ResourceService.getResource({ workspace: $workspaceStore!, path }))
|
||||
.value
|
||||
}
|
||||
|
||||
$: asJson = JSON.stringify(value, null, 4)
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={jsonViewer} size="400px">
|
||||
<Drawer bind:this={jsonViewer} size="800px">
|
||||
<DrawerContent title="See JSON" on:close={jsonViewer.toggleDrawer}>
|
||||
<Highlight language={json} code={JSON.stringify(jsonViewerContent, null, 4)} />
|
||||
</DrawerContent>
|
||||
@@ -42,14 +41,29 @@
|
||||
await getResource(value.substring('$res:'.length))
|
||||
jsonViewer.toggleDrawer()
|
||||
}}>{value}</button
|
||||
>{:else if asJson.length > 40}
|
||||
{truncate(asJson, 40)}<a
|
||||
href="#json"
|
||||
on:click|preventDefault={() => {
|
||||
jsonViewerContent = value
|
||||
jsonViewer.toggleDrawer()
|
||||
}}>(+)</a
|
||||
>
|
||||
{:else if typeof value !== 'object'}
|
||||
{truncate(value, 40)}
|
||||
{#if JSON.stringify(value).length > 40}
|
||||
<button
|
||||
class="text-xs text-blue-500"
|
||||
on:click={() => {
|
||||
jsonViewerContent = value
|
||||
jsonViewer.toggleDrawer()
|
||||
}}>See expanded</button
|
||||
>
|
||||
{/if}
|
||||
{:else}
|
||||
{asJson}
|
||||
<div class="max-h-40 overflow-auto">
|
||||
<ObjectViewer pureViewer={true} json={value} />
|
||||
</div>
|
||||
{#if JSON.stringify(value).length > 120}
|
||||
<button
|
||||
class="text-xs text-blue-500"
|
||||
on:click={() => {
|
||||
jsonViewerContent = value
|
||||
jsonViewer.toggleDrawer()
|
||||
}}>See JSON</button
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
{#if job && job.args && Object.keys(job.args).length > 0}
|
||||
{#each Object.entries(job.args) as [arg, value]}
|
||||
<tr>
|
||||
<td>{arg}</td>
|
||||
<td> <ArgInfo {value} /></td>
|
||||
<td class="font-semibold">{arg}</td>
|
||||
<td><ArgInfo {value} /></td>
|
||||
</tr>
|
||||
{/each}
|
||||
{:else if job}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import Icon from 'svelte-awesome'
|
||||
import { check } from 'svelte-awesome/icons'
|
||||
import { Badge } from '../common'
|
||||
|
||||
const SMALL_ICON_SCALE = 0.7
|
||||
|
||||
@@ -95,19 +96,12 @@
|
||||
{/if}
|
||||
</div>
|
||||
<div class="whitespace-nowrap">
|
||||
{#if job.script_hash}
|
||||
<a href="/scripts/get/{job.script_hash}" class="commit-hash"
|
||||
>{truncateHash(job.script_hash ?? '')}</a
|
||||
{#if 'job_kind' in job}<a href="/run/{job.id}"
|
||||
><Badge color="blue">{job.job_kind}</Badge></a
|
||||
>
|
||||
{/if}
|
||||
{#if 'job_kind' in job && job.job_kind != 'script'}<span
|
||||
class="bg-blue-200 text-gray-700 text-xs rounded px-1 whitespace-nowrap"
|
||||
><a href="/run/{job.id}">{job.job_kind}</a></span
|
||||
>
|
||||
{:else if job.is_flow_step}
|
||||
<span class="bg-blue-200 text-gray-700 text-xs rounded px-1 "
|
||||
><a href="/run/{job.parent_job}">step of flow</a></span
|
||||
>
|
||||
{#if (job.is_flow_step && job.job_kind == 'script') || job.job_kind == 'preview'}
|
||||
<a href="/run/{job.parent_job}"><Badge color="gray">flow step</Badge></a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
export let pureViewer = false
|
||||
export let collapsed = level == 3 || Array.isArray(json)
|
||||
export let rawKey = false
|
||||
export let topBrackets = false
|
||||
|
||||
const collapsedSymbol = '...'
|
||||
let keys: string | any[]
|
||||
@@ -44,12 +45,13 @@
|
||||
{#if level != 0}
|
||||
<span class="cursor-pointer hover:bg-gray-200 px-1 rounded" on:click={collapse}> (-) </span>
|
||||
{/if}
|
||||
{#if level == 0 && topBrackets}<span class="h-0">{openBracket}</span>{/if}
|
||||
<ul class="w-full">
|
||||
{#each keys as key, index}
|
||||
<li class="pt-1">
|
||||
<button
|
||||
on:click={() => selectProp(key)}
|
||||
class="key font-normal rounded px-1 hover:bg-blue-100"
|
||||
class="key {pureViewer ? 'cursor-auto' : ''} font-normal rounded px-1 hover:bg-blue-100"
|
||||
>
|
||||
{!isArray ? key : index}:
|
||||
</button>
|
||||
@@ -65,7 +67,9 @@
|
||||
/>
|
||||
{:else}
|
||||
<button
|
||||
class="val rounded px-1 hover:bg-blue-100 {getTypeAsString(json[key])}"
|
||||
class="val {pureViewer
|
||||
? 'cursor-auto'
|
||||
: ''} rounded px-1 hover:bg-blue-100 {getTypeAsString(json[key])}"
|
||||
on:click={() => selectProp(key)}
|
||||
>
|
||||
{#if json[key] === NEVER_TESTED_THIS_FAR}
|
||||
@@ -80,6 +84,7 @@
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{#if level == 0 && topBrackets}<span class="h-0">{closeBracket}</span>{/if}
|
||||
</span>
|
||||
<span
|
||||
class="cursor-pointer hover:bg-gray-200 {level == 0 ? 'ml-2' : ''}"
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
canWrite,
|
||||
sendUserToast,
|
||||
defaultIfEmptyString,
|
||||
flowToHubUrl
|
||||
flowToHubUrl,
|
||||
copyToClipboard
|
||||
} from '$lib/utils'
|
||||
import {
|
||||
faPlay,
|
||||
@@ -24,7 +25,8 @@
|
||||
faCalendar,
|
||||
faShare,
|
||||
faGlobe,
|
||||
faCodeFork
|
||||
faCodeFork,
|
||||
faClipboard
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
@@ -37,7 +39,10 @@
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import FlowViewer from '$lib/components/FlowViewer.svelte'
|
||||
import ObjectViewer from '$lib/components/propertyPicker/ObjectViewer.svelte'
|
||||
import { Button, ActionRow, Skeleton } from '$lib/components/common'
|
||||
import { Button, ActionRow, Skeleton, Badge } from '$lib/components/common'
|
||||
import UserSettings from '$lib/components/UserSettings.svelte'
|
||||
|
||||
let userSettings: UserSettings
|
||||
|
||||
let flow: Flow | undefined
|
||||
let schedule: Schedule | undefined
|
||||
@@ -87,8 +92,12 @@
|
||||
flow = await FlowService.getFlowByPath({ workspace: $workspaceStore!, path })
|
||||
can_write = canWrite(flow.path, flow.extra_perms!, $userStore)
|
||||
}
|
||||
|
||||
$: url = `${$page.url.hostname}/api/w/${$workspaceStore}/jobs/run/f/${flow?.path}`
|
||||
</script>
|
||||
|
||||
<UserSettings bind:this={userSettings} />
|
||||
|
||||
<Skeleton
|
||||
class="!max-w-6xl !px-4 sm:!px-6 md:!px-8"
|
||||
loading={!flow}
|
||||
@@ -200,10 +209,11 @@
|
||||
<p class="text-sm text-gray-600"
|
||||
>Edited {displayDaysAgo(flow.edited_at ?? '')} by {flow.edited_by}</p
|
||||
>
|
||||
<h2>{flow.summary}</h2>
|
||||
|
||||
<div class="prose">
|
||||
<SvelteMarkdown source={defaultIfEmptyString(flow.description, 'No description')} />
|
||||
<div>
|
||||
<h2 class="font-bold mb-2">{flow.summary}</h2>
|
||||
<div class="prose">
|
||||
<SvelteMarkdown source={defaultIfEmptyString(flow.description, 'No description')} />
|
||||
</div>
|
||||
</div>
|
||||
{#if schedule}
|
||||
<div>
|
||||
@@ -242,19 +252,38 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div>
|
||||
<span>Webhook to run this flow:</span>
|
||||
<Tooltip
|
||||
>Send a POST http request with a token as bearer token and the args respecting the
|
||||
corresponding jsonschema as payload. To create a permanent token, go to your user setting
|
||||
by clicking your username on the top-left.</Tooltip
|
||||
>
|
||||
<pre
|
||||
><code
|
||||
><a href="/api/w/{$workspaceStore}/jobs/run/f/{flow?.path}"
|
||||
>/api/w/{$workspaceStore}/jobs/run/f/{flow?.path}</a
|
||||
></code
|
||||
></pre
|
||||
<h3 class="text-lg mb-1 font-bold text-gray-600"
|
||||
>Webhook<Tooltip
|
||||
>To trigger this script with a webhook, do a POST request to the endpoint below. Flows
|
||||
are not public and can only be run by users with at least view rights on them. You will
|
||||
need to pass a bearer token to authentify as a user. You can either pass it as a Bearer
|
||||
token or as query arg `?token=XXX`. <a
|
||||
href="https://docs.windmill.dev/docs/getting_started/webhooks">See docs</a
|
||||
></Tooltip
|
||||
></h3
|
||||
>
|
||||
<div class="max-w-lg border border-blue-200 p-4">
|
||||
<div class="flex flex-row gap-x-2">
|
||||
<a
|
||||
href={$page.url.protocol + '//' + url}
|
||||
class="whitespace-nowrap text-ellipsis overflow-hidden mr-1"
|
||||
>
|
||||
{url}
|
||||
</a>
|
||||
<Button
|
||||
on:click={() => copyToClipboard($page.url.protocol + '//' + url)}
|
||||
color="blue"
|
||||
size="xs"
|
||||
startIcon={{ icon: faClipboard }}
|
||||
btnClasses="ml-2"
|
||||
>
|
||||
Copy
|
||||
</Button>
|
||||
</div>
|
||||
<div class="flex flex-row-reverse mt-2">
|
||||
<Button size="xs" on:click={userSettings.toggleDrawer}>Create token</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-gray-700 pb-1 mb-3 border-b">Flow</h2>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
import JobArgs from '$lib/components/JobArgs.svelte'
|
||||
import FlowProgressBar from '$lib/components/flows/FlowProgressBar.svelte'
|
||||
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
|
||||
import Badge from '$lib/components/common/badge/Badge.svelte'
|
||||
|
||||
let workspace_id_query: string | undefined = $page.url.searchParams.get('workspace') ?? undefined
|
||||
let workspace_id: string | undefined
|
||||
@@ -206,14 +207,11 @@
|
||||
{/if}
|
||||
{job.script_path ?? (job.job_kind == 'dependencies' ? 'lock dependencies' : 'No path')}
|
||||
{#if job.script_hash}
|
||||
<a
|
||||
href="/scripts/get/{job.script_hash}"
|
||||
class="text-2xs text-gray-500 bg-gray-100 font-mono">{truncateHash(job.script_hash)}</a
|
||||
<a href="/scripts/get/{job.script_hash}"
|
||||
><Badge color="gray">{truncateHash(job.script_hash)}</Badge></a
|
||||
>
|
||||
{/if}
|
||||
{#if job && 'job_kind' in job}<span
|
||||
class="bg-blue-200 text-gray-700 text-xs rounded px-1 mx-3">{job.job_kind}</span
|
||||
>
|
||||
{#if job && 'job_kind' in job}<Badge color="blue">{job.job_kind}</Badge>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
@@ -255,9 +253,11 @@
|
||||
<Tabs bind:selected={viewTab}>
|
||||
<Tab value="result">Result</Tab>
|
||||
<Tab value="logs">Logs</Tab>
|
||||
<Tab value="code"
|
||||
>{job?.job_kind == 'dependencies' ? 'Input Dependencies' : 'Code previewed'}</Tab
|
||||
>
|
||||
{#if job?.job_kind == 'dependencies'}
|
||||
<Tab value="code">Dependencies</Tab>
|
||||
{:else if job?.job_kind == 'preview'}
|
||||
<Tab value="code">Code</Tab>
|
||||
{/if}
|
||||
</Tabs>
|
||||
|
||||
<Skeleton loading={!job} layout={[[5]]} />
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
import Tab from '$lib/components/common/tabs/Tab.svelte'
|
||||
import JobDetail from '$lib/components/jobs/JobDetail.svelte'
|
||||
import { Skeleton } from '$lib/components/common'
|
||||
import Tooltip from '../../lib/components/Tooltip.svelte'
|
||||
import { goto } from '$app/navigation'
|
||||
import PageHeader from '$lib/components/PageHeader.svelte'
|
||||
|
||||
|
||||
@@ -43,7 +43,9 @@
|
||||
import HighlightCode from '$lib/components/HighlightCode.svelte'
|
||||
import { Badge, Tabs, Tab, TabContent, Button, ActionRow } from '$lib/components/common'
|
||||
import Skeleton from '../../../lib/components/common/skeleton/Skeleton.svelte'
|
||||
import UserSettings from '$lib/components/UserSettings.svelte'
|
||||
|
||||
let userSettings: UserSettings
|
||||
let script: Script | undefined
|
||||
let topHash: string | undefined
|
||||
let can_write = false
|
||||
@@ -128,6 +130,8 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<UserSettings bind:this={userSettings} />
|
||||
|
||||
<Skeleton {loading} class="!px-4 sm:!px-6 md:!px-8 !max-w-6xl" layout={[0.75, [2, 0, 2], 1]} />
|
||||
{#if script}
|
||||
<ActionRow applyPageWidth stickToTop>
|
||||
@@ -326,7 +330,16 @@
|
||||
|
||||
<div class="flex flex-col lg:flex-row gap-4">
|
||||
<div class="lg:w-1/2">
|
||||
<h3 class="text-lg mb-1 font-bold text-gray-600">Webhooks</h3>
|
||||
<h3 class="text-lg mb-1 font-bold text-gray-600"
|
||||
>Webhooks<Tooltip
|
||||
>To trigger this script with a webhook, do a POST request to the endpoints below.
|
||||
Scripts are not public and can only be run by users with at least view rights on them.
|
||||
You will need to pass a bearer token to authentify as a user. You can either pass it as
|
||||
a Bearer token or as query arg `?token=XXX`. <a
|
||||
href="https://docs.windmill.dev/docs/getting_started/webhooks">See docs</a
|
||||
></Tooltip
|
||||
></h3
|
||||
>
|
||||
<Skeleton {loading} layout={[[8.5]]} />
|
||||
{#if script}
|
||||
<div class="box">
|
||||
@@ -363,6 +376,9 @@
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<div class="flex flex-row-reverse mt-2">
|
||||
<Button size="xs" on:click={userSettings.toggleDrawer}>Create token</Button>
|
||||
</div>
|
||||
</TabContent>
|
||||
{/each}
|
||||
</svelte:fragment>
|
||||
|
||||
Reference in New Issue
Block a user