Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion frontend/src/nodeTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,14 @@ export interface NodeTypeDefinition {

export const TRIGGER_CATEGORY = 'Triggers'
export const AI_CATEGORY = 'AI'
// File-manipulation actions only (tag, comment, move, copy, rename): things that mutate the
// file itself. "Send Notification" is deliberately kept out of this bucket — see
// NOTIFICATION_CATEGORY below — because it doesn't touch the file at all, it sends a message
// to an external destination (Slack, email, a webhook, ...). Grouping it with file operations
// made the "Actions" picker section read as "everything that isn't AI", which stops being a
// useful scanning aid as more node types are added.
export const ACTION_CATEGORY = 'Actions'
export const NOTIFICATION_CATEGORY = 'Notifications'

export const NODE_TYPES: NodeTypeDefinition[] = [
{
Expand Down Expand Up @@ -112,7 +119,7 @@ export const NODE_TYPES: NodeTypeDefinition[] = [
label: 'Send Notification',
description: 'Send a notification to Slack, email, or 100+ other services',
icon: 'notification-3',
category: ACTION_CATEGORY,
category: NOTIFICATION_CATEGORY,
defaultData: { actionType: 'notify' }
}
]
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/views/WorkflowBuilder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ import ExecutionsPanel from '../components/ExecutionsPanel.vue'
import { useWorkflowsApi } from '../composables/useWorkflowsApi'
import { useAppConfig } from '../composables/useAppConfig'
import { builderPath, listPath } from '../router'
import { findNodeType, TRIGGER_CATEGORY, AI_CATEGORY, ACTION_CATEGORY } from '../nodeTypes'
import { findNodeType, TRIGGER_CATEGORY, AI_CATEGORY, ACTION_CATEGORY, NOTIFICATION_CATEGORY } from '../nodeTypes'
import type { TriggerType, WorkflowEdge, WorkflowNode, WorkflowNodeData } from '../types/workflow'

const props = defineProps<{ id: string }>()
Expand Down Expand Up @@ -184,7 +184,10 @@ const fitViewSoon = () => {
const openPicker = (fromNodeId: string | null, allowedCategories?: string[]) => {
pickerConnectFrom.value = fromNodeId
pickerAllowedCategories.value =
allowedCategories ?? (nodes.value.some((n) => n.type === 'trigger') ? [AI_CATEGORY, ACTION_CATEGORY] : [TRIGGER_CATEGORY])
allowedCategories ??
(nodes.value.some((n) => n.type === 'trigger')
? [AI_CATEGORY, ACTION_CATEGORY, NOTIFICATION_CATEGORY]
: [TRIGGER_CATEGORY])
pickerOpen.value = true
}

Expand Down
34 changes: 34 additions & 0 deletions frontend/tests/unit/nodeTypes.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { describe, expect, it } from 'vitest'
import {
ACTION_CATEGORY,
AI_CATEGORY,
NODE_TYPES,
NOTIFICATION_CATEGORY,
TRIGGER_CATEGORY,
findNodeType
} from '../../src/nodeTypes'

describe('node type categorization', () => {
it('gives Send Notification its own category, distinct from the file-manipulation actions', () => {
const notify = findNodeType('action-notify')

expect(notify?.category).toBe(NOTIFICATION_CATEGORY)
expect(notify?.category).not.toBe(ACTION_CATEGORY)
})

it('keeps the file-manipulation actions (tag, comment, move, copy, rename) under Actions', () => {
const fileActionIds = ['action-tag', 'action-comment', 'action-move', 'action-copy', 'action-rename']

for (const id of fileActionIds) {
expect(findNodeType(id)?.category).toBe(ACTION_CATEGORY)
}
})

it('surfaces three distinct non-trigger categories for the node picker to group by', () => {
const nonTriggerCategories = new Set(
NODE_TYPES.filter((t) => t.category !== TRIGGER_CATEGORY).map((t) => t.category)
)

expect(nonTriggerCategories).toEqual(new Set([AI_CATEGORY, ACTION_CATEGORY, NOTIFICATION_CATEGORY]))
})
})
Loading