diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml
index b821951a39..8f1dc9101d 100644
--- a/backend/windmill-api/openapi.yaml
+++ b/backend/windmill-api/openapi.yaml
@@ -13009,6 +13009,11 @@ paths:
properties:
enabled:
type: boolean
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ schedule in a fork whose parent has the same path enabled.
required:
- enabled
@@ -13455,6 +13460,11 @@ paths:
properties:
mode:
$ref: "#/components/schemas/TriggerMode"
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ trigger in a fork whose parent has the same path enabled.
required:
- mode
responses:
@@ -13622,6 +13632,11 @@ paths:
properties:
mode:
$ref: "#/components/schemas/TriggerMode"
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ trigger in a fork whose parent has the same path enabled.
required:
- mode
responses:
@@ -13822,6 +13837,11 @@ paths:
properties:
mode:
$ref: "#/components/schemas/TriggerMode"
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ trigger in a fork whose parent has the same path enabled.
required:
- mode
responses:
@@ -14063,6 +14083,11 @@ paths:
properties:
mode:
$ref: "#/components/schemas/TriggerMode"
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ trigger in a fork whose parent has the same path enabled.
required:
- mode
responses:
@@ -14258,6 +14283,11 @@ paths:
properties:
mode:
$ref: "#/components/schemas/TriggerMode"
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ trigger in a fork whose parent has the same path enabled.
required:
- mode
responses:
@@ -15046,6 +15076,11 @@ paths:
properties:
mode:
$ref: "#/components/schemas/TriggerMode"
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ trigger in a fork whose parent has the same path enabled.
required:
- mode
responses:
@@ -15241,6 +15276,11 @@ paths:
properties:
mode:
$ref: "#/components/schemas/TriggerMode"
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ trigger in a fork whose parent has the same path enabled.
required:
- mode
responses:
@@ -15495,6 +15535,11 @@ paths:
properties:
mode:
$ref: "#/components/schemas/TriggerMode"
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ trigger in a fork whose parent has the same path enabled.
required:
- mode
responses:
@@ -16041,6 +16086,11 @@ paths:
properties:
mode:
$ref: "#/components/schemas/TriggerMode"
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ trigger in a fork whose parent has the same path enabled.
required:
- mode
responses:
@@ -16267,6 +16317,11 @@ paths:
properties:
mode:
$ref: "#/components/schemas/TriggerMode"
+ force:
+ type: boolean
+ description: >
+ Bypass the parent-state conflict warning when enabling a
+ trigger in a fork whose parent has the same path enabled.
required:
- mode
responses:
diff --git a/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte
index 87149dea68..f202c652d9 100644
--- a/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/azure/AzureTriggerEditorInner.svelte
@@ -5,6 +5,7 @@
import Path from '$lib/components/Path.svelte'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
import {
@@ -265,11 +266,15 @@
async function handleToggleMode(newMode: TriggerMode) {
mode = newMode
if (!trigger?.draftConfig) {
- await AzureTriggerService.setAzureTriggerMode({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { mode: newMode }
- })
+ await withForkConflictRetry(
+ (force) =>
+ AzureTriggerService.setAzureTriggerMode({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { mode: newMode, force }
+ }),
+ 'Azure trigger'
+ )
sendUserToast(`${capitalize(newMode)} Azure trigger ${initialPath}`)
onUpdate?.(initialPath)
}
diff --git a/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte
index 2cde08dc89..6b45c1c5ac 100644
--- a/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/email/EmailTriggerEditorInner.svelte
@@ -15,6 +15,7 @@
} from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -257,11 +258,15 @@
async function handleToggleMode(newMode: TriggerMode) {
mode = newMode
if (!trigger?.draftConfig) {
- await EmailTriggerService.setEmailTriggerMode({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { mode: newMode }
- })
+ await withForkConflictRetry(
+ (force) =>
+ EmailTriggerService.setEmailTriggerMode({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { mode: newMode, force }
+ }),
+ 'email trigger'
+ )
sendUserToast(`${capitalize(newMode)} email trigger ${initialPath}`)
onUpdate(initialPath)
diff --git a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte
index 87b22f3255..21351be1b6 100644
--- a/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/gcp/GcpTriggerEditorInner.svelte
@@ -5,6 +5,7 @@
import Path from '$lib/components/Path.svelte'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
import {
@@ -280,11 +281,15 @@
async function handleToggleMode(newMode: TriggerMode) {
mode = newMode
if (!trigger?.draftConfig) {
- await GcpTriggerService.setGcpTriggerMode({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { mode: newMode }
- })
+ await withForkConflictRetry(
+ (force) =>
+ GcpTriggerService.setGcpTriggerMode({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { mode: newMode, force }
+ }),
+ 'GCP Pub/Sub trigger'
+ )
sendUserToast(`${capitalize(newMode)} GCP Pub/Sub trigger ${initialPath}`)
onUpdate?.(initialPath)
diff --git a/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte b/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte
index 00391437f3..4933de3086 100644
--- a/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/http/RouteEditorInner.svelte
@@ -23,6 +23,7 @@
generateRandomString,
sendUserToast
} from '$lib/utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2, Pipette, Plus } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -408,11 +409,15 @@
async function handleToggleMode(newMode: TriggerMode) {
mode = newMode
if (!trigger?.draftConfig) {
- await HttpTriggerService.setHttpTriggerMode({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { mode: newMode }
- })
+ await withForkConflictRetry(
+ (force) =>
+ HttpTriggerService.setHttpTriggerMode({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { mode: newMode, force }
+ }),
+ 'HTTP trigger'
+ )
sendUserToast(`${capitalize(newMode)} HTTP trigger ${initialPath}`)
onUpdate(initialPath)
diff --git a/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte
index f2bfd02f28..cf32e08301 100644
--- a/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/kafka/KafkaTriggerEditorInner.svelte
@@ -9,6 +9,7 @@
import { KafkaTriggerService, type ErrorHandler, type Retry, type TriggerMode } from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2, RotateCcw } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -318,11 +319,15 @@
async function handleToggleMode(newMode: TriggerMode) {
mode = newMode
if (!trigger?.draftConfig) {
- await KafkaTriggerService.setKafkaTriggerMode({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { mode: newMode }
- })
+ await withForkConflictRetry(
+ (force) =>
+ KafkaTriggerService.setKafkaTriggerMode({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { mode: newMode, force }
+ }),
+ 'Kafka trigger'
+ )
sendUserToast(`${capitalize(newMode)} Kafka trigger ${initialPath}`)
onUpdate?.(initialPath)
diff --git a/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte
index 537d14bef0..bb60857e8a 100644
--- a/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/mqtt/MqttTriggerEditorInner.svelte
@@ -8,6 +8,7 @@
import ScriptPicker from '$lib/components/ScriptPicker.svelte'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -304,11 +305,15 @@
async function handleToggleMode(newMode: TriggerMode) {
mode = newMode
if (!trigger?.draftConfig) {
- await MqttTriggerService.setMqttTriggerMode({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { mode: newMode }
- })
+ await withForkConflictRetry(
+ (force) =>
+ MqttTriggerService.setMqttTriggerMode({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { mode: newMode, force }
+ }),
+ 'MQTT trigger'
+ )
sendUserToast(`${capitalize(newMode)} MQTT trigger ${initialPath}`)
onUpdate?.(initialPath)
diff --git a/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte
index 135c08b9d8..7d58123925 100644
--- a/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/nats/NatsTriggerEditorInner.svelte
@@ -8,6 +8,7 @@
import { NatsTriggerService, type ErrorHandler, type Retry, type TriggerMode } from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -284,11 +285,15 @@
async function handleToggleMode(newMode: TriggerMode) {
mode = newMode
if (!trigger?.draftConfig) {
- await NatsTriggerService.setNatsTriggerMode({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { mode: newMode }
- })
+ await withForkConflictRetry(
+ (force) =>
+ NatsTriggerService.setNatsTriggerMode({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { mode: newMode, force }
+ }),
+ 'NATS trigger'
+ )
sendUserToast(`${capitalize(newMode)} NATS trigger ${initialPath}`)
onUpdate?.(initialPath)
diff --git a/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte
index 4d59b0b68c..1682c2842e 100644
--- a/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/postgres/PostgresTriggerEditorInner.svelte
@@ -15,6 +15,7 @@
} from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, emptyString, emptyStringTrimmed, sendUserToast } from '$lib/utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -445,11 +446,15 @@
async function handleToggleMode(newMode: TriggerMode) {
mode = newMode
if (!trigger?.draftConfig) {
- await PostgresTriggerService.setPostgresTriggerMode({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { mode: newMode }
- })
+ await withForkConflictRetry(
+ (force) =>
+ PostgresTriggerService.setPostgresTriggerMode({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { mode: newMode, force }
+ }),
+ 'postgres trigger'
+ )
sendUserToast(`${capitalize(newMode)} postgres trigger ${initialPath}`)
onUpdate?.(initialPath)
diff --git a/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte b/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte
index 85a1ff843d..661f64d094 100644
--- a/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/schedules/ScheduleEditorInner.svelte
@@ -37,6 +37,7 @@
import WorkerTagPicker from '$lib/components/WorkerTagPicker.svelte'
import { runScheduleNow } from '../scheduled/utils'
import { handleConfigChange } from '../utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import TextInput from '$lib/components/text_input/TextInput.svelte'
import { twMerge } from 'tailwind-merge'
import PermissionedAsLine from '../PermissionedAsLine.svelte'
@@ -629,11 +630,15 @@
async function handleToggleEnabled(nEnabled: boolean) {
enabled = nEnabled
if (!trigger?.draftConfig) {
- await ScheduleService.setScheduleEnabled({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { enabled: nEnabled }
- })
+ await withForkConflictRetry(
+ (force) =>
+ ScheduleService.setScheduleEnabled({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { enabled: nEnabled, force }
+ }),
+ 'schedule'
+ )
sendUserToast(`${nEnabled ? 'enabled' : 'disabled'} schedule ${initialPath}`)
onUpdate?.(initialPath)
}
diff --git a/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte
index 09f7782e1d..ee12536236 100644
--- a/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/sqs/SqsTriggerEditorInner.svelte
@@ -5,6 +5,7 @@
import Path from '$lib/components/Path.svelte'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, capitalize, emptyString, sendUserToast } from '$lib/utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import { Loader2 } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
import {
@@ -242,11 +243,15 @@
async function handleToggleMode(newMode: TriggerMode) {
mode = newMode
if (!trigger?.draftConfig) {
- await SqsTriggerService.setSqsTriggerMode({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { mode: newMode }
- })
+ await withForkConflictRetry(
+ (force) =>
+ SqsTriggerService.setSqsTriggerMode({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { mode: newMode, force }
+ }),
+ 'SQS trigger'
+ )
sendUserToast(`${capitalize(newMode)} SQS trigger ${initialPath}`)
onUpdate?.(initialPath)
diff --git a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte
index ce807c7e3c..ba90c7ea56 100644
--- a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte
+++ b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte
@@ -21,6 +21,7 @@
} from '$lib/gen'
import { usedTriggerKinds, userStore, workspaceStore } from '$lib/stores'
import { canWrite, emptySchema, emptyString, sendUserToast } from '$lib/utils'
+ import { withForkConflictRetry } from '$lib/utils/forkConflict'
import Section from '$lib/components/Section.svelte'
import { Loader2, X, Plus } from 'lucide-svelte'
import Label from '$lib/components/Label.svelte'
@@ -372,11 +373,15 @@
async function handleToggleMode(newMode: TriggerMode) {
mode = newMode
if (!trigger?.draftConfig) {
- await WebsocketTriggerService.setWebsocketTriggerMode({
- path: initialPath,
- workspace: $workspaceStore ?? '',
- requestBody: { mode: newMode }
- })
+ await withForkConflictRetry(
+ (force) =>
+ WebsocketTriggerService.setWebsocketTriggerMode({
+ path: initialPath,
+ workspace: $workspaceStore ?? '',
+ requestBody: { mode: newMode, force }
+ }),
+ 'websocket trigger'
+ )
sendUserToast(`${capitalize(newMode)} websocket trigger ${initialPath}`)
onUpdate?.(initialPath)
diff --git a/frontend/src/lib/components/workspaceSettings/CreateWorkspaceInner.svelte b/frontend/src/lib/components/workspaceSettings/CreateWorkspaceInner.svelte
index e1f5d125bc..2fc26522ff 100644
--- a/frontend/src/lib/components/workspaceSettings/CreateWorkspaceInner.svelte
+++ b/frontend/src/lib/components/workspaceSettings/CreateWorkspaceInner.svelte
@@ -56,6 +56,7 @@
let workspaceColor: string | undefined = $state(undefined)
let colorEnabled = $state(false)
+ let forkTriggers = $state(false)
function generateRandomColor() {
const randomColor =
@@ -208,7 +209,8 @@
id: prefixed_id,
name,
color: colorEnabled && workspaceColor ? workspaceColor : undefined,
- forked_datatables: forkedDatatables
+ forked_datatables: forkedDatatables,
+ fork_triggers: forkTriggers
}
})
} catch (e) {
@@ -507,6 +509,15 @@
forkCreationLoading = false
}}
/>
+
{/if}
{#if !automateUsernameCreation}