mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-05 08:02:18 +00:00
fix: improve flow editor step switch performance
* replace on click wt on pointer down on flow node click
* pointerdown on virtualitems
* Load monaco async with a placeholder to avoid size flash
* monaco placeholder for editor
* less flashing
* simulate first line bg
* better match to monaco
* more fine tune
* fix for increased browser font sizes
* flow nodes feel much better to click on
* move setTimeout upwards
* only load async in flow editor
* load async monaco in app
* lots of components dont respect the type and pass undefined
* weird outline when opening and closing OutputPicker
* fixed hover flow nodes
* moved setTimeout upwards
* hover color for virtual items
* wrong Cargo.lock
* disable interaction if not selectable
* pixel perfect editor placeholder
* fake monaco editor perfect in flow editor
* fake monaco for app json editor
* (temp) never load editor monaco
* os dependant constants in monaco
* Revert " (temp) never load editor monaco"
This reverts commit c20fca134d.
---------
Co-authored-by: Diego Imbert <diego@windmill.dev>
This commit is contained in:
co-authored by
Diego Imbert
parent
34b307b2be
commit
58fa4c8006
@@ -175,6 +175,7 @@
|
||||
import GlobalReviewButtons from './copilot/chat/GlobalReviewButtons.svelte'
|
||||
import { writable } from 'svelte/store'
|
||||
import { formatResourceTypes } from './copilot/chat/core'
|
||||
import FakeMonacoPlaceHolder from './FakeMonacoPlaceHolder.svelte'
|
||||
// import EditorTheme from './EditorTheme.svelte'
|
||||
|
||||
let divEl: HTMLDivElement | null = null
|
||||
@@ -221,6 +222,7 @@
|
||||
export let disabled: boolean = false
|
||||
export let lineNumbersMinChars = 3
|
||||
export let isAiPanelOpen: boolean = false
|
||||
export let loadAsync = false
|
||||
|
||||
const rHash = randomHash()
|
||||
$: filePath = computePath(path)
|
||||
@@ -1374,9 +1376,14 @@
|
||||
})
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
onMount(async () => {
|
||||
if (BROWSER) {
|
||||
loadMonaco().then((x) => (disposeMethod = x))
|
||||
if (loadAsync) {
|
||||
setTimeout(() => loadMonaco().then((x) => (disposeMethod = x)), 0)
|
||||
} else {
|
||||
let m = await loadMonaco()
|
||||
disposeMethod = m
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1408,6 +1415,11 @@
|
||||
</script>
|
||||
|
||||
<EditorTheme />
|
||||
{#if !editor}
|
||||
<div class="inset-0 absolute overflow-clip">
|
||||
<FakeMonacoPlaceHolder {code} />
|
||||
</div>
|
||||
{/if}
|
||||
<div bind:this={divEl} class="{$$props.class} editor {disabled ? 'disabled' : ''}"></div>
|
||||
{#if $vimMode}
|
||||
<div class="fixed bottom-0 z-30" bind:this={statusDiv}></div>
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
<!-- Used to avoid height jitter when loading monaco asynchronously -->
|
||||
|
||||
<script lang="ts">
|
||||
import { getOS } from '$lib/utils'
|
||||
|
||||
type Props = {
|
||||
code?: string
|
||||
autoheight?: boolean
|
||||
lineNumbersWidth?: number
|
||||
lineNumbersOffset?: number
|
||||
class?: string
|
||||
fontSize?: number
|
||||
}
|
||||
|
||||
let {
|
||||
code,
|
||||
autoheight = false,
|
||||
lineNumbersWidth = 51,
|
||||
lineNumbersOffset = 0,
|
||||
class: className = '',
|
||||
fontSize = 14
|
||||
}: Props = $props()
|
||||
|
||||
// https://github.com/microsoft/vscode/blob/baa2dad3cdacd97ac02eff0604984faf1167ff1e/src/vs/editor/common/config/editorOptions.ts#L5421
|
||||
const DEFAULT_WINDOWS_FONT_FAMILY = "Consolas, 'Courier New', monospace"
|
||||
const DEFAULT_MAC_FONT_FAMILY = "Menlo, Monaco, 'Courier New', monospace"
|
||||
const DEFAULT_LINUX_FONT_FAMILY = "'Droid Sans Mono', 'monospace', monospace"
|
||||
const fontFamily =
|
||||
getOS() === 'Windows'
|
||||
? DEFAULT_WINDOWS_FONT_FAMILY
|
||||
: getOS() === 'macOS'
|
||||
? DEFAULT_MAC_FONT_FAMILY
|
||||
: DEFAULT_LINUX_FONT_FAMILY
|
||||
|
||||
// https://github.com/microsoft/vscode/blob/baa2dad3cdacd97ac02eff0604984faf1167ff1e/src/vs/editor/common/config/fontInfo.ts#L14
|
||||
const GOLDEN_LINE_HEIGHT_RATIO = getOS() == 'macOS' ? 1.5 : 1.35
|
||||
|
||||
let lines = $derived(code?.split('\n') ?? [])
|
||||
|
||||
const charWidth = 9 // try to match as closely as possible to monaco editor
|
||||
|
||||
const lineHeight = fontSize * GOLDEN_LINE_HEIGHT_RATIO
|
||||
|
||||
let [clientWidth, clientHeight] = $state([0, 0])
|
||||
let showHorizontalScrollbar = $derived(
|
||||
lines.some((line) => line.length * charWidth > clientWidth - 40)
|
||||
)
|
||||
|
||||
let [editorWidth, editorHeight] = $derived([
|
||||
clientWidth,
|
||||
autoheight ? lines.length * lineHeight + (showHorizontalScrollbar ? 12 : 0) : clientHeight
|
||||
])
|
||||
</script>
|
||||
|
||||
<!-- Copy pasted from actual monaco editor in the web inspector -->
|
||||
|
||||
<div
|
||||
bind:clientWidth
|
||||
bind:clientHeight
|
||||
class="h-full w-full relative editor dark:bg-[#272D38] {className}"
|
||||
style="--vscode-editorCodeLens-lineHeight: 18px; --vscode-editorCodeLens-fontSize: 12px; --vscode-editorCodeLens-fontFeatureSettings: 'liga' off, 'calt' off; --code-editorInlayHintsFontFamily: {fontFamily};"
|
||||
>
|
||||
<div
|
||||
class="monaco-editor no-user-select mac standalone showUnused showDeprecated vs-dark"
|
||||
role="code"
|
||||
>
|
||||
<div class="overflow-guard" style="width: {editorWidth}px; height: {editorHeight}px;">
|
||||
<div
|
||||
class="margin"
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
style="position: absolute; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; width: {editorWidth}px; height: {editorHeight}px;"
|
||||
>
|
||||
<div
|
||||
class="margin-view-overlays"
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
style="position: absolute; font-family: {fontFamily}; font-weight: normal; font-size: {fontSize}px; font-feature-settings: 'liga' 0, 'calt' 0; font-variation-settings: normal; line-height: {lineHeight}px; letter-spacing: 0px; width: {lineNumbersWidth}px; height: 4893px;"
|
||||
>
|
||||
{#each lines as _, i}
|
||||
<div style="top:{lineHeight * i}px;height:{lineHeight}px;">
|
||||
<div class="line-numbers" style="left:{lineNumbersOffset}px;width:25px;">{i + 1}</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="monaco-scrollable-element editor-scrollable vs-dark mac"
|
||||
style="position: absolute; overflow: hidden; left: {lineNumbersWidth}px; width: {editorWidth}px; height: {editorHeight}px"
|
||||
>
|
||||
<div
|
||||
class="lines-content monaco-editor-background"
|
||||
style="position: absolute; overflow: hidden; width: 1.67772e+07px; height: 1.67772e+07px; transform: translate3d(0px, 0px, 0px); contain: strict; top: 0px; left: 0px;"
|
||||
>
|
||||
<div
|
||||
class="view-lines monaco-mouse-cursor-text text-tertiary/60"
|
||||
style="line-height: {lineHeight}px; position: absolute; font-family: {fontFamily}; font-weight: normal; font-size: {fontSize}px; font-feature-settings: 'liga' 0, 'calt' 0; font-variation-settings: normal; line-height: {lineHeight}px; letter-spacing: 0px; width: 1143px; height: 789px;"
|
||||
>
|
||||
{#each lines as line, i}
|
||||
<div
|
||||
style="height: {lineHeight}px; top: {i * lineHeight}px;"
|
||||
class="text-nowrap whitespace-pre"
|
||||
>
|
||||
{line}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -515,6 +515,7 @@
|
||||
on:change={() => {
|
||||
dispatch('change', { argName, arg })
|
||||
}}
|
||||
loadAsync
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -583,6 +584,7 @@
|
||||
focused = false
|
||||
}}
|
||||
autoHeight
|
||||
loadAsync
|
||||
/>
|
||||
</div>
|
||||
{#if !hideHelpButton}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
export let error = ''
|
||||
export let editor: SimpleEditor | undefined = undefined
|
||||
export let small = false
|
||||
export let loadAsync = false
|
||||
|
||||
$: tooBig = code && code?.length > 1000000
|
||||
|
||||
@@ -38,6 +39,7 @@
|
||||
<div class="flex flex-col w-full">
|
||||
<div class="border w-full">
|
||||
<SimpleEditor
|
||||
{loadAsync}
|
||||
{small}
|
||||
on:focus
|
||||
on:blur
|
||||
|
||||
@@ -135,7 +135,7 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<div class="flex flex-col w-full items-start">
|
||||
<div class="flex flex-col w-full items-start min-h-9">
|
||||
<div class="flex flex-row w-full items-center">
|
||||
{#if collection?.length > 0}
|
||||
<Select
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
import { vimMode } from '$lib/stores'
|
||||
import { initVim } from './monaco_keybindings'
|
||||
import { buildWorkerDefinition } from '$lib/monaco_workers/build_workers'
|
||||
import FakeMonacoPlaceHolder from './FakeMonacoPlaceHolder.svelte'
|
||||
// import { createConfiguredEditor } from 'vscode/monaco'
|
||||
// import type { IStandaloneCodeEditor } from 'vscode/vscode/vs/editor/standalone/browser/standaloneCodeEditor'
|
||||
|
||||
@@ -99,7 +100,8 @@
|
||||
autofocus = false,
|
||||
allowVim = false,
|
||||
tailwindClasses = [],
|
||||
class: className = ''
|
||||
class: className = '',
|
||||
loadAsync = false
|
||||
} = $props<{
|
||||
lang: string
|
||||
code?: string
|
||||
@@ -121,6 +123,7 @@
|
||||
allowVim?: boolean
|
||||
tailwindClasses?: string[]
|
||||
class?: string
|
||||
loadAsync?: boolean
|
||||
}>()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -279,6 +282,8 @@
|
||||
}
|
||||
})
|
||||
|
||||
let fontSize = $derived(small ? 12 : 14)
|
||||
|
||||
async function loadMonaco() {
|
||||
await initializeVscode()
|
||||
initialized = true
|
||||
@@ -327,7 +332,7 @@
|
||||
model,
|
||||
lineDecorationsWidth: 6,
|
||||
lineNumbersMinChars: 2,
|
||||
fontSize: small ? 12 : 14,
|
||||
fontSize: fontSize,
|
||||
quickSuggestions: disableSuggestions
|
||||
? { other: false, comments: false, strings: false }
|
||||
: { other: true, comments: true, strings: true },
|
||||
@@ -511,12 +516,16 @@
|
||||
|
||||
onMount(async () => {
|
||||
if (BROWSER) {
|
||||
mounted = true
|
||||
await loadMonaco()
|
||||
if (autofocus) {
|
||||
setTimeout(() => {
|
||||
focus()
|
||||
if (loadAsync) {
|
||||
setTimeout(async () => {
|
||||
await loadMonaco()
|
||||
mounted = true
|
||||
if (autofocus) setTimeout(() => focus(), 0)
|
||||
}, 0)
|
||||
} else {
|
||||
await loadMonaco()
|
||||
mounted = true
|
||||
if (autofocus) setTimeout(() => focus(), 0)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -556,9 +565,22 @@
|
||||
{suggestion}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if !editor}
|
||||
<FakeMonacoPlaceHolder
|
||||
{code}
|
||||
autoheight
|
||||
lineNumbersWidth={(23 * fontSize) / 14}
|
||||
lineNumbersOffset={fontSize == 14 ? -8 : -11}
|
||||
{fontSize}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
bind:this={divEl}
|
||||
class="relative {className} editor simple-editor {!allowVim ? 'nonmain-editor' : ''}"
|
||||
class="relative {className} {!editor ? 'hidden' : ''} editor simple-editor {!allowVim
|
||||
? 'nonmain-editor'
|
||||
: ''}"
|
||||
bind:clientWidth={width}
|
||||
>
|
||||
{#if placeholder}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import { initializeVscode } from './vscode'
|
||||
import EditorTheme from './EditorTheme.svelte'
|
||||
import { buildWorkerDefinition } from '$lib/monaco_workers/build_workers'
|
||||
import FakeMonacoPlaceHolder from './FakeMonacoPlaceHolder.svelte'
|
||||
|
||||
export const conf = {
|
||||
wordPattern:
|
||||
@@ -374,6 +375,7 @@
|
||||
export let autoHeight = true
|
||||
export let fixedOverflowWidgets = true
|
||||
export let fontSize = 16
|
||||
export let loadAsync = false
|
||||
|
||||
if (typeof code != 'string') {
|
||||
code = ''
|
||||
@@ -594,8 +596,15 @@
|
||||
let mounted = false
|
||||
onMount(async () => {
|
||||
if (BROWSER) {
|
||||
await loadMonaco()
|
||||
mounted = true
|
||||
if (loadAsync) {
|
||||
setTimeout(async () => {
|
||||
await loadMonaco()
|
||||
mounted = true
|
||||
}, 0)
|
||||
} else {
|
||||
await loadMonaco()
|
||||
mounted = true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -626,10 +635,22 @@
|
||||
|
||||
<EditorTheme />
|
||||
|
||||
{#if !editor}
|
||||
<FakeMonacoPlaceHolder
|
||||
autoheight
|
||||
{code}
|
||||
lineNumbersWidth={23}
|
||||
lineNumbersOffset={-8}
|
||||
class="border template nonmain-editor rounded min-h-4 mx-0.5 overflow-clip"
|
||||
/>
|
||||
{/if}
|
||||
<div
|
||||
bind:this={divEl}
|
||||
style="height: 18px;"
|
||||
class="{$$props.class ?? ''} border template nonmain-editor rounded min-h-4 mx-0.5 overflow-clip"
|
||||
class="{$$props.class ??
|
||||
''} border template nonmain-editor rounded min-h-4 mx-0.5 overflow-clip {!editor
|
||||
? 'hidden'
|
||||
: ''}"
|
||||
bind:clientWidth={width}
|
||||
></div>
|
||||
|
||||
|
||||
+4
-2
@@ -73,10 +73,11 @@
|
||||
<Splitpanes horizontal class="h-full">
|
||||
<Pane size={50}>
|
||||
<SimpleEditor
|
||||
loadAsync
|
||||
class="h-full w-full"
|
||||
bind:this={editor}
|
||||
lang="javascript"
|
||||
bind:code={componentInput.expr}
|
||||
bind:code={() => componentInput.expr ?? '', (e) => (componentInput.expr = e)}
|
||||
shouldBindKey={false}
|
||||
fixedOverflowWidgets={false}
|
||||
{extraLib}
|
||||
@@ -105,10 +106,11 @@
|
||||
<div class="border relative">
|
||||
{#if !fullscreen}
|
||||
<SimpleEditor
|
||||
loadAsync
|
||||
small
|
||||
bind:this={editor}
|
||||
lang="javascript"
|
||||
bind:code={componentInput.expr}
|
||||
bind:code={() => componentInput.expr ?? '', (e) => (componentInput.expr = e)}
|
||||
shouldBindKey={false}
|
||||
{extraLib}
|
||||
autoHeight
|
||||
|
||||
+1
@@ -235,6 +235,7 @@
|
||||
{:else}
|
||||
<div class="flex w-full flex-col">
|
||||
<JsonEditor
|
||||
loadAsync
|
||||
small
|
||||
bind:value={componentInput.value}
|
||||
code={JSON.stringify(componentInput.value, null, 2)}
|
||||
|
||||
@@ -358,11 +358,12 @@
|
||||
|
||||
<div class="min-h-0 flex-grow" id="flow-editor-editor">
|
||||
<Splitpanes horizontal>
|
||||
<Pane bind:size={editorPanelSize} minSize={10}>
|
||||
<Pane bind:size={editorPanelSize} minSize={10} class="relative">
|
||||
{#if flowModule.value.type === 'rawscript'}
|
||||
{#if !noEditor}
|
||||
{#key flowModule.id}
|
||||
<Editor
|
||||
loadAsync
|
||||
folding
|
||||
path={$pathStore + '/' + flowModule.id}
|
||||
bind:websocketAlive
|
||||
|
||||
@@ -8,7 +8,10 @@
|
||||
|
||||
$: settingsClass = classNames(
|
||||
'border w-full rounded-sm p-2 bg-surface text-sm cursor-pointer flex items-center',
|
||||
$selectedId == 'constants' ? 'border border-1 border-slate-800 dark:bg-white/5 dark:border-slate-400/60 dark:border-gray-400' : ''
|
||||
$selectedId == 'constants'
|
||||
? 'border border-1 border-slate-800 dark:bg-white/5 dark:border-slate-400/60 dark:border-gray-400'
|
||||
: '',
|
||||
'hover:!bg-surface-secondary active:!bg-surface'
|
||||
)
|
||||
</script>
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
export let path: string = ''
|
||||
export let modType: string | undefined = undefined
|
||||
export let bgColor: string = ''
|
||||
export let bgHoverColor: string = ''
|
||||
export let concurrency: boolean = false
|
||||
export let retries: number | undefined = undefined
|
||||
export let warningMessage: string | undefined = undefined
|
||||
@@ -195,15 +196,17 @@
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class={classNames(
|
||||
'w-full module flex rounded-sm cursor-pointer max-w-full',
|
||||
selected ? 'outline outline-offset-0 outline-2 outline-slate-500 dark:outline-gray-400' : '',
|
||||
'w-full module flex rounded-sm cursor-pointer max-w-full outline-offset-0 outline-slate-500 dark:outline-gray-400',
|
||||
selected ? 'outline outline-2' : 'active:outline active:outline-2',
|
||||
'flex relative',
|
||||
$copilotCurrentStepStore === id ? 'z-[901]' : ''
|
||||
)}
|
||||
style="width: 275px; height: 38px; background-color: {bgColor};"
|
||||
style="width: 275px; height: 38px; background-color: {hover && bgHoverColor
|
||||
? bgHoverColor
|
||||
: bgColor};"
|
||||
on:mouseenter={() => (hover = true)}
|
||||
on:mouseleave={() => (hover = false)}
|
||||
on:pointerdown|preventDefault|stopPropagation
|
||||
on:pointerdown|preventDefault|stopPropagation={() => dispatch('pointerdown')}
|
||||
>
|
||||
<div class="absolute text-sm right-12 -bottom-3 flex flex-row gap-1 z-10">
|
||||
{#if retry}
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
'border w-full rounded-sm p-2 bg-surface text-sm cursor-pointer flex items-center h-[32px]',
|
||||
$selectedId?.startsWith('settings')
|
||||
? 'border border-1 border-slate-800 dark:bg-white/5 dark:border-slate-400/60 dark:border-gray-400'
|
||||
: ''
|
||||
: '',
|
||||
'hover:!bg-surface-secondary active:!bg-surface'
|
||||
)
|
||||
</script>
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
export let insertable: boolean
|
||||
export let annotation: string | undefined = undefined
|
||||
export let bgColor: string = ''
|
||||
export let bgHoverColor: string = ''
|
||||
export let moving: string | undefined = undefined
|
||||
export let duration_ms: number | undefined = undefined
|
||||
|
||||
@@ -129,6 +130,7 @@
|
||||
}}
|
||||
{...itemProps}
|
||||
{bgColor}
|
||||
{bgHoverColor}
|
||||
warningMessage={mod?.value?.type === 'forloopflow' &&
|
||||
mod?.value?.iterator?.type === 'javascript' &&
|
||||
mod?.value?.iterator?.expr === ''
|
||||
@@ -153,6 +155,7 @@
|
||||
id={mod.id}
|
||||
label={mod.summary || 'Run one branch'}
|
||||
{bgColor}
|
||||
{bgHoverColor}
|
||||
>
|
||||
<div slot="icon">
|
||||
<GitBranch size={16} />
|
||||
@@ -170,6 +173,7 @@
|
||||
{...itemProps}
|
||||
label={mod.summary || `Run all branches${mod.value.parallel ? ' (parallel)' : ''}`}
|
||||
{bgColor}
|
||||
{bgHoverColor}
|
||||
>
|
||||
<div slot="icon">
|
||||
<GitBranch size={16} />
|
||||
@@ -192,6 +196,7 @@
|
||||
{...itemProps}
|
||||
modType={mod.value.type}
|
||||
{bgColor}
|
||||
{bgHoverColor}
|
||||
label={mod.summary ||
|
||||
(mod.id === 'preprocessor'
|
||||
? 'Preprocessor'
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
export let label: string | undefined = undefined
|
||||
export let bgColor: string = ''
|
||||
export let bgHoverColor: string = ''
|
||||
export let selected: boolean
|
||||
export let selectable: boolean
|
||||
export let id: string | undefined = undefined
|
||||
@@ -36,6 +37,7 @@
|
||||
<VirtualItemWrapper
|
||||
{label}
|
||||
{bgColor}
|
||||
{bgHoverColor}
|
||||
{selected}
|
||||
{selectable}
|
||||
{id}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
export let id: string | undefined
|
||||
export let onTop: boolean = false
|
||||
export let bgColor: string
|
||||
export let bgHoverColor: string = ''
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
insert: {
|
||||
@@ -28,18 +29,17 @@
|
||||
<div
|
||||
class={classNames(
|
||||
'w-full flex relative rounded-sm',
|
||||
selectable ? 'cursor-pointer' : '',
|
||||
selected ? 'outline outline-offset-1 outline-2 outline-gray-600 dark:outline-gray-400' : '',
|
||||
onTop ? 'z-[901]' : ''
|
||||
selectable ? 'cursor-pointer active:outline active:outline-2' : '',
|
||||
selected ? 'outline outline-2' : '',
|
||||
onTop ? 'z-[901]' : '',
|
||||
'outline-offset-1 outline-gray-600 dark:outline-gray-400'
|
||||
)}
|
||||
style="width: 275px; max-height: 38px; background-color: {bgColor} !important;"
|
||||
style="width: 275px; max-height: 38px; background-color: {hover && bgHoverColor && selectable
|
||||
? bgHoverColor
|
||||
: bgColor};"
|
||||
on:pointerdown={() => {
|
||||
if (selectable) {
|
||||
if (id) {
|
||||
dispatch('select', id)
|
||||
} else {
|
||||
dispatch('select', label || label || '')
|
||||
}
|
||||
dispatch('select', id || label || '')
|
||||
}
|
||||
}}
|
||||
on:mouseenter={() => {
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
fullScreenWidthOffset={2 * width}
|
||||
extraProps={{ 'data-prop-picker': true }}
|
||||
closeOnOtherPopoverOpen
|
||||
class="outline-none"
|
||||
>
|
||||
<svelte:fragment slot="trigger" let:isOpen>
|
||||
<div
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import { X } from 'lucide-svelte'
|
||||
import type { GraphModuleState } from '../../model'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
import { computeBorderStatus } from '../utils'
|
||||
@@ -33,14 +33,15 @@
|
||||
selectable
|
||||
selected={data.selected}
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
bgHoverColor={getStateHoverColor(undefined, darkMode)}
|
||||
borderColor={borderStatus
|
||||
? getStateColor(borderStatus, darkMode) + (!darkMode ? '; border-width: 3px' : '')
|
||||
: undefined}
|
||||
on:select={() => {
|
||||
data.eventHandlers.select(data.id)
|
||||
setTimeout(() => data.eventHandlers.select(data.id))
|
||||
}}
|
||||
on:insert={(e) => {
|
||||
data.eventHandlers.insert(e.detail)
|
||||
setTimeout(() => data.eventHandlers.insert(e.detail))
|
||||
}}
|
||||
/>
|
||||
{#if data.insertable}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import { X } from 'lucide-svelte'
|
||||
import type { GraphModuleState } from '../../model'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
import { computeBorderStatus } from '../utils'
|
||||
@@ -26,7 +26,6 @@
|
||||
'branchone',
|
||||
data.flowModuleStates?.[data.id]
|
||||
)
|
||||
|
||||
</script>
|
||||
|
||||
<NodeWrapper let:darkMode offset={data.offset}>
|
||||
@@ -36,9 +35,10 @@
|
||||
selectable
|
||||
selected={data.selected}
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
bgHoverColor={getStateHoverColor(undefined, darkMode)}
|
||||
borderColor={borderStatus ? getStateColor(borderStatus, darkMode) : undefined}
|
||||
on:select={() => {
|
||||
data.eventHandlers.select(data.id)
|
||||
setTimeout(() => data?.eventHandlers?.select(data.id))
|
||||
}}
|
||||
/>
|
||||
{#if data.insertable}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
borderColor={getStateColor(data.flowModuleStates?.[data.id]?.type, darkMode)}
|
||||
on:select={(e) => {
|
||||
data?.eventHandlers?.select(e.detail)
|
||||
setTimeout(() => data?.eventHandlers?.select(e.detail))
|
||||
}}
|
||||
/>
|
||||
{:else}
|
||||
@@ -38,7 +38,7 @@
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
borderColor={getStateColor(data.flowModuleStates?.[data.id]?.type, darkMode)}
|
||||
on:select={(e) => {
|
||||
data?.eventHandlers?.select(e.detail)
|
||||
setTimeout(() => data?.eventHandlers?.select(e.detail))
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import VirtualItem from '$lib/components/flows/map/VirtualItem.svelte'
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import type { FlowModule, FlowStatusModule } from '$lib/gen'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
import type { GraphModuleState } from '../../model'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
import { getContext } from 'svelte'
|
||||
@@ -38,9 +38,11 @@
|
||||
return {}
|
||||
}
|
||||
|
||||
function computeStatus(state: GraphModuleState | undefined): FlowStatusModule["type"] | undefined {
|
||||
function computeStatus(
|
||||
state: GraphModuleState | undefined
|
||||
): FlowStatusModule['type'] | undefined {
|
||||
if (state?.type == 'InProgress' || state?.type == 'Success' || state?.type == 'Failure') {
|
||||
let r = state?.flow_jobs_success?.[state?.selectedForloopIndex ?? 0]
|
||||
let r = state?.flow_jobs_success?.[state?.selectedForloopIndex ?? 0]
|
||||
if (r == undefined) return 'InProgress'
|
||||
return r ? 'Success' : 'InProgress'
|
||||
}
|
||||
@@ -77,9 +79,10 @@
|
||||
id={data.id}
|
||||
hideId
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
bgHoverColor={getStateHoverColor(undefined, darkMode)}
|
||||
borderColor={getStateColor(computeStatus(data.flowModuleStates?.[data.id]), darkMode)}
|
||||
on:select={(e) => {
|
||||
data?.eventHandlers?.select(e.detail)
|
||||
setTimeout(() => data?.eventHandlers?.select(e.detail))
|
||||
}}
|
||||
inputJson={filteredInput}
|
||||
prefix="flow_input"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
import { getContext } from 'svelte'
|
||||
import type { Writable } from 'svelte/store'
|
||||
import InsertModuleButton from '$lib/components/flows/map/InsertModuleButton.svelte'
|
||||
@@ -73,11 +73,12 @@
|
||||
selectable
|
||||
selected={$selectedId === 'Input'}
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
bgHoverColor={getStateHoverColor(undefined, darkMode)}
|
||||
on:insert={(e) => {
|
||||
data.eventHandlers?.insert(e.detail)
|
||||
setTimeout(() => data?.eventHandlers?.insert(e.detail))
|
||||
}}
|
||||
on:select={(e) => {
|
||||
data.eventHandlers?.select(e.detail)
|
||||
setTimeout(() => data?.eventHandlers?.select(e.detail))
|
||||
}}
|
||||
inputJson={topFlowInput}
|
||||
prefix="flow_input"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
import type { GraphModuleState } from '../../model'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
|
||||
export let data: {
|
||||
offset: number
|
||||
@@ -41,7 +41,7 @@
|
||||
selected: state?.selectedForloopIndex ?? 0,
|
||||
selectedManually: state?.selectedForLoopSetManually,
|
||||
flowJobsSuccess: state?.flow_jobs_success
|
||||
}
|
||||
}
|
||||
: (undefined as any)
|
||||
</script>
|
||||
|
||||
@@ -66,13 +66,14 @@
|
||||
annotation={flowJobs &&
|
||||
(data.module.value.type === 'forloopflow' || data.module.value.type === 'whileloopflow')
|
||||
? 'Iteration: ' +
|
||||
((state?.selectedForloopIndex ?? 0) >= 0
|
||||
((state?.selectedForloopIndex ?? 0) >= 0
|
||||
? (state?.selectedForloopIndex ?? 0) + 1
|
||||
: state?.flow_jobs?.length) +
|
||||
'/' +
|
||||
(state?.iteration_total ?? '?')
|
||||
'/' +
|
||||
(state?.iteration_total ?? '?')
|
||||
: ''}
|
||||
bgColor={getStateColor(type, darkMode, true, state?.skipped)}
|
||||
bgHoverColor={getStateHoverColor(type, darkMode, true, state?.skipped)}
|
||||
moving={data.moving}
|
||||
duration_ms={state?.duration_ms}
|
||||
retries={data.retries}
|
||||
@@ -93,7 +94,7 @@
|
||||
data.eventHandlers.newBranch(data.module)
|
||||
}}
|
||||
on:select={(e) => {
|
||||
data.eventHandlers.select(e.detail)
|
||||
setTimeout(() => data.eventHandlers.select(e.detail))
|
||||
}}
|
||||
on:selectedIteration={(e) => {
|
||||
data.eventHandlers.selectedIteration(e.detail, data.module.id)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
import type { GraphModuleState } from '../../model'
|
||||
import { computeBorderStatus } from '../utils'
|
||||
|
||||
@@ -31,9 +31,10 @@
|
||||
selectable={true}
|
||||
selected={false}
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
bgHoverColor={getStateHoverColor(undefined, darkMode)}
|
||||
borderColor={getStateColor(borderStatus, darkMode)}
|
||||
on:select={(e) => {
|
||||
data?.eventHandlers?.select(e.detail)
|
||||
setTimeout(() => data?.eventHandlers?.select(e.detail))
|
||||
}}
|
||||
/>
|
||||
</NodeWrapper>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
import type { Writable } from 'svelte/store'
|
||||
import { getContext } from 'svelte'
|
||||
|
||||
@@ -29,8 +29,12 @@
|
||||
data.success == undefined ? undefined : data.success ? 'Success' : 'Failure',
|
||||
darkMode
|
||||
)}
|
||||
bgHoverColor={getStateHoverColor(
|
||||
data.success == undefined ? undefined : data.success ? 'Success' : 'Failure',
|
||||
darkMode
|
||||
)}
|
||||
on:select={(e) => {
|
||||
data?.eventHandlers?.select(e.detail)
|
||||
setTimeout(() => data?.eventHandlers?.select(e.detail))
|
||||
}}
|
||||
/>
|
||||
</NodeWrapper>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import { Minimize2 } from 'lucide-svelte'
|
||||
import type { GraphModuleState } from '../../model'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
|
||||
@@ -28,9 +28,10 @@
|
||||
selectable
|
||||
selected={data.selected}
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
bgHoverColor={getStateHoverColor(undefined, darkMode)}
|
||||
borderColor={undefined}
|
||||
on:select={() => {
|
||||
data.eventHandlers.select(data.id)
|
||||
setTimeout(() => data.eventHandlers?.select(data.id))
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { getContext } from 'svelte'
|
||||
import type { Writable } from 'svelte/store'
|
||||
import { Maximize2, Minimize2, Calendar } from 'lucide-svelte'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
import { setScheduledPollSchedule, type TriggerContext } from '$lib/components/triggers'
|
||||
import VirtualItemWrapper from '$lib/components/flows/map/VirtualItemWrapper.svelte'
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
isEditor={data.isEditor}
|
||||
path={data.path}
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
bgHoverColor={getStateHoverColor(undefined, darkMode)}
|
||||
on:new={(e) => {
|
||||
data?.eventHandlers.insert({
|
||||
modules: data.modules,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import type { FlowModule } from '$lib/gen'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
import type { GraphModuleState } from '../../model'
|
||||
|
||||
export let data: {
|
||||
@@ -23,6 +23,7 @@
|
||||
selectable={true}
|
||||
selected={false}
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
bgHoverColor={getStateHoverColor(undefined, darkMode)}
|
||||
borderColor={getStateColor(data?.flowModuleStates?.[data?.id]?.type, darkMode)}
|
||||
on:select={(e) => {
|
||||
data?.eventHandlers?.select(e.detail)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import VirtualItem from '$lib/components/flows/map/VirtualItem.svelte'
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import type { GraphEventHandlers } from '../../graphBuilder'
|
||||
import { getStateColor } from '../../util'
|
||||
import { getStateColor, getStateHoverColor } from '../../util'
|
||||
import type { GraphModuleState } from '../../model'
|
||||
|
||||
export let data: {
|
||||
@@ -21,9 +21,10 @@
|
||||
selectable={true}
|
||||
selected={false}
|
||||
bgColor={getStateColor(undefined, darkMode)}
|
||||
bgHoverColor={getStateHoverColor(undefined, darkMode)}
|
||||
borderColor={getStateColor(data?.flowModuleStates?.[data?.id]?.type, darkMode)}
|
||||
on:select={(e) => {
|
||||
data?.eventHandlers?.select(e.detail)
|
||||
setTimeout(() => data?.eventHandlers?.select(e.detail))
|
||||
}}
|
||||
/>
|
||||
</NodeWrapper>
|
||||
|
||||
@@ -15,19 +15,24 @@
|
||||
export let disableAi: boolean = false
|
||||
export let modules: FlowModule[] = []
|
||||
export let bgColor: string
|
||||
export let bgHoverColor: string = ''
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let hover = false
|
||||
</script>
|
||||
|
||||
<div style={`width: ${NODE.width}px;`}>
|
||||
<button
|
||||
style="background-color: {bgColor} !important;"
|
||||
style="background-color: {hover && bgHoverColor ? bgHoverColor : bgColor};"
|
||||
class="flex w-full flex-row gap-1 px-2 p-1 items-center {selected
|
||||
? 'outline outline-2 outline-gray-600 rounded-sm dark:bg-white/5 dark:outline-gray-400'
|
||||
: ''}"
|
||||
on:pointerdown={() => {
|
||||
dispatch('select')
|
||||
}}
|
||||
on:mouseenter={() => (hover = true)}
|
||||
on:mouseleave={() => (hover = false)}
|
||||
>
|
||||
<div class="flex flex-col mr-1 ml-1">
|
||||
<div class="flex flex-row items-center text-2xs font-normal"> Triggers </div>
|
||||
|
||||
@@ -38,3 +38,26 @@ export function getStateColor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getStateHoverColor(
|
||||
state: FlowStatusModule['type'] | undefined,
|
||||
isDark: boolean,
|
||||
nonVirtualItem?: boolean,
|
||||
isSkipped?: boolean
|
||||
): string {
|
||||
switch (state) {
|
||||
case 'Success':
|
||||
case 'Failure':
|
||||
case 'InProgress':
|
||||
case 'WaitingForEvents':
|
||||
case 'WaitingForExecutor':
|
||||
return getStateColor(state, isDark, nonVirtualItem, isSkipped)
|
||||
|
||||
default:
|
||||
if (nonVirtualItem) {
|
||||
return isDark ? '#343B46' : '#f6f6f6'
|
||||
} else {
|
||||
return isDark ? '#343B46' : '#d5dee8'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1226,3 +1226,24 @@ export function formatDateShort(dateString: string | undefined): string {
|
||||
day: 'numeric'
|
||||
}).format(date)
|
||||
}
|
||||
|
||||
export function getOS() {
|
||||
const userAgent = window.navigator.userAgent
|
||||
const platform = window.navigator.platform
|
||||
const macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K']
|
||||
const windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE']
|
||||
const iosPlatforms = ['iPhone', 'iPad', 'iPod']
|
||||
if (macosPlatforms.includes(platform)) {
|
||||
return 'macOS' as const
|
||||
} else if (iosPlatforms.includes(platform)) {
|
||||
return 'iOS' as const
|
||||
} else if (windowsPlatforms.includes(platform)) {
|
||||
return 'Windows' as const
|
||||
} else if (/Android/.test(userAgent)) {
|
||||
return 'Android' as const
|
||||
} else if (/Linux/.test(platform)) {
|
||||
return 'Linux' as const
|
||||
}
|
||||
|
||||
return 'Unknown OS' as const
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user