Compare commits
10 Commits
wmill-scri
...
fix/fronte
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01030ec3f8 | ||
|
|
b7f22b693e | ||
|
|
e1d67d82ce | ||
|
|
e60466397c | ||
|
|
00cbdcef36 | ||
|
|
318c55dccd | ||
|
|
d7c96160f9 | ||
|
|
eb20023ca8 | ||
|
|
088534c02d | ||
|
|
5d3459aaf1 |
@@ -4,10 +4,10 @@
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import { getScriptByPath } from '$lib/scripts'
|
||||
|
||||
import { CornerDownLeft, Loader2 } from 'lucide-svelte'
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import Button from './common/button/Button.svelte'
|
||||
import { RunButton } from '$lib/components/common'
|
||||
import DisplayResult from './DisplayResult.svelte'
|
||||
import type { FlowEditorContext } from './flows/types'
|
||||
import LogViewer from './LogViewer.svelte'
|
||||
@@ -36,6 +36,7 @@
|
||||
let testJobLoader: TestJobLoader
|
||||
let testIsLoading = false
|
||||
let testJob: Job | undefined = undefined
|
||||
let cancelLoading = false
|
||||
|
||||
let jobProgressReset: () => void
|
||||
|
||||
@@ -106,6 +107,7 @@
|
||||
<TestJobLoader
|
||||
toastError={noEditor}
|
||||
on:done={() => jobDone()}
|
||||
on:cancel-loading={({ detail }) => (cancelLoading = detail)}
|
||||
bind:scriptProgress
|
||||
bind:this={testJobLoader}
|
||||
bind:isLoading={testIsLoading}
|
||||
@@ -120,24 +122,12 @@
|
||||
{/if}
|
||||
|
||||
<div class="w-full justify-center flex">
|
||||
{#if testIsLoading}
|
||||
<Button size="sm" on:click={testJobLoader?.cancelJob} btnClasses="w-full" color="red">
|
||||
<Loader2 size={16} class="animate-spin mr-1" />
|
||||
Cancel
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
color="dark"
|
||||
btnClasses="truncate"
|
||||
size="sm"
|
||||
on:click={() => runTest(stepArgs)}
|
||||
shortCut={{
|
||||
Icon: CornerDownLeft
|
||||
}}
|
||||
>
|
||||
Run
|
||||
</Button>
|
||||
{/if}
|
||||
<RunButton
|
||||
on:run={() => runTest(stepArgs)}
|
||||
on:cancel={() => testJobLoader?.cancelJob()}
|
||||
{testIsLoading}
|
||||
bind:cancelLoading
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ModulePreviewForm {pickableProperties} {mod} {schema} bind:args={stepArgs} />
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
import TestJobLoader from './TestJobLoader.svelte'
|
||||
import JobProgressBar from '$lib/components/jobs/JobProgressBar.svelte'
|
||||
import { createEventDispatcher, onDestroy, onMount } from 'svelte'
|
||||
import { Button } from './common'
|
||||
import { Button, RunButton } from './common'
|
||||
import SplitPanesWrapper from './splitPanes/SplitPanesWrapper.svelte'
|
||||
import WindmillIcon from './icons/WindmillIcon.svelte'
|
||||
//import WindmillIcon from './icons/WindmillIcon.svelte'
|
||||
import * as Y from 'yjs'
|
||||
import { scriptLangToEditorLang } from '$lib/scripts'
|
||||
import { WebsocketProvider } from 'y-websocket'
|
||||
import Modal from './common/modal/Modal.svelte'
|
||||
import DiffEditor from './DiffEditor.svelte'
|
||||
import { Clipboard, CornerDownLeft, Github, Play } from 'lucide-svelte'
|
||||
import { Clipboard, Github } from 'lucide-svelte'
|
||||
import { setLicense } from '$lib/enterpriseUtils'
|
||||
import type { ScriptEditorWhitelabelCustomUi } from './custom_ui'
|
||||
import Tabs from './common/tabs/Tabs.svelte'
|
||||
@@ -31,6 +31,7 @@
|
||||
import CaptureTable from '$lib/components/triggers/CaptureTable.svelte'
|
||||
import CaptureButton from './triggers/CaptureButton.svelte'
|
||||
import { setContext } from 'svelte'
|
||||
import CaptureIcon from './triggers/CaptureIcon.svelte'
|
||||
|
||||
// Exported
|
||||
export let schema: Schema | any = emptySchema()
|
||||
@@ -92,6 +93,8 @@
|
||||
let yContent: Y.Text | undefined = undefined
|
||||
let peers: { name: string }[] = []
|
||||
let showCollabPopup = false
|
||||
let captureItems: Item[] = []
|
||||
let cancelLoading = false
|
||||
|
||||
const url = new URL(window.location.toString())
|
||||
let initialCollab = /true|1/i.test(url.searchParams.get('collab') ?? '0')
|
||||
@@ -272,12 +275,17 @@
|
||||
|
||||
<TestJobLoader
|
||||
on:done={loadPastTests}
|
||||
on:cancel-loading={() => (cancelLoading = true)}
|
||||
bind:scriptProgress
|
||||
bind:this={testJobLoader}
|
||||
bind:isLoading={testIsLoading}
|
||||
bind:job={testJob}
|
||||
/>
|
||||
|
||||
{#if customUi?.previewPanel?.disableTriggerButton !== true}
|
||||
<CaptureButton on:openTriggers hidden bind:items={captureItems} />
|
||||
{/if}
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
|
||||
<Modal title="Invite others" bind:open={showCollabPopup}>
|
||||
@@ -406,63 +414,17 @@
|
||||
{/if}
|
||||
|
||||
<div class="flex justify-center pt-1">
|
||||
{#if testIsLoading}
|
||||
<Button on:click={testJobLoader?.cancelJob} btnClasses="w-full" color="red" size="xs">
|
||||
<WindmillIcon
|
||||
white={true}
|
||||
class="mr-2 text-white"
|
||||
height="16px"
|
||||
width="20px"
|
||||
spin="fast"
|
||||
/>
|
||||
Cancel
|
||||
</Button>
|
||||
{:else if customUi?.previewPanel?.disableTriggerButton !== true}
|
||||
<div class="flex flex-row divide-x divide-gray-800 dark:divide-gray-300 items-stretch">
|
||||
<Button
|
||||
color="dark"
|
||||
on:click={() => {
|
||||
runTest()
|
||||
}}
|
||||
btnClasses="w-full rounded-r-none"
|
||||
size="xs"
|
||||
startIcon={{
|
||||
icon: Play,
|
||||
classes: 'animate-none'
|
||||
}}
|
||||
shortCut={{ Icon: CornerDownLeft, hide: testIsLoading }}
|
||||
>
|
||||
{#if testIsLoading}
|
||||
Running
|
||||
{:else}
|
||||
Test
|
||||
{/if}
|
||||
</Button>
|
||||
<CaptureButton on:openTriggers />
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex flex-row divide-x divide-gray-800 dark:divide-gray-300 items-stretch">
|
||||
<Button
|
||||
color="dark"
|
||||
on:click={() => {
|
||||
runTest()
|
||||
}}
|
||||
btnClasses="w-full"
|
||||
size="xs"
|
||||
startIcon={{
|
||||
icon: Play,
|
||||
classes: 'animate-none'
|
||||
}}
|
||||
shortCut={{ Icon: CornerDownLeft, hide: testIsLoading }}
|
||||
>
|
||||
{#if testIsLoading}
|
||||
Running
|
||||
{:else}
|
||||
Test
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
<RunButton
|
||||
on:cancel={testJobLoader?.cancelJob}
|
||||
on:run={() => runTest()}
|
||||
{testIsLoading}
|
||||
bind:dropdownItems={captureItems}
|
||||
bind:cancelLoading
|
||||
>
|
||||
<svelte:fragment slot="dropdownIcon">
|
||||
<CaptureIcon variant="redDot" />
|
||||
</svelte:fragment>
|
||||
</RunButton>
|
||||
</div>
|
||||
<Splitpanes horizontal class="!max-h-[calc(100%-43px)]">
|
||||
<Pane size={33}>
|
||||
|
||||
@@ -150,8 +150,9 @@
|
||||
export async function cancelJob() {
|
||||
const id = currentId
|
||||
if (id) {
|
||||
dispatch('cancel', id)
|
||||
currentId = undefined
|
||||
// currentId = undefined why do we need this? This leads to not watching the job anymore hence not getting the update of the cancelled job
|
||||
// dispatch('cancel', id) this event is not used anywhere
|
||||
dispatch('cancel-loading', true)
|
||||
try {
|
||||
await JobService.cancelQueuedJob({
|
||||
workspace: $workspaceStore ?? '',
|
||||
@@ -159,6 +160,7 @@
|
||||
requestBody: {}
|
||||
})
|
||||
} catch (err) {
|
||||
dispatch('cancel-loading', false)
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
@@ -283,7 +285,7 @@
|
||||
|
||||
async function syncer(id: string): Promise<void> {
|
||||
if (currentId != id) {
|
||||
dispatch('cancel', id)
|
||||
// dispatch('cancel', id) This event is not used anywhere
|
||||
return
|
||||
}
|
||||
syncIteration++
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
import { base } from '$lib/base'
|
||||
import ClipboardPanel from '$lib/components/details/ClipboardPanel.svelte'
|
||||
import LazyModePanel from './contextPanel/LazyModePanel.svelte'
|
||||
import { RunButton } from '$lib/components/common'
|
||||
|
||||
async function hash(message) {
|
||||
try {
|
||||
@@ -956,11 +957,21 @@
|
||||
}, 500)
|
||||
}
|
||||
$: customPath !== undefined && validateCustomPath(customPath)
|
||||
|
||||
let cancelLoading = false
|
||||
$: if (cancelLoading && !testIsLoading) {
|
||||
cancelLoading = false
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
|
||||
<TestJobLoader bind:this={testJobLoader} bind:isLoading={testIsLoading} bind:job />
|
||||
<TestJobLoader
|
||||
bind:this={testJobLoader}
|
||||
bind:isLoading={testIsLoading}
|
||||
bind:job
|
||||
on:cancel-loading={({ detail }) => (cancelLoading = detail)}
|
||||
/>
|
||||
|
||||
{#if $$slots.unsavedConfirmationModal}
|
||||
<slot
|
||||
@@ -1412,16 +1423,12 @@
|
||||
{:else}
|
||||
<div class="flex flex-col h-full w-full mb-4">
|
||||
{#if job?.['running']}
|
||||
<div class="flex flex-row-reverse w-full">
|
||||
<Button
|
||||
color="red"
|
||||
variant="border"
|
||||
on:click={() => testJobLoader?.cancelJob()}
|
||||
>
|
||||
<Loader2 size={14} class="animate-spin mr-2" />
|
||||
|
||||
Cancel
|
||||
</Button>
|
||||
<div class="flex flex-row-reverse w-full p-2 justify-center">
|
||||
<RunButton
|
||||
on:cancel={() => testJobLoader?.cancelJob()}
|
||||
{testIsLoading}
|
||||
{cancelLoading}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if job?.args}
|
||||
|
||||
@@ -294,7 +294,13 @@
|
||||
>
|
||||
Format
|
||||
</Button>
|
||||
<RunButton bind:runLoading {id} inlineScript={!transformer ? inlineScript : undefined} />
|
||||
<RunButton
|
||||
bind:runLoading
|
||||
{id}
|
||||
inlineScript={!transformer ? inlineScript : undefined}
|
||||
size="xs2"
|
||||
btnClasses="w-24 h-[28px]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
CancelablePromise,
|
||||
InlineScript
|
||||
} from '../../types'
|
||||
import { Button } from '$lib/components/common'
|
||||
import { CornerDownLeft, Loader2 } from 'lucide-svelte'
|
||||
import { RunButton } from '$lib/components/common'
|
||||
|
||||
export let id: string
|
||||
export let inlineScript: InlineScript | undefined = undefined
|
||||
export let runLoading = false
|
||||
export let hideShortcut = false
|
||||
export let size: 'xs' | 'xs2' = 'xs'
|
||||
export let btnClasses = ''
|
||||
|
||||
const { runnableComponents } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { runnableJobEditorPanel } = getContext<AppEditorContext>('AppEditorContext')
|
||||
@@ -20,38 +21,23 @@
|
||||
</script>
|
||||
|
||||
{#if $runnableComponents[id] != undefined}
|
||||
{#if !runLoading}
|
||||
<Button
|
||||
loading={runLoading}
|
||||
size="xs"
|
||||
color="dark"
|
||||
btnClasses="!px-2 !py-1"
|
||||
on:click={async () => {
|
||||
runLoading = true
|
||||
$runnableJobEditorPanel.focused = true
|
||||
try {
|
||||
cancelable = $runnableComponents[id]?.cb?.map((f) => f(inlineScript, true))
|
||||
await Promise.all(cancelable)
|
||||
} catch {}
|
||||
runLoading = false
|
||||
}}
|
||||
shortCut={{ Icon: CornerDownLeft, hide: hideShortcut }}
|
||||
>
|
||||
Run
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
size="xs"
|
||||
color="red"
|
||||
variant="border"
|
||||
btnClasses="!px-2 !py-1 !ml-[3px]"
|
||||
on:click={async () => {
|
||||
cancelable?.forEach((f) => f.cancel())
|
||||
runLoading = false
|
||||
}}
|
||||
>
|
||||
<Loader2 size={12} class="animate-spin mr-2" />
|
||||
Cancel
|
||||
</Button>
|
||||
{/if}
|
||||
<RunButton
|
||||
{btnClasses}
|
||||
testIsLoading={runLoading}
|
||||
{hideShortcut}
|
||||
on:cancel={async () => {
|
||||
cancelable?.forEach((f) => f.cancel())
|
||||
runLoading = false
|
||||
}}
|
||||
on:run={async () => {
|
||||
runLoading = true
|
||||
$runnableJobEditorPanel.focused = true
|
||||
try {
|
||||
cancelable = $runnableComponents[id]?.cb?.map((f) => f(inlineScript, true))
|
||||
await Promise.all(cancelable)
|
||||
} catch {}
|
||||
runLoading = false
|
||||
}}
|
||||
{size}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
56
frontend/src/lib/components/common/RunButton.svelte
Normal file
56
frontend/src/lib/components/common/RunButton.svelte
Normal file
@@ -0,0 +1,56 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/common'
|
||||
import WindmillIcon from '$lib/components/icons/WindmillIcon.svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { CornerDownLeft, Play } from 'lucide-svelte'
|
||||
import type { Item } from '$lib/utils'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let testIsLoading = false
|
||||
export let cancelLoading = false
|
||||
export let dropdownItems: Item[] = []
|
||||
export let btnClasses = ''
|
||||
export let hideShortcut = false
|
||||
export let size: 'xs' | 'xs2' = 'xs'
|
||||
|
||||
$: if (cancelLoading && !testIsLoading) {
|
||||
cancelLoading = false
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
if (testIsLoading) {
|
||||
dispatch('cancel')
|
||||
} else {
|
||||
dispatch('run')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Button
|
||||
color={testIsLoading ? 'red' : 'dark'}
|
||||
btnClasses={twMerge('w-28', btnClasses)}
|
||||
{size}
|
||||
on:click={handleClick}
|
||||
shortCut={testIsLoading || hideShortcut
|
||||
? undefined
|
||||
: {
|
||||
Icon: CornerDownLeft
|
||||
}}
|
||||
{dropdownItems}
|
||||
dropdownDisabled={testIsLoading}
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2 align-left">
|
||||
{#if testIsLoading}
|
||||
<WindmillIcon white={true} class="text-white" height="16px" width="16px" spin="fast" />
|
||||
{cancelLoading ? 'Canceling...' : 'Cancel'}
|
||||
{:else}
|
||||
<Play size={16} />
|
||||
Run
|
||||
{/if}
|
||||
</div>
|
||||
<svelte:fragment slot="dropdownIcon">
|
||||
<slot name="dropdownIcon" />
|
||||
</svelte:fragment>
|
||||
</Button>
|
||||
@@ -34,6 +34,7 @@
|
||||
export let shortCut:
|
||||
| { key?: string; hide?: boolean; Icon?: any; withoutModifier?: boolean }
|
||||
| undefined = undefined
|
||||
export let dropdownDisabled: boolean = false
|
||||
|
||||
type MenuItem = {
|
||||
label: string
|
||||
@@ -42,10 +43,25 @@
|
||||
icon?: any
|
||||
disabled?: boolean
|
||||
}
|
||||
export let dropdownItems: MenuItem[] | (() => MenuItem[]) | undefined = undefined
|
||||
export let dropdownItems: MenuItem[] | (() => MenuItem[]) | Item[] | undefined = undefined
|
||||
|
||||
function computeDropdowns(menuItems: MenuItem[] | (() => MenuItem[])): Item[] {
|
||||
function computeDropdowns(menuItems: MenuItem[] | (() => MenuItem[]) | Item[]): Item[] {
|
||||
const items = typeof menuItems === 'function' ? menuItems() : menuItems
|
||||
|
||||
function isItemArray(items: any[]): items is Item[] {
|
||||
return items.every(
|
||||
(item) =>
|
||||
'displayName' in item &&
|
||||
typeof item.displayName === 'string' &&
|
||||
(!('action' in item) || typeof item.action === 'function' || item.action === undefined) &&
|
||||
(!('disabled' in item) || typeof item.disabled === 'boolean')
|
||||
)
|
||||
}
|
||||
|
||||
if (items.length > 0 && isItemArray(items)) {
|
||||
return items
|
||||
}
|
||||
|
||||
return items.map((item) => ({
|
||||
displayName: item.label,
|
||||
action: item.onClick ? (e) => item.onClick?.(e) : undefined,
|
||||
@@ -232,7 +248,11 @@
|
||||
{/if}
|
||||
|
||||
{#if dropdownItems && dropdownItems.length > 0}
|
||||
<Dropdown items={computeDropdowns(dropdownItems)} class="h-auto w-fit">
|
||||
<Dropdown
|
||||
items={computeDropdowns(dropdownItems)}
|
||||
class="h-auto w-fit"
|
||||
disabled={dropdownDisabled}
|
||||
>
|
||||
<svelte:fragment slot="buttonReplacement">
|
||||
<div
|
||||
class={twMerge(
|
||||
@@ -242,7 +262,11 @@
|
||||
'rounded-r-md !rounded-l-none'
|
||||
)}
|
||||
>
|
||||
<ChevronDown class="w-5 h-5" />
|
||||
{#if $$slots.dropdownIcon}
|
||||
<slot name="dropdownIcon" />
|
||||
{:else}
|
||||
<ChevronDown class="w-5 h-5" />
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
</Dropdown>
|
||||
|
||||
@@ -16,6 +16,7 @@ export { default as TabContent } from './tabs/TabContent.svelte'
|
||||
export { default as Tabs } from './tabs/Tabs.svelte'
|
||||
export { default as Breadcrumb } from './breadcrumb/Breadcrumb.svelte'
|
||||
export { default as FileInput } from './fileInput/FileInput.svelte'
|
||||
export { default as RunButton } from './RunButton.svelte'
|
||||
|
||||
export * from './alert/model'
|
||||
export * from './badge/model'
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
import MqttIcon from '../icons/MqttIcon.svelte'
|
||||
|
||||
export let small = false
|
||||
export let hidden = false
|
||||
export let items: Item[] = []
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -75,32 +77,34 @@
|
||||
]
|
||||
</script>
|
||||
|
||||
<DropdownV2 {items} placement="bottom-start" fixedHeight={false}>
|
||||
<svelte:fragment slot="buttonReplacement">
|
||||
{#if small}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
variant="border"
|
||||
wrapperClasses="h-full"
|
||||
nonCaptureEvent
|
||||
title="Test trigger"
|
||||
>
|
||||
<div class="flex flex-row items-center gap-1">
|
||||
{#if !hidden}
|
||||
<DropdownV2 {items} placement="bottom-start" fixedHeight={false}>
|
||||
<svelte:fragment slot="buttonReplacement">
|
||||
{#if small}
|
||||
<Button
|
||||
color="light"
|
||||
size="xs"
|
||||
variant="border"
|
||||
wrapperClasses="h-full"
|
||||
nonCaptureEvent
|
||||
title="Test trigger"
|
||||
>
|
||||
<div class="flex flex-row items-center gap-1">
|
||||
<CaptureIcon variant="redDot" />
|
||||
<Plus size={10} class="text-red" />
|
||||
</div>
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
color="dark"
|
||||
btnClasses="!rounded-l-none"
|
||||
wrapperClasses="h-full"
|
||||
nonCaptureEvent
|
||||
title="Test trigger"
|
||||
>
|
||||
<CaptureIcon variant="redDot" />
|
||||
<Plus size={10} class="text-red" />
|
||||
</div>
|
||||
</Button>
|
||||
{:else}
|
||||
<Button
|
||||
color="dark"
|
||||
btnClasses="!rounded-l-none"
|
||||
wrapperClasses="h-full"
|
||||
nonCaptureEvent
|
||||
title="Test trigger"
|
||||
>
|
||||
<CaptureIcon variant="redDot" />
|
||||
</Button>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</DropdownV2>
|
||||
</Button>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</DropdownV2>
|
||||
{/if}
|
||||
|
||||
@@ -527,7 +527,7 @@
|
||||
{#if !forceCancel}
|
||||
<Button
|
||||
color="red"
|
||||
size="md"
|
||||
size="sm"
|
||||
startIcon={{ icon: TimerOff }}
|
||||
on:click|once={() => {
|
||||
if (job?.id) {
|
||||
@@ -543,7 +543,7 @@
|
||||
{:else}
|
||||
<Button
|
||||
color="red"
|
||||
size="md"
|
||||
size="sm"
|
||||
startIcon={{ icon: TimerOff }}
|
||||
on:click|once={() => {
|
||||
if (job?.id) {
|
||||
@@ -580,6 +580,7 @@
|
||||
restartFlow(job?.id, selectedJobStep, 0)
|
||||
}}
|
||||
startIcon={{ icon: RefreshCw }}
|
||||
size="sm"
|
||||
>
|
||||
Re-start from
|
||||
<Badge baseClass="ml-1" color="indigo">
|
||||
|
||||
Reference in New Issue
Block a user