mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 16:02:19 +00:00
87cda7a4d7
* use melt menu in sidebar * stop keyboard navigation for disabled items * use melt menu for FavoriteMenu and WorkspaceMenu * fix popover placement for menuButton * use melt menu for operator menu * fix notification * fix operator menu * Use melt menu in FlowJobsMenu * use melt menu for AppMenu * clean code * clean code * add use clickOutside option to Menu * use pointerdown_outside * use pointerdown_outside # Conflicts: # frontend/src/lib/components/meltComponents/Menu.svelte * use pointerdown in menus * add max-h to app dropdown menu * keep more open in operator menu * add a MenuItem component * clean * nit * nit * clean code * put conditionalMelt as utility function * remove unused Portal * Add debounce effect in operator menu * fix component jumping due to z-index * format pages * migrate dropdown to melt * migrate popup to melt popover * feat: remove `pip` fallback option for python and ansible (#5186) * refactor!: Remove `pip` fallback option for python and ansible BREAKING CHANGE: pip was deprecated since 1.425.0 (2024-11-15) * fix errors in main.rs * fix tests * remove nsjail for pip * fix imports * fix compilation error * reinforce melt types * fix racing condition issue in closing operator menu * nit * fix id conflix with melt element * nit * clean code * use melt dropdown instead of menubar * prevent modal from closing on click outside button in menu * fix nit * nit * close dropdown when opening a new one * replace MenuV2 with melt Menu (1/4) (#5214) * use melt menu in sidebar * stop keyboard navigation for disabled items * use melt menu for FavoriteMenu and WorkspaceMenu * fix popover placement for menuButton * use melt menu for operator menu * fix notification * fix operator menu * Use melt menu in FlowJobsMenu * use melt menu for AppMenu * clean code * clean code * add use clickOutside option to Menu * use pointerdown_outside * use pointerdown_outside # Conflicts: # frontend/src/lib/components/meltComponents/Menu.svelte * use pointerdown in menus * add max-h to app dropdown menu * keep more open in operator menu * add a MenuItem component * clean * nit * nit * clean code * put conditionalMelt as utility function * remove unused Portal * Add debounce effect in operator menu * fix component jumping due to z-index * feat: remove `pip` fallback option for python and ansible (#5186) * refactor!: Remove `pip` fallback option for python and ansible BREAKING CHANGE: pip was deprecated since 1.425.0 (2024-11-15) * fix errors in main.rs * fix tests * remove nsjail for pip * fix imports * fix compilation error * reinforce melt types * fix racing condition issue in closing operator menu * nit * fix id conflix with melt element * nit * prevent modal from closing on click outside button in menu --------- Co-authored-by: pyranota <92104930+pyranota@users.noreply.github.com> Co-authored-by: Ruben Fiszel <ruben@windmill.dev> # Conflicts: # frontend/src/lib/components/meltComponents/MenuItem.svelte # frontend/src/lib/utils.ts * clean * fix z index and render * fix initialize of dropdownmenu after melt migration * feat: add support for | None and Optional in python (#5361) * feat: add support for | None and Optional in python * update python parser package * add local rooting for MenuItem * fix z index * clean * nit * nit * clean code * nit --------- Co-authored-by: pyranota <92104930+pyranota@users.noreply.github.com> Co-authored-by: Ruben Fiszel <ruben@windmill.dev> Co-authored-by: HugoCasa <hugo@casademont.ch>
243 lines
6.1 KiB
Svelte
243 lines
6.1 KiB
Svelte
<script lang="ts">
|
|
import { Button, Drawer, DrawerContent } from '$lib/components/common'
|
|
import { base } from '$lib/base'
|
|
import FlowModuleScript from '$lib/components/flows/content/FlowModuleScript.svelte'
|
|
import FlowPathViewer from '$lib/components/flows/content/FlowPathViewer.svelte'
|
|
import { emptySchema } from '$lib/utils'
|
|
import { getContext, tick } from 'svelte'
|
|
import type {
|
|
ConnectedAppInput,
|
|
RowAppInput,
|
|
RunnableByPath,
|
|
StaticAppInput,
|
|
UserAppInput
|
|
} from '../../inputType'
|
|
import type { AppViewerContext } from '../../types'
|
|
import { workspaceStore } from '$lib/stores'
|
|
import { createEventDispatcher } from 'svelte'
|
|
import { deepEqual } from 'fast-equals'
|
|
import { computeFields } from './utils'
|
|
import { inferArgs, loadSchema } from '$lib/infer'
|
|
import RunButton from './RunButton.svelte'
|
|
import { getScriptByPath } from '$lib/scripts'
|
|
import { sendUserToast } from '$lib/toast'
|
|
import { autoPlacement } from '@floating-ui/core'
|
|
import { ExternalLink, Eye, GitFork, Pen, RefreshCw, Trash } from 'lucide-svelte'
|
|
import Popover from '$lib/components/meltComponents/Popover.svelte'
|
|
|
|
export let runnable: RunnableByPath
|
|
export let fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
|
export let id: string
|
|
|
|
const { stateId } = getContext<AppViewerContext>('AppViewerContext')
|
|
|
|
let drawerFlowViewer: Drawer
|
|
let flowPath: string = ''
|
|
let notFound = false
|
|
|
|
const dispatch = createEventDispatcher()
|
|
|
|
async function refreshScript(x: RunnableByPath) {
|
|
try {
|
|
let { schema } = await getScriptByPath(x.path)
|
|
if (!deepEqual(x.schema, schema)) {
|
|
x.schema = schema
|
|
if (!x.schema.order) {
|
|
x.schema.order = Object.keys(x.schema.properties ?? {})
|
|
}
|
|
fields = computeFields(schema, false, fields)
|
|
}
|
|
} catch (e) {
|
|
notFound = true
|
|
console.error(e)
|
|
}
|
|
}
|
|
|
|
async function refreshFlow(x: RunnableByPath) {
|
|
try {
|
|
const { schema } = (await loadSchema($workspaceStore ?? '', x.path, 'flow')) ?? emptySchema()
|
|
if (!deepEqual(x.schema, schema)) {
|
|
x.schema = schema
|
|
if (!x.schema.order) {
|
|
x.schema.order = Object.keys(x.schema.properties ?? {})
|
|
}
|
|
fields = computeFields(schema, false, fields)
|
|
}
|
|
} catch (e) {
|
|
notFound = true
|
|
console.error(e)
|
|
}
|
|
}
|
|
|
|
async function fork(path: string) {
|
|
let { content, language, schema } = await getScriptByPath(path)
|
|
if (!schema || typeof schema == 'string' || Object.keys(schema).length == 0) {
|
|
schema = emptySchema()
|
|
await inferArgs(language, content, schema)
|
|
}
|
|
dispatch('fork', {
|
|
type: 'runnableByName',
|
|
name: path,
|
|
inlineScript: {
|
|
content,
|
|
language,
|
|
schema,
|
|
path
|
|
}
|
|
})
|
|
}
|
|
|
|
let lastRunnable: RunnableByPath | undefined = undefined
|
|
function refresh(runnable) {
|
|
if (deepEqual(runnable, lastRunnable)) {
|
|
return
|
|
}
|
|
notFound = false
|
|
if (runnable.runType == 'script') {
|
|
refreshScript(runnable)
|
|
} else if (runnable.runType == 'flow') {
|
|
refreshFlow(runnable)
|
|
}
|
|
lastRunnable = runnable
|
|
}
|
|
$: refresh(runnable)
|
|
</script>
|
|
|
|
<Drawer bind:this={drawerFlowViewer} size="1200px">
|
|
<DrawerContent title="Flow {flowPath}" on:close={drawerFlowViewer.closeDrawer}>
|
|
<FlowPathViewer path={flowPath ?? ''} />
|
|
</DrawerContent>
|
|
</Drawer>
|
|
|
|
<div class="p-2 h-full flex flex-col gap-2">
|
|
<div class="flex flex-row-reverse w-full gap-2">
|
|
<RunButton hideShortcut {id} />
|
|
|
|
<Button
|
|
variant="border"
|
|
size="xs"
|
|
color="light"
|
|
startIcon={{ icon: RefreshCw }}
|
|
on:click={async () => {
|
|
sendUserToast('Refreshing inputs')
|
|
refresh(runnable)
|
|
$stateId = $stateId + 1
|
|
await tick()
|
|
}}
|
|
/>
|
|
<Button
|
|
size="xs"
|
|
variant="border"
|
|
color="red"
|
|
startIcon={{ icon: Trash }}
|
|
on:click={() => {
|
|
dispatch('delete')
|
|
}}
|
|
>
|
|
Clear
|
|
</Button>
|
|
{#if runnable.runType == 'flow'}
|
|
<Button
|
|
variant="border"
|
|
size="xs"
|
|
color="light"
|
|
startIcon={{ icon: Eye }}
|
|
on:click={() => {
|
|
flowPath = runnable.path
|
|
drawerFlowViewer.openDrawer()
|
|
}}
|
|
>
|
|
Expand
|
|
</Button>
|
|
<Button
|
|
variant="border"
|
|
size="xs"
|
|
color="light"
|
|
startIcon={{ icon: Pen }}
|
|
endIcon={{ icon: ExternalLink }}
|
|
target="_blank"
|
|
href="{base}/flows/edit/{runnable.path}?nodraft=true">Edit</Button
|
|
>
|
|
<Button
|
|
variant="border"
|
|
size="xs"
|
|
color="light"
|
|
startIcon={{ icon: Eye }}
|
|
endIcon={{ icon: ExternalLink }}
|
|
target="_blank"
|
|
href="{base}/flows/get/{runnable.path}?workspace={$workspaceStore}"
|
|
>
|
|
Details
|
|
</Button>
|
|
{:else}
|
|
<Button
|
|
size="xs"
|
|
variant="border"
|
|
startIcon={{ icon: GitFork }}
|
|
on:click={() => {
|
|
fork(runnable.path)
|
|
}}
|
|
>
|
|
Fork
|
|
</Button>
|
|
{/if}
|
|
<Popover
|
|
floatingConfig={{
|
|
middleware: [
|
|
autoPlacement({
|
|
allowedPlacements: [
|
|
'bottom-start',
|
|
'bottom-end',
|
|
'top-start',
|
|
'top-end',
|
|
'top',
|
|
'bottom'
|
|
]
|
|
})
|
|
]
|
|
}}
|
|
closeButton
|
|
contentClasses="block text-primary text-xs p-4 w-[20vh]"
|
|
>
|
|
<svelte:fragment slot="trigger">
|
|
<Button
|
|
nonCaptureEvent={true}
|
|
btnClasses={'bg-surface text-primay hover:bg-hover'}
|
|
color="light"
|
|
variant="border"
|
|
size="xs">Cache</Button
|
|
>
|
|
</svelte:fragment>
|
|
<svelte:fragment slot="content">
|
|
Since this is a reference to a workspace {runnable.runType}, set the cache in the {runnable.runType}
|
|
settings directly by editing it. The cache will be shared by any app or flow that uses this
|
|
{runnable.runType}.
|
|
</svelte:fragment>
|
|
</Popover>
|
|
|
|
<input
|
|
on:keydown|stopPropagation
|
|
bind:value={runnable.name}
|
|
placeholder="Background runnable name"
|
|
class="!text-xs !rounded-xs"
|
|
/>
|
|
</div>
|
|
<div class="w-full grow overflow-y-auto">
|
|
{#key $stateId}
|
|
{#if notFound}
|
|
<div class="text-red-400"
|
|
>{runnable.runType} not found at {runnable.path} in workspace {$workspaceStore}</div
|
|
>
|
|
{:else if runnable.runType == 'script' || runnable.runType == 'hubscript'}
|
|
<div class="border">
|
|
<FlowModuleScript path={runnable.path} />
|
|
</div>
|
|
{:else if runnable.runType == 'flow'}
|
|
<FlowPathViewer path={runnable.path} />
|
|
{:else}
|
|
Unrecognized runType {runnable.runType}
|
|
{/if}
|
|
{/key}
|
|
</div>
|
|
</div>
|