mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-09 00:04:10 +00:00
feat(frontend): Badge component and script page (#617)
* fix(frontend): Consistent tooltip font size * feature(frontend): Add new badge component * feature(frontend): Add color type to badge * feature(frontend): Add copy to clipboard utility * feature(frontend): Update common badge component * feature(frontend): Update badge to handle icons * feature(frontend): Update script page design * feat(frontend): Add capitalize option to badges * fix(frontend): Fix shared badge text display
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
<script lang="ts">
|
||||
import { userStore } from '$lib/stores'
|
||||
import { faPeopleGroup } from '@fortawesome/free-solid-svg-icons'
|
||||
import Icon from 'svelte-awesome'
|
||||
import Badge from './common/badge/Badge.svelte'
|
||||
|
||||
import Badge from './Badge.svelte'
|
||||
export let extraPerms: Record<string, boolean> = {}
|
||||
export let canWrite: boolean
|
||||
|
||||
@@ -48,15 +47,8 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if kind == 'read' || kind == 'write'}
|
||||
<span class="mr-1 align-center">
|
||||
{#if kind == 'read'}
|
||||
<Badge tooltip={reason}>
|
||||
<Icon data={faPeopleGroup} scale={0.7} />
|
||||
read</Badge
|
||||
>
|
||||
{:else if kind == 'write'}
|
||||
<Badge tooltip={reason}><Icon data={faPeopleGroup} scale={0.7} /></Badge>
|
||||
{/if}
|
||||
</span>
|
||||
{#if kind === 'read' || kind === 'write'}
|
||||
<Badge icon={{ data: faPeopleGroup }} capitalize color="blue">
|
||||
{kind}
|
||||
</Badge>
|
||||
{/if}
|
||||
|
||||
@@ -58,6 +58,6 @@
|
||||
|
||||
<style>
|
||||
#tooltip {
|
||||
@apply z-50 font-normal text-gray-300 bg-zinc-800 p-4 rounded-xl whitespace-normal;
|
||||
@apply z-50 text-base font-normal text-gray-300 bg-zinc-800 p-4 rounded-xl whitespace-normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<script lang="ts">
|
||||
import { classNames } from '$lib/utils'
|
||||
import { CloseButton } from 'flowbite-svelte'
|
||||
import Icon from 'svelte-awesome'
|
||||
import { type BadgeColor, type BadgeIconProps, ColorModifier } from './model'
|
||||
|
||||
export let color: BadgeColor = 'gray'
|
||||
export let large = false
|
||||
export let href = ''
|
||||
export let rounded = false
|
||||
export let index = false
|
||||
export let dismissable = false
|
||||
export let baseClass = 'text-center -mb-0.5'
|
||||
export let capitalize = false
|
||||
export let icon: BadgeIconProps | undefined = undefined
|
||||
|
||||
let defaulIconProps: BadgeIconProps = {
|
||||
data: undefined,
|
||||
position: 'left',
|
||||
scale: 0.7
|
||||
}
|
||||
let hidden = false
|
||||
const colors: Record<BadgeColor, string> = {
|
||||
gray: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300',
|
||||
blue: 'bg-blue-100 text-blue-800 dark:bg-blue-200 dark:text-blue-800',
|
||||
red: 'bg-red-100 text-red-800 dark:bg-red-200 dark:text-red-900',
|
||||
green: 'bg-green-100 text-green-800 dark:bg-green-200 dark:text-green-900',
|
||||
yellow: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-200 dark:text-yellow-900',
|
||||
indigo: 'bg-indigo-100 text-indigo-800 dark:bg-indigo-200 dark:text-indigo-900',
|
||||
purple: 'bg-purple-100 text-purple-800 dark:bg-purple-200 dark:text-purple-900',
|
||||
pink: 'bg-pink-100 text-pink-800 dark:bg-pink-200 dark:text-pink-900',
|
||||
['dark-gray']: 'bg-gray-500 text-gray-100',
|
||||
['dark-blue']: 'bg-blue-500 text-blue-100',
|
||||
['dark-red']: 'bg-red-500 text-white',
|
||||
['dark-green']: 'bg-green-500 text-green-100',
|
||||
['dark-yellow']: 'bg-yellow-300 text-yellow-800',
|
||||
['dark-indigo']: 'bg-indigo-500 text-indigo-100',
|
||||
['dark-purple']: 'bg-purple-500 text-purple-100',
|
||||
['dark-pink']: 'bg-pink-500 text-pink-100'
|
||||
}
|
||||
const hovers: Partial<Record<BadgeColor, string>> = {
|
||||
gray: 'hover:bg-gray-200 dark:hover:bg-gray-300',
|
||||
blue: 'hover:bg-blue-200 dark:hover:bg-blue-300',
|
||||
red: 'hover:bg-red-200 dark:hover:bg-red-300',
|
||||
green: 'hover:bg-green-200 dark:hover:bg-green-300',
|
||||
yellow: 'hover:bg-yellow-200 dark:hover:bg-yellow-300',
|
||||
indigo: 'hover:bg-indigo-200 dark:hover:bg-indigo-300',
|
||||
purple: 'hover:bg-purple-200 dark:hover:bg-purple-300',
|
||||
pink: 'hover:bg-pink-200 dark:hover:bg-pink-300'
|
||||
}
|
||||
|
||||
$: badgeClass = classNames(
|
||||
baseClass,
|
||||
large ? 'text-sm font-medium' : 'text-xs font-semibold',
|
||||
colors[color],
|
||||
href &&
|
||||
(color.startsWith(ColorModifier) ? hovers[color.replace(ColorModifier, '')] : hovers[color]),
|
||||
rounded ? 'rounded-full px-2 py-1' : 'rounded px-2.5 py-0.5',
|
||||
index
|
||||
? 'absolute flex justify-center items-center font-bold overflow-hidden border-2 border-white dark:border-gray-900 ' +
|
||||
(large ? 'w-7 h-7 -top-3.5 -right-3.5' : 'w-6 h-6 -top-3 -right-3')
|
||||
: '',
|
||||
$$props.class
|
||||
)
|
||||
$: iconProps = icon ? { ...defaulIconProps, ...icon } : { data: undefined }
|
||||
const handleHide = () => (hidden = !hidden)
|
||||
</script>
|
||||
|
||||
<span class="inline-flex justify-center items-center">
|
||||
<svelte:element
|
||||
this={href ? 'a' : 'span'}
|
||||
{href}
|
||||
{...$$restProps}
|
||||
class={badgeClass}
|
||||
class:hidden
|
||||
class:capitalize
|
||||
>
|
||||
{#if iconProps.data && iconProps.position === 'left'}
|
||||
<Icon {...iconProps} />
|
||||
{/if}
|
||||
<slot />
|
||||
{#if iconProps.data && iconProps.position === 'right'}
|
||||
<Icon {...iconProps} />
|
||||
{/if}
|
||||
{#if dismissable}
|
||||
<CloseButton
|
||||
{color}
|
||||
on:click={handleHide}
|
||||
size={large ? 'sm' : 'xs'}
|
||||
class="ml-1.5 -mr-1.5"
|
||||
/>
|
||||
{/if}
|
||||
</svelte:element>
|
||||
</span>
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { IconProps } from 'svelte-awesome/components/Icon.svelte'
|
||||
|
||||
type BaseColor = 'blue' | 'gray' | 'red' | 'green' | 'yellow' | 'indigo' | 'purple' | 'pink'
|
||||
export const ColorModifier = 'dark-'
|
||||
export type BadgeColor = BaseColor | `${typeof ColorModifier}${BaseColor}`
|
||||
|
||||
export interface BadgeIconProps extends IconProps {
|
||||
position?: 'left' | 'right'
|
||||
}
|
||||
@@ -571,3 +571,16 @@ export function scriptLangToEditorLang(lang: Script.language): 'typescript' | 'p
|
||||
return lang
|
||||
}
|
||||
}
|
||||
|
||||
export async function copyToClipboard(value: string, sendToast = true): Promise<boolean> {
|
||||
let success = false
|
||||
if (navigator?.clipboard) {
|
||||
success = await navigator.clipboard
|
||||
.writeText(value)
|
||||
.then(() => true)
|
||||
.catch(() => false)
|
||||
}
|
||||
sendToast &&
|
||||
sendUserToast(success ? 'Copied to clipboard!' : "Couldn't copy to clipboard", !success)
|
||||
return success
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
displayDaysAgo,
|
||||
canWrite,
|
||||
defaultIfEmptyString,
|
||||
scriptToHubUrl
|
||||
scriptToHubUrl,
|
||||
copyToClipboard
|
||||
} from '$lib/utils'
|
||||
import Icon from 'svelte-awesome'
|
||||
import {
|
||||
@@ -28,7 +29,8 @@
|
||||
faShare,
|
||||
faSpinner,
|
||||
faGlobe,
|
||||
faCodeFork
|
||||
faCodeFork,
|
||||
faClipboard
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
@@ -41,6 +43,10 @@
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import { onDestroy } from 'svelte'
|
||||
import HighlightCode from '$lib/components/HighlightCode.svelte'
|
||||
import Badge from '$lib/components/common/badge/Badge.svelte'
|
||||
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
|
||||
import Tab from '$lib/components/common/tabs/Tab.svelte'
|
||||
import TabContent from '$lib/components/common/tabs/TabContent.svelte'
|
||||
|
||||
let script: Script | undefined
|
||||
let topHash: string | undefined
|
||||
@@ -50,9 +56,17 @@
|
||||
|
||||
let shareModal: ShareModal
|
||||
|
||||
$: {
|
||||
if ($workspaceStore) {
|
||||
loadScript($page.params.hash)
|
||||
$: if ($workspaceStore) {
|
||||
loadScript($page.params.hash)
|
||||
}
|
||||
$: webhooks = {
|
||||
uuid: {
|
||||
hash: `${$page.url.hostname}/api/w/${$workspaceStore}/jobs/run/h/${script?.hash}`,
|
||||
path: `${$page.url.hostname}/api/w/${$workspaceStore}/jobs/run/p/${script?.path}`
|
||||
},
|
||||
result: {
|
||||
hash: `${$page.url.hostname}/api/w/${$workspaceStore}/jobs/run_wait_result/h/${script?.hash}`,
|
||||
path: `${$page.url.hostname}/api/w/${$workspaceStore}/jobs/run_wait_result/p/${script?.path}`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,35 +132,100 @@
|
||||
</script>
|
||||
|
||||
<CenteredPage>
|
||||
<div class="flex flex-row justify-between">
|
||||
<h1>
|
||||
{script?.path ?? 'Loading...'}
|
||||
<span class="whitespace-nowrap">
|
||||
<a href="/scripts/get/{script?.hash}"
|
||||
><span class="commit-hash">{truncateHash(script?.hash ?? '')}</span></a
|
||||
>
|
||||
<Tooltip>Each script version has an immutable hash.</Tooltip>
|
||||
</span>
|
||||
{#if script?.is_template}
|
||||
<span class="mx-2 bg-blue-500 rounded-md bg-opacity-25 text-sm font-normal px-1 py-px"
|
||||
>Template</span
|
||||
>
|
||||
{/if}
|
||||
{#if script && script.kind != 'script'}
|
||||
<span class="mx-2 bg-blue-500 rounded-md bg-opacity-25 text-sm font-normal px-1 py-px"
|
||||
>{script.kind}</span
|
||||
>
|
||||
{/if}
|
||||
<SharedBadge canWrite={can_write} extraPerms={script?.extra_perms ?? {}} />
|
||||
{#if deploymentInProgress}
|
||||
<span class="bg-yellow-200 text-gray-700 text-xs rounded px-1 mx-3">
|
||||
Deployment in progress <Icon class="animate-spin" data={faSpinner} scale={0.8} />
|
||||
<div class="flex flex-row flex-wrap justify-between gap-4">
|
||||
<div>
|
||||
<div class="flex items-center flex-wrap mb-2">
|
||||
<h1 class="font-bold text-blue-500 break-all !p-0 mr-2">
|
||||
{script?.path ?? 'Loading...'}
|
||||
</h1>
|
||||
<div class="flex items-center gap-2">
|
||||
<Badge color="dark-gray">
|
||||
{truncateHash(script?.hash ?? '')}
|
||||
</Badge>
|
||||
{#if script?.is_template}
|
||||
<Badge color="blue">Template</Badge>
|
||||
{/if}
|
||||
{#if script && script.kind !== 'script'}
|
||||
<Badge color="blue">
|
||||
{script?.kind}
|
||||
</Badge>
|
||||
{/if}
|
||||
{#if deploymentInProgress}
|
||||
<Badge
|
||||
color="yellow"
|
||||
icon={{ data: faSpinner, position: 'right', class: 'animate-spin' }}
|
||||
>
|
||||
Deployment in progress
|
||||
</Badge>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
<p class="mb-2">
|
||||
<SharedBadge canWrite={can_write} extraPerms={script?.extra_perms ?? {}} />
|
||||
<span class="text-sm text-gray-500">
|
||||
{#if script}
|
||||
Edited {displayDaysAgo(script.created_at || '')} by {script.created_by || 'unknown'}
|
||||
{/if}
|
||||
</span>
|
||||
{/if}
|
||||
</h1>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{#if script}
|
||||
<div class="flex flex-row-reverse px-6">
|
||||
<div class="flex items-start flex-wrap gap-1">
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/scripts/run/{script.hash}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faPlay} scale={0.5} />
|
||||
<span class="pl-1">Run</span>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/scripts/edit/{script.hash}?step=2"
|
||||
class:disabled={!can_write}
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faEdit} scale={0.5} />
|
||||
<span class="pl-1">Edit</span>
|
||||
</div>
|
||||
</a>
|
||||
{#if !topHash}
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/scripts/add?template={script.path}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faCodeFork} scale={0.5} />
|
||||
<span class="pl-1">Use as template/Fork</span>
|
||||
</div>
|
||||
</a>
|
||||
{/if}
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/runs/{script.path}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faList} scale={0.5} />
|
||||
<span class="pl-1">View runs</span>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
target="_blank"
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href={scriptToHubUrl(
|
||||
script.content,
|
||||
script.summary,
|
||||
script.description ?? '',
|
||||
script.kind
|
||||
).toString()}
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faGlobe} scale={0.5} />
|
||||
<span class="pl-1">Publish to Hub</span>
|
||||
</div>
|
||||
</a>
|
||||
<Dropdown
|
||||
dropdownItems={[
|
||||
{
|
||||
@@ -187,213 +266,146 @@
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<div class="px-1">
|
||||
<a
|
||||
target="_blank"
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href={scriptToHubUrl(
|
||||
script.content,
|
||||
script.summary,
|
||||
script.description ?? '',
|
||||
script.kind
|
||||
).toString()}
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faGlobe} scale={0.5} />
|
||||
<span class="pl-1">Publish to Hub</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="px-1">
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/runs/{script.path}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faList} scale={0.5} />
|
||||
<span class="pl-1">View runs</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{#if !topHash}
|
||||
<div class="px-1">
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/scripts/edit/{script.hash}?step=2"
|
||||
class:disabled={!can_write}
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faEdit} scale={0.5} />
|
||||
<span class="pl-1">Edit</span>
|
||||
</div>
|
||||
</a>
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/scripts/add?template={script.path}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faCodeFork} scale={0.5} />
|
||||
<span class="pl-1">Use as template/Fork</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="px-1">
|
||||
<a
|
||||
class="inline-flex items-center default-button bg-transparent hover:bg-blue-500 text-blue-700 font-normal hover:text-white py-0 px-1 border-blue-500 hover:border-transparent rounded"
|
||||
href="/scripts/run/{script.hash}"
|
||||
>
|
||||
<div class="inline-flex items-center justify-center">
|
||||
<Icon class="text-blue-500" data={faPlay} scale={0.5} />
|
||||
<span class="pl-1">Run</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<ShareModal bind:this={shareModal} kind="script" path={script?.path ?? ''} />
|
||||
|
||||
<div class="grid grid-cols-1 gap-6 max-w-7xl pb-6">
|
||||
<div class="flex flex-col gap-8 max-w-7xl pb-2">
|
||||
{#if script === undefined}
|
||||
<p>loading</p>
|
||||
{:else}
|
||||
<p class="text-sm">Edited {displayDaysAgo(script.created_at ?? '')} by {script.created_by}</p>
|
||||
|
||||
<h2>{script.summary}</h2>
|
||||
|
||||
<div class="prose">
|
||||
<SvelteMarkdown source={defaultIfEmptyString(script.description, 'No description')} />
|
||||
<div>
|
||||
<h2 class="font-bold mt-8 mb-2">{script.summary}</h2>
|
||||
<div class="prose">
|
||||
<SvelteMarkdown source={defaultIfEmptyString(script.description, 'No description')} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if script.lock_error_logs}
|
||||
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4" role="alert">
|
||||
<p class="font-bold">Error deploying this script</p>
|
||||
<p>This script has not been deployed successfully because of the following errors:</p>
|
||||
<pre class="w-full text-xs mt-2 whitespace-pre-wrap">{script.lock_error_logs}</pre>
|
||||
</div>
|
||||
{/if}
|
||||
{#if topHash}
|
||||
<div class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-4" role="alert">
|
||||
<p class="font-bold">Not HEAD</p>
|
||||
<p>
|
||||
This hash is not HEAD (latest non-archived version at this path) :
|
||||
<a href="/scripts/get/{topHash}">Go to the HEAD of this path</a>
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if script.archived}
|
||||
<div class="bg-red-100 border-l-4 border-red-500 text-orange-700 p-4" role="alert">
|
||||
<p class="font-bold">Archived</p>
|
||||
<p>This version was archived</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if script.deleted}
|
||||
<div class="bg-red-100 border-l-4 border-red-600 text-orange-700 p-4" role="alert">
|
||||
<p class="font-bold">Deleted</p>
|
||||
<p>The content of this script was deleted (by an admin, no less)</p>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div>
|
||||
<h3>
|
||||
Current hash <Tooltip
|
||||
>The hash is an immutable and perpetual unique identifier for this version of this
|
||||
script. The history of all hashes of a script constitute its lineage. This mechanism
|
||||
shares some of the principles of git which identify each commit with an equivalent hash</Tooltip
|
||||
>
|
||||
</h3>
|
||||
<p class="text-gray-700">
|
||||
<a href="/scripts/get/{script?.hash}">{script?.hash}</a>
|
||||
</p>
|
||||
<h3 class="whitespace-nowrap mt-2">
|
||||
Webhook to run this script and get job's uuid as response
|
||||
<Tooltip
|
||||
>Send a POST http request with a token as bearer token (or pass it as query arg '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
|
||||
>
|
||||
</h3>
|
||||
|
||||
<pre><code
|
||||
>By hash: <a
|
||||
href="//{$page.url.hostname}/api/w/{$workspaceStore}/jobs/run/h/{script?.hash}"
|
||||
>{$page.url.hostname}/api/w/{$workspaceStore}/jobs/run/h/{script?.hash}</a
|
||||
></code
|
||||
></pre>
|
||||
<pre><code
|
||||
>By path: <a
|
||||
href="//{$page.url.hostname}/api/w/{$workspaceStore}/jobs/run/p/{script?.path}"
|
||||
>{$page.url.hostname}/api/w/{$workspaceStore}/jobs/run/p/{script?.path}</a
|
||||
></code
|
||||
></pre>
|
||||
<h3 class="whitespace-nowrap mt-2">
|
||||
Endpoint to run this script and get job's result as response
|
||||
<Tooltip
|
||||
>Send a POST http request with a token as bearer token (or pass it as query arg '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
|
||||
>
|
||||
</h3>
|
||||
|
||||
<pre><code
|
||||
><a
|
||||
href="//{$page.url
|
||||
.hostname}/api/w/{$workspaceStore}/jobs/run_wait_result/p/{script?.path}"
|
||||
>{$page.url.hostname}/api/w/{$workspaceStore}/jobs/run_wait_result/p/{script?.path}</a
|
||||
></code
|
||||
></pre>
|
||||
<pre><code
|
||||
><a
|
||||
href="//{$page.url
|
||||
.hostname}/api/w/{$workspaceStore}/jobs/run_wait_result/h/{script?.hash}"
|
||||
>{$page.url.hostname}/api/w/{$workspaceStore}/jobs/run_wait_result/h/{script?.hash}</a
|
||||
></code
|
||||
></pre>
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
Previous versions of this script <Tooltip
|
||||
>When you edit a script, a new hash is created and the hashes corresponding to the
|
||||
previous versions of this script are archived</Tooltip
|
||||
>
|
||||
</h3>
|
||||
<ul>
|
||||
{#each script?.parent_hashes ?? [] as p_hash}
|
||||
<li><a href="/scripts/get/{p_hash}">{p_hash}</a></li>
|
||||
{/each}
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<div class="grid grid-cols-2 gap-4 pb-1 mb-3 border-b">
|
||||
<h3 class="text-gray-700 ">
|
||||
Arguments JSON schema <Tooltip
|
||||
>The jsonschema defines the constraints that the payload must respect to be compatible
|
||||
with the input parameters of this script. The UI form is generated automatically from
|
||||
the script jsonschema. See <a href="https://json-schema.org/"
|
||||
>jsonschema documentation</a
|
||||
></Tooltip
|
||||
{#if script.lock_error_logs || topHash || script.archived || script.deleted}
|
||||
<div class="flex flex-col gap-2">
|
||||
{#if script.lock_error_logs}
|
||||
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4" role="alert">
|
||||
<p class="font-bold">Error deploying this script</p>
|
||||
<p>This script has not been deployed successfully because of the following errors:</p>
|
||||
<pre class="w-full text-xs mt-2 whitespace-pre-wrap">{script.lock_error_logs}</pre>
|
||||
</div>
|
||||
{/if}
|
||||
{#if topHash}
|
||||
<div
|
||||
class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-4"
|
||||
role="alert"
|
||||
>
|
||||
</h3>
|
||||
<p class="font-bold">Not HEAD</p>
|
||||
<p>
|
||||
This hash is not HEAD (latest non-archived version at this path) :
|
||||
<a href="/scripts/get/{topHash}">Go to the HEAD of this path</a>
|
||||
</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if script.archived}
|
||||
<div class="bg-red-100 border-l-4 border-red-500 text-orange-700 p-4" role="alert">
|
||||
<p class="font-bold">Archived</p>
|
||||
<p>This version was archived</p>
|
||||
</div>
|
||||
{/if}
|
||||
{#if script.deleted}
|
||||
<div class="bg-red-100 border-l-4 border-red-600 text-orange-700 p-4" role="alert">
|
||||
<p class="font-bold">Deleted</p>
|
||||
<p>The content of this script was deleted (by an admin, no less)</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<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>
|
||||
<div class="border rounded-sm shadow-sm p-4">
|
||||
<Tabs selected="uuid">
|
||||
<Tab value="uuid">UUID</Tab>
|
||||
<Tab value="result">Result</Tab>
|
||||
<svelte:fragment slot="content">
|
||||
{#each Object.keys(webhooks) as key}
|
||||
<TabContent value={key}>
|
||||
<ul>
|
||||
{#each Object.keys(webhooks[key]) as type}
|
||||
{@const url = webhooks[key][type]}
|
||||
<li class="flex justify-between items-center mt-2">
|
||||
<a
|
||||
href={'//' + url}
|
||||
class="whitespace-nowrap text-ellipsis overflow-hidden mr-1"
|
||||
>
|
||||
{url}
|
||||
</a>
|
||||
<div class="flex">
|
||||
<Badge color="dark-gray" capitalize>
|
||||
{type}
|
||||
</Badge>
|
||||
<button
|
||||
on:click|preventDefault={() => copyToClipboard(url)}
|
||||
class="flex items-center bg-blue-600 text-white rounded-md px-2 ml-2"
|
||||
>
|
||||
<Icon data={faClipboard} />
|
||||
<span class="ml-1">Copy</span>
|
||||
</button>
|
||||
</div>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
</TabContent>
|
||||
{/each}
|
||||
</svelte:fragment>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
<div class="lg:w-1/2">
|
||||
<h3 class="text-lg mb-1 font-bold text-gray-600">Versions</h3>
|
||||
<div class="border rounded-sm shadow-sm p-4">
|
||||
<h4 class="font-bold text-gray-500">Current</h4>
|
||||
<div class="mt-1">
|
||||
{script?.hash}
|
||||
</div>
|
||||
<h4 class="font-bold text-gray-500 mt-2">Previous</h4>
|
||||
{#if script?.parent_hashes?.length}
|
||||
<ul class="max-h-20 overflow-y-auto">
|
||||
{#each script.parent_hashes as hash}
|
||||
<li class="mt-1">
|
||||
<a href="/scripts/get/{hash}">{hash}</a>
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
{:else}
|
||||
<p class="text-sm text-gray-500">There are no previous versions</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg mb-1 font-bold text-gray-600">
|
||||
Arguments JSON schema
|
||||
<Tooltip>
|
||||
The jsonschema defines the constraints that the payload must respect to be compatible
|
||||
with the input parameters of this script. The UI form is generated automatically from
|
||||
the script jsonschema. See
|
||||
<a href="https://json-schema.org/"> jsonschema documentation </a>
|
||||
</Tooltip>
|
||||
</h3>
|
||||
<SchemaViewer schema={script.schema} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-gray-700 pb-1 mb-3 border-b">Code</h3>
|
||||
<h3 class="text-lg mb-1 font-bold text-gray-600">Code</h3>
|
||||
<HighlightCode language={script.language} code={script.content} />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-gray-700 pb-1 mb-3 border-b">Dependencies lock file</h3>
|
||||
<pre class="text-xs">{script.lock}</pre>
|
||||
<h3 class="text-lg mb-1 font-bold text-gray-600">Dependencies lock file</h3>
|
||||
{#if script?.lock}
|
||||
<pre class="text-xs">{script.lock}</pre>
|
||||
{:else}
|
||||
<p class="text-sm text-gray-500">There is no lock file for this script</p>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</CenteredPage>
|
||||
|
||||
<style>
|
||||
h3 {
|
||||
@apply text-lg mb-2 mt-4 text-gray-600;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user