improvement(serializer): canonical subblock, serialization cleanups, schedules/webhooks are deployment version friendly (#2848)

* hide form deployment tab from docs

* progress

* fix resolution

* cleanup code

* fix positioning

* cleanup dead sockets adv mode ops

* address greptile comments

* fix tests plus more simplification

* fix cleanup

* bring back advanced mode with specific definition

* revert feature flags

* improvement(subblock): ui

* resolver change to make all var references optional chaining

* fix(webhooks/schedules): deployment version friendly

* fix tests

* fix credential sets with new lifecycle

* prep merge

* add back migration

* fix display check for adv fields

* fix trigger vs block scoping

---------

Co-authored-by: Emir Karabeg <emirkarabeg@berkeley.edu>
This commit is contained in:
Vikhyath Mondreti
2026-01-16 15:23:43 -08:00
committed by GitHub
parent ce3ddb6ba0
commit 78e4ca9d45
70 changed files with 12806 additions and 1011 deletions

View File

@@ -0,0 +1,26 @@
ALTER TABLE "webhook" DROP CONSTRAINT "webhook_block_id_workflow_blocks_id_fk";
--> statement-breakpoint
ALTER TABLE "workflow_schedule" DROP CONSTRAINT "workflow_schedule_block_id_workflow_blocks_id_fk";
--> statement-breakpoint
DROP INDEX "path_idx";--> statement-breakpoint
DROP INDEX "workflow_schedule_workflow_block_unique";--> statement-breakpoint
ALTER TABLE "webhook" ADD COLUMN "deployment_version_id" text;--> statement-breakpoint
ALTER TABLE "workflow_schedule" ADD COLUMN "deployment_version_id" text;--> statement-breakpoint
ALTER TABLE "webhook" ADD CONSTRAINT "webhook_deployment_version_id_workflow_deployment_version_id_fk" FOREIGN KEY ("deployment_version_id") REFERENCES "public"."workflow_deployment_version"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "workflow_schedule" ADD CONSTRAINT "workflow_schedule_deployment_version_id_workflow_deployment_version_id_fk" FOREIGN KEY ("deployment_version_id") REFERENCES "public"."workflow_deployment_version"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE UNIQUE INDEX "path_deployment_unique" ON "webhook" USING btree ("path","deployment_version_id");--> statement-breakpoint
CREATE INDEX "webhook_workflow_deployment_idx" ON "webhook" USING btree ("workflow_id","deployment_version_id");--> statement-breakpoint
CREATE UNIQUE INDEX "workflow_schedule_workflow_block_deployment_unique" ON "workflow_schedule" USING btree ("workflow_id","block_id","deployment_version_id");--> statement-breakpoint
CREATE INDEX "workflow_schedule_workflow_deployment_idx" ON "workflow_schedule" USING btree ("workflow_id","deployment_version_id");--> statement-breakpoint
UPDATE "webhook" AS w
SET "deployment_version_id" = dv."id"
FROM "workflow_deployment_version" AS dv
WHERE dv."workflow_id" = w."workflow_id"
AND dv."is_active" = true
AND w."deployment_version_id" IS NULL;--> statement-breakpoint
UPDATE "workflow_schedule" AS ws
SET "deployment_version_id" = dv."id"
FROM "workflow_deployment_version" AS dv
WHERE dv."workflow_id" = ws."workflow_id"
AND dv."is_active" = true
AND ws."deployment_version_id" IS NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -1009,6 +1009,13 @@
"when": 1768582494384,
"tag": "0144_old_killer_shrike",
"breakpoints": true
},
{
"idx": 145,
"version": "7",
"when": 1768602646955,
"tag": "0145_messy_archangel",
"breakpoints": true
}
]
}

View File

@@ -492,7 +492,11 @@ export const workflowSchedule = pgTable(
workflowId: text('workflow_id')
.notNull()
.references(() => workflow.id, { onDelete: 'cascade' }),
blockId: text('block_id').references(() => workflowBlocks.id, { onDelete: 'cascade' }),
deploymentVersionId: text('deployment_version_id').references(
() => workflowDeploymentVersion.id,
{ onDelete: 'cascade' }
),
blockId: text('block_id'),
cronExpression: text('cron_expression'),
nextRunAt: timestamp('next_run_at'),
lastRanAt: timestamp('last_ran_at'),
@@ -507,9 +511,14 @@ export const workflowSchedule = pgTable(
},
(table) => {
return {
workflowBlockUnique: uniqueIndex('workflow_schedule_workflow_block_unique').on(
workflowBlockUnique: uniqueIndex('workflow_schedule_workflow_block_deployment_unique').on(
table.workflowId,
table.blockId
table.blockId,
table.deploymentVersionId
),
workflowDeploymentIdx: index('workflow_schedule_workflow_deployment_idx').on(
table.workflowId,
table.deploymentVersionId
),
}
}
@@ -522,7 +531,11 @@ export const webhook = pgTable(
workflowId: text('workflow_id')
.notNull()
.references(() => workflow.id, { onDelete: 'cascade' }),
blockId: text('block_id').references(() => workflowBlocks.id, { onDelete: 'cascade' }), // ID of the webhook trigger block (nullable for legacy starter block webhooks)
deploymentVersionId: text('deployment_version_id').references(
() => workflowDeploymentVersion.id,
{ onDelete: 'cascade' }
),
blockId: text('block_id'),
path: text('path').notNull(),
provider: text('provider'), // e.g., "whatsapp", "github", etc.
providerConfig: json('provider_config'), // Store provider-specific configuration
@@ -537,13 +550,17 @@ export const webhook = pgTable(
},
(table) => {
return {
// Ensure webhook paths are unique
pathIdx: uniqueIndex('path_idx').on(table.path),
// Ensure webhook paths are unique per deployment version
pathIdx: uniqueIndex('path_deployment_unique').on(table.path, table.deploymentVersionId),
// Optimize queries for webhooks by workflow and block
workflowBlockIdx: index('idx_webhook_on_workflow_id_block_id').on(
table.workflowId,
table.blockId
),
workflowDeploymentIdx: index('webhook_workflow_deployment_idx').on(
table.workflowId,
table.deploymentVersionId
),
// Optimize queries for credential set webhooks
credentialSetIdIdx: index('webhook_credential_set_id_idx').on(table.credentialSetId),
}

View File

@@ -260,6 +260,7 @@ const BLOCK_OPERATIONS = {
TOGGLE_ENABLED: 'toggle-enabled',
UPDATE_PARENT: 'update-parent',
UPDATE_ADVANCED_MODE: 'update-advanced-mode',
UPDATE_CANONICAL_MODE: 'update-canonical-mode',
TOGGLE_HANDLES: 'toggle-handles',
} as const

View File

@@ -169,8 +169,20 @@ export const mockBlockConfigs: Record<string, any> = {
config: { tool: () => 'slack_send_message' },
},
subBlocks: [
{ id: 'channel', type: 'dropdown', title: 'Channel', mode: 'basic' },
{ id: 'manualChannel', type: 'short-input', title: 'Channel ID', mode: 'advanced' },
{
id: 'channel',
type: 'dropdown',
title: 'Channel',
mode: 'basic',
canonicalParamId: 'channel',
},
{
id: 'manualChannel',
type: 'short-input',
title: 'Channel ID',
mode: 'advanced',
canonicalParamId: 'channel',
},
{ id: 'text', type: 'long-input', title: 'Message' },
{ id: 'username', type: 'short-input', title: 'Username', mode: 'both' },
],