improve flow script editor performances

This commit is contained in:
Ruben Fiszel
2025-04-26 20:42:20 +02:00
parent 42edbfac66
commit 4bb9d64d4f
32 changed files with 236 additions and 193 deletions

View File

@@ -4,10 +4,21 @@
@tailwind utilities;
@layer base {
*,
::before,
::after {
@apply dark:border-gray-600;
/* Light mode: default border color */
.border, .border-t, .border-r, .border-b, .border-l,
.border-x, .border-y,
.divide-x > :not([hidden]) ~ :not([hidden]),
.divide-y > :not([hidden]) ~ :not([hidden]) {
border-color: #e5e7eb; /* gray-200 */
}
/* Dark mode: change border color */
.dark .border, .dark .border-t, .dark .border-r, .dark .border-b, .dark .border-l,
.dark .border-x, .dark .border-y,
.dark .divide-x > :not([hidden]) ~ :not([hidden]),
.dark .divide-y > :not([hidden]) ~ :not([hidden]) {
border-color: #4b5563; /* gray-700 */
}
/* Chrome, Edge, and Safari */
@@ -82,6 +93,18 @@
}
}
.driver-popover-title {
@apply leading-6 !text-primary !text-base;
}
.driver-popover-description {
@apply !text-secondary !text-sm;
}
.driver-popover {
@apply p-6 !bg-surface !max-w-2xl;
}
.splitpanes--vertical > .splitpanes__pane {
transition: none !important;
}
@@ -165,3 +188,4 @@ svelte-virtual-list-contents > * + * {
rgba(0, 0, 192, 0.6) 20px
);
}

View File

@@ -81,17 +81,3 @@
<span> You need to create a new flow before starting the tutorial.</span>
</div>
</ConfirmationModal>
<style global>
.driver-popover-title {
@apply leading-6 text-primary text-base;
}
.driver-popover-description {
@apply text-secondary text-sm;
}
.driver-popover {
@apply p-6 bg-surface max-w-2xl;
}
</style>

View File

@@ -8,6 +8,7 @@
export let path: string
export let selected: string | undefined = undefined
export let selectInitial: boolean = false
const dispatch = createEventDispatcher()
async function loadInitial() {
@@ -19,7 +20,9 @@
perPage: 1
})
if (jobs.length > 0) {
dispatch('select', { jobId: jobs[0].id, initial: true })
if (selectInitial) {
dispatch('select', { jobId: jobs[0].id, initial: true })
}
} else {
dispatch('nohistory')
}

View File

@@ -26,12 +26,18 @@
export let jobId: string | undefined = undefined
export let job: Job | undefined = undefined
let selectedJobStep: string | undefined = undefined
let branchOrIterationN: number = 0
let restartBranchNames: [number, string][] = []
export let initial: boolean = false
let selectedJobStepIsTopLevel: boolean | undefined = undefined
let selectedJobStepType: 'single' | 'forloop' | 'branchall' = 'single'
export let selectedJobStep: string | undefined = undefined
export let selectedJobStepIsTopLevel: boolean | undefined = undefined
export let selectedJobStepType: 'single' | 'forloop' | 'branchall' = 'single'
export let rightColumnSelect: 'timeline' | 'node_status' | 'node_definition' | 'user_states' =
'timeline'
export let branchOrIterationN: number = 0
export let scrollTop: number = 0
let restartBranchNames: [number, string][] = []
let isRunning: boolean = false
let jobProgressReset: () => void
@@ -59,7 +65,6 @@
const dispatch = createEventDispatcher()
let renderCount: number = 0
let initial: boolean = false
let schemaFormWithArgPicker: SchemaFormWithArgPicker | undefined = undefined
let currentJobId: string | undefined = undefined
@@ -210,6 +215,19 @@
}
})
}
let scrollableDiv: HTMLDivElement | undefined = undefined
function handleScroll() {
scrollTop = scrollableDiv?.scrollTop ?? 0
}
$: scrollableDiv && onScrollableDivChange()
function onScrollableDivChange() {
if (scrollTop != 0 && scrollableDiv) {
scrollableDiv.scrollTop = scrollTop
}
}
</script>
<svelte:window on:keydown={onKeyDown} />
@@ -375,7 +393,11 @@
<FlowProgressBar {job} bind:reset={jobProgressReset} />
</div>
<div class="overflow-y-auto grow flex flex-col pt-4">
<div
bind:this={scrollableDiv}
class="overflow-y-auto grow flex flex-col pt-4"
on:scroll={(e) => handleScroll()}
>
<div class="border-b">
<SchemaFormWithArgPicker
bind:this={schemaFormWithArgPicker}
@@ -448,6 +470,7 @@
class="absolute top-[22px] right-2 border p-1.5 hover:bg-surface-hover rounded-md center-center"
>
<FlowHistoryJobPicker
selectInitial={jobId == undefined}
on:nohistory={() => {
loadIndividualStepsStates()
}}
@@ -499,6 +522,7 @@
}
}}
bind:selectedJobStep
bind:rightColumnSelect
/>
{:else}
<div class="italic text-tertiary h-full grow"> Flow status will be displayed here </div>

View File

@@ -19,7 +19,8 @@
export let hideNodeDefinition = false
export let hideJobId = false
export let hideDownloadLogs = false
export let rightColumnSelect: 'timeline' | 'node_status' | 'node_definition' | 'user_states' =
'timeline'
export let isOwner = false
export let wideResults = false
@@ -77,4 +78,5 @@
{workspaceId}
{isOwner}
{wideResults}
bind:rightColumnSelect
/>

View File

@@ -13,7 +13,7 @@
import FlowPreviewStatus from './preview/FlowPreviewStatus.svelte'
import { createEventDispatcher, getContext, tick } from 'svelte'
import { onDestroy } from 'svelte'
import { Badge, Button, Tab } from './common'
import { Badge, Button, Skeleton, Tab } from './common'
import DisplayResult from './DisplayResult.svelte'
import Tabs from './common/tabs/Tabs.svelte'
import { type DurationStatus, type FlowStatusViewerContext, type GraphModuleState } from './graph'
@@ -81,6 +81,8 @@
export let isForloopSelected = false
export let parentRecursiveRefresh: Record<string, (clear, root) => Promise<void>> = {}
export let job: Job | undefined = undefined
export let rightColumnSelect: 'timeline' | 'node_status' | 'node_definition' | 'user_states' =
'timeline'
let recursiveRefresh: Record<string, (clear, root) => Promise<void>> = {}
@@ -96,6 +98,8 @@
$: flowJobIds?.moduleId && onFlowModuleId()
let selectedId: Writable<string | undefined> = writable(selectedNode)
function onFlowModuleId() {
if (globalRefreshes) {
let modId = flowJobIds?.moduleId
@@ -793,8 +797,6 @@
let flowTimeline: FlowTimeline
let rightColumnSelect: 'timeline' | 'node_status' | 'node_definition' | 'user_states' = 'timeline'
function loadPreviousIters(lenToAdd: number) {
let r = $localDurationStatuses[flowJobIds?.moduleId ?? '']
if (r.iteration_from) {
@@ -1244,6 +1246,7 @@
</div>
<FlowGraphV2
{selectedId}
triggerNode={true}
download={!hideDownloadInGraph}
minHeight={wrapperHeight}
@@ -1455,7 +1458,7 @@
{/if}
{/if}
{:else}
<Loader2 class="animate-spin" />
<Skeleton layout={[[15], 1, [70]]}></Skeleton>
{/if}
<style>

View File

@@ -2,32 +2,73 @@
import { workerTags, workspaceStore } from '$lib/stores'
import { WorkerService } from '$lib/gen'
export let tag: string | undefined
export let noLabel: boolean = false
export let nullTag: string | undefined = undefined
export let disabled = false
import Select from './apps/svelte-select/lib/index'
import { createEventDispatcher } from 'svelte'
import DarkModeObserver from './DarkModeObserver.svelte'
import { SELECT_INPUT_DEFAULT_STYLE } from '$lib/defaults'
let {
tag = $bindable(),
noLabel = false,
nullTag = undefined,
disabled = false
} = $props<{
tag: string | undefined
noLabel?: boolean
nullTag?: string | undefined
disabled?: boolean
}>()
loadWorkerGroups()
const dispatch = createEventDispatcher()
async function loadWorkerGroups() {
if (!$workerTags) {
$workerTags = await WorkerService.getCustomTags({ workspace: $workspaceStore })
}
}
let items = $derived([
// ...(tag ? ['reset to default'] : [nullTag ? `default: ${nullTag}` : '']),
...(tag && tag != '' && !($workerTags ?? []).includes(tag) ? [tag] : []),
...($workerTags ?? [])
])
let darkMode: boolean = $state(false)
</script>
<DarkModeObserver bind:darkMode />
<div class="flex gap-1 items-center">
{#if !noLabel}
<div class="text-tertiary text-2xs">tag</div>
{/if}
<select
<Select
{disabled}
placeholder={nullTag ? `default: ${nullTag}` : 'lang default'}
containerStyles={'--height: 30px !important; --input-padding: 0px !important;' + darkMode
? SELECT_INPUT_DEFAULT_STYLE.containerStylesDark
: SELECT_INPUT_DEFAULT_STYLE.containerStyles}
{items}
value={tag ? { value: tag, label: tag } : undefined}
on:clear={() => {
tag = undefined
dispatch('change', undefined)
}}
on:change={(e) => {
console.log('change', e.detail)
dispatch('change', e.detail.value)
}}
bind:justValue={tag}
/>
<!-- <select
class="min-w-32"
placeholder="Tag"
bind:value={tag}
on:change={(e) => {
onchange={(e) => {
if (tag == '') {
tag = undefined
}
dispatch('change', tag)
}}
{disabled}
>
@@ -42,5 +83,5 @@
{#each $workerTags ?? [] as tag (tag)}
<option value={tag}>{tag}</option>
{/each}
</select>
</select> -->
</div>

View File

@@ -119,17 +119,3 @@
<span> This tutorial can only be run on a new app.</span>
</div>
</ConfirmationModal>
<style global>
.driver-popover-title {
@apply leading-6 text-primary text-base;
}
.driver-popover-description {
@apply text-secondary text-sm;
}
.driver-popover {
@apply p-6 bg-surface max-w-2xl;
}
</style>

View File

@@ -70,7 +70,7 @@
<button
class={twMerge(
'absolute -top-[10px] -right-[10px] rounded-full h-[20px] w-[20px] trash center-center text-primary',
'border-[1.5px] border-gray-700 bg-surface duration-150 hover:bg-red-400 hover:text-white hover:border-red-700',
'border-[1.5px] border-gray-700 bg-surface duration-0 hover:bg-red-400 hover:text-white hover:border-red-700',
'group-hover:opacity-100 opacity-0'
)}
on:click|preventDefault|stopPropagation={() => {

View File

@@ -720,69 +720,6 @@
<style>
.svelte-select {
/* deprecating camelCase custom props in favour of kebab-case for v5 */
--borderRadius: var(--border-radius);
--clearSelectColor: var(--clear-select-color);
--clearSelectWidth: var(--clear-select-width);
--disabledBackground: var(--disabled-background);
--disabledBorderColor: var(--disabled-border-color);
--disabledColor: var(--disabled-color);
--disabledPlaceholderColor: var(--disabled-placeholder-color);
--disabledPlaceholderOpacity: var(--disabled-placeholder-opacity);
--errorBackground: var(--error-background);
--errorBorder: var(--error-border);
--groupItemPaddingLeft: var(--group-item-padding-left);
--groupTitleColor: var(--group-title-color);
--groupTitleFontSize: var(--group-title-font-size);
--groupTitleFontWeight: var(--group-title-font-weight);
--groupTitlePadding: var(--group-title-padding);
--groupTitleTextTransform: var(--group-title-text-transform);
--indicatorColor: var(--chevron-color);
--indicatorHeight: var(--chevron-height);
--indicatorWidth: var(--chevron-width);
--inputColor: var(--input-color);
--inputLeft: var(--input-left);
--inputLetterSpacing: var(--input-letter-spacing);
--inputMargin: var(--input-margin);
--inputPadding: var(--input-padding);
--itemActiveBackground: var(--item-active-background);
--itemColor: var(--item-color);
--itemFirstBorderRadius: var(--item-first-border-radius);
--itemHoverBG: var(--item-hover-bg);
--itemHoverColor: var(--item-hover-color);
--itemIsActiveBG: var(--item-is-active-bg);
--itemIsActiveColor: var(--item-is-active-color);
--itemIsNotSelectableColor: var(--item-is-not-selectable-color);
--itemPadding: var(--item-padding);
--listBackground: var(--list-background);
--listBorder: var(--list-border);
--listBorderRadius: var(--list-border-radius);
--listEmptyColor: var(--list-empty-color);
--listEmptyPadding: var(--list-empty-padding);
--listEmptyTextAlign: var(--list-empty-text-align);
--listMaxHeight: var(--list-max-height);
--listPosition: var(--list-position);
--listShadow: var(--list-shadow);
--listZIndex: var(--list-z-index);
--multiItemBG: var(--multi-item-bg);
--multiItemBorderRadius: var(--multi-item-border-radius);
--multiItemDisabledHoverBg: var(--multi-item-disabled-hover-bg);
--multiItemDisabledHoverColor: var(--multi-item-disabled-hover-color);
--multiItemHeight: var(--multi-item-height);
--multiItemMargin: var(--multi-item-margin);
--multiItemPadding: var(--multi-item-padding);
--multiSelectInputMargin: var(--multi-select-input-margin);
--multiSelectInputPadding: var(--multi-select-input-padding);
--multiSelectPadding: var(--multi-select-padding);
--placeholderColor: var(--placeholder-color);
--placeholderOpacity: var(--placeholder-opacity);
--selectedItemPadding: var(--selected-item-padding);
--spinnerColor: var(--spinner-color);
--spinnerHeight: var(--spinner-height);
--spinnerWidth: var(--spinner-width);
--internal-padding: 0 0 0 16px;
border: var(--border, 1px solid #d8dbdf);
border-radius: var(--border-radius, 6px);
min-height: var(--height, 42px);
@@ -837,9 +774,9 @@
cursor: default;
border: none;
color: var(--input-color, var(--item-color));
padding: var(--input-padding, 0);
padding: var(--input-padding, 0) !important;
letter-spacing: var(--input-letter-spacing, inherit);
margin: var(--input-margin, 0);
margin: var(--input-margin, 0) !important;
min-width: 10px;
top: 0;
right: 0;

View File

@@ -1,16 +1,16 @@
<script lang="ts">
import type { FlowModule } from '$lib/gen'
import type { FlowModuleValue } from '$lib/gen'
import FlowCardHeader from './FlowCardHeader.svelte'
export let title: string | undefined = undefined
export let flowModule: FlowModule | undefined = undefined
export let summary: string | undefined = undefined
export let noEditor: boolean
export let flowModuleValue: FlowModuleValue | undefined = undefined
</script>
<div class="flex flex-col h-full">
{#if !noEditor}
<div>
<FlowCardHeader on:reload {title} bind:flowModule>
<FlowCardHeader on:setHash on:reload {title} bind:summary {flowModuleValue}>
<slot name="header" />
</FlowCardHeader>
</div>

View File

@@ -4,13 +4,14 @@
import LanguageIcon from '$lib/components/common/languageIcons/LanguageIcon.svelte'
import MetadataGen from '$lib/components/copilot/MetadataGen.svelte'
import IconedPath from '$lib/components/IconedPath.svelte'
import { ScriptService, type FlowModule, type PathScript } from '$lib/gen'
import { ScriptService, type FlowModuleValue, type PathScript } from '$lib/gen'
import { workspaceStore } from '$lib/stores'
import { Lock, RefreshCw, Unlock } from 'lucide-svelte'
import { createEventDispatcher } from 'svelte'
export let flowModule: FlowModule | undefined = undefined
export let flowModuleValue: FlowModuleValue | undefined = undefined
export let title: string | undefined = undefined
export let summary: string | undefined = undefined
let latestHash: string | undefined = undefined
async function loadLatestHash(value: PathScript) {
@@ -24,45 +25,45 @@
const dispatch = createEventDispatcher()
$: $workspaceStore &&
flowModule?.value.type === 'script' &&
flowModule.value.path &&
!flowModule.value.path.startsWith('hub/') &&
loadLatestHash(flowModule.value)
flowModuleValue?.type === 'script' &&
flowModuleValue.path &&
!flowModuleValue.path.startsWith('hub/') &&
loadLatestHash(flowModuleValue)
</script>
<div
class="overflow-x-auto scrollbar-hidden flex items-center justify-between px-4 py-1 flex-nowrap"
>
{#if flowModule}
{#if flowModuleValue}
<span class="text-sm w-full mr-4">
<div class="flex items-center space-x-2">
{#if flowModule.value.type === 'identity'}
{#if flowModuleValue.type === 'identity'}
<span class="font-bold text-xs">Identity (input copied to output)</span>
{:else if flowModule?.value.type === 'rawscript'}
{:else if flowModuleValue.type === 'rawscript'}
<div class="mx-0.5">
<LanguageIcon lang={flowModule.value.language} width={20} height={20} />
<LanguageIcon lang={flowModuleValue.language} width={20} height={20} />
</div>
<MetadataGen
bind:content={flowModule.summary}
bind:content={summary}
promptConfigName="summary"
code={flowModule.value.content}
code={flowModuleValue.content}
class="w-full"
elementProps={{
placeholder: 'Summary'
}}
/>
{:else if flowModule?.value.type === 'script' && 'path' in flowModule.value && flowModule.value.path}
<IconedPath path={flowModule.value.path} hash={flowModule.value.hash} class="grow" />
{:else if flowModuleValue.type === 'script' && 'path' in flowModuleValue && flowModuleValue.path}
<IconedPath path={flowModuleValue.path} hash={flowModuleValue.hash} class="grow" />
{#if flowModule.value.hash}
{#if latestHash != flowModule.value.hash}
{#if flowModuleValue.hash}
{#if latestHash != flowModuleValue.hash}
<Button
color="light"
size="xs"
variant="border"
on:click={() => {
if (flowModule?.value.type == 'script') {
flowModule.value.hash = latestHash
if (flowModuleValue.type == 'script') {
dispatch('setHash', latestHash)
}
dispatch('reload')
}}>Update to latest hash</Button
@@ -74,8 +75,8 @@
btnClasses="text-tertiary inline-flex gap-1 items-center"
color="light"
on:click={() => {
if (flowModule?.value.type == 'script') {
flowModule.value.hash = undefined
if (flowModuleValue.type == 'script') {
dispatch('setHash', undefined)
}
}}><Unlock size={12} />hash</Button
>
@@ -87,8 +88,8 @@
size="xs"
btnClasses="text-tertiary inline-flex gap-1 items-center"
on:click={() => {
if (flowModule?.value.type == 'script') {
flowModule.value.hash = latestHash
if (flowModuleValue.type == 'script') {
dispatch('setHash', latestHash)
}
}}><Lock size={12} />hash</Button
>
@@ -102,10 +103,10 @@
>
</div>
{/if}
<input bind:value={flowModule.summary} placeholder="Summary" class="w-full grow" />
{:else if flowModule?.value.type === 'flow'}
<input bind:value={summary} placeholder="Summary" class="w-full grow" />
{:else if flowModuleValue.type === 'flow'}
<Badge color="indigo" capitalize>flow</Badge>
<input bind:value={flowModule.summary} placeholder="Summary" class="w-full grow" />
<input bind:value={summary} placeholder="Summary" class="w-full grow" />
{/if}
</div>
</span>

View File

@@ -283,17 +283,31 @@
{#if flowModule.value}
<div class="h-full" bind:clientWidth={width}>
<FlowCard
flowModuleValue={flowModule?.value}
on:reload={() => {
forceReload++
reload(flowModule)
}}
{noEditor}
bind:flowModule
on:setHash={(e) => {
if (flowModule.value.type == 'script') {
flowModule.value.hash = e.detail
}
}}
bind:summary={flowModule.summary}
>
<svelte:fragment slot="header">
<FlowModuleHeader
{tag}
bind:module={flowModule}
module={flowModule}
on:tagChange={(e) => {
console.log('tagChange', e.detail)
if (flowModule.value.type == 'script') {
flowModule.value.tag_override = e.detail
} else if (flowModule.value.type == 'rawscript') {
flowModule.value.tag = e.detail
}
}}
on:toggleSuspend={() => selectAdvanced('suspend')}
on:toggleSleep={() => selectAdvanced('sleep')}
on:toggleMock={() => selectAdvanced('mock')}

View File

@@ -29,13 +29,11 @@
const dispatch = createEventDispatcher()
let customUi: undefined | FlowBuilderWhitelabelCustomUi = getContext('customUi')
$: moduleRetry = module.retry?.constant || module.retry?.exponential
</script>
<div class="flex flex-row space-x-1">
{#if module.value.type === 'script' || module.value.type === 'rawscript' || module.value.type == 'flow'}
{#if moduleRetry}
{#if module.retry?.constant || module.retry?.exponential}
<Popover
placement="bottom"
class="center-center rounded p-2 bg-blue-100 text-blue-800 border border-blue-300 hover:bg-blue-200 dark:bg-frost-700 dark:text-frost-100 dark:border-frost-600"
@@ -133,7 +131,11 @@
</Button>
{/if}
{#if customUi?.tagEdit != false}
<FlowModuleWorkerTagSelect nullTag={tag} bind:tag={module.value.tag_override} />
<FlowModuleWorkerTagSelect
nullTag={tag}
tag={module.value.tag_override}
on:change={(e) => dispatch('tagChange', e.detail)}
/>
{/if}
{#if customUi?.scriptFork != false}
<Button
@@ -146,8 +148,7 @@
Fork
</Button>
{/if}
{/if}
{#if module.value.type === 'flow'}
{:else if module.value.type === 'flow'}
<Button
size="xs"
color="light"
@@ -175,7 +176,10 @@
{/if}
<div class="px-0.5"></div>
{#if module.value.type === 'rawscript'}
<FlowModuleWorkerTagSelect bind:tag={module.value.tag} />
<FlowModuleWorkerTagSelect
tag={module.value.tag}
on:change={(e) => dispatch('tagChange', e.detail)}
/>
<Button
size="xs"
color="light"

View File

@@ -1,15 +1,18 @@
<script lang="ts">
import { getContext } from 'svelte'
import { createEventDispatcher, getContext } from 'svelte'
import type { FlowEditorContext } from '../types'
import { workerTags, workspaceStore } from '$lib/stores'
import { WorkerService } from '$lib/gen'
import WorkerTagSelect from '$lib/components/WorkerTagSelect.svelte'
export let tag: string | undefined
export let nullTag: string | undefined = undefined
let { tag = $bindable(), nullTag = $bindable() } = $props<{
tag: string | undefined
nullTag?: string | undefined
}>()
const { flowStore, selectedId } = getContext<FlowEditorContext>('FlowEditorContext')
const dispatch = createEventDispatcher()
loadWorkerGroups()
async function loadWorkerGroups() {
@@ -23,12 +26,12 @@
{#if $workerTags?.length > 0}
<div class="w-40">
{#if $flowStore.tag == undefined}
<WorkerTagSelect {nullTag} bind:tag />
<WorkerTagSelect {nullTag} bind:tag on:change={(e) => dispatch('change', e.detail)} />
{:else}
<button
title="Worker Group is defined at the flow level"
class="w-full text-left items-center font-normal p-1 py-2 border text-xs rounded"
on:click={() => ($selectedId = 'settings-worker-group')}
onclick={() => ($selectedId = 'settings-worker-group')}
>
Flow's WG: {$flowStore.tag}
</button>

View File

@@ -32,6 +32,14 @@
let jobId: string | undefined = undefined
let job: Job | undefined = undefined
let preventEscape = false
let initial = false
let selectedJobStep: string | undefined = undefined
let selectedJobStepIsTopLevel: boolean | undefined = undefined
let selectedJobStepType: 'single' | 'forloop' | 'branchall' = 'single'
let branchOrIterationN: number = 0
let scrollTop: number = 0
let rightColumnSelect: 'timeline' | 'node_status' | 'node_definition' | 'user_states' = 'timeline'
$: upToDisabled =
$selectedId == undefined ||
@@ -99,9 +107,16 @@
<FlowPreviewContent
bind:this={flowPreviewContent}
open={previewOpen}
bind:scrollTop
bind:previewMode
bind:job
bind:jobId
bind:initial
bind:selectedJobStep
bind:selectedJobStepIsTopLevel
bind:selectedJobStepType
bind:branchOrIterationN
bind:rightColumnSelect
on:close={() => {
previewOpen = false
}}

View File

@@ -351,7 +351,7 @@
{#if deletable}
<button
class="absolute -top-[10px] -right-[10px] rounded-full h-[20px] w-[20px] trash center-center text-secondary
outline-[1px] outline dark:outline-gray-500 outline-gray-300 bg-surface duration-150 hover:bg-red-400 hover:text-white
outline-[1px] outline dark:outline-gray-500 outline-gray-300 bg-surface duration-0 hover:bg-red-400 hover:text-white
{hover || selected ? '' : '!hidden'}"
title="Delete"
on:click|preventDefault|stopPropagation={(event) =>
@@ -363,7 +363,7 @@
{#if id !== 'preprocessor'}
<button
class="absolute -top-[10px] right-[60px] rounded-full h-[20px] w-[20px] trash center-center text-secondary
outline-[1px] outline dark:outline-gray-500 outline-gray-300 bg-surface duration-150 hover:bg-blue-400 hover:text-white
outline-[1px] outline dark:outline-gray-500 outline-gray-300 bg-surface duration-0 hover:bg-blue-400 hover:text-white
{hover ? '' : '!hidden'}"
on:click|preventDefault|stopPropagation={(event) => dispatch('move')}
title="Move"
@@ -388,7 +388,7 @@ outline-[1px] outline dark:outline-gray-500 outline-gray-300 bg-surface duration
</svelte:fragment>
<div
class={twMerge(
'flex items-center justify-center h-full w-full rounded-md p-0.5 border duration-150 ',
'flex items-center justify-center h-full w-full rounded-md p-0.5 border duration-0 ',
id &&
Object.values($flowInputsStore?.[id]?.flowStepWarnings || {})?.some(
(x) => x.type === 'error'

View File

@@ -53,7 +53,7 @@
>
{#if deletable}
<button
class="absolute -left-[28px] z-10 h-[20px] rounded-l rounded-t rounded-s w-[20px] trash center-center text-secondary bg-surface duration-150 hover:bg-blue-400 {editId
class="absolute -left-[28px] z-10 h-[20px] rounded-l rounded-t rounded-s w-[20px] trash center-center text-secondary bg-surface duration-0 hover:bg-blue-400 {editId
? '!bg-blue-400'
: ''} hover:text-white
hover:border-blue-700 hover:!visible {hover ? '' : '!hidden'}"

View File

@@ -69,15 +69,15 @@ shouldUsePortal={true} -->
kind === 'failure'
? ' failure module '
: kind === 'preprocessor'
? 'preprocessor step'
: kind === 'trigger'
? 'trigger'
: 'step'
? 'preprocessor step'
: kind === 'trigger'
? 'trigger'
: 'step'
}`}
id={`flow-editor-add-step-${index}`}
type="button"
class={twMerge(
'w-[17.5px] h-[17.5px] flex items-center justify-center outline-[1px] outline dark:outline-gray-500 outline-gray-300 text-secondary bg-surface focus:outline-none hover:bg-surface-hover rounded',
'w-[17.5px] h-[17.5px] flex items-center justify-center !outline-[1px] outline dark:outline-gray-500 outline-gray-300 text-secondary bg-surface focus:outline-none hover:bg-surface-hover rounded',
$$props.class
)}
on:pointerdown|preventDefault|stopPropagation={() => {

View File

@@ -52,7 +52,7 @@
'rounded-full center-center h-[18px] w-[18px]',
isConnecting
? 'bg-surface text-blue-500'
: 'outline-[1px] outline dark:outline-gray-500 outline-gray-300 duration-150 bg-blue-500 hover:bg-blue-700 text-white'
: 'outline-[1px] outline dark:outline-gray-500 outline-gray-300 duration-0 bg-blue-500 hover:bg-blue-700 text-white'
)}
>
<Plug size={12} strokeWidth={2} />

View File

@@ -77,7 +77,6 @@
allowFullScreen
contentClasses="overflow-hidden resize rounded-md"
contentStyle={`width: calc(${width}px); min-width: calc(${width}px); height: calc(${height}px); min-height: calc(${height}px);`}
fullScreenWidthOffset={2 * width}
extraProps={{ 'data-prop-picker': true }}
closeOnOtherPopoverOpen
class="outline-none"

View File

@@ -48,7 +48,7 @@
<button
title="Delete branch"
class="z-50 absolute -top-[10px] -right-[10px] rounded-full h-[20px] w-[20px] center-center text-primary
outline-[1px] outline outline-gray-700 bg-surface duration-150 hover:bg-red-400 hover:text-white
outline-[1px] outline outline-gray-700 bg-surface duration-0 hover:bg-red-400 hover:text-white
hover:border-red-700"
on:click|preventDefault|stopPropagation={() => {
data.eventHandlers.deleteBranch(

View File

@@ -45,7 +45,7 @@
<button
title="Delete branch"
class="z-50 absolute -top-[10px] -right-[10px] rounded-full h-[20px] w-[20px] center-center text-primary
border-[1.5px] border-gray-700 bg-surface duration-150 hover:bg-red-400 hover:text-white
border-[1.5px] border-gray-700 bg-surface duration-0 hover:bg-red-400 hover:text-white
hover:border-red-700"
on:click|preventDefault|stopPropagation={() => {
data.eventHandlers.deleteBranch(

View File

@@ -49,7 +49,7 @@
{#if data.module.value.type == 'flow'}
<button
title="Expand subflow"
class="z-50 absolute -top-[10px] right-[25px] rounded-full h-[20px] w-[20px] center-center text-primary bg-surface duration-150 hover:bg-surface-hover"
class="z-50 absolute -top-[10px] right-[25px] rounded-full h-[20px] w-[20px] center-center text-primary bg-surface duration-0 hover:bg-surface-hover"
on:click|preventDefault|stopPropagation={() => {
if (data.module.value.type == 'flow') {
data.eventHandlers.expandSubflow(data.module.id, data.module.value.path)

View File

@@ -36,7 +36,7 @@
/>
<button
title="Unexpand subflow"
class="z-50 absolute -top-[10px] right-[25px] rounded-full h-[20px] w-[20px] center-center text-primary bg-surface duration-150 hover:bg-surface-hover"
class="z-50 absolute -top-[10px] right-[25px] rounded-full h-[20px] w-[20px] center-center text-primary bg-surface duration-0 hover:bg-surface-hover"
on:click|preventDefault|stopPropagation={() => {
data.eventHandlers.minimizeSubflow(data.subflowId)
}}

View File

@@ -106,7 +106,7 @@
{#if data.simplifiableFlow != undefined}
<button
class="absolute -top-[10px] -right-[10px] rounded-full h-[20px] w-[20px] trash center-center text-secondary
outline-[1px] outline dark:outline-gray-500 outline-gray-300 bg-surface duration-150 hover:bg-nord-950 hover:text-white"
outline-[1px] outline dark:outline-gray-500 outline-gray-300 bg-surface duration-0 hover:bg-nord-950 hover:text-white"
on:click|preventDefault|stopPropagation={() =>
data?.eventHandlers?.simplifyFlow(!data.simplifiableFlow?.simplifiedFlow)}
title={data.simplifiableFlow?.simplifiedFlow

View File

@@ -30,7 +30,6 @@
export let portal: string | HTMLElement | null = 'body'
export let closeOnOtherPopoverOpen: boolean = false
export let allowFullScreen: boolean = false
export let fullScreenWidthOffset: number = 0
export let extraProps: Record<string, any> = {}
export let disabled: boolean = false
export let documentationLink: string | undefined = undefined
@@ -143,9 +142,7 @@
)}
data-popover
{...extraProps}
style={fullScreen
? `width: calc(90vw - ${fullScreenWidthOffset}px); height: 90vh;`
: contentStyle}
style={fullScreen ? `width: 90vw; max-width: 800px; height: 90vh;` : contentStyle}
>
{#if displayArrow}
<div use:melt={$arrow}></div>

View File

@@ -57,7 +57,7 @@
>
{#each dropdownItems as item}
<button
class="hover:bg-surface-hover p-2 transition-colors duration-150 w-full {item.selected
class="hover:bg-surface-hover p-2 transition-colors duration-0 w-full {item.selected
? 'bg-surface-selected'
: 'text-secondary'}"
on:click={() => {

View File

@@ -1,11 +1,11 @@
<script lang="ts">
import { driver, type Driver, type DriveStep } from 'driver.js'
import 'driver.js/dist/driver.css'
import { createEventDispatcher, mount } from 'svelte'
import { updateProgress } from '$lib/tutorialUtils'
import { ignoredTutorials } from './ignoredTutorials'
import SkipTutorials from './SkipTutorials.svelte'
import TutorialControls from './TutorialControls.svelte'
import TutorialInner from './TutorialInner.svelte'
export let index: number = 0
export let name: string = 'action'
@@ -132,12 +132,6 @@
}
</script>
<style>
:global(.driver-popover) {
padding: 32px;
}
:global(.driver-popover-title) {
font-size: 1.2rem !important;
line-height: 2 !important;
}
</style>
{#if tutorial}
<TutorialInner />
{/if}

View File

@@ -0,0 +1,3 @@
<script lang="ts">
import 'driver.js/dist/driver.css'
</script>

View File

@@ -146,7 +146,7 @@ export function extToLang(ext: string) {
return 'nu'
case 'java':
return 'java'
// for related places search: ADD_NEW_LANG
// for related places search: ADD_NEW_LANG
default:
return 'unknown'
}

View File

@@ -1259,3 +1259,10 @@ export function getOS() {
return 'Unknown OS' as const
}
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}