Draft 1 : insert shedule poll in the trigger

This commit is contained in:
Guilhem
2024-10-14 14:51:42 +02:00
parent 9aed6f39e0
commit 5e60d32c7d
9 changed files with 437 additions and 92 deletions
+4 -1
View File
@@ -489,7 +489,10 @@
setContext<TriggerContext>('TriggerContext', {
httpTriggers: httpTriggersStore,
schedule: scheduleStore,
primarySchedule: primaryScheduleStore
primarySchedule: primaryScheduleStore,
triggerModule: writable(undefined),
selectedTrigger: selectedTriggerStore,
schedules: schedulesStore
})
setContext<FlowEditorContext>('FlowEditorContext', {
selectedId: selectedIdStore,
+10 -1
View File
@@ -83,7 +83,7 @@
import Summary from './Summary.svelte'
import type { FlowBuilderWhitelabelCustomUi } from './custom_ui'
import FlowYamlEditor from './flows/header/FlowYamlEditor.svelte'
import type { TriggerContext } from './triggers'
export let initialPath: string = ''
export let pathStoreInit: string | undefined = undefined
export let newFlow: boolean
@@ -405,6 +405,15 @@
const schedulesStore = writable<Schedule[] | undefined>(undefined)
let insertButtonOpen = writable<boolean>(false)
const primaryScheduleStore = writable<Schedule | undefined | boolean>(undefined)
setContext<TriggerContext>('TriggerContext', {
httpTriggers: httpTriggersStore,
schedule: scheduleStore,
primarySchedule: primaryScheduleStore,
triggerModule: writable(undefined),
selectedTrigger: selectedTriggerStore,
schedules: schedulesStore
})
setContext<FlowEditorContext>('FlowEditorContext', {
selectedId: selectedIdStore,
selectedTrigger: selectedTriggerStore,
@@ -0,0 +1,52 @@
<script lang="ts">
import FlowModuleComponent from '$lib/components/flows/content/FlowModuleComponent.svelte'
import Label from '$lib/components/Label.svelte'
import type { TriggerContext } from '$lib/components/triggers'
import PrimarySchedule from '$lib/components/PrimarySchedule.svelte'
import { getContext } from 'svelte'
import ScheduleEditor from '$lib/components/ScheduleEditor.svelte'
let schedulePollExists: boolean = true
export let path: string
export let isFlow: boolean
export let setScheduleEnabled: (path: string, enabled: boolean) => void
const { triggerModule, primarySchedule } = getContext<TriggerContext>('TriggerContext')
let scheduleEditor: ScheduleEditor
</script>
<ScheduleEditor on:update={() => {}} bind:this={scheduleEditor} />
<div class="flex flex-col gap-8">
{#if schedulePollExists && $triggerModule}
<Label label="Schedule">
{#if $primarySchedule}
<PrimarySchedule
{scheduleEditor}
schedule={$primarySchedule}
can_write={true}
{path}
{isFlow}
{setScheduleEnabled}
/>
{:else}
<div> No schedule poll triggers </div>
{/if}
</Label>
<Label label="Script">
<FlowModuleComponent
previousModule={undefined}
noEditor={false}
bind:flowModule={$triggerModule}
failureModule={false}
preprocessorModule={false}
scriptKind={'script'}
scriptTemplate={'script'}
enableAi={false}
/>
</Label>
{:else}
<div> No schedule poll triggers </div>
{/if}
</div>
@@ -10,12 +10,14 @@
import FlowCard from '../common/FlowCard.svelte'
import { getContext } from 'svelte'
import type { FlowEditorContext } from '../types'
import SchedulePollPanel from '$lib/components/details/SchedulePollPanel.svelte'
import type { TriggerContext } from '$lib/components/triggers'
export let noEditor: boolean
export let newFlow = false
let path = ''
const { pathStore, selectedTrigger } = getContext<FlowEditorContext>('FlowEditorContext')
const { triggerModule } = getContext<TriggerContext>('TriggerContext')
$: path = $pathStore
</script>
@@ -27,6 +29,9 @@
<Tab value="mail" selectedClass="text-primary text-sm font-semibold">Email</Tab>
<Tab value="routes" selectedClass="text-primary text-sm font-semibold">Routes</Tab>
<Tab value="schedules" selectedClass="text-primary text-sm font-semibold">Schedules</Tab>
<Tab value="schedule_poll" selectedClass="text-primary text-sm font-semibold"
>Schedule Poll</Tab
>
<svelte:fragment slot="content">
{#if $selectedTrigger === 'webhooks'}
@@ -70,6 +75,12 @@
/>
</div>
{/if}
{#if $selectedTrigger === 'schedule_poll' && triggerModule}
<div class="p-4">
<SchedulePollPanel flowModule={$triggerModule} />
</div>
{/if}
</svelte:fragment>
</Tabs>
</div>
@@ -0,0 +1,120 @@
<script lang="ts">
import { Cross, Zap } from 'lucide-svelte'
import StepGenQuick from '$lib/components/copilot/StepGenQuick.svelte'
import FlowInputsQuick from '../content/FlowInputsQuick.svelte'
import type { FlowModule } from '$lib/gen'
import ToggleHubWorkspaceQuick from '$lib/components/ToggleHubWorkspaceQuick.svelte'
import { twMerge } from 'tailwind-merge'
import type { ComputeConfig } from 'svelte-floating-ui'
import PopupV2 from '$lib/components/common/popup/PopupV2.svelte'
import { flip, offset } from 'svelte-floating-ui/dom'
// import type { Writable } from 'svelte/store'
export let index: number = 0
export let funcDesc = ''
export let modules: FlowModule[] = []
export let disableAi = false
export let kind: 'script' | 'trigger' | 'preprocessor' | 'failure' = 'script'
type Alignment = 'start' | 'end' | 'center'
type Side = 'top' | 'bottom'
type Placement = `${Side}-${Alignment}`
export let placement: Placement = 'bottom-center'
let floatingConfig: ComputeConfig = {
strategy: 'fixed',
// @ts-ignore
placement,
middleware: [offset(8), flip()],
autoUpdate: true
}
$: !open && (funcDesc = '')
let preFilter: 'all' | 'workspace' | 'hub' = 'all'
let loading = false
let small = false
let open = false
$: small = kind === 'preprocessor' || kind === 'failure'
</script>
<!-- <Menu transitionDuration={0} pointerDown bind:show={open} noMinW {placement} let:close> -->
<!-- {floatingConfig}
floatingClasses="mt-2"
containerClasses="border rounded-lg shadow-lg bg-surface"
noTransition
shouldUsePortal={true} -->
<PopupV2 {floatingConfig} bind:open let:close target="#flow-editor">
<svelte:fragment let:pointerdown let:pointerup slot="button">
<button
title={`Add ${
kind === 'failure'
? ' failure module '
: kind === 'preprocessor'
? 'preprocessor step'
: kind === 'trigger'
? 'trigger'
: 'step'
}`}
id={`flow-editor-add-step-${index}`}
type="button"
class={twMerge(
'w-5 h-5 flex items-center justify-center',
'outline-[1px] outline dark:outline-gray-500 outline-gray-300',
'text-secondary',
'bg-surface focus:outline-none hover:bg-surface-hover rounded '
)}
on:pointerdown|preventDefault|stopPropagation={pointerdown}
on:pointerup={pointerup}
>
{#if kind === 'trigger'}
<Zap size={12} />
{:else}
<Cross size={12} />
{/if}
</button>
</svelte:fragment>
<!-- FOO -->
<div
id="flow-editor-insert-module"
class="flex flex-col h-[400px] {small ? 'w-[450px]' : 'w-[650px]'} pt-1 pr-1 pl-1 gap-1.5"
on:wheel={(e) => {
e.stopPropagation()
}}
role="none"
>
<div class="flex flex-row items-center gap-2">
<StepGenQuick {disableAi} on:insert bind:funcDesc {preFilter} {loading} />
<ToggleHubWorkspaceQuick bind:selected={preFilter} />
</div>
<div class="flex flex-row grow min-h-0">
<div class="flex-none flex flex-col text-xs text-primary">
<slot name="topLevelNodes" {close} />
</div>
<FlowInputsQuick
selectedKind={'trigger'}
bind:loading
filter={funcDesc}
{modules}
{index}
{disableAi}
{funcDesc}
{kind}
on:close={() => {
close(null)
}}
on:new
on:pickScript
on:pickFlow
{preFilter}
{small}
/>
</div>
</div>
</PopupV2>
@@ -1,6 +1,18 @@
<script lang="ts">
import BarsStaggered from '$lib/components/icons/BarsStaggered.svelte'
import { CheckCircle2, ChevronRight, Code, GitBranch, Repeat, Square, Zap } from 'lucide-svelte'
import {
CheckCircle2,
ChevronRight,
Code,
GitBranch,
Repeat,
Square,
Zap,
Calendar,
Mail,
Webhook,
Route
} from 'lucide-svelte'
import { createEventDispatcher } from 'svelte'
import { twMerge } from 'tailwind-merge'
@@ -52,6 +64,22 @@
{:else if label === 'Branch to all'}
<GitBranch size={14} />
Branch to all
{:else if label === 'Schedule'}
<Calendar size={14} />
Schedule
{:else if label === 'Schedule poll'}
<Repeat size={14} />
Schedule poll
<ChevronRight size={12} class="ml-auto" color="#4c566a" />
{:else if label === 'Http route'}
<Route size={14} />
Http route
{:else if label === 'Webhook'}
<Webhook size={14} />
Webhook
{:else if label === 'Email'}
<Mail size={14} />
Email
{/if}
</span>
{#if returnIcon && selected}
@@ -1,5 +1,5 @@
<script lang="ts">
import { Calendar, Mail, Webhook } from 'lucide-svelte'
import { Calendar, Mail, Webhook, Repeat } from 'lucide-svelte'
import TriggerButton from './TriggerButton.svelte'
import { NODE } from '../../util'
import { HttpTriggerService, ScheduleService } from '$lib/gen'
@@ -11,7 +11,9 @@
import { canWrite } from '$lib/utils'
import { getContext } from 'svelte'
import type { FlowEditorContext } from '../../../flows/types'
import InsertTriggersButton from '../../../flows/map/InsertTriggersButton.svelte'
import TopLevelNode from '$lib/components/flows/pickers/TopLevelNode.svelte'
import type { TriggerContext } from '../../../triggers'
export let path: string
export let isEditor: boolean
export let newFlow: boolean
@@ -50,7 +52,7 @@
return { canWrite: canWrite(x.path, x.extra_perms!, $userStore), ...x }
})
} catch (e) {
console.error('impossible to load http routes')
console.error('impossible to load routes')
}
}
@@ -64,6 +66,31 @@
const { httpTriggers, selectedId, selectedTrigger, schedules, primarySchedule } =
getContext<FlowEditorContext>('FlowEditorContext') ?? {}
const { triggerModule } = getContext<TriggerContext>('TriggerContext') ?? {}
import { writable } from 'svelte/store'
import { pickScript } from '$lib/components/flows/flowStateUtils'
async function pickScriptEventHandler(path: string, summary: string, id: string) {
var module
var state
;[module, state] = await pickScript(path, summary, id)
$triggerModule = module
}
const modifiableTriggers = writable<
{ type: 'routes' | 'webhooks' | 'schedule' | 'email' | 'schedule_poll' }[]
>([{ type: 'schedule' }])
function addTrigger(triggerType: 'routes' | 'webhooks' | 'schedule' | 'email' | 'schedule_poll') {
modifiableTriggers.update((triggers) => [...triggers, { type: triggerType }])
}
/* function removeTrigger(
triggerType: 'routes' | 'webhooks' | 'schedule' | 'email' | 'schedule_poll'
) {
modifiableTriggers.update((triggers) => triggers.filter((t) => t.type !== triggerType))
} */
</script>
{#if isEditor}
@@ -80,90 +107,175 @@
<div class="flex flex-col">
<div class="flex flex-row items-center text-2xs font-normal"> Triggers </div>
</div>
<Popover>
<svelte:fragment slot="text">
{#if newFlow}
Deploy the flow to see webhooks triggers
{:else}
See default webhooks triggers
{/if}
{#if $modifiableTriggers.some((trigger) => trigger.type === 'webhooks')}
<Popover>
<svelte:fragment slot="text">
{#if newFlow}
Deploy the flow to see webhooks triggers
{:else}
See default webhooks triggers
{/if}
</svelte:fragment>
<TriggerButton
on:click={() => {
if (isEditor) {
$selectedTrigger = 'webhooks'
$selectedId = 'webhooks'
} else {
dispatch('triggerDetail', 'webhooks')
}
}}
disabled={newFlow}
>
<Webhook size={12} />
</TriggerButton>
</Popover>
{/if}
{#if $modifiableTriggers.some((trigger) => trigger.type === 'email')}
<Popover>
<svelte:fragment slot="text">
{#if newFlow}
Deploy the flow to see email triggers
{:else}
See all email triggers
{/if}
</svelte:fragment>
<TriggerButton
on:click={() => {
if (isEditor) {
$selectedTrigger = 'mail'
$selectedId = 'mail'
} else {
dispatch('triggerDetail', 'mail')
}
}}
disabled={newFlow}
>
<Mail size={12} />
</TriggerButton>
</Popover>
{/if}
{#if $modifiableTriggers.some((trigger) => trigger.type === 'routes')}
<Popover>
<svelte:fragment slot="text">
{#if newFlow}
Deploy the flow to add routes triggers
{:else}
See all routes triggers
{/if}
</svelte:fragment>
<TriggerButton
on:click={() => {
if (isEditor) {
$selectedTrigger = 'routes'
$selectedId = 'routes'
} else {
dispatch('triggerDetail', 'routes')
}
}}
disabled={newFlow}
>
<TriggerCount count={$httpTriggers?.length} />
<Route size={12} />
</TriggerButton>
</Popover>
{/if}
{#if $modifiableTriggers.some((trigger) => trigger.type === 'schedule')}
<Popover>
<svelte:fragment slot="text">See all schedules triggers</svelte:fragment>
<TriggerButton
on:click={() => {
if (isEditor) {
$selectedTrigger = 'schedules'
$selectedId = 'schedules'
} else {
dispatch('triggerDetail', 'schedule')
}
}}
disabled={newFlow}
>
<TriggerCount count={($schedules?.length ?? 0) + ($primarySchedule ? 1 : 0)} />
<Calendar size={12} />
</TriggerButton>
</Popover>
{/if}
{#if $modifiableTriggers.some((trigger) => trigger.type === 'schedule_poll')}
<Popover>
<svelte:fragment slot="text">See all schedules poll triggers</svelte:fragment>
<TriggerButton
on:click={() => {
if (isEditor) {
$selectedTrigger = 'schedule_poll'
$selectedId = 'schedule_poll'
} else {
dispatch('triggerDetail', 'schedule_poll')
}
}}
disabled={newFlow}
>
<Repeat size={12} />
</TriggerButton>
</Popover>
{/if}
<!-- index={data.index ?? 0}
allowTrigger={data.enableTrigger}
modules={data?.modules ?? []} -->
<InsertTriggersButton
on:new={(e) => {
// console.log('new', e)
$selectedId = 'triggers'
$selectedTrigger = 'schedule_poll'
addTrigger('schedule_poll')
}}
on:pickScript={(e) => {
pickScriptEventHandler(e.detail.path, e.detail.summary, e.detail.id)
// console.log('pickScript', e)
close(null)
}}
>
<svelte:fragment slot="topLevelNodes" let:close>
{#each ['schedule', 'routes', 'email', 'webhooks', 'schedule_poll'] as triggersType}
{#if !$modifiableTriggers.some((trigger) => trigger.type === triggersType)}
{#if triggersType === 'schedule'}
<TopLevelNode
label="Schedule"
on:select={() => {
close(null)
addTrigger('schedule')
}}
/>
{:else if triggersType === 'routes'}
<TopLevelNode
label="Http route"
on:select={() => {
close(null)
addTrigger('routes')
}}
/>
{:else if triggersType === 'email'}
<TopLevelNode
label="Email"
on:select={() => {
close(null)
addTrigger('email')
}}
/>
{:else if triggersType === 'webhooks'}
<TopLevelNode
label="Webhook"
on:select={() => {
close(null)
addTrigger('webhooks')
}}
/>
{:else if triggersType === 'schedule_poll'}
<TopLevelNode label="Schedule poll" />
{/if}
{/if}
{/each}
</svelte:fragment>
<TriggerButton
on:click={() => {
if (isEditor) {
$selectedTrigger = 'webhooks'
$selectedId = 'webhooks'
} else {
dispatch('triggerDetail', 'webhooks')
}
}}
disabled={newFlow}
>
<Webhook size={12} />
</TriggerButton>
</Popover>
<Popover>
<svelte:fragment slot="text">
{#if newFlow}
Deploy the flow to see email triggers
{:else}
See all email triggers
{/if}
</svelte:fragment>
<TriggerButton
on:click={() => {
if (isEditor) {
$selectedTrigger = 'mail'
$selectedId = 'mail'
} else {
dispatch('triggerDetail', 'mail')
}
}}
disabled={newFlow}
>
<Mail size={12} />
</TriggerButton>
</Popover>
<Popover>
<svelte:fragment slot="text">
{#if newFlow}
Deploy the flow to add routes triggers
{:else}
See all routes triggers
{/if}
</svelte:fragment>
<TriggerButton
on:click={() => {
if (isEditor) {
$selectedTrigger = 'routes'
$selectedId = 'routes'
} else {
dispatch('triggerDetail', 'routes')
}
}}
disabled={newFlow}
>
<TriggerCount count={$httpTriggers?.length} />
<Route size={12} />
</TriggerButton>
</Popover>
<Popover>
<svelte:fragment slot="text">See all schedules triggers</svelte:fragment>
<TriggerButton
on:click={() => {
if (isEditor) {
$selectedTrigger = 'schedules'
$selectedId = 'schedules'
} else {
dispatch('triggerDetail', 'schedule')
}
}}
disabled={newFlow}
>
<TriggerCount count={($schedules?.length ?? 0) + ($primarySchedule ? 1 : 0)} />
<Calendar size={12} />
</TriggerButton>
</Popover>
</InsertTriggersButton>
</button>
</div>
</div>
+2 -1
View File
@@ -1,4 +1,4 @@
import type { HttpTrigger, Schedule } from '$lib/gen'
import type { HttpTrigger, Schedule, FlowModule } from '$lib/gen'
import type { Writable } from 'svelte/store'
export type ScheduleTrigger = {
@@ -15,4 +15,5 @@ export type TriggerContext = {
schedule: Writable<ScheduleTrigger>
primarySchedule: Writable<Schedule | undefined | boolean>
schedules: Writable<Schedule[] | undefined>
triggerModule: Writable<FlowModule | undefined>
}
+10 -1
View File
@@ -17,7 +17,7 @@
import { getUserExt } from '$lib/user'
import DarkModeToggle from '$lib/components/sidebar/DarkModeToggle.svelte'
import type { Schedule as ScheduleUtils } from '$lib/components/flows/scheduleUtils'
import type { TriggerContext } from '$lib/components/triggers'
let token = $page.url.searchParams.get('wm_token') ?? undefined
let workspace = $page.url.searchParams.get('workspace') ?? undefined
let themeDarkRaw = $page.url.searchParams.get('activeColorTheme')
@@ -86,6 +86,15 @@
// selectedIdStore.set(selectedId)
// }
setContext<TriggerContext>('TriggerContext', {
httpTriggers: httpTriggersStore,
schedule: scheduleStore,
primarySchedule: primaryScheduleStore,
triggerModule: writable(undefined),
selectedTrigger: selectedTriggerStore,
schedules: schedulesStore
})
setContext<FlowEditorContext>('FlowEditorContext', {
selectedId: selectedIdStore,
selectedTrigger: selectedTriggerStore,