+ {`${isFlow ? 'Your flow' : 'Your script'} has draft triggers. Select which draft triggers to deploy with the ${isFlow ? 'flow' : 'script'}. Undeployed
+ draft triggers will be permanently deleted.`}
+
{#if SCRIPT_VIEW_SHOW_CREATE_TOKEN_BUTTON}
diff --git a/frontend/src/lib/components/details/EmailTriggerPanel.svelte b/frontend/src/lib/components/details/EmailTriggerPanel.svelte
index 3687c1e710..a38aa4c035 100644
--- a/frontend/src/lib/components/details/EmailTriggerPanel.svelte
+++ b/frontend/src/lib/components/details/EmailTriggerPanel.svelte
@@ -7,20 +7,20 @@
import { SettingService } from '$lib/gen'
import Skeleton from '../common/skeleton/Skeleton.svelte'
import TriggerTokens from '../triggers/TriggerTokens.svelte'
- import TriggersEditorSection from '../triggers/TriggersEditorSection.svelte'
import Description from '../Description.svelte'
+ import Section from '../Section.svelte'
+ import { createEventDispatcher } from 'svelte'
+ import EmailTriggerConfigSection from './EmailTriggerConfigSection.svelte'
let userSettings: UserSettings
+ const dispatch = createEventDispatcher()
+
export let token: string
export let scopes: string[] = []
export let isFlow: boolean = false
export let hash: string | undefined = undefined
export let path: string
- export let isEditor: boolean = false
- export let canHavePreprocessor: boolean = false
- export let hasPreprocessor: boolean = false
- export let newItem: boolean = false
let emailDomain: string | null = null
let triggerTokens: TriggerTokens | undefined = undefined
@@ -35,6 +35,8 @@
}
getEmailDomain()
+
+ $: emailDomain && dispatch('email-domain', emailDomain)
@@ -50,7 +52,7 @@
{scopes}
/>
-
+
Email triggers execute scripts and flows when emails are sent to specific addresses. Each
trigger has its own unique email address that can be used to invoke the script or flow.
@@ -59,23 +61,7 @@
{:else}
{#if emailDomain}
-
+
{:else}
@@ -95,4 +81,4 @@
{/if}
-
+
diff --git a/frontend/src/lib/components/flows/FlowEditor.svelte b/frontend/src/lib/components/flows/FlowEditor.svelte
index 411a5e9311..a7c22a2e16 100644
--- a/frontend/src/lib/components/flows/FlowEditor.svelte
+++ b/frontend/src/lib/components/flows/FlowEditor.svelte
@@ -13,6 +13,7 @@
import type { PropPickerContext, FlowPropPickerConfig } from '$lib/components/prop_picker'
import type { PickableProperties } from '$lib/components/flows/previousResults'
import type { Flow } from '$lib/gen'
+ import type { Trigger } from '$lib/components/triggers/utils'
const { flowStore } = getContext('FlowEditorContext')
export let loading: boolean
@@ -28,6 +29,8 @@
draft?: Flow | undefined
})
| undefined = undefined
+ export let onDeployTrigger: (trigger: Trigger) => void = () => {}
+
let size = 50
const { currentStepStore: copilotCurrentStepStore } =
@@ -84,6 +87,7 @@
enableAi={!disableAi}
on:applyArgs
on:testWithArgs
+ {onDeployTrigger}
/>
{/if}
diff --git a/frontend/src/lib/components/flows/common/FlowCard.svelte b/frontend/src/lib/components/flows/common/FlowCard.svelte
index 9b1969adaf..d2e14015ae 100644
--- a/frontend/src/lib/components/flows/common/FlowCard.svelte
+++ b/frontend/src/lib/components/flows/common/FlowCard.svelte
@@ -1,14 +1,16 @@
- {#if !noEditor}
+ {#if !noEditor && !noHeader}
diff --git a/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte b/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte
index 9e4f439fb0..613145f6c2 100644
--- a/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte
+++ b/frontend/src/lib/components/flows/content/FlowEditorPanel.svelte
@@ -6,13 +6,14 @@
import FlowInput from './FlowInput.svelte'
import FlowFailureModule from './FlowFailureModule.svelte'
import FlowConstants from './FlowConstants.svelte'
- import TriggersEditor from '../../triggers/TriggersEditor.svelte'
import type { FlowModule, Flow } from '$lib/gen'
import { initFlowStepWarnings } from '../utils'
import { dfs } from '../dfs'
import FlowPreprocessorModule from './FlowPreprocessorModule.svelte'
import type { TriggerContext } from '$lib/components/triggers'
import { insertNewPreprocessorModule } from '../flowStateUtils'
+ import TriggersEditor from '../../triggers/TriggersEditor.svelte'
+ import { handleSelectTriggerFromKind, type Trigger } from '$lib/components/triggers/utils'
export let noEditor = false
export let enableAi = false
@@ -23,7 +24,7 @@
draft?: Flow | undefined
})
| undefined = undefined
-
+ export let onDeployTrigger: (trigger: Trigger) => void = () => {}
const {
selectedId,
flowStore,
@@ -36,7 +37,7 @@
flowInputEditorState
} = getContext('FlowEditorContext')
- const { selectedTrigger, defaultValues, captureOn, showCaptureHint } =
+ const { showCaptureHint, triggersState, triggersCount } =
getContext('TriggerContext')
function checkDup(modules: FlowModule[]): string | undefined {
let seenModules: string[] = []
@@ -82,9 +83,7 @@
disabled={disabledFlowInputs}
on:openTriggers={(ev) => {
$selectedId = 'triggers'
- selectedTrigger.set(ev.detail.kind)
- defaultValues.set(ev.detail.config)
- captureOn.set(true)
+ handleSelectTriggerFromKind(triggersState, triggersCount, savedFlow?.path, ev.detail.kind)
showCaptureHint.set(true)
}}
on:applyArgs
@@ -118,16 +117,18 @@
}
}}
on:testWithArgs
- args={$previewArgs}
currentPath={$pathStore}
initialPath={$initialPathStore}
{fakeInitialPath}
- schema={$flowStore.schema}
{noEditor}
newItem={newFlow}
isFlow={true}
hasPreprocessor={!!$flowStore.value.preprocessor_module}
canHavePreprocessor={true}
+ args={$previewArgs}
+ isDeployed={savedFlow && !savedFlow?.draft_only}
+ schema={$flowStore.schema}
+ {onDeployTrigger}
/>
{:else if $selectedId.startsWith('subflow:')}
-
-
-
+
+
- {#if captureInfo.active}
-
- {:else}
-
- Start capturing to test your runnables with real data. Once active, all incoming
- payloads will be captured and displayed below, allowing you to test your runnables
- effectively.
-
+
+ {#if captureInfo.active}
+
+ {/if}
+
+
+
+
+
+ {#if displayAlert}
+
+ Capturing will suscribe to the trigger endpoint. Treat carefully.
+
+ {/if}
+
+
+ {#key (captureInfo.active, disabled)}
+
+ {#if disabled === true}
+ Enter a valid configuration to start capturing.
+ {:else}
+ {@render description?.()}
+ {/if}
+
Enable Google Cloud authentication for push delivery using a verified token.
If the subscription uses push delivery, its endpoint URL must
- match the following format: {base_endpoint}/*, meaning it must
- start with
- {base_endpoint} followed by any path segment.
+ match the following format: {`${base_endpoint}/${path}`}/*,
+ meaning it must start with
+ {`${base_endpoint}/${path}`} followed by any path segment.
+ {#if description}
+ {@render description()}
+ {/if}
+ {#if !hideTooltips}
{#if edit}
Changes can take up to 30 seconds to take effect.
@@ -227,23 +316,26 @@
New GCP Pub/Sub trigger can take up to 30 seconds to start listening.
{/if}
+ {/if}
+
+
+
+
+
+
-
-
-
-
-
-
+ {#if !hideTarget}
Pick a script or flow to be triggered
@@ -256,35 +348,38 @@
allowFlow={true}
bind:itemKind
bind:scriptPath={script_path}
- allowRefresh
+ allowRefresh={can_write}
+ allowEdit={!$userStore?.operator}
/>
{#if emptyString(script_path)}
Create from template
{/if}
+ {/if}
-
-
- {/if}
-
-
+
+
+ {/if}
+{/snippet}
diff --git a/frontend/src/lib/components/triggers/gcp/GcpTriggerPanel.svelte b/frontend/src/lib/components/triggers/gcp/GcpTriggerPanel.svelte
index fe9c587c1b..348a3a17b8 100644
--- a/frontend/src/lib/components/triggers/gcp/GcpTriggerPanel.svelte
+++ b/frontend/src/lib/components/triggers/gcp/GcpTriggerPanel.svelte
@@ -1,131 +1,68 @@
- {
- loadTriggers()
- }}
- bind:this={gcpTriggerEditor}
-/>
+ onMount(() => {
+ gcpTriggerEditor && openGcpTriggerEditor(isFlow, selectedTrigger.isDraft ?? false)
+ })
+
+ const cloudDisabled = $derived(isCloudHosted())
+
{#if !$enterpriseLicense}
GCP Pub/Sub triggers are an enterprise only feature.
-{:else if isCloudHosted()}
-
- GCP Pub/Sub triggers are disabled in the multi-tenant cloud.
-
{:else}
-
- GCP Pub/Sub triggers allow your scripts or flows to process messages from Google Cloud
- Pub/Sub in real time. Each trigger listens to a Pub/Sub subscription and executes a script or
- a flow when new messages are published to the corresponding topic.
-
-
- {#if !newItem && gcpTriggers && gcpTriggers.length > 0}
-
-
-
- {#each gcpTriggers as gcpTrigger (gcpTrigger.path)}
-
+ {#if description}
+ {@render description()}
+ {/if}
+ {#if !hideTooltips}
+
+ {#if edit}
+ Changes can take up to 30 seconds to take effect.
+ {:else}
+ Kafka consumers can take up to 30 seconds to start.
+ {/if}
+
+ {/if}
+
+
+
+
+
+
+
+
+ {#if !hideTarget}
Pick a script or flow to be triggered
@@ -235,20 +357,23 @@
btnClasses="ml-4 mt-2"
color="dark"
size="xs"
+ disabled={!can_write}
href={itemKind === 'flow' ? '/flows/add?hub=65' : '/scripts/add?hub=hub%2F19659'}
target="_blank">Create from template
{/if}
+ {#if description}
+ {@render description()}
+ {/if}
+ {#if !hideTooltips}
+
{#if edit}
Changes can take up to 30 seconds to take effect.
{:else}
New MQTT triggers can take up to 30 seconds to start listening.
{/if}
+ {/if}
+
+
+
+
+
+
-
-
-
-
-
-
+ {#if !hideTarget}
Pick a script or flow to be triggered
@@ -232,32 +360,37 @@
allowFlow={true}
bind:itemKind
bind:scriptPath={script_path}
- allowRefresh
+ allowRefresh={can_write}
+ allowEdit={!$userStore?.operator}
/>
{#if emptyString(script_path)}
Create from template
+ Create from template
+
{/if}
-
- Windmill can connect to an MQTT broker and subscribes to specific topics thus allowing the
- execution of script/flows based on the event triggered by those subscribed topics
-
-
- {#if !newItem && mqttTriggers && mqttTriggers.length > 0}
-
-
-
- {#each mqttTriggers as mqttTriggers (mqttTriggers.path)}
-
+
+ {#snippet description()}
+ {#if cloudDisabled}
+
+ MQTT triggers are disabled in the multi-tenant cloud.
+
+ {:else}
+
+ MQTT triggers allow you to execute scripts and flows in response to MQTT messages. They
+ can be configured to subscribe to specific topics with different QoS levels.
+
+ {/if}
+ {/snippet}
+
+
- {/if}
- {#if can_write}
-
- Save
-
- {/if}
+{#if useDrawer}
+
+
+
+ {@render actions()}
+
+ {@render config()}
+
+
+{:else}
+
+
+ {#if customLabel}
+ {@render customLabel()}
{/if}
- {#if drawerLoading}
+
+ {@render actions()}
+
+ {@render config()}
+
+{/if}
+
+{#snippet actions()}
+ {#if !drawerLoading}
+
+ {/if}
+{/snippet}
+
+{#snippet config()}
+ {#if drawerLoading}
+ {#if showLoading}
- {:else}
-
- {#if edit}
- Changes can take up to 30 seconds to take effect.
- {:else}
- NATS consumers can take up to 30 seconds to start.
- {/if}
-
-
-
-
-
-
-
+ {/if}
+ {:else}
+
+ {#if description}
+ {@render description()}
+ {/if}
+ {#if !hideTooltips}
+
+ {#if edit}
+ Changes can take up to 30 seconds to take effect.
+ {:else}
+ NATS consumers can take up to 30 seconds to start.
+ {/if}
+
+ {/if}
+
+
+
+
+
+
+
+ {#if !hideTarget}
Pick a script or flow to be triggered
@@ -243,19 +360,29 @@
color="dark"
size="xs"
href={itemKind === 'flow' ? '/flows/add?hub=66' : '/scripts/add?hub=hub%2F19663'}
- target="_blank">Create from template
+ Create from template
+
{/if}
- {#if postgres_resource_path}
-
-
-
- Choose the types of database transactions that should trigger a script or flow. You
- can select from Insert, Update,
- Delete, or any combination of these operations to define when the
- trigger should activate.
-
-
-
-
-
- {:else}
-
- {#if edit}
- Changes can take up to 30 seconds to take effect.
- {:else}
- New postgres triggers can take up to 30 seconds to start listening.
- {/if}
-
-
+ {#if description}
+ {@render description()}
+ {/if}
+ {#if !hideTooltips}
+
+ {#if edit}
+ Changes can take up to 30 seconds to take effect.
+ {:else}
+ New postgres triggers can take up to 30 seconds to start listening.
+ {/if}
+
+ {/if}
+
+
+
+
+
+ {#if !hideTarget}
Pick a script or flow to be triggered
@@ -355,7 +496,8 @@
allowFlow={true}
bind:itemKind
bind:scriptPath={script_path}
- allowRefresh
+ allowRefresh={can_write}
+ allowEdit={!$userStore?.operator}
/>
{#if emptyStringTrimmed(script_path) && is_flow === false}
@@ -380,218 +522,239 @@
{/if}
-
-
- Pick a database to connect to
-
-
-
-
-
-
+ {/if}
+
+
+ {#if isEditor}
+
+ {/if}
+
+
+ Pick a database to connect to
+
+
+
+
+
+
- {#if postgres_resource_path}
-
-
-
-
- Choose the types of database transactions that should trigger a script or
- flow. You can select from Insert, Update,
- Delete, or any combination of these operations to define when
- the trigger should activate.
-
+ Choose the types of database transactions that should trigger a script or flow.
+ You can select from Insert, Update,
+ Delete, or any combination of these operations to define when
+ the trigger should activate.
+
-
-
-
-
-
-
+ Select the tables to track. You can choose to track
+ all tables in your database,
+ all tables within a specific schema,
+ specific tables in a schema, or even
+ specific columns of a table. Additionally, you can apply a
+ filter to retrieve only rows that do not match the specified criteria.
+
+
+ {#if !emptyStringTrimmed(errorMessage)}
+
-
- Select the tables to track. You can choose to track
- all tables in your database,
- all tables within a specific schema,
- specific tables in a schema, or even
- specific columns of a table. Additionally, you can apply a
- filter to retrieve only rows that do not match the specified criteria.
-
-
-
-
-
Basic
Choose the relations to track without worrying about the
- underlying mechanics of creating a
- publication
- or slot. This simplified option lets you focus only on
- the data you want to monitor.
-
Advanced
Select a specific publication from your database to
- track, and manage it by creating,
- updating, or deleting. For
- slots, you can create or
- delete
- them. Both non-active slots and the
- currently used slot by the trigger will be retrieved from
- your database for management.
Choose the relations to track without worrying about the
+ underlying mechanics of creating a
+ publication
+ or slot. This simplified option lets you focus only on the
+ data you want to monitor.
+
Advanced
Select a specific publication from your database to track,
+ and manage it by creating,
+ updating, or deleting. For
+ slots, you can create or
+ delete
+ them. Both non-active slots and the
+ currently used slot by the trigger will be retrieved from your
+ database for management.
-
- Windmill can connect to a Postgres database and trigger runnables (scripts, flows) in response
- to database transactions (INSERT, UPDATE, DELETE) on specified tables, schemas, or the entire
- database. Listening is done using Postgres's logical replication streaming protocol, ensuring
- efficient and low-latency triggering.
-
-
- {#if !newItem && postgresTriggers && postgresTriggers.length > 0}
-
-
-
- {#each postgresTriggers as postgresTriggers (postgresTriggers.path)}
-
+
+ {#snippet description()}
+ {#if cloudDisabled}
+
+ Postgres triggers are disabled in the multi-tenant cloud.
+
+ {:else}
+
+ Windmill can connect to a Postgres database and trigger runnables (scripts, flows) in
+ response to database transactions (INSERT, UPDATE, DELETE) on specified tables, schemas,
+ or the entire database. Listening is done using Postgres's logical replication streaming
+ protocol, ensuring efficient and low-latency triggering.
+
+ {/if}
+ {/snippet}
+
+
diff --git a/frontend/src/lib/components/triggers/postgres/PublicationPicker.svelte b/frontend/src/lib/components/triggers/postgres/PublicationPicker.svelte
index 77b168a0f8..840d9a6856 100644
--- a/frontend/src/lib/components/triggers/postgres/PublicationPicker.svelte
+++ b/frontend/src/lib/components/triggers/postgres/PublicationPicker.svelte
@@ -16,6 +16,7 @@
export let postgres_resource_path: string = ''
export let relations: Relations[] | undefined = undefined
export let transaction_to_track: string[] = []
+ export let disabled: boolean = false
async function listDatabasePublication() {
try {
@@ -84,18 +85,17 @@
listDatabasePublication()
let darkMode = false
-
-
- If defined, upon error this schedule will be retried with a delay and a maximum
- number of attempts as defined below.
-
- This is only available for individual script. For flows, retries can be set on each
- flow step in the flow editor.
-
-
-
-
- {:else if optionTabSelected === 'tag'}
-
-
-
+ {/if}
+ {:else if script_path != ''}
+
+ You cannot see the the {is_flow ? 'flow' : 'script'} input form as you do not have access
+ to it.
+
+ {:else}
+
+ Pick a {is_flow ? 'flow' : 'script'} and fill its argument here
+
+
+ If defined, upon error this schedule will be retried with a delay and a maximum number
+ of attempts as defined below.
+
+ This is only available for individual script. For flows, retries can be set on each flow
+ step in the flow editor.
+
+ {/snippet}
+
+
+ {:else if optionTabSelected === 'tag'}
+
+
+
+ {/if}
+ {:else}
+
{/if}
-
-
+
+ {#if description}
+ {@render description()}
+ {/if}
+ {#if !hideTooltips}
+
{#if edit}
Changes can take up to 30 seconds to take effect.
{:else}
- New postgres triggers can take up to 30 seconds to start listening.
+ New SQS triggers can take up to 30 seconds to start listening.
{/if}
+ {/if}
+
+
+
+
+
+
-
-
-
-
-
-
+ {#if !hideTarget}
Pick a script or flow to be triggered
@@ -218,30 +343,35 @@
allowFlow={true}
bind:itemKind
bind:scriptPath={script_path}
- allowRefresh
+ allowRefresh={can_write}
+ allowEdit={!$userStore?.operator}
/>
{#if emptyString(script_path)}
Create from template
+ Create from template
+
{/if}
+ {/if}
-
-
- {/if}
-
-
+
+
+ {/if}
+{/snippet}
diff --git a/frontend/src/lib/components/triggers/sqs/SqsTriggerPanel.svelte b/frontend/src/lib/components/triggers/sqs/SqsTriggerPanel.svelte
index e981d7dedf..24bd1137f0 100644
--- a/frontend/src/lib/components/triggers/sqs/SqsTriggerPanel.svelte
+++ b/frontend/src/lib/components/triggers/sqs/SqsTriggerPanel.svelte
@@ -1,135 +1,69 @@
- {
- loadTriggers()
- }}
- bind:this={sqsTriggerEditor}
-/>
+ onMount(() => {
+ sqsTriggerEditor && openSqsTriggerEditor(isFlow, selectedTrigger.isDraft ?? false)
+ })
+
+ const cloudDisabled = $derived(isCloudHosted())
+
{#if !$enterpriseLicense}
SQS triggers are an enterprise only feature.
-{:else if isCloudHosted()}
-
- SQS triggers are disabled in the multi-tenant cloud.
-
{:else}
-
- SQS triggers allow your scripts/flows to process messages from Amazon Simple Queue Service
- (SQS) in real time. Each trigger listens to an SQS queue and executes a script or a flow when
- new messages arrive.
-
-
- {#if !newItem && sqsTriggers && sqsTriggers.length > 0}
-
-
-
- {#each sqsTriggers as sqsTriggers (sqsTriggers.path)}
-
+
-
-
+ userSettings.openDrawer()}>
+ Create a Webhook-specific Token
+
+ The token will have a scope such that it can only be used to trigger this script. It is
+ safe to share as it cannot be used to impersonate you.
+
+
+
+
{/if}
-
- {#if SCRIPT_VIEW_SHOW_CREATE_TOKEN_BUTTON}
-
-
-
- userSettings.openDrawer()}
- >
- Create a Webhook-specific Token
-
- The token will have a scope such that it can only be used to trigger this script. It
- is safe to share as it cannot be used to impersonate you.
-
-
-
diff --git a/frontend/src/lib/components/triggers/webhook/WebhooksPanel.svelte b/frontend/src/lib/components/triggers/webhook/WebhooksPanel.svelte
index 485a433e97..5893ee2a17 100644
--- a/frontend/src/lib/components/triggers/webhook/WebhooksPanel.svelte
+++ b/frontend/src/lib/components/triggers/webhook/WebhooksPanel.svelte
@@ -2,30 +2,40 @@
import { Alert } from '$lib/components/common'
import Description from '$lib/components/Description.svelte'
import HighlightTheme from '$lib/components/HighlightTheme.svelte'
- import TriggersEditorSection from '../TriggersEditorSection.svelte'
+ import WebhooksConfigSection from './WebhooksConfigSection.svelte'
+ import { Section } from '$lib/components/common'
- export let token: string
- export let args: Record = {}
- export let scopes: string[] = []
- export let isFlow: boolean = false
- export let hash: string | undefined = undefined
- export let path: string
- export let newItem: boolean = false
- export let isEditor: boolean = false
- export let canHavePreprocessor: boolean = false
- export let hasPreprocessor: boolean = false
+ interface Props {
+ token: string
+ args?: Record
+ scopes?: string[]
+ isFlow?: boolean
+ hash?: string | undefined
+ path: string
+ newItem?: boolean
+ }
- $: data = {
+ let {
+ token,
+ args = {},
+ scopes = [],
+ isFlow = false,
+ hash = undefined,
+ path,
+ newItem = false
+ }: Props = $props()
+
+ let data = $derived({
hash,
token,
scopes,
args
- }
+ })
-
+
Webhooks trigger scripts or flows via HTTP requests. Each webhook can be configured to run
synchronously or asynchronously. You can secure webhooks using tokens with specific permissions.
@@ -37,22 +47,12 @@
{/if}
-
-
+ {#if description}
+ {@render description()}
+ {/if}
+ {#if !hideTooltips}
+
+ {#if edit}
+ Changes can take up to 30 seconds to take effect.
+ {:else}
+ New WebSocket triggers can take up to 30 seconds to start listening.
+ {/if}
+
+ {/if}
+
@@ -312,230 +439,244 @@
rightTooltip:
'Whether the runnable result should be sent as a message to the websocket server when not null.'
}}
+ disabled={!can_write}
/>
+ {/if}
-
+
-
-
- Initial messages are sent at the beginning of the connection. They are sent in order.
- Raw messages and runnable results are supported.
-
-
- {#each initial_messages as v, i}
-
-
-
-
-
Type
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
{#if stepDetail}
{/if}
+
+
+
{/if}
diff --git a/frontend/src/routes/(root)/(logged)/gcp_triggers/+page.svelte b/frontend/src/routes/(root)/(logged)/gcp_triggers/+page.svelte
index 9fcaa0f202..2fd36a1cc1 100644
--- a/frontend/src/routes/(root)/(logged)/gcp_triggers/+page.svelte
+++ b/frontend/src/routes/(root)/(logged)/gcp_triggers/+page.svelte
@@ -263,7 +263,7 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+ {
@@ -122,7 +120,6 @@
searchParams={$page.url.searchParams}
{script}
{showMeta}
- {savedPrimarySchedule}
replaceStateFn={(path) => replaceState(path, $page.state)}
>
diff --git a/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte b/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte
index fbe85f83c0..803b29bce8 100644
--- a/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte
+++ b/frontend/src/routes/(root)/(logged)/scripts/edit/[...path]/+page.svelte
@@ -12,6 +12,7 @@
import UnsavedConfirmationModal from '$lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte'
import type { ScheduleTrigger } from '$lib/components/triggers'
import type { GetInitialAndModifiedValues } from '$lib/components/common/confirmationModal/unsavedTypes'
+ import type { Trigger } from '$lib/components/triggers/utils'
let initialState = window.location.hash != '' ? window.location.hash.slice(1) : undefined
let initialArgs = {}
@@ -26,7 +27,8 @@
let scriptLoadedFromUrl = initialState != undefined ? decodeState(initialState) : undefined
- let script: NewScript | undefined = undefined
+
+ let script: (NewScript & { draft_triggers?: Trigger[] }) | undefined = undefined
let initialPath: string = ''
@@ -37,7 +39,7 @@
let savedScript: NewScriptWithDraft | undefined = undefined
let fullyLoaded = false
- let savedPrimarySchedule: ScheduleTrigger | undefined = scriptLoadedFromUrl?.primarySchedule
+ let savedPrimarySchedule: ScheduleTrigger | undefined = undefined
async function loadScript(): Promise {
fullyLoaded = false
@@ -98,10 +100,12 @@
savedScript = structuredClone(scriptWithDraft)
if (scriptWithDraft.draft != undefined) {
script = scriptWithDraft.draft
+ scriptBuilder?.setDraftTriggers(script.draft_triggers)
if (script['primary_schedule']) {
savedPrimarySchedule = script['primary_schedule']
scriptBuilder?.setPrimarySchedule(savedPrimarySchedule)
}
+
if (!scriptWithDraft.draft_only) {
reloadAction = async () => {
scriptLoadedFromUrl = undefined
@@ -153,6 +157,7 @@
if (script) {
initialPath = script.path
+ scriptBuilder?.setDraftTriggers(script.draft_triggers)
scriptBuilder?.setCode(script.content)
if (topHash) {
script.parent_hash = topHash
@@ -176,6 +181,7 @@
}
diffDrawer.closeDrawer()
goto(`/scripts/edit/${savedScript.draft.path}`)
+ scriptLoadedFromUrl = undefined
loadScript()
}
@@ -193,6 +199,7 @@
})
}
goto(`/scripts/edit/${savedScript.path}`)
+ scriptLoadedFromUrl = undefined
loadScript()
}
diff --git a/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte b/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte
index 0a7d41a4dc..dd4f7fa15f 100644
--- a/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte
+++ b/frontend/src/routes/(root)/(logged)/scripts/get/[...hash]/+page.svelte
@@ -21,7 +21,7 @@
import { enterpriseLicense, hubBaseUrlStore, userStore, workspaceStore } from '$lib/stores'
import { isDeployable, ALL_DEPLOYABLE } from '$lib/utils_deployable'
- import { onDestroy } from 'svelte'
+ import { onDestroy, setContext, tick } from 'svelte'
import HighlightCode from '$lib/components/HighlightCode.svelte'
import {
Tabs,
@@ -42,10 +42,8 @@
import DeployWorkspaceDrawer from '$lib/components/DeployWorkspaceDrawer.svelte'
import SavedInputsV2 from '$lib/components/SavedInputsV2.svelte'
- import WebhooksPanel from '$lib/components/triggers/webhook/WebhooksPanel.svelte'
import DetailPageLayout from '$lib/components/details/DetailPageLayout.svelte'
import DetailPageHeader from '$lib/components/details/DetailPageHeader.svelte'
- import CliHelpBox from '$lib/components/CliHelpBox.svelte'
import {
Activity,
Archive,
@@ -68,30 +66,22 @@
import { scriptToHubUrl } from '$lib/hub'
import SharedBadge from '$lib/components/SharedBadge.svelte'
import ScriptVersionHistory from '$lib/components/ScriptVersionHistory.svelte'
- import RunPageSchedules from '$lib/components/RunPageSchedules.svelte'
import { createAppFromScript } from '$lib/components/details/createAppFromScript'
import { importStore } from '$lib/components/apps/store'
import TimeAgo from '$lib/components/TimeAgo.svelte'
- import ClipboardPanel from '$lib/components/details/ClipboardPanel.svelte'
import PersistentScriptDrawer from '$lib/components/PersistentScriptDrawer.svelte'
import GfmMarkdown from '$lib/components/GfmMarkdown.svelte'
- import EmailTriggerPanel from '$lib/components/details/EmailTriggerPanel.svelte'
import Star from '$lib/components/Star.svelte'
import LogViewer from '$lib/components/LogViewer.svelte'
- import RoutesPanel from '$lib/components/triggers/http/RoutesPanel.svelte'
import { Highlight } from 'svelte-highlight'
import json from 'svelte-highlight/languages/json'
import { writable } from 'svelte/store'
- import TriggersBadge from '$lib/components/graph/renderers/triggers/TriggersBadge.svelte'
- import WebsocketTriggersPanel from '$lib/components/triggers/websocket/WebsocketTriggersPanel.svelte'
- import KafkaTriggersPanel from '$lib/components/triggers/kafka/KafkaTriggersPanel.svelte'
- import NatsTriggersPanel from '$lib/components/triggers/nats/NatsTriggersPanel.svelte'
- import PostgresTriggersPanel from '$lib/components/triggers/postgres/PostgresTriggersPanel.svelte'
import Toggle from '$lib/components/Toggle.svelte'
import InputSelectedBadge from '$lib/components/schema/InputSelectedBadge.svelte'
- import MqttTriggersPanel from '$lib/components/triggers/mqtt/MqttTriggersPanel.svelte'
- import SqsTriggerPanel from '$lib/components/triggers/sqs/SqsTriggerPanel.svelte'
- import GcpTriggerPanel from '$lib/components/triggers/gcp/GcpTriggerPanel.svelte'
+ import type { TriggerContext } from '$lib/components/triggers'
+ import TriggersBadge from '$lib/components/graph/renderers/triggers/TriggersBadge.svelte'
+ import TriggersEditor from '$lib/components/triggers/TriggersEditor.svelte'
+ import { Triggers } from '$lib/components/triggers/triggers.svelte'
let script: Script | undefined
let topHash: string | undefined
@@ -107,7 +97,14 @@
let inputSelected: 'saved' | 'history' | undefined = undefined
let jsonView = false
- $: cliCommand = `wmill script run ${script?.path} -d '${JSON.stringify(args)}'`
+ $: {
+ const cliTrigger = triggersState.triggers.find((t) => t.type === 'cli')
+ if (cliTrigger) {
+ cliTrigger.extra = {
+ cliCommand: `wmill script run ${script?.path} -d '${JSON.stringify(args)}'`
+ }
+ }
+ }
$: loading = !script
@@ -121,6 +118,19 @@
const triggersCount = writable(undefined)
+ // Add triggers context store
+ const triggersState = new Triggers([
+ { type: 'webhook', path: '', isDraft: false },
+ { type: 'email', path: '', isDraft: false },
+ { type: 'cli', path: '', isDraft: false }
+ ])
+ setContext('TriggerContext', {
+ triggersCount,
+ simplifiedPoll: writable(false),
+ showCaptureHint: writable(undefined),
+ triggersState
+ })
+
async function deleteScript(hash: string): Promise {
try {
await ScriptService.deleteScriptByHash({ workspace: $workspaceStore!, hash })
@@ -167,11 +177,15 @@
}
let starred: boolean | undefined = undefined
- async function loadTriggersCount(path: string) {
- $triggersCount = await ScriptService.getTriggersCountOfScript({
- workspace: $workspaceStore!,
- path: path
- })
+ async function loadTriggers(path: string): Promise {
+ await triggersState.fetchTriggers(
+ triggersCount,
+ $workspaceStore,
+ path,
+ false,
+ undefined,
+ $userStore
+ )
}
async function loadScript(hash: string): Promise {
@@ -194,7 +208,7 @@
can_write =
script.workspace_id == $workspaceStore &&
canWrite(script.path, script.extra_perms!, $userStore)
- loadTriggersCount(script.path)
+ loadTriggers(script.path)
if (script.path && script.archived) {
const script_by_path = await ScriptService.getScriptByPath({
@@ -497,7 +511,6 @@
}
}
- let token = 'TOKEN_TO_CREATE'
let rightPaneSelected = 'saved_inputs'
let savedInputsV2: SavedInputsV2 | undefined = undefined
@@ -533,11 +546,7 @@
{#key script.hash}
-
+ {
+ rightPaneSelected = 'triggers'
+ }}
>
{
- rightPaneSelected = 'triggers'
+ selected={rightPaneSelected === 'triggers'}
+ onSelect={async (triggerIndex: number) => {
+ if (rightPaneSelected !== 'triggers') {
+ rightPaneSelected = 'triggers'
+ }
+ await tick()
+ triggersState.selectedTriggerIndex = triggerIndex
}}
/>
@@ -740,76 +757,18 @@
/>
{/if}
-
-