mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-11 08:07:15 +00:00
fix(frontend): fix refresh with manual dependencies (#1319)
* fix(frontend): fix refresh with manual dependencies * fix(frontend): fix id generation * fix(frontend): wip * fix(frontend): wip * fix(frontend): Fix binding + hide toggle for frontend scripts
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
{#if Boolean(options?.left)}
|
||||
<span
|
||||
class={twMerge(
|
||||
'ml-2 font-medium duration-200',
|
||||
'mr-2 font-medium duration-200',
|
||||
disabled ? 'text-gray-500' : 'text-gray-900',
|
||||
size === 'xs' ? 'text-xs' : 'text-sm',
|
||||
textClass
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
export let inlineScript: InlineScript | undefined
|
||||
export let fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
export let autoRefresh: boolean
|
||||
export let doNotRecomputeOnInputChanged: boolean = false
|
||||
|
||||
let result: any = undefined
|
||||
|
||||
@@ -31,6 +32,7 @@
|
||||
{id}
|
||||
{fields}
|
||||
{autoRefresh}
|
||||
{doNotRecomputeOnInputChanged}
|
||||
bind:result
|
||||
transformer={undefined}
|
||||
runnable={{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation'
|
||||
import type { Schema } from '$lib/common'
|
||||
import Alert from '$lib/components/common/alert/Alert.svelte'
|
||||
import LightweightSchemaForm from '$lib/components/LightweightSchemaForm.svelte'
|
||||
@@ -33,6 +32,7 @@
|
||||
export let recomputable: boolean = false
|
||||
export let outputs: { result: Output<any>; loading: Output<boolean> }
|
||||
export let extraKey = ''
|
||||
export let doNotRecomputeOnInputChanged: boolean = false
|
||||
|
||||
const {
|
||||
worldStore,
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
if (recomputable || autoRefresh) {
|
||||
if ((recomputable || autoRefresh) && !doNotRecomputeOnInputChanged) {
|
||||
$runnableComponents[id] = async (inlineScript?: InlineScript) => {
|
||||
await executeComponent(true, inlineScript)
|
||||
}
|
||||
@@ -91,8 +91,12 @@
|
||||
testJobLoader &&
|
||||
refreshIfAutoRefresh('arg changed')
|
||||
|
||||
$: refreshOn =
|
||||
runnable && runnable.type === 'runnableByName' ? runnable.inlineScript?.refreshOn ?? [] : []
|
||||
|
||||
function refreshIfAutoRefresh(_src: string) {
|
||||
if (autoRefresh && $worldStore.initialized) {
|
||||
const refreshEnabled = !doNotRecomputeOnInputChanged && (autoRefresh || refreshOn.length > 0)
|
||||
if (refreshEnabled && $worldStore.initialized) {
|
||||
setDebouncedExecute()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
runnable={componentInput.runnable}
|
||||
transformer={componentInput.transformer}
|
||||
{autoRefresh}
|
||||
bind:doNotRecomputeOnInputChanged={componentInput.doNotRecomputeOnInputChanged}
|
||||
{id}
|
||||
{extraQueryParams}
|
||||
{forceSchemaDisplay}
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
name={script.name}
|
||||
fields={script.fields}
|
||||
autoRefresh={script.autoRefresh ?? true}
|
||||
doNotRecomputeOnInputChanged={script.doNotRecomputeOnInputChanged}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
bind:checked={script.autoRefresh}
|
||||
options={{ right: 'Run on start and app refresh' }}
|
||||
/>
|
||||
<Tooltip
|
||||
>You may want to disable this so that the background script is only triggered by changes
|
||||
to other values or triggered by another computation on a button (See 'Recompute Others')</Tooltip
|
||||
>
|
||||
<Tooltip>
|
||||
You may want to disable this so that the background script is only triggered by changes
|
||||
to other values or triggered by another computation on a button (See 'Recompute Others')
|
||||
</Tooltip>
|
||||
</div>
|
||||
</PanelSection>
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
fields={script.fields}
|
||||
autoRefresh={script.autoRefresh}
|
||||
id={`bg_${index}`}
|
||||
bind:doNotRecomputeOnInputChanged={script.doNotRecomputeOnInputChanged}
|
||||
bind:inlineScript={script.inlineScript}
|
||||
/>
|
||||
{:else}
|
||||
|
||||
@@ -71,7 +71,7 @@ export function findGridItem(app: App, id: string): GridItem | undefined {
|
||||
export function getNextGridItemId(app: App): string {
|
||||
const subgridsKeys = allItems(app.grid, app.subgrids).map((x) => x.id)
|
||||
const withoutDash = subgridsKeys.map((element) => element.split('-')[0])
|
||||
const id = getNextId([...new Set(withoutDash), 'do'])
|
||||
const id = getNextId([...new Set(withoutDash)])
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
+1
@@ -49,6 +49,7 @@
|
||||
name: newScriptPath,
|
||||
inlineScript: undefined,
|
||||
autoRefresh: true,
|
||||
|
||||
fields: {}
|
||||
})
|
||||
$app.hiddenInlineScripts = $app.hiddenInlineScripts
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<script lang="ts">
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import { faClose, faEdit } from '@fortawesome/free-solid-svg-icons'
|
||||
import { includes } from 'lodash'
|
||||
import { getContext } from 'svelte'
|
||||
import type { ResultAppInput } from '../../inputType'
|
||||
import type { AppEditorContext, AppViewerContext } from '../../types'
|
||||
@@ -97,11 +99,22 @@
|
||||
</div>
|
||||
|
||||
{#if appInput.runnable?.type === 'runnableByName' && appInput.runnable.inlineScript}
|
||||
{#if !['buttoncomponent', 'formbuttoncomponent', 'formcomponent'].includes(appComponent.type)}
|
||||
<div class="flex items-center">
|
||||
<Toggle
|
||||
bind:checked={appInput.doNotRecomputeOnInputChanged}
|
||||
options={{ right: "Don't recompute on input changed" }}
|
||||
/>
|
||||
<Tooltip>Whenever an input is changed, the script will be re-run.</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div>
|
||||
<ComponentTriggerList
|
||||
bind:runnable={appInput.runnable}
|
||||
{appComponent}
|
||||
fields={appInput.fields}
|
||||
doNotRecomputeOnInputChanged={appInput.doNotRecomputeOnInputChanged}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
+17
-1
@@ -6,6 +6,8 @@
|
||||
UserAppInput
|
||||
} from '$lib/components/apps/inputType'
|
||||
import type { InlineScript } from '$lib/components/apps/types'
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
|
||||
import TriggerBadgesList from './TriggerBadgesList.svelte'
|
||||
import { getDependencies } from './triggerListUtils'
|
||||
@@ -14,11 +16,25 @@
|
||||
export let autoRefresh: boolean = false
|
||||
export let id: string
|
||||
export let inlineScript: InlineScript
|
||||
export let doNotRecomputeOnInputChanged: boolean = false
|
||||
|
||||
$: dependencies = getDependencies(fields)
|
||||
</script>
|
||||
|
||||
{#if inlineScript.language !== 'frontend'}
|
||||
<div class="flex items-center px-1">
|
||||
<Toggle
|
||||
bind:checked={doNotRecomputeOnInputChanged}
|
||||
options={{ right: "Don't recompute on input changed" }}
|
||||
/>
|
||||
<Tooltip>Whenever an input is changed, the script will be re-run.</Tooltip>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<TriggerBadgesList
|
||||
bind:inlineScript
|
||||
{id}
|
||||
inputDependencies={getDependencies(fields)}
|
||||
inputDependencies={dependencies}
|
||||
onLoad={autoRefresh}
|
||||
{doNotRecomputeOnInputChanged}
|
||||
/>
|
||||
|
||||
+2
@@ -16,6 +16,7 @@
|
||||
export let fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
export let appComponent: AppComponent
|
||||
export let runnable: RunnableByName
|
||||
export let doNotRecomputeOnInputChanged: boolean = false
|
||||
|
||||
const onClick = ['buttoncomponent', 'formbuttoncomponent', 'formcomponent'].includes(
|
||||
appComponent.type
|
||||
@@ -32,6 +33,7 @@
|
||||
inputDependencies={onClick ? [] : getDependencies(fields)}
|
||||
bind:inlineScript={runnable.inlineScript}
|
||||
{onLoad}
|
||||
{doNotRecomputeOnInputChanged}
|
||||
id={$selectedComponent}
|
||||
{onClick}
|
||||
/>
|
||||
|
||||
+6
-3
@@ -11,6 +11,7 @@
|
||||
export let onClick: boolean = false
|
||||
export let onLoad: boolean = false
|
||||
export let id: string | undefined = undefined
|
||||
export let doNotRecomputeOnInputChanged: boolean = false
|
||||
|
||||
const colors = {
|
||||
red: 'text-red-800 border-red-600 bg-red-100',
|
||||
@@ -102,7 +103,9 @@
|
||||
<div class="flex flex-row gap-2 flex-wrap">
|
||||
{#if onLoad}
|
||||
<span class={classNames(badgeClass, colors['green'])}>Start</span>
|
||||
<span class={classNames(badgeClass, colors['green'])}>Refresh</span>
|
||||
{#if !doNotRecomputeOnInputChanged}
|
||||
<span class={classNames(badgeClass, colors['green'])}>Refresh</span>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if onClick}
|
||||
<span class={classNames(badgeClass, colors['green'])}>Click</span>
|
||||
@@ -110,7 +113,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if inputDependencies.length > 0}
|
||||
{#if inputDependencies.length > 0 && !doNotRecomputeOnInputChanged}
|
||||
<div class="w-full">
|
||||
<div class="flex justify-between items-center mb-1">
|
||||
<div class="text-xs font-semibold text-slate-800">Change on values</div>
|
||||
@@ -136,7 +139,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
{#if frontendDependencies}
|
||||
{#if frontendDependencies && !doNotRecomputeOnInputChanged}
|
||||
<div class="w-full">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="text-xs font-semibold text-slate-800 mb-1">Change on values</div>
|
||||
|
||||
@@ -87,6 +87,7 @@ export type ResultInput = {
|
||||
fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
type: 'runnable'
|
||||
value?: any
|
||||
doNotRecomputeOnInputChanged?: boolean
|
||||
}
|
||||
|
||||
type AppInputSpec<T extends InputType, U, V extends InputType = never> = (
|
||||
|
||||
@@ -112,6 +112,7 @@ export type App = {
|
||||
inlineScript: InlineScript | undefined
|
||||
fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
autoRefresh?: boolean
|
||||
doNotRecomputeOnInputChanged?: boolean
|
||||
}>
|
||||
css?: Partial<
|
||||
Record<'viewer' | 'grid' | AppComponent['type'], Record<string, ComponentCssProperty>>
|
||||
|
||||
@@ -43,6 +43,8 @@ export async function loadFlowModuleState(flowModule: FlowModule): Promise<FlowM
|
||||
|
||||
export const idMutex = new Mutex()
|
||||
|
||||
const forbiddenIds: string[] = ['do']
|
||||
|
||||
export function getNextId(currentKeys: string[]): string {
|
||||
const max = currentKeys.reduce((acc, key) => {
|
||||
if (key === 'failure' || key.includes('branch') || key.includes('loop')) {
|
||||
@@ -52,12 +54,17 @@ export function getNextId(currentKeys: string[]): string {
|
||||
return Math.max(acc, num + 1)
|
||||
}
|
||||
}, 0)
|
||||
return numberToChars(max)
|
||||
const char = numberToChars(max)
|
||||
|
||||
if (forbiddenIds.includes(char)) {
|
||||
return getNextId(currentKeys.concat(char))
|
||||
} else {
|
||||
return char
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the next available id
|
||||
export function nextId(flowState: FlowState): string {
|
||||
|
||||
const max = Object.keys(flowState).reduce((acc, key) => {
|
||||
if (key === 'failure' || key.includes('branch') || key.includes('loop')) {
|
||||
return acc
|
||||
|
||||
Reference in New Issue
Block a user