Compare commits
62 Commits
rf/cliImpr
...
fr/flow-tr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a6aa25016 | ||
|
|
c69d55817a | ||
|
|
cee9d8c611 | ||
|
|
5a899177a2 | ||
|
|
28a1288ebc | ||
|
|
31ab0f1aea | ||
|
|
5c47ede54e | ||
|
|
64150cf3ec | ||
|
|
4925d2e07f | ||
|
|
7fe0a8f366 | ||
|
|
f20688d220 | ||
|
|
97d8428664 | ||
|
|
f3b8ab7a34 | ||
|
|
54b3e648a1 | ||
|
|
fcb3b41cd5 | ||
|
|
36a2fab953 | ||
|
|
d95b37baf2 | ||
|
|
893e3571bb | ||
|
|
73532d4218 | ||
|
|
ba1f637743 | ||
|
|
7d200ad940 | ||
|
|
2c9103de08 | ||
|
|
5e506c3a23 | ||
|
|
f086b849af | ||
|
|
c6fd9b39c8 | ||
|
|
fd6b1af532 | ||
|
|
6c62a60a4b | ||
|
|
4d7bc5c651 | ||
|
|
8f1cb11ea8 | ||
|
|
c782434cae | ||
|
|
87a1043312 | ||
|
|
073c806252 | ||
|
|
48998fc073 | ||
|
|
3c7ccc192e | ||
|
|
c752e72b90 | ||
|
|
355792b5a3 | ||
|
|
30e25cae07 | ||
|
|
e81b2d2529 | ||
|
|
6ad2b3a0d5 | ||
|
|
c56f6ea374 | ||
|
|
3ea2529640 | ||
|
|
542998de14 | ||
|
|
68eeb7ef0f | ||
|
|
76fea32da0 | ||
|
|
4170db79f5 | ||
|
|
c8b7205749 | ||
|
|
7cff84fee7 | ||
|
|
7a379da666 | ||
|
|
d3b37b0b2d | ||
|
|
b3a032f35a | ||
|
|
2b6730c074 | ||
|
|
dde040c5a6 | ||
|
|
17e5b16eab | ||
|
|
19e3bf12e7 | ||
|
|
df1b0ffb24 | ||
|
|
d9dcde32d4 | ||
|
|
073ac9108c | ||
|
|
70d8cd475e | ||
|
|
fa87b01c1c | ||
|
|
9fc977c720 | ||
|
|
9abeccbe72 | ||
|
|
1c7b67d0ee |
@@ -12,6 +12,7 @@
|
||||
description?: string
|
||||
value: FlowValue
|
||||
schema?: any
|
||||
path?: string
|
||||
}
|
||||
export let overflowAuto = false
|
||||
export let noSide = false
|
||||
|
||||
@@ -17,13 +17,17 @@
|
||||
|
||||
async function loadSchedules() {
|
||||
try {
|
||||
schedules = (
|
||||
await ScheduleService.listSchedules({
|
||||
workspace: $workspaceStore ?? '',
|
||||
path: initialPath,
|
||||
isFlow: true
|
||||
})
|
||||
).filter((s) => s.path != initialPath)
|
||||
schedules = await ScheduleService.listSchedules({
|
||||
workspace: $workspaceStore ?? '',
|
||||
path: initialPath,
|
||||
isFlow: true
|
||||
})
|
||||
|
||||
console.log(
|
||||
schedules,
|
||||
initialPath,
|
||||
schedules.filter((s) => s.path === initialPath)
|
||||
)
|
||||
} catch (e) {
|
||||
console.error('impossible to load schedules')
|
||||
}
|
||||
|
||||
@@ -253,6 +253,7 @@
|
||||
|
||||
<div class="z-10 flex-auto grow" bind:clientHeight={minHeight}>
|
||||
<FlowGraphV2
|
||||
path={$flowStore['path']}
|
||||
{disableAi}
|
||||
insertable
|
||||
scroll
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
import { encodeState } from '$lib/utils'
|
||||
import BranchOneStart from './renderers/nodes/BranchOneStart.svelte'
|
||||
import NoBranchNode from './renderers/nodes/NoBranchNode.svelte'
|
||||
import TriggersNode from './renderers/nodes/TriggersNode.svelte'
|
||||
import HiddenBaseEdge from './renderers/edges/HiddenBaseEdge.svelte'
|
||||
|
||||
export let success: boolean | undefined = undefined
|
||||
export let modules: FlowModule[] | undefined = []
|
||||
@@ -40,7 +42,6 @@
|
||||
export let maxHeight: number | undefined = undefined
|
||||
export let notSelectable = false
|
||||
export let flowModuleStates: Record<string, GraphModuleState> | undefined = undefined
|
||||
|
||||
export let selectedId: Writable<string | undefined> = writable<string | undefined>(undefined)
|
||||
|
||||
export let insertable = false
|
||||
@@ -54,6 +55,7 @@
|
||||
export let flowInputsStore: Writable<FlowInput | undefined> = writable<FlowInput | undefined>(
|
||||
undefined
|
||||
)
|
||||
export let path: string | undefined = undefined
|
||||
|
||||
let useDataflow: Writable<boolean | undefined> = writable<boolean | undefined>(false)
|
||||
|
||||
@@ -126,13 +128,13 @@
|
||||
disableAi,
|
||||
insertable,
|
||||
flowModuleStates,
|
||||
selectedId: $selectedId
|
||||
selectedId: $selectedId,
|
||||
path
|
||||
},
|
||||
failureModule,
|
||||
{
|
||||
deleteBranch: (detail, label) => {
|
||||
$selectedId = label
|
||||
|
||||
dispatch('deleteBranch', detail)
|
||||
},
|
||||
insert: (detail) => {
|
||||
@@ -148,7 +150,6 @@
|
||||
},
|
||||
delete: (detail, label) => {
|
||||
$selectedId = label
|
||||
|
||||
dispatch('delete', detail)
|
||||
},
|
||||
newBranch: (module) => {
|
||||
@@ -193,13 +194,15 @@
|
||||
whileLoopEnd: ForLoopEndNode,
|
||||
branchOneStart: BranchOneStart,
|
||||
branchOneEnd: BranchAllEndNode,
|
||||
noBranch: NoBranchNode
|
||||
noBranch: NoBranchNode,
|
||||
trigger: TriggersNode
|
||||
} as any
|
||||
|
||||
const edgeTypes = {
|
||||
edge: BaseEdge,
|
||||
empty: EmptyEdge,
|
||||
dataflowedge: DataflowEdge
|
||||
dataflowedge: DataflowEdge,
|
||||
hiddenedge: HiddenBaseEdge
|
||||
} as any
|
||||
|
||||
const proOptions = { hideAttribution: true }
|
||||
|
||||
@@ -95,6 +95,15 @@ export default function graphBuilder(
|
||||
})
|
||||
}
|
||||
|
||||
const triggerNode: Node = {
|
||||
id: 'Trigger',
|
||||
position: { x: -1, y: -1 },
|
||||
type: 'trigger',
|
||||
data: {
|
||||
path: extra.path
|
||||
}
|
||||
}
|
||||
|
||||
const inputNode: Node = {
|
||||
id: 'Input',
|
||||
position: { x: -1, y: -1 },
|
||||
@@ -102,7 +111,6 @@ export default function graphBuilder(
|
||||
data: {
|
||||
eventHandlers: eventHandlers,
|
||||
modules: modules,
|
||||
|
||||
...extra
|
||||
}
|
||||
}
|
||||
@@ -119,6 +127,13 @@ export default function graphBuilder(
|
||||
type: 'result'
|
||||
}
|
||||
|
||||
if (extra.path) {
|
||||
nodes.push(triggerNode)
|
||||
addEdge('Trigger', 'Input', {
|
||||
type: 'hiddenedge'
|
||||
})
|
||||
}
|
||||
|
||||
nodes.push(inputNode)
|
||||
nodes.push(resultNode)
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { BaseEdge } from '@xyflow/svelte'
|
||||
|
||||
export let markerEnd: string | undefined = undefined
|
||||
</script>
|
||||
|
||||
<BaseEdge path={''} {markerEnd} class="hidden" />
|
||||
@@ -29,9 +29,9 @@
|
||||
}>('FlowGraphContext')
|
||||
</script>
|
||||
|
||||
<NodeWrapper enableTargetHandle={false} let:darkMode>
|
||||
<NodeWrapper let:darkMode sourceOffset={-160}>
|
||||
{#if data.insertable && !data.disableAi}
|
||||
<div class="absolute -top-10 left-1/2 transform -translate-x-1/2 z-10">
|
||||
<div class="absolute -top-8 left-1/2 transform -translate-x-1/2 z-10">
|
||||
<Popover>
|
||||
<div class={openNoCopilot ? 'z-10' : ''}>
|
||||
<Menu pointerDown noMinW placement="bottom-center" let:close bind:show={openNoCopilot}>
|
||||
@@ -46,9 +46,9 @@
|
||||
: undefined}
|
||||
slot="trigger"
|
||||
type="button"
|
||||
class=" bg-surface text-violet-800 dark:text-violet-400 border mx-0.5 focus:outline-none hover:bg-surface-hover focus:ring-4 focus:ring-gray-200 font-medium rounded-full text-sm w-8 h-8 flex items-center justify-center"
|
||||
class=" bg-surface text-violet-800 dark:text-violet-400 border mx-0.5 focus:outline-none hover:bg-surface-hover focus:ring-4 focus:ring-gray-200 font-medium rounded-full text-sm w-6 h-6 flex items-center justify-center"
|
||||
>
|
||||
<Wand2 size={16} />
|
||||
<Wand2 size={14} />
|
||||
</button>
|
||||
{#if !$copilotInfo.exists_openai_resource_path}
|
||||
<div class="text-primary p-4">
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
<script lang="ts">
|
||||
import DarkModeObserver from '$lib/components/DarkModeObserver.svelte'
|
||||
import { Handle, Position } from '@xyflow/svelte'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
export let enableSourceHandle: boolean = true
|
||||
export let enableTargetHandle: boolean = true
|
||||
export let offset: number = 0
|
||||
export let wrapperClass: string = ''
|
||||
export let sourceOffset: number = 0
|
||||
|
||||
let darkMode: boolean = false
|
||||
</script>
|
||||
|
||||
<DarkModeObserver bind:darkMode />
|
||||
|
||||
<div class="relative shadow-md" style={`margin-left: ${offset}px;`}>
|
||||
<div class={twMerge('relative shadow-md', wrapperClass)} style={`margin-left: ${offset}px;`}>
|
||||
<slot {darkMode} />
|
||||
</div>
|
||||
|
||||
@@ -20,5 +23,5 @@
|
||||
{/if}
|
||||
|
||||
{#if enableTargetHandle}
|
||||
<Handle type="target" position={Position.Top} style={`margin-left: ${offset / 2}px;`} />
|
||||
<Handle type="target" position={Position.Top} style={`margin-left: ${sourceOffset / 2}px;`} />
|
||||
{/if}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<script lang="ts">
|
||||
import NodeWrapper from './NodeWrapper.svelte'
|
||||
import TriggersWrapper from '../triggers/TriggersWrapper.svelte'
|
||||
</script>
|
||||
|
||||
<NodeWrapper wrapperClass="shadow-none">
|
||||
<TriggersWrapper />
|
||||
</NodeWrapper>
|
||||
@@ -0,0 +1,14 @@
|
||||
<script>
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
</script>
|
||||
|
||||
<button
|
||||
on:click
|
||||
class={twMerge(
|
||||
'bg-surface-secondary hover:bg-surface-hover rounded-md border text-xs',
|
||||
'w-6 h-6',
|
||||
'relative center-center'
|
||||
)}
|
||||
>
|
||||
<slot />
|
||||
</button>
|
||||
@@ -0,0 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { Loader2 } from 'lucide-svelte'
|
||||
export let count: number | undefined = undefined
|
||||
</script>
|
||||
|
||||
<div class="absolute -right-2 -top-2">
|
||||
<div class="bg-blue-500 rounded-full h-4 w-4 p-1 flex center-center text-white text-2xs">
|
||||
{#if count === undefined}
|
||||
<Loader2 class="animate-spin text-2xs" />
|
||||
{:else}
|
||||
{count}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,128 @@
|
||||
<script lang="ts">
|
||||
import { Calendar, Mail, Webhook } from 'lucide-svelte'
|
||||
import TriggerButton from './TriggerButton.svelte'
|
||||
import { NODE } from '../../util'
|
||||
import { ScheduleService, type Schedule } from '$lib/gen'
|
||||
import { workspaceStore } from '$lib/stores'
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import Drawer from '$lib/components/common/drawer/Drawer.svelte'
|
||||
import { DrawerContent, Tabs } from '$lib/components/common'
|
||||
import WebhooksPanel from '$lib/components/details/WebhooksPanel.svelte'
|
||||
import Tab from '$lib/components/common/tabs/Tab.svelte'
|
||||
import EmailTriggerPanel from '$lib/components/details/EmailTriggerPanel.svelte'
|
||||
import type { FlowEditorContext } from '$lib/components/flows/types'
|
||||
import { getContext } from 'svelte'
|
||||
import TriggerCount from './TriggerCount.svelte'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
|
||||
let schedules: Schedule[] | undefined = undefined
|
||||
|
||||
const { selectedId, pathStore } = getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
async function loadSchedules() {
|
||||
if (!$pathStore) return
|
||||
|
||||
try {
|
||||
schedules = await ScheduleService.listSchedules({
|
||||
workspace: $workspaceStore ?? '',
|
||||
path: $pathStore,
|
||||
isFlow: true
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('impossible to load schedules')
|
||||
}
|
||||
}
|
||||
|
||||
loadSchedules()
|
||||
|
||||
let drawer: Drawer | undefined = undefined
|
||||
|
||||
let selectedTab: 'webhooks' | 'mail' = 'webhooks'
|
||||
</script>
|
||||
|
||||
<Drawer bind:this={drawer} size="600px">
|
||||
<DrawerContent
|
||||
title="Triggers"
|
||||
noPadding
|
||||
on:close={drawer.closeDrawer}
|
||||
tooltip="Resources represent connections to third party systems. Learn more on how to integrate external APIs."
|
||||
documentationLink="https://www.windmill.dev/docs/integrations/integrations_on_windmill"
|
||||
>
|
||||
<Tabs bind:selected={selectedTab}>
|
||||
<Tab value="webhooks">Webhooks</Tab>
|
||||
<Tab value="mail">Mail</Tab>
|
||||
<svelte:fragment slot="content">
|
||||
{#if selectedTab === 'webhooks'}
|
||||
<WebhooksPanel
|
||||
scopes={[`run:flow/${$pathStore}`]}
|
||||
path={$pathStore}
|
||||
isFlow={true}
|
||||
args={{}}
|
||||
token=""
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if selectedTab === 'mail'}
|
||||
<EmailTriggerPanel
|
||||
token=""
|
||||
scopes={[`run:flow/${$pathStore}`]}
|
||||
path={$pathStore}
|
||||
isFlow={true}
|
||||
/>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Tabs>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
<div style={`width: ${NODE.width}px;`}>
|
||||
<div class="flex flex-col mx-auto w-min">
|
||||
<div
|
||||
class="flex flex-row gap-2 px-2 border p-1 rounded-md border-surface-selected bg-surface shadow-md items-center"
|
||||
>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex flex-row items-center text-2xs">
|
||||
Triggers
|
||||
|
||||
<Tooltip small wrapperClass="center-center">
|
||||
The flow can be triggered by webhooks, emails, or schedules. Click on the icons to see
|
||||
the triggers.
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<Popover>
|
||||
<svelte:fragment slot="text">See default webhooks triggers</svelte:fragment>
|
||||
<TriggerButton
|
||||
on:click={() => {
|
||||
selectedTab = 'webhooks'
|
||||
drawer?.openDrawer()
|
||||
}}
|
||||
>
|
||||
<Webhook size={12} />
|
||||
</TriggerButton>
|
||||
</Popover>
|
||||
<Popover>
|
||||
<svelte:fragment slot="text">See default mail trigger</svelte:fragment>
|
||||
<TriggerButton
|
||||
on:click={() => {
|
||||
selectedTab = 'mail'
|
||||
drawer?.openDrawer()
|
||||
}}
|
||||
>
|
||||
<Mail size={12} />
|
||||
</TriggerButton>
|
||||
</Popover>
|
||||
<Popover>
|
||||
<svelte:fragment slot="text">See all schedules</svelte:fragment>
|
||||
<TriggerButton
|
||||
on:click={() => {
|
||||
$selectedId = 'settings-schedule'
|
||||
}}
|
||||
>
|
||||
<TriggerCount count={schedules?.length} />
|
||||
<Calendar size={12} />
|
||||
</TriggerButton>
|
||||
</Popover>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
5
frontend/src/routes/(root)/(logged)/routing/+page.js
Normal file
5
frontend/src/routes/(root)/(logged)/routing/+page.js
Normal file
@@ -0,0 +1,5 @@
|
||||
export function load() {
|
||||
return {
|
||||
stuff: { title: 'Routing' }
|
||||
}
|
||||
}
|
||||
86
frontend/src/routes/(root)/(logged)/routing/+page.svelte
Normal file
86
frontend/src/routes/(root)/(logged)/routing/+page.svelte
Normal file
@@ -0,0 +1,86 @@
|
||||
<script lang="ts">
|
||||
import CenteredPage from '$lib/components/CenteredPage.svelte'
|
||||
import { Badge, Button } from '$lib/components/common'
|
||||
import PageHeader from '$lib/components/PageHeader.svelte'
|
||||
import DataTable from '$lib/components/table/DataTable.svelte'
|
||||
import Head from '$lib/components/table/Head.svelte'
|
||||
import Cell from '$lib/components/table/Cell.svelte'
|
||||
import { Plus } from 'lucide-svelte'
|
||||
|
||||
const workers: {
|
||||
method: string
|
||||
route: string
|
||||
path: string
|
||||
}[] = [
|
||||
{
|
||||
method: 'GET',
|
||||
route: '/api/v1/{:id}/flows',
|
||||
path: 'flows'
|
||||
},
|
||||
{
|
||||
method: 'POST',
|
||||
route: '/api/v1/flows',
|
||||
path: 'flows'
|
||||
},
|
||||
{
|
||||
method: 'GET',
|
||||
route: '/api/v1/flows/:id',
|
||||
path: 'flows'
|
||||
},
|
||||
{
|
||||
method: 'PUT',
|
||||
route: '/api/v1/flows/:id',
|
||||
path: 'flows'
|
||||
},
|
||||
{
|
||||
method: 'DELETE',
|
||||
route: '/api/v1/flows/:id',
|
||||
path: 'flows'
|
||||
}
|
||||
]
|
||||
</script>
|
||||
|
||||
<CenteredPage>
|
||||
<PageHeader
|
||||
title="Routing"
|
||||
tooltip="Trigger Scripts and Flows according to a cron schedule"
|
||||
documentationLink="https://www.windmill.dev/docs/core_concepts/routing"
|
||||
>
|
||||
<Button size="md" startIcon={{ icon: Plus }} on:click={() => {}}>New route</Button>
|
||||
</PageHeader>
|
||||
<div class="w-full h-full flex flex-col">
|
||||
<DataTable>
|
||||
<Head>
|
||||
<tr>
|
||||
<Cell head first class="w-24">Method</Cell>
|
||||
<Cell head>Path</Cell>
|
||||
<Cell head last>Flow/Script</Cell>
|
||||
</tr>
|
||||
</Head>
|
||||
<tbody class="divide-y">
|
||||
{#each workers as x}
|
||||
<tr>
|
||||
<Cell first class="!w-24">
|
||||
<select value={x.method} class="!w-24">
|
||||
<option value="GET" class="!text-green-500">GET</option>
|
||||
<option value="POST">POST</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
</select>
|
||||
</Cell>
|
||||
<Cell>
|
||||
<Badge small>
|
||||
{x.route}
|
||||
</Badge>
|
||||
</Cell>
|
||||
<Cell last>
|
||||
<Badge small>
|
||||
{x.path}
|
||||
</Badge>
|
||||
</Cell>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</DataTable>
|
||||
</div>
|
||||
</CenteredPage>
|
||||
@@ -13,5 +13,6 @@
|
||||
download="flow.json"
|
||||
href={'data:text/json;charset=utf-8,' +
|
||||
encodeURIComponent(JSON.stringify({ value: { modules, failureModule }, summary: '' }, null, 4))}
|
||||
>Download</a
|
||||
>
|
||||
Download
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user