Compare commits

...

62 Commits

Author SHA1 Message Date
Faton Ramadani
7a6aa25016 feat(frontend): wip 2024-08-19 13:50:06 +02:00
Faton Ramadani
c69d55817a feat(frontend): wip 2024-08-19 10:40:18 +02:00
Faton Ramadani
cee9d8c611 feat(frontend): Correctly merge main 2024-08-19 09:32:39 +02:00
Faton Ramadani
5a899177a2 feat(frontend): merge main 2024-08-19 09:29:03 +02:00
Faton Ramadani
28a1288ebc feat(frontend): merge main 2024-08-19 09:28:02 +02:00
Faton Ramadani
31ab0f1aea Merge branch 'main' into fr/flow-triggers 2024-08-19 09:19:24 +02:00
Faton Ramadani
5c47ede54e feat(frontend): wip 2024-08-15 17:16:34 +02:00
Faton Ramadani
64150cf3ec feat(frontend): UI nits 2024-08-15 11:49:30 +02:00
Faton Ramadani
4925d2e07f feat(frontend): UI nits 2024-08-15 11:22:17 +02:00
Faton Ramadani
7fe0a8f366 feat(frontend): Fix node position 2024-08-15 09:30:26 +02:00
Faton Ramadani
f20688d220 Merge branch 'main' into fr/xyflow 2024-08-14 16:04:15 +02:00
Faton Ramadani
97d8428664 feat(frontend): fix build 2024-08-14 16:04:06 +02:00
Faton Ramadani
f3b8ab7a34 Merge branch 'main' into fr/xyflow 2024-08-14 13:34:59 +02:00
Faton Ramadani
54b3e648a1 feat(frontend): fix viewgraph 2024-08-14 13:34:41 +02:00
Faton Ramadani
fcb3b41cd5 feat(frontend): style fix 2024-08-14 13:31:59 +02:00
Faton Ramadani
36a2fab953 feat(frontend): fix viewport 2024-08-14 13:22:53 +02:00
Faton Ramadani
d95b37baf2 feat(frontend): fix vertical alignement 2024-08-14 12:22:40 +02:00
Faton Ramadani
893e3571bb feat(frontend): fix move 2024-08-14 12:09:19 +02:00
Faton Ramadani
73532d4218 feat(frontend): remove dead code 2024-08-13 16:14:46 +02:00
Faton Ramadani
ba1f637743 Merge branch 'main' into fr/xyflow 2024-08-13 16:06:31 +02:00
Faton Ramadani
7d200ad940 Merge branch 'main' into fr/xyflow 2024-08-13 16:01:37 +02:00
Faton Ramadani
2c9103de08 feat(frontend): fix build 2024-08-13 16:00:48 +02:00
Faton Ramadani
5e506c3a23 Merge branch 'main' into fr/xyflow 2024-08-13 15:51:19 +02:00
Faton Ramadani
f086b849af feat(frontend): fix light theme 2024-08-13 15:27:32 +02:00
Faton Ramadani
c6fd9b39c8 Merge branch 'main' into fr/xyflow 2024-08-13 15:04:54 +02:00
Faton Ramadani
fd6b1af532 feat(frontend): fix No branch for branch one 2024-08-13 15:04:47 +02:00
Faton Ramadani
6c62a60a4b feat(frontend): fix move 2024-08-13 14:52:32 +02:00
Faton Ramadani
4d7bc5c651 feat(frontend): add support for triggers 2024-08-13 14:45:59 +02:00
Faton Ramadani
8f1cb11ea8 feat(frontend): add missing trigger 2024-08-13 14:33:09 +02:00
Faton Ramadani
c782434cae feat(frontend): code improvement 2024-08-13 13:54:35 +02:00
Faton Ramadani
87a1043312 feat(frontend): Fix graph height in the flow status viewer 2024-08-12 17:53:18 +02:00
Faton Ramadani
073c806252 feat(frontend): Make the iterations menu work 2024-08-12 17:38:14 +02:00
Faton Ramadani
48998fc073 feat(frontend): fix add and delete branches 2024-08-12 16:32:16 +02:00
Faton Ramadani
3c7ccc192e feat(frontend): Support default branch for branch one 2024-08-12 16:06:13 +02:00
Faton Ramadani
c752e72b90 feat(frontend): Fix branch one 2024-08-12 15:50:10 +02:00
Faton Ramadani
355792b5a3 feat(frontend): Fix insert 2024-08-12 15:32:38 +02:00
Faton Ramadani
30e25cae07 feat(frontend): add missing insert button for empty loops 2024-08-12 15:22:58 +02:00
Faton Ramadani
e81b2d2529 feat(frontend): clean up 2024-08-12 14:16:45 +02:00
Faton Ramadani
6ad2b3a0d5 feat(frontend): fix min-height 2024-08-12 14:09:38 +02:00
Faton Ramadani
c56f6ea374 feat(frontend): clean up 2024-08-12 13:59:11 +02:00
Faton Ramadani
3ea2529640 feat(frontend): clean up 2024-08-12 13:42:03 +02:00
Faton Ramadani
542998de14 feat(frontend): clean up 2024-08-12 13:35:24 +02:00
Faton Ramadani
68eeb7ef0f Merge branch 'main' into fr/xyflow 2024-08-12 13:06:46 +02:00
Faton Ramadani
76fea32da0 feat(frontend): dataflow 2024-08-12 11:54:29 +02:00
Faton Ramadani
4170db79f5 feat(frontend): migrate to xyflow 2024-08-12 08:23:10 +02:00
Faton Ramadani
c8b7205749 Merge branch 'main' into fr/xyflow 2024-08-09 13:38:23 +02:00
Faton Ramadani
7cff84fee7 fix(frontend): wip 2024-08-09 10:48:30 +02:00
Faton Ramadani
7a379da666 feat(frontend): flow status viewer 2024-08-09 08:25:13 +02:00
Faton Ramadani
d3b37b0b2d Merge main 2024-08-08 16:46:02 +02:00
Faton Ramadani
b3a032f35a fix(frontend): wip 2024-08-08 13:40:55 +02:00
Faton Ramadani
2b6730c074 Merge branch 'main' into fr/xyflow 2024-08-08 10:16:40 +02:00
Faton Ramadani
dde040c5a6 fix(frontend): wip 2024-08-08 10:16:21 +02:00
Faton Ramadani
17e5b16eab fix(frontend): same view as before 2024-08-07 13:21:44 +02:00
Faton Ramadani
19e3bf12e7 Merge branch 'main' into fr/xyflow 2024-08-06 17:44:54 +02:00
Faton Ramadani
df1b0ffb24 fix(frontend): wip 2024-08-06 17:44:41 +02:00
Faton Ramadani
d9dcde32d4 Merge branch 'main' into fr/xyflow 2024-08-06 16:48:10 +02:00
Faton Ramadani
073ac9108c fix(frontend): wip 2024-08-06 09:38:24 +02:00
Faton Ramadani
70d8cd475e feat(frontend): Merge main 2024-08-05 16:25:15 +02:00
Faton Ramadani
fa87b01c1c fix(frontend): wip 2024-08-05 10:38:54 +02:00
Faton Ramadani
9fc977c720 fix(frontend): fix while loops + theme 2024-08-02 17:52:44 +02:00
Faton Ramadani
9abeccbe72 fix(frontend): wip 2024-08-02 17:42:06 +02:00
Faton Ramadani
1c7b67d0ee fix(frontend): wip 2024-08-02 16:48:03 +02:00
15 changed files with 311 additions and 21 deletions

View File

@@ -12,6 +12,7 @@
description?: string
value: FlowValue
schema?: any
path?: string
}
export let overflowAuto = false
export let noSide = false

View File

@@ -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')
}

View File

@@ -253,6 +253,7 @@
<div class="z-10 flex-auto grow" bind:clientHeight={minHeight}>
<FlowGraphV2
path={$flowStore['path']}
{disableAi}
insertable
scroll

View File

@@ -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 }

View File

@@ -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)

View File

@@ -0,0 +1,7 @@
<script lang="ts">
import { BaseEdge } from '@xyflow/svelte'
export let markerEnd: string | undefined = undefined
</script>
<BaseEdge path={''} {markerEnd} class="hidden" />

View File

@@ -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">

View File

@@ -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}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -0,0 +1,5 @@
export function load() {
return {
stuff: { title: 'Routing' }
}
}

View 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&nbsp;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>

View File

@@ -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>