mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-07 16:03:21 +00:00
fix(frontend): Fix tutorials + Move into itself + Disable app history… (#3181)
* fix(frontend): Fix tutorials + Move into itself + Disable app history for unsaved apps + several toggle fix * fix(frontend): clean up * fix(frontend): add missing result for transformer
This commit is contained in:
@@ -2,10 +2,12 @@
|
||||
import { enterpriseLicense } from '$lib/stores'
|
||||
import { AlertTriangle, ChevronDown, ChevronRight } from 'lucide-svelte'
|
||||
import Tooltip from './Tooltip.svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let label: string | undefined = undefined
|
||||
export let tooltip: string | undefined = undefined
|
||||
export let eeOnly = false
|
||||
export let small: boolean = false
|
||||
|
||||
export let collapsable: boolean = false
|
||||
let collapsed: boolean = true
|
||||
@@ -13,7 +15,12 @@
|
||||
|
||||
<div class="w-full">
|
||||
<div class="flex flex-row justify-between items-center mb-2">
|
||||
<h2 class="text-base font-semibold flex flex-row items-center gap-1">
|
||||
<h2
|
||||
class={twMerge(
|
||||
'font-semibold flex flex-row items-center gap-1',
|
||||
small ? 'text-sm' : 'text-base'
|
||||
)}
|
||||
>
|
||||
{#if collapsable}
|
||||
<button class="flex items-center gap-1" on:click={() => (collapsed = !collapsed)}>
|
||||
{#if collapsed}
|
||||
|
||||
@@ -611,7 +611,8 @@
|
||||
icon: History,
|
||||
action: () => {
|
||||
historyBrowserDrawerOpen = true
|
||||
}
|
||||
},
|
||||
disabled: !savedApp
|
||||
},
|
||||
{
|
||||
displayName: 'Export',
|
||||
|
||||
@@ -174,7 +174,7 @@
|
||||
|
||||
{#if componentSettings?.item?.data}
|
||||
{@const component = componentSettings.item.data}
|
||||
<div class="flex justify-between items-center px-3 py-2 bg-surface-selected">
|
||||
<div class="flex justify-between items-center px-3 py-2 bg-surface-secondary">
|
||||
<div class="text-xs text-primary font-semibold"
|
||||
>{components[componentSettings.item.data.type]?.name ?? 'Unknown'}</div
|
||||
>
|
||||
@@ -296,7 +296,7 @@
|
||||
<div class="flex flex-row items-center gap-2 text-sm font-semibold">
|
||||
Runnable Inputs
|
||||
|
||||
<Tooltip wrapperClass="flex">
|
||||
<Tooltip>
|
||||
The runnable inputs are inferred from the inputs of the flow or script
|
||||
parameters this component is attached to.
|
||||
</Tooltip>
|
||||
|
||||
@@ -39,12 +39,12 @@
|
||||
<tbody>
|
||||
{#each Object.keys($runnableComponents ?? {}).filter((id) => id !== ownId) as id}
|
||||
<tr>
|
||||
<td class="whitespace-nowrap px-4 text-xs">
|
||||
<td class="whitespace-nowrap px-2 text-xs">
|
||||
<Badge color="indigo">{id}</Badge>
|
||||
</td>
|
||||
<td class="relative whitespace-nowrap px-4">
|
||||
<Toggle
|
||||
class="windmillapp"
|
||||
class="windmillapp my-1"
|
||||
size="xs"
|
||||
on:change={(e) => onChange(e.detail, id)}
|
||||
checked={recomputeIds?.includes(id)}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
|
||||
{#if canConfigureRecomputeOnInputChanged || canConfigureRunOnStart}
|
||||
<ScriptSettingsSection title="Triggers">
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-col gap-2 mb-4">
|
||||
{#if autoRefresh !== undefined && canConfigureRunOnStart}
|
||||
<div class="flex items-center justify-between w-full gap-1">
|
||||
<div class="flex flex-row items-center gap-2 text-xs mb-0.5">
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
export let actions: ActionType[] = []
|
||||
</script>
|
||||
|
||||
<div class="flex flex-row p-2 border-gray-200 justify-between bg-blue-50/60 dark:bg-frost-900/60">
|
||||
<div class="flex flex-row px-2 py-1 justify-between bg-surface-secondary border rounded">
|
||||
<div class="flex flex-row gap-2 items-center min-w-0">
|
||||
<FunctionSquare size={16} color="#3b82f6" />
|
||||
<span class="text-xs font-semibold truncate">
|
||||
|
||||
+1
@@ -17,6 +17,7 @@
|
||||
<Section
|
||||
label="Transformer"
|
||||
tooltip={"A transformer is an optional frontend script that is executed right after the component's script whose purpose is to do lightweight transformation in the browser. It takes the previous computation's result as `result`"}
|
||||
small
|
||||
>
|
||||
<svelte:fragment slot="action">
|
||||
<Button
|
||||
|
||||
@@ -264,6 +264,9 @@ declare const file: File | undefined;
|
||||
/** The group fields within the context of a container's group */
|
||||
declare const group: Record<string, any>;
|
||||
|
||||
/** The result within the context of a transformer */
|
||||
declare const result: any;
|
||||
|
||||
`
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +136,7 @@
|
||||
editor?.insertAtCursor(detail)
|
||||
editor?.focus()
|
||||
}}
|
||||
noPadding
|
||||
>
|
||||
<SimpleEditor
|
||||
bind:this={editor}
|
||||
|
||||
@@ -318,7 +318,9 @@
|
||||
<Tab value="test">Test this step</Tab>
|
||||
<Tab value="advanced">Advanced</Tab>
|
||||
</Tabs>
|
||||
<div class="h-[calc(100%-32px)]">
|
||||
<div
|
||||
class={advancedSelected === 'runtime' ? 'h-[calc(100%-64px)]' : 'h-[calc(100%-32px)]'}
|
||||
>
|
||||
{#if selected === 'inputs' && (flowModule.value.type == 'rawscript' || flowModule.value.type == 'script' || flowModule.value.type == 'flow')}
|
||||
<div class="h-full overflow-auto" id="flow-editor-step-input">
|
||||
<PropPickerWrapper
|
||||
@@ -439,31 +441,38 @@
|
||||
}
|
||||
}}
|
||||
options={{
|
||||
right: 'High priority flow step',
|
||||
right: 'Enabled high priority flow step',
|
||||
rightTooltip: `Jobs scheduled from this step when the flow is executed are labeled as high priority and take precedence over the other jobs in the jobs queue. ${
|
||||
!$enterpriseLicense
|
||||
? 'This is a feature only available on enterprise edition.'
|
||||
: ''
|
||||
}`
|
||||
}}
|
||||
>
|
||||
<svelte:fragment slot="right">
|
||||
<input
|
||||
type="number"
|
||||
class="!w-14 ml-4"
|
||||
disabled={flowModule.priority === undefined}
|
||||
bind:value={flowModule.priority}
|
||||
on:focus
|
||||
on:change={() => {
|
||||
if (flowModule.priority && flowModule.priority > 100) {
|
||||
flowModule.priority = 100
|
||||
} else if (flowModule.priority && flowModule.priority < 0) {
|
||||
flowModule.priority = 0
|
||||
}
|
||||
}}
|
||||
/>
|
||||
/>
|
||||
<Label label="Priority number">
|
||||
<svelte:fragment slot="header">
|
||||
<Tooltip>The higher the number, the higher the priority.</Tooltip>
|
||||
</svelte:fragment>
|
||||
</Toggle>
|
||||
<input
|
||||
type="number"
|
||||
class="!w-24"
|
||||
disabled={flowModule.priority === undefined}
|
||||
bind:value={flowModule.priority}
|
||||
on:focus
|
||||
on:change={() => {
|
||||
if (flowModule.priority && flowModule.priority > 100) {
|
||||
flowModule.priority = 100
|
||||
} else if (flowModule.priority && flowModule.priority < 0) {
|
||||
flowModule.priority = 0
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Label>
|
||||
|
||||
<Alert type="warning" title="Limitation" size="xs">
|
||||
Setting priority is only available for enterprise edition and not available
|
||||
on the cloud.
|
||||
</Alert>
|
||||
</Section>
|
||||
{:else if advancedSelected === 'runtime' && advancedRuntimeSelected === 'lifetime'}
|
||||
<div>
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
export let modules: FlowModule[]
|
||||
export let moving: string | undefined = undefined
|
||||
export let duration_ms: number | undefined = undefined
|
||||
export let disableAi
|
||||
export let disableAi: boolean = false
|
||||
export let wrapperId: string | undefined = undefined
|
||||
|
||||
$: idx = modules.findIndex((m) => m.id === mod.id)
|
||||
|
||||
@@ -80,6 +81,7 @@
|
||||
dispatch('insert', { modules, index: idx, detail: 'move' })
|
||||
}}
|
||||
type="button"
|
||||
disabled={wrapperId === moving}
|
||||
class=" text-primary bg-surface border mx-[1px] border-gray-300 dark:border-gray-500 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-full text-sm w-[25px] h-[25px] flex items-center justify-center"
|
||||
>
|
||||
<ClipboardCopy class="m-[5px]" size={15} />
|
||||
@@ -227,6 +229,7 @@
|
||||
dispatch('insert', { modules, index: idx + 1, detail: 'move' })
|
||||
}}
|
||||
type="button"
|
||||
disabled={wrapperId === moving}
|
||||
class=" text-primary bg-surface border mx-[1px] border-gray-300 dark:border-gray-500 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-full text-sm w-[25px] h-[25px] flex items-center justify-center"
|
||||
>
|
||||
<ClipboardCopy class="m-[5px]" size={15} />
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
export let id: string | undefined = undefined
|
||||
export let moving: string | undefined = undefined
|
||||
export let center = true
|
||||
export let disableAi = false
|
||||
export let disableAi: boolean = false
|
||||
export let wrapperNode: FlowModule | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher<{
|
||||
insert: {
|
||||
@@ -116,6 +117,7 @@
|
||||
}
|
||||
}}
|
||||
type="button"
|
||||
disabled={wrapperNode?.id === moving}
|
||||
class="text-primary bg-surface border mx-[1px] border-gray-300 dark:border-gray-500 focus:outline-none hover:bg-gray-100 focus:ring-4 focus:ring-gray-200 font-medium rounded-full text-sm w-[25px] h-[25px] flex items-center justify-center"
|
||||
>
|
||||
<ClipboardCopy size={12} />
|
||||
|
||||
@@ -24,12 +24,14 @@
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { writable, type Writable } from 'svelte/store'
|
||||
import type { PickableProperties } from '../previousResults'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let pickableProperties: PickableProperties | undefined
|
||||
export let result: any = undefined
|
||||
export let error: boolean = false
|
||||
export let displayContext = true
|
||||
export let notSelectable = false
|
||||
export let noPadding: boolean = false
|
||||
|
||||
const propPickerConfig = writable<PropPickerConfig | undefined>(undefined)
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -55,7 +57,11 @@
|
||||
on:click_outside={() => propPickerConfig.set(undefined)}
|
||||
>
|
||||
<Splitpanes>
|
||||
<Pane minSize={20} size={60} class="relative p-2 !transition-none">
|
||||
<Pane
|
||||
minSize={20}
|
||||
size={60}
|
||||
class={twMerge('relative !transition-none', noPadding ? '' : 'p-2')}
|
||||
>
|
||||
<slot />
|
||||
</Pane>
|
||||
<Pane
|
||||
|
||||
@@ -216,7 +216,8 @@
|
||||
edgeLabel: string | undefined,
|
||||
loopDepth: number,
|
||||
insertableEnd: boolean,
|
||||
modules: FlowModule[]
|
||||
modules: FlowModule[],
|
||||
wrapper: FlowModule | undefined = undefined
|
||||
): GraphItem | undefined {
|
||||
const type = module.value.type
|
||||
const parentIds = getParentIds(parent)
|
||||
@@ -257,7 +258,8 @@
|
||||
loopDepth,
|
||||
insertableEnd,
|
||||
false,
|
||||
modules
|
||||
modules,
|
||||
wrapper
|
||||
)
|
||||
}
|
||||
|
||||
@@ -300,7 +302,8 @@
|
||||
loopDepth: number,
|
||||
insertableEnd: boolean,
|
||||
branchable: boolean,
|
||||
modules: FlowModule[]
|
||||
modules: FlowModule[],
|
||||
wrapper: FlowModule | undefined = undefined
|
||||
): Node {
|
||||
return {
|
||||
type: 'node',
|
||||
@@ -320,7 +323,8 @@
|
||||
annotation,
|
||||
modules,
|
||||
moving,
|
||||
disableAi
|
||||
disableAi,
|
||||
wrapperId: wrapper?.id
|
||||
},
|
||||
cb: (e: string, detail: any) => {
|
||||
if (e == 'delete') {
|
||||
@@ -379,6 +383,7 @@
|
||||
]
|
||||
}
|
||||
const innerModules = module.value.modules
|
||||
|
||||
loop.items.push(
|
||||
createVirtualNode(
|
||||
getParentIds(loop.items),
|
||||
@@ -391,17 +396,20 @@
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined
|
||||
undefined,
|
||||
true,
|
||||
module
|
||||
)
|
||||
)
|
||||
innerModules.forEach((module, i) => {
|
||||
innerModules.forEach((innerModule, i) => {
|
||||
const item = getConvertedFlowModule(
|
||||
module,
|
||||
innerModule,
|
||||
loop.items,
|
||||
undefined,
|
||||
loopDepth + 1,
|
||||
i + 1 == innerModules?.length,
|
||||
innerModules
|
||||
innerModules,
|
||||
module
|
||||
)
|
||||
item && loop.items.push(item)
|
||||
})
|
||||
@@ -432,6 +440,7 @@
|
||||
loopDepth: number,
|
||||
branchall: boolean
|
||||
): Branch | Node {
|
||||
const wrapper = JSON.parse(JSON.stringify(module))
|
||||
const node = flowModuleToNode(
|
||||
getParentIds(parent),
|
||||
module,
|
||||
@@ -464,6 +473,7 @@
|
||||
|
||||
branches.forEach(({ summary, modules, removable }, i) => {
|
||||
const items: NestedNodes = []
|
||||
|
||||
items.push(
|
||||
createVirtualNode(
|
||||
branchParent,
|
||||
@@ -477,18 +487,20 @@
|
||||
removable ? { module, index: i } : undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
false
|
||||
false,
|
||||
wrapper
|
||||
)
|
||||
)
|
||||
if (modules.length) {
|
||||
modules.forEach((module, j) => {
|
||||
modules.forEach((innerModule, j) => {
|
||||
const item = getConvertedFlowModule(
|
||||
module,
|
||||
innerModule,
|
||||
items,
|
||||
undefined,
|
||||
loopDepth,
|
||||
j + 1 == modules?.length,
|
||||
modules
|
||||
modules,
|
||||
module
|
||||
)
|
||||
item && items.push(item)
|
||||
})
|
||||
@@ -642,9 +654,11 @@
|
||||
deleteBranch: { module: FlowModule; index: number } | undefined,
|
||||
mid: string | undefined,
|
||||
fixed_id: string | undefined,
|
||||
center: boolean = true
|
||||
center: boolean = true,
|
||||
wrapperNode: FlowModule | undefined = undefined
|
||||
): Node {
|
||||
const id = fixed_id ?? -idGenerator.next().value - 2 + (offset ?? 0)
|
||||
|
||||
return {
|
||||
type: 'node',
|
||||
id: id.toString(),
|
||||
@@ -674,7 +688,8 @@
|
||||
id: mid,
|
||||
moving,
|
||||
center,
|
||||
disableAi
|
||||
disableAi,
|
||||
wrapperNode
|
||||
},
|
||||
cb: (e: string, detail: any) => {
|
||||
if (e == 'insert') {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
import ObjectViewer from './ObjectViewer.svelte'
|
||||
import { keepByKey } from './utils'
|
||||
import type { PickableProperties } from '../flows/previousResults'
|
||||
import ClearableInput from '../common/clearableInput/ClearableInput.svelte'
|
||||
|
||||
export let pickableProperties: PickableProperties
|
||||
export let displayContext = true
|
||||
@@ -79,12 +80,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<input
|
||||
type="text"
|
||||
bind:value={search}
|
||||
class="bg-gray-50 mt-2 border border-gray-300 text-primary text-sm rounded-lg block mb-2 w-full"
|
||||
placeholder="Search prop..."
|
||||
/>
|
||||
<ClearableInput bind:value={search} placeholder="Search prop..." wrapperClass="py-2" />
|
||||
</div>
|
||||
<div
|
||||
class="overflow-y-auto px-2 pt-2 grow"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
btnClasses="font-normal"
|
||||
variant="border"
|
||||
on:click={() => {
|
||||
dispatch('skipThis')
|
||||
dispatch('skipAll')
|
||||
}}
|
||||
>
|
||||
Mark all tutorials as completed
|
||||
|
||||
Reference in New Issue
Block a user