mirror of
https://github.com/simstudioai/sim.git
synced 2026-10-24 01:23:02 +08:00
improvement(workflows): stop writing placeholder workflow descriptions (#5729)
* improvement(workflows): stop writing placeholder workflow descriptions * fix(workflows): scrub placeholder descriptions at the import boundary * test(workflows): pin import-boundary description scrubbing behavior
This commit is contained in:
@@ -144,7 +144,7 @@ export function Home({ chatId, userName, userId }: HomeProps) {
|
||||
filename: `${seed.workflowName}.json`,
|
||||
workspaceId,
|
||||
nameOverride: seed.workflowName,
|
||||
descriptionOverride: seed.workflowDescription || 'Imported from landing template',
|
||||
descriptionOverride: seed.workflowDescription || undefined,
|
||||
createWorkflow: async ({ name, description, workspaceId }) => {
|
||||
return requestJson(createWorkflowContract, {
|
||||
body: {
|
||||
|
||||
+5
-9
@@ -17,6 +17,7 @@ import {
|
||||
} from '@sim/emcn'
|
||||
import { getErrorMessage } from '@sim/utils/errors'
|
||||
import { useParams } from 'next/navigation'
|
||||
import { getMeaningfulWorkflowDescription } from '@/lib/mcp/workflow-tool-schema'
|
||||
import { normalizeInputFormatValue } from '@/lib/workflows/input-format'
|
||||
import { isInputDefinitionTrigger } from '@/lib/workflows/triggers/input-definition-triggers'
|
||||
import type { InputFormatField } from '@/lib/workflows/types'
|
||||
@@ -89,14 +90,9 @@ export function ApiInfoModal({ open, onOpenChange, workflowId }: ApiInfoModalPro
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
const normalizedDesc = workflowMetadata?.description?.toLowerCase().trim()
|
||||
const isDefaultDescription =
|
||||
!workflowMetadata?.description ||
|
||||
workflowMetadata.description === workflowMetadata.name ||
|
||||
normalizedDesc === 'new workflow' ||
|
||||
normalizedDesc === 'your first workflow - start building here!'
|
||||
|
||||
const initialDescription = isDefaultDescription ? '' : workflowMetadata?.description || ''
|
||||
const initialDescription =
|
||||
getMeaningfulWorkflowDescription(workflowMetadata?.description, workflowMetadata?.name) ??
|
||||
''
|
||||
setDescription(initialDescription)
|
||||
initialDescriptionRef.current = initialDescription
|
||||
|
||||
@@ -181,7 +177,7 @@ export function ApiInfoModal({ open, onOpenChange, workflowId }: ApiInfoModalPro
|
||||
await updateWorkflowMutation.mutateAsync({
|
||||
workspaceId,
|
||||
workflowId,
|
||||
metadata: { description: description.trim() || 'New workflow' },
|
||||
metadata: { description: description.trim() },
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ export function useCreateWorkflow() {
|
||||
body: {
|
||||
id,
|
||||
name: name || generateCreativeWorkflowName(),
|
||||
description: description || 'New workflow',
|
||||
description,
|
||||
workspaceId,
|
||||
folderId: folderId || null,
|
||||
sortOrder,
|
||||
@@ -226,7 +226,7 @@ export function useCreateWorkflow() {
|
||||
name: variables.name || generateCreativeWorkflowName(),
|
||||
lastModified: new Date(),
|
||||
createdAt: new Date(),
|
||||
description: variables.description || 'New workflow',
|
||||
description: variables.description ?? '',
|
||||
workspaceId: variables.workspaceId,
|
||||
folderId: variables.folderId || null,
|
||||
sortOrder,
|
||||
|
||||
@@ -2,9 +2,14 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
vi.unmock('@/blocks/registry')
|
||||
|
||||
vi.mock('@/lib/api/client/request', () => ({
|
||||
requestJson: vi.fn().mockResolvedValue({}),
|
||||
}))
|
||||
|
||||
import {
|
||||
extractWorkflowName,
|
||||
parseWorkflowJson,
|
||||
persistImportedWorkflow,
|
||||
sanitizePathSegment,
|
||||
} from '@/lib/workflows/operations/import-export'
|
||||
|
||||
@@ -134,6 +139,67 @@ describe('workflow import/export parsing', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('persistImportedWorkflow description handling', () => {
|
||||
function buildContent(description?: string) {
|
||||
const state = createLegacyState()
|
||||
return JSON.stringify({
|
||||
data: {
|
||||
version: '1.0',
|
||||
workflow: { name: 'Imported Workflow' },
|
||||
state: {
|
||||
...state,
|
||||
metadata: { name: 'Imported Workflow', description },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async function importWithContent(content: string, descriptionOverride?: string) {
|
||||
const createWorkflow = vi.fn().mockResolvedValue({ id: 'wf-1' })
|
||||
await persistImportedWorkflow({
|
||||
content,
|
||||
filename: 'imported-workflow.json',
|
||||
workspaceId: 'ws-1',
|
||||
descriptionOverride,
|
||||
createWorkflow,
|
||||
})
|
||||
return createWorkflow.mock.calls[0][0].description as string
|
||||
}
|
||||
|
||||
it('scrubs placeholder metadata descriptions to an empty string', async () => {
|
||||
expect(await importWithContent(buildContent('New workflow'))).toBe('')
|
||||
expect(
|
||||
await importWithContent(buildContent('Your first workflow - start building here!'))
|
||||
).toBe('')
|
||||
})
|
||||
|
||||
it('scrubs name-equal metadata descriptions to an empty string', async () => {
|
||||
expect(await importWithContent(buildContent('Imported Workflow'))).toBe('')
|
||||
})
|
||||
|
||||
it('preserves meaningful metadata descriptions', async () => {
|
||||
expect(await importWithContent(buildContent('Syncs leads from HubSpot to Slack'))).toBe(
|
||||
'Syncs leads from HubSpot to Slack'
|
||||
)
|
||||
})
|
||||
|
||||
it('uses an empty string when no description is present', async () => {
|
||||
expect(await importWithContent(buildContent(undefined))).toBe('')
|
||||
})
|
||||
|
||||
it('prefers a meaningful override over metadata', async () => {
|
||||
expect(
|
||||
await importWithContent(buildContent('Metadata description'), 'Override description')
|
||||
).toBe('Override description')
|
||||
})
|
||||
|
||||
it('falls back to meaningful metadata when the override is a placeholder', async () => {
|
||||
expect(await importWithContent(buildContent('Metadata description'), 'New workflow')).toBe(
|
||||
'Metadata description'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('sanitizePathSegment', () => {
|
||||
it('should preserve ASCII alphanumeric characters', () => {
|
||||
expect(sanitizePathSegment('workflow-123_abc')).toBe('workflow-123_abc')
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
type WorkflowStateContractInput,
|
||||
workflowVariablesContract,
|
||||
} from '@/lib/api/contracts/workflows'
|
||||
import { getMeaningfulWorkflowDescription } from '@/lib/mcp/workflow-tool-schema'
|
||||
import { migrateSubblockIds } from '@/lib/workflows/migrations/subblock-migrations'
|
||||
import {
|
||||
type ExportWorkflowState,
|
||||
@@ -677,7 +678,10 @@ export async function persistImportedWorkflow({
|
||||
|
||||
const createdWorkflow = await createWorkflow({
|
||||
name: workflowName,
|
||||
description: descriptionOverride || workflowData.metadata?.description || 'Imported from JSON',
|
||||
description:
|
||||
getMeaningfulWorkflowDescription(descriptionOverride, workflowName) ??
|
||||
getMeaningfulWorkflowDescription(workflowData.metadata?.description, workflowName) ??
|
||||
'',
|
||||
workspaceId,
|
||||
folderId,
|
||||
sortOrder,
|
||||
|
||||
Reference in New Issue
Block a user