mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix(serializer): default canonical modes construction (#3330)
* fix(serializer): default canonical modes construction * defaults for copilot * address bugbot comments
This commit is contained in:
@@ -2,7 +2,11 @@ import crypto from 'crypto'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import type { PermissionGroupConfig } from '@/lib/permission-groups/types'
|
||||
import { getEffectiveBlockOutputs } from '@/lib/workflows/blocks/block-outputs'
|
||||
import { buildCanonicalIndex, isCanonicalPair } from '@/lib/workflows/subblocks/visibility'
|
||||
import {
|
||||
buildCanonicalIndex,
|
||||
buildDefaultCanonicalModes,
|
||||
isCanonicalPair,
|
||||
} from '@/lib/workflows/subblocks/visibility'
|
||||
import { hasTriggerCapability } from '@/lib/workflows/triggers/trigger-utils'
|
||||
import { getAllBlocks } from '@/blocks/registry'
|
||||
import type { BlockConfig } from '@/blocks/types'
|
||||
@@ -130,6 +134,12 @@ export function createBlockFromParams(
|
||||
}
|
||||
})
|
||||
|
||||
const defaultModes = buildDefaultCanonicalModes(blockConfig.subBlocks)
|
||||
if (Object.keys(defaultModes).length > 0) {
|
||||
if (!blockState.data) blockState.data = {}
|
||||
blockState.data.canonicalModes = defaultModes
|
||||
}
|
||||
|
||||
if (validatedInputs) {
|
||||
updateCanonicalModesForInputs(blockState, Object.keys(validatedInputs), blockConfig)
|
||||
}
|
||||
|
||||
@@ -75,6 +75,23 @@ export function isCanonicalPair(group?: CanonicalGroup): boolean {
|
||||
return Boolean(group?.basicId && group?.advancedIds?.length)
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds default canonical mode overrides for a block's subblocks.
|
||||
* All canonical pairs default to `'basic'`.
|
||||
*/
|
||||
export function buildDefaultCanonicalModes(
|
||||
subBlocks: SubBlockConfig[]
|
||||
): Record<string, 'basic' | 'advanced'> {
|
||||
const index = buildCanonicalIndex(subBlocks)
|
||||
const modes: Record<string, 'basic' | 'advanced'> = {}
|
||||
for (const group of Object.values(index.groupsById)) {
|
||||
if (isCanonicalPair(group)) {
|
||||
modes[group.canonicalId] = 'basic'
|
||||
}
|
||||
}
|
||||
return modes
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the active mode for a canonical group.
|
||||
*/
|
||||
|
||||
@@ -683,34 +683,37 @@ describe('Serializer', () => {
|
||||
expect(slackBlock?.config.params.username).toBe('bot')
|
||||
})
|
||||
|
||||
it.concurrent('should fall back to legacy advancedMode when canonicalModes not set', () => {
|
||||
const serializer = new Serializer()
|
||||
it.concurrent(
|
||||
'should fall back to legacy advancedMode for non-credential canonical groups when canonicalModes not set',
|
||||
() => {
|
||||
const serializer = new Serializer()
|
||||
|
||||
const block: any = {
|
||||
id: 'slack-1',
|
||||
type: 'slack',
|
||||
name: 'Test Slack Block',
|
||||
position: { x: 0, y: 0 },
|
||||
advancedMode: true,
|
||||
subBlocks: {
|
||||
operation: { value: 'send' },
|
||||
destinationType: { value: 'channel' },
|
||||
channel: { value: 'general' },
|
||||
manualChannel: { value: 'C1234567890' },
|
||||
text: { value: 'Hello world' },
|
||||
username: { value: 'bot' },
|
||||
},
|
||||
outputs: {},
|
||||
enabled: true,
|
||||
const block: any = {
|
||||
id: 'slack-1',
|
||||
type: 'slack',
|
||||
name: 'Test Slack Block',
|
||||
position: { x: 0, y: 0 },
|
||||
advancedMode: true,
|
||||
subBlocks: {
|
||||
operation: { value: 'send' },
|
||||
destinationType: { value: 'channel' },
|
||||
channel: { value: 'general' },
|
||||
manualChannel: { value: 'C1234567890' },
|
||||
text: { value: 'Hello world' },
|
||||
username: { value: 'bot' },
|
||||
},
|
||||
outputs: {},
|
||||
enabled: true,
|
||||
}
|
||||
|
||||
const serialized = serializer.serializeWorkflow({ 'slack-1': block }, [], {})
|
||||
const slackBlock = serialized.blocks.find((b) => b.id === 'slack-1')
|
||||
|
||||
expect(slackBlock).toBeDefined()
|
||||
expect(slackBlock?.config.params.channel).toBe('C1234567890')
|
||||
expect(slackBlock?.config.params.manualChannel).toBeUndefined()
|
||||
}
|
||||
|
||||
const serialized = serializer.serializeWorkflow({ 'slack-1': block }, [], {})
|
||||
const slackBlock = serialized.blocks.find((b) => b.id === 'slack-1')
|
||||
|
||||
expect(slackBlock).toBeDefined()
|
||||
expect(slackBlock?.config.params.channel).toBe('C1234567890')
|
||||
expect(slackBlock?.config.params.manualChannel).toBeUndefined()
|
||||
})
|
||||
)
|
||||
|
||||
it.concurrent('should use basic value by default when no mode specified', () => {
|
||||
const serializer = new Serializer()
|
||||
|
||||
@@ -61,8 +61,9 @@ function shouldSerializeSubBlock(
|
||||
const group = canonicalId ? canonicalIndex.groupsById[canonicalId] : undefined
|
||||
if (group && isCanonicalPair(group)) {
|
||||
const mode =
|
||||
canonicalModeOverrides?.[group.canonicalId] ??
|
||||
(displayAdvancedOptions ? 'advanced' : resolveCanonicalMode(group, values))
|
||||
canonicalModeOverrides?.[group.canonicalId] != null || !displayAdvancedOptions
|
||||
? resolveCanonicalMode(group, values, canonicalModeOverrides)
|
||||
: 'advanced'
|
||||
const matchesMode =
|
||||
mode === 'advanced'
|
||||
? group.advancedIds.includes(subBlockConfig.id)
|
||||
@@ -374,8 +375,11 @@ export class Serializer {
|
||||
|
||||
Object.values(canonicalIndex.groupsById).forEach((group) => {
|
||||
const { basicValue, advancedValue } = getCanonicalValues(group, params)
|
||||
const hasExplicitOverride = canonicalModeOverrides?.[group.canonicalId] != null
|
||||
const pairMode =
|
||||
canonicalModeOverrides?.[group.canonicalId] ?? (legacyAdvancedMode ? 'advanced' : 'basic')
|
||||
hasExplicitOverride || !legacyAdvancedMode
|
||||
? resolveCanonicalMode(group, allValues, canonicalModeOverrides)
|
||||
: 'advanced'
|
||||
const chosen = pairMode === 'advanced' ? advancedValue : basicValue
|
||||
|
||||
const sourceIds = [group.basicId, ...group.advancedIds].filter(Boolean) as string[]
|
||||
|
||||
@@ -3,6 +3,7 @@ import { v4 as uuidv4 } from 'uuid'
|
||||
import { DEFAULT_DUPLICATE_OFFSET } from '@/lib/workflows/autolayout/constants'
|
||||
import { getEffectiveBlockOutputs } from '@/lib/workflows/blocks/block-outputs'
|
||||
import { mergeSubblockStateWithValues } from '@/lib/workflows/subblocks'
|
||||
import { buildDefaultCanonicalModes } from '@/lib/workflows/subblocks/visibility'
|
||||
import { hasTriggerCapability } from '@/lib/workflows/triggers/trigger-utils'
|
||||
import { TriggerUtils } from '@/lib/workflows/triggers/triggers'
|
||||
import { getBlock } from '@/blocks'
|
||||
@@ -196,6 +197,13 @@ export function prepareBlockState(options: PrepareBlockStateOptions): BlockState
|
||||
preferToolOutputs: !effectiveTriggerMode,
|
||||
})
|
||||
|
||||
if (blockConfig.subBlocks) {
|
||||
const canonicalModes = buildDefaultCanonicalModes(blockConfig.subBlocks)
|
||||
if (Object.keys(canonicalModes).length > 0) {
|
||||
blockData.canonicalModes = canonicalModes
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
type,
|
||||
|
||||
Reference in New Issue
Block a user