@octaviaflow/flow-rules 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3010 -28
- package/package.json +14 -5
- package/dist/catalog/actions/console-log/config.js +0 -70
- package/dist/catalog/actions/console-log/index.js +0 -89
- package/dist/catalog/actions/delay/config.js +0 -79
- package/dist/catalog/actions/delay/index.js +0 -71
- package/dist/catalog/actions/delay/migrate.js +0 -38
- package/dist/catalog/actions/delay/types.js +0 -17
- package/dist/catalog/actions/http-request/config.js +0 -111
- package/dist/catalog/actions/http-request/index.js +0 -223
- package/dist/catalog/ai/ai-agent/index.js +0 -72
- package/dist/catalog/ai/idp-extract/index.js +0 -90
- package/dist/catalog/api/graphql-query/config.js +0 -31
- package/dist/catalog/api/graphql-query/index.js +0 -75
- package/dist/catalog/communication/email-send/config.js +0 -80
- package/dist/catalog/communication/email-send/index.js +0 -152
- package/dist/catalog/communication/google-chat/config.js +0 -28
- package/dist/catalog/communication/google-chat/index.js +0 -36
- package/dist/catalog/communication/slack-message/config.js +0 -36
- package/dist/catalog/communication/slack-message/index.js +0 -37
- package/dist/catalog/communication/teams-message/config.js +0 -29
- package/dist/catalog/communication/teams-message/index.js +0 -39
- package/dist/catalog/communication/webhook-call/config.js +0 -31
- package/dist/catalog/communication/webhook-call/index.js +0 -43
- package/dist/catalog/communication/whatsapp-send/config.js +0 -36
- package/dist/catalog/communication/whatsapp-send/index.js +0 -57
- package/dist/catalog/general/query/config.js +0 -257
- package/dist/catalog/general/query/index.js +0 -271
- package/dist/catalog/general/query/types.js +0 -82
- package/dist/catalog/general/transform/config.js +0 -95
- package/dist/catalog/general/transform/index.js +0 -63
- package/dist/catalog/index.js +0 -168
- package/dist/catalog/logic/condition/config.js +0 -93
- package/dist/catalog/logic/condition/index.js +0 -64
- package/dist/catalog/logic/for-each/config.js +0 -75
- package/dist/catalog/logic/for-each/index.js +0 -92
- package/dist/catalog/logic/for-each/pathOptions.js +0 -151
- package/dist/catalog/logic/group/index.js +0 -46
- package/dist/catalog/policies.js +0 -62
- package/dist/catalog/storage/csv-action/index.js +0 -38
- package/dist/catalog/storage/dropbox-action/index.js +0 -33
- package/dist/catalog/storage/excel-action/index.js +0 -32
- package/dist/catalog/storage/file-action/index.js +0 -119
- package/dist/catalog/storage/file-operation/config.js +0 -45
- package/dist/catalog/storage/file-operation/index.js +0 -111
- package/dist/catalog/storage/ftp-action/index.js +0 -33
- package/dist/catalog/storage/google-drive-action/index.js +0 -38
- package/dist/catalog/storage/json-action/index.js +0 -31
- package/dist/catalog/storage/onedrive-action/index.js +0 -33
- package/dist/catalog/storage/s3-action/index.js +0 -36
- package/dist/catalog/storage/storage-action/index.js +0 -72
- package/dist/catalog/storage/storageCapabilities.js +0 -207
- package/dist/catalog/storage/xml-action/index.js +0 -31
- package/dist/catalog/transforms/format/config.js +0 -19
- package/dist/catalog/transforms/format/index.js +0 -39
- package/dist/catalog/triggers/connector-trigger/index.js +0 -72
- package/dist/catalog/triggers/manual-trigger/config.js +0 -60
- package/dist/catalog/triggers/manual-trigger/index.js +0 -74
- package/dist/catalog/triggers/schedule-trigger/config.js +0 -42
- package/dist/catalog/triggers/schedule-trigger/index.js +0 -102
- package/dist/catalog/triggers/webhook-trigger/config.js +0 -27
- package/dist/catalog/triggers/webhook-trigger/index.js +0 -89
- package/dist/catalog/types.js +0 -135
- package/dist/catalog/utility/debug/config.js +0 -90
- package/dist/catalog/utility/debug/index.js +0 -38
- package/dist/catalog/utility/error/config.js +0 -25
- package/dist/catalog/utility/error/index.js +0 -46
- package/dist/catalog/utility/variables/config.js +0 -70
- package/dist/catalog/utility/variables/index.js +0 -40
- package/dist/catalog/workflow.js +0 -25
- package/dist/ids.js +0 -53
- package/dist/rules/nodeConfigStatus.js +0 -217
- package/dist/rules/workflowValidator.js +0 -358
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error Configuration
|
|
3
|
-
*/
|
|
4
|
-
export const ErrorConfig = {
|
|
5
|
-
defaults: {
|
|
6
|
-
message: '',
|
|
7
|
-
code: undefined,
|
|
8
|
-
},
|
|
9
|
-
schema: {
|
|
10
|
-
message: { type: 'string', required: true },
|
|
11
|
-
code: { type: 'string', required: false },
|
|
12
|
-
},
|
|
13
|
-
validate: (config) => {
|
|
14
|
-
const errors = [];
|
|
15
|
-
if (!config.message)
|
|
16
|
-
errors.push('Error message is required');
|
|
17
|
-
return { valid: errors.length === 0, errors };
|
|
18
|
-
},
|
|
19
|
-
merge: (userConfig) => {
|
|
20
|
-
return { ...ErrorConfig.defaults, ...userConfig };
|
|
21
|
-
},
|
|
22
|
-
getLabel: (config) => {
|
|
23
|
-
return `Error: ${config.message}`;
|
|
24
|
-
},
|
|
25
|
-
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Error Action
|
|
3
|
-
*
|
|
4
|
-
* Throw an error to stop workflow execution
|
|
5
|
-
*/
|
|
6
|
-
import { ActionCategory, ActionType, ActionStatus, FieldType } from '../../types';
|
|
7
|
-
export const errorDefinition = {
|
|
8
|
-
id: 'error',
|
|
9
|
-
name: 'Error',
|
|
10
|
-
description: 'Throw an error to stop workflow execution',
|
|
11
|
-
category: ActionCategory.Utility,
|
|
12
|
-
type: ActionType.Error,
|
|
13
|
-
tags: ['utility', 'error', 'control', 'built-in'],
|
|
14
|
-
status: ActionStatus.Stable,
|
|
15
|
-
icon: 'ErrorFilled',
|
|
16
|
-
color: '#da3742',
|
|
17
|
-
inputSchema: {
|
|
18
|
-
fields: [
|
|
19
|
-
{
|
|
20
|
-
key: 'message',
|
|
21
|
-
label: 'Error Message',
|
|
22
|
-
type: FieldType.String,
|
|
23
|
-
description: 'Error message to throw',
|
|
24
|
-
validation: { required: true },
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
key: 'code',
|
|
28
|
-
label: 'Error Code',
|
|
29
|
-
type: FieldType.String,
|
|
30
|
-
description: 'Error code',
|
|
31
|
-
validation: { required: false },
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
},
|
|
35
|
-
outputSchema: {
|
|
36
|
-
type: 'void',
|
|
37
|
-
properties: [],
|
|
38
|
-
sampleOutput: null,
|
|
39
|
-
},
|
|
40
|
-
version: '1.0.0',
|
|
41
|
-
createdAt: '2025-01-01T00:00:00Z',
|
|
42
|
-
updatedAt: '2025-12-15T00:00:00Z',
|
|
43
|
-
createdBy: 'system',
|
|
44
|
-
isOfficial: true,
|
|
45
|
-
testable: true,
|
|
46
|
-
};
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Variables Action — Config Types
|
|
3
|
-
*
|
|
4
|
-
* Mirrors the engine's `VariableField` shape so the UI and engine
|
|
5
|
-
* agree on serialization with no translation layer.
|
|
6
|
-
*/
|
|
7
|
-
const RESERVED_KEYS = new Set(['_lineage', '_meta', '_redacted', '_error']);
|
|
8
|
-
const KEY_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
|
9
|
-
export const VariablesConfig = {
|
|
10
|
-
defaults: {
|
|
11
|
-
fields: [],
|
|
12
|
-
},
|
|
13
|
-
/**
|
|
14
|
-
* Pre-flight validation — runs at config save in the panel. Returns
|
|
15
|
-
* `valid: true` when every row passes; otherwise an array of human-
|
|
16
|
-
* readable error strings tagged with the offending key.
|
|
17
|
-
*/
|
|
18
|
-
validate(config) {
|
|
19
|
-
const errors = [];
|
|
20
|
-
const fields = config.fields ?? [];
|
|
21
|
-
const seen = new Set();
|
|
22
|
-
for (const f of fields) {
|
|
23
|
-
if (!f.key) {
|
|
24
|
-
errors.push('Each field needs a key.');
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
if (RESERVED_KEYS.has(f.key)) {
|
|
28
|
-
errors.push(`"${f.key}" is reserved — pick another key.`);
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
if (!KEY_PATTERN.test(f.key)) {
|
|
32
|
-
errors.push(`"${f.key}" is not a valid identifier (letters, digits, underscore; must not start with a digit).`);
|
|
33
|
-
continue;
|
|
34
|
-
}
|
|
35
|
-
if (seen.has(f.key)) {
|
|
36
|
-
errors.push(`Duplicate key "${f.key}".`);
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
seen.add(f.key);
|
|
40
|
-
if (!f.type)
|
|
41
|
-
errors.push(`"${f.key}" is missing a type.`);
|
|
42
|
-
if (!f.source)
|
|
43
|
-
errors.push(`"${f.key}" is missing a source.`);
|
|
44
|
-
}
|
|
45
|
-
return { valid: errors.length === 0, errors };
|
|
46
|
-
},
|
|
47
|
-
/**
|
|
48
|
-
* Compute the action's `_outputSchema` from a field list. Maps each
|
|
49
|
-
* field's declared type to a JSONSchema node so downstream Field
|
|
50
|
-
* Mappers see real fields without a preview run.
|
|
51
|
-
*/
|
|
52
|
-
computeOutputSchema(fields) {
|
|
53
|
-
const properties = {};
|
|
54
|
-
for (const f of fields) {
|
|
55
|
-
properties[f.key] = fieldToJsonSchema(f);
|
|
56
|
-
}
|
|
57
|
-
return { type: 'object', properties };
|
|
58
|
-
},
|
|
59
|
-
};
|
|
60
|
-
function fieldToJsonSchema(f) {
|
|
61
|
-
const node = { type: f.type };
|
|
62
|
-
if (f.description)
|
|
63
|
-
node.description = f.description;
|
|
64
|
-
if (f.validation?.enum)
|
|
65
|
-
node.enum = f.validation.enum;
|
|
66
|
-
// For arrays we don't know the item shape from the row alone (the
|
|
67
|
-
// user picks `array` but the source value may be string, number, or
|
|
68
|
-
// object). Leave items unset — Field Mapper synthesis can handle.
|
|
69
|
-
return node;
|
|
70
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Variables Action
|
|
3
|
-
*
|
|
4
|
-
* Emit one or more typed user-defined values as a step output. Five
|
|
5
|
-
* source kinds — literal, expression, prompt, secret, env — each
|
|
6
|
-
* captured via a row in the config panel. Replaces the legacy
|
|
7
|
-
* USER_INPUT pattern with first-class typed step output.
|
|
8
|
-
*
|
|
9
|
-
* See:
|
|
10
|
-
* (design notes live in the platform's own documentation)
|
|
11
|
-
*/
|
|
12
|
-
import { ActionCategory, ActionType, ActionStatus } from '../../types';
|
|
13
|
-
export const variablesDefinition = {
|
|
14
|
-
id: 'variables',
|
|
15
|
-
name: 'Variables',
|
|
16
|
-
description: 'Emit one or more typed user-defined values as a step output. Sources: literal, expression, prompt, secret, env.',
|
|
17
|
-
category: ActionCategory.Utility,
|
|
18
|
-
type: ActionType.Write,
|
|
19
|
-
tags: ['utility', 'variables', 'value', 'expression', 'built-in'],
|
|
20
|
-
status: ActionStatus.Stable,
|
|
21
|
-
icon: 'Parameter',
|
|
22
|
-
color: '#0F62FE',
|
|
23
|
-
// Custom panel handles all input editing — no generic field list.
|
|
24
|
-
inputSchema: { fields: [] },
|
|
25
|
-
// Output schema is computed at config-save time from the field rows
|
|
26
|
-
// (the panel emits `_outputSchema` into config). The static fallback
|
|
27
|
-
// here is just a placeholder so the picker shows *something* before
|
|
28
|
-
// the user defines fields.
|
|
29
|
-
outputSchema: {
|
|
30
|
-
type: 'object',
|
|
31
|
-
properties: [],
|
|
32
|
-
sampleOutput: {},
|
|
33
|
-
},
|
|
34
|
-
version: '1.0.0',
|
|
35
|
-
createdAt: '2026-05-02T00:00:00Z',
|
|
36
|
-
updatedAt: '2026-05-02T00:00:00Z',
|
|
37
|
-
createdBy: 'system',
|
|
38
|
-
isOfficial: true,
|
|
39
|
-
testable: false,
|
|
40
|
-
};
|
package/dist/catalog/workflow.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// ============================================
|
|
2
|
-
// workflow.d.ts - Workflow Canvas Type Definitions
|
|
3
|
-
// ============================================
|
|
4
|
-
// ============================================
|
|
5
|
-
// WORKFLOW NODE
|
|
6
|
-
// ============================================
|
|
7
|
-
export var NodeStatus;
|
|
8
|
-
(function (NodeStatus) {
|
|
9
|
-
NodeStatus["Idle"] = "idle";
|
|
10
|
-
NodeStatus["Running"] = "running";
|
|
11
|
-
NodeStatus["Success"] = "success";
|
|
12
|
-
NodeStatus["Error"] = "error";
|
|
13
|
-
NodeStatus["Warning"] = "warning";
|
|
14
|
-
NodeStatus["Disabled"] = "disabled";
|
|
15
|
-
})(NodeStatus || (NodeStatus = {}));
|
|
16
|
-
// ============================================
|
|
17
|
-
// WORKFLOW EDGE (CONNECTION)
|
|
18
|
-
// ============================================
|
|
19
|
-
export var EdgeType;
|
|
20
|
-
(function (EdgeType) {
|
|
21
|
-
EdgeType["Default"] = "default";
|
|
22
|
-
EdgeType["Conditional"] = "conditional";
|
|
23
|
-
EdgeType["Loop"] = "loop";
|
|
24
|
-
EdgeType["Error"] = "error";
|
|
25
|
-
})(EdgeType || (EdgeType = {}));
|
package/dist/ids.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ID Generator Utilities
|
|
3
|
-
*
|
|
4
|
-
* All randomness comes from the Web Crypto API (`crypto.getRandomValues`),
|
|
5
|
-
* which is available in every browser and as a Node global (≥18), so these
|
|
6
|
-
* helpers work both client- and server-side. Using crypto instead of
|
|
7
|
-
* `Math.random()` also clears the weak-PRNG security hotspot. These IDs are
|
|
8
|
-
* NOT secrets — crypto is used for collision resistance, not unpredictability.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Cryptographically-strong short token: `length` base36 chars (0-9a-z).
|
|
12
|
-
* Drop-in replacement for the old `Math.random().toString(36).slice(2, 2+n)`
|
|
13
|
-
* pattern — same character set and length, collision-resistant source.
|
|
14
|
-
*/
|
|
15
|
-
export function randomSuffix(length = 7) {
|
|
16
|
-
const bytes = new Uint8Array(length);
|
|
17
|
-
crypto.getRandomValues(bytes);
|
|
18
|
-
let out = '';
|
|
19
|
-
for (let i = 0; i < length; i++) {
|
|
20
|
-
out += (bytes[i] % 36).toString(36);
|
|
21
|
-
}
|
|
22
|
-
return out;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Generate a UUID v4 string using the Web Crypto API.
|
|
26
|
-
*/
|
|
27
|
-
export function generateUUIDv4() {
|
|
28
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
29
|
-
const r = crypto.getRandomValues(new Uint8Array(1))[0] % 16;
|
|
30
|
-
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
31
|
-
return v.toString(16);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Generate a workflow ID using UUID v4
|
|
36
|
-
*/
|
|
37
|
-
export function generateWorkflowId() {
|
|
38
|
-
return generateUUIDv4();
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Generate a step/node ID with prefix for clarity
|
|
42
|
-
*/
|
|
43
|
-
export function generateStepId() {
|
|
44
|
-
return `node_${Date.now()}_${randomSuffix(7)}`;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Generate an edge/connection ID with prefix for clarity
|
|
48
|
-
*/
|
|
49
|
-
export function generateEdgeId(sourceId, targetId) {
|
|
50
|
-
// Random suffix (same pattern as generateStepId) guarantees uniqueness even for
|
|
51
|
-
// two calls in the same millisecond with identical source/target.
|
|
52
|
-
return `edge_${sourceId}_${targetId}_${Date.now()}_${randomSuffix(7)}`;
|
|
53
|
-
}
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Node Config Status Utility
|
|
3
|
-
*
|
|
4
|
-
* Determines the status indicator for a workflow node based on
|
|
5
|
-
* how completely its configuration has been filled out relative
|
|
6
|
-
* to the action definition's input schema.
|
|
7
|
-
*
|
|
8
|
-
* Handles:
|
|
9
|
-
* - Nested config keys (e.g., "visualConfig.tables" → config.visualConfig.tables)
|
|
10
|
-
* - Conditional required fields (only enforced when their condition is met)
|
|
11
|
-
* - Default values (count as filled if present)
|
|
12
|
-
*/
|
|
13
|
-
import { getActionById } from '../catalog/index';
|
|
14
|
-
/**
|
|
15
|
-
* Action IDs whose nodes should not display a config status indicator.
|
|
16
|
-
*/
|
|
17
|
-
const HIDDEN_STATUS_ACTIONS = new Set(['console_log']);
|
|
18
|
-
/**
|
|
19
|
-
* Check if a config value is considered "filled" (non-empty).
|
|
20
|
-
*/
|
|
21
|
-
function isFieldFilled(value) {
|
|
22
|
-
if (value === undefined || value === null)
|
|
23
|
-
return false;
|
|
24
|
-
if (typeof value === 'string')
|
|
25
|
-
return value.trim().length > 0;
|
|
26
|
-
if (typeof value === 'number')
|
|
27
|
-
return true;
|
|
28
|
-
if (typeof value === 'boolean')
|
|
29
|
-
return true;
|
|
30
|
-
if (Array.isArray(value))
|
|
31
|
-
return value.length > 0;
|
|
32
|
-
if (typeof value === 'object')
|
|
33
|
-
return Object.keys(value).length > 0;
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Some actions persist part of their required configuration out-of-band rather
|
|
38
|
-
* than in `node.config`. The Connector Trigger is the canonical case: its
|
|
39
|
-
* watched entity/operation events are registered in the backend webhook
|
|
40
|
-
* subscription store (keyed by flow + connector), and the node config only
|
|
41
|
-
* carries a `subscribed` / `eventCount` summary of that subscription. For such
|
|
42
|
-
* fields, that summary — not a literal `config.<key>` value — is the source of
|
|
43
|
-
* truth for whether the field is configured.
|
|
44
|
-
*
|
|
45
|
-
* Returns true when the given required field should be treated as satisfied by
|
|
46
|
-
* an out-of-band signal, so it is not falsely reported as missing. Removing a
|
|
47
|
-
* subscription resets the summary (eventCount → 0), so an unconfigured trigger
|
|
48
|
-
* still fails validation as expected.
|
|
49
|
-
*/
|
|
50
|
-
function isSatisfiedOutOfBand(actionId, fieldKey, config) {
|
|
51
|
-
if (actionId === 'connector_trigger' && fieldKey === 'events') {
|
|
52
|
-
return Number(config.eventCount ?? 0) > 0;
|
|
53
|
-
}
|
|
54
|
-
// Messaging actions: the body can be plain text OR Block Kit, and the config
|
|
55
|
-
// panel stores the text under `text` while the action definition names the
|
|
56
|
-
// field `message` (its legacy alias). Without this, a Slack step that sends
|
|
57
|
-
// perfectly well reported "Missing required settings: message" — and since
|
|
58
|
-
// Flow Doctor errors BLOCK ACTIVATION, such a flow could run manually but
|
|
59
|
-
// never be scheduled.
|
|
60
|
-
if (MESSAGE_BODY_ACTIONS.has(actionId) && (fieldKey === 'message' || fieldKey === 'text')) {
|
|
61
|
-
const text = config.text ?? config.message;
|
|
62
|
-
if (typeof text === 'string' && text.trim().length > 0)
|
|
63
|
-
return true;
|
|
64
|
-
return Array.isArray(config.blocks) && config.blocks.length > 0;
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
/** Actions whose body may be text or blocks — see `isSatisfiedOutOfBand`. */
|
|
69
|
-
const MESSAGE_BODY_ACTIONS = new Set([
|
|
70
|
-
'slack_message',
|
|
71
|
-
'teams_message',
|
|
72
|
-
'google_chat',
|
|
73
|
-
]);
|
|
74
|
-
/**
|
|
75
|
-
* Resolve a nested key path (e.g., "visualConfig.tables") from a config object.
|
|
76
|
-
*/
|
|
77
|
-
function getNestedValue(config, keyPath) {
|
|
78
|
-
const parts = keyPath.split('.');
|
|
79
|
-
let current = config;
|
|
80
|
-
for (const part of parts) {
|
|
81
|
-
if (current === null || current === undefined || typeof current !== 'object') {
|
|
82
|
-
return undefined;
|
|
83
|
-
}
|
|
84
|
-
current = current[part];
|
|
85
|
-
}
|
|
86
|
-
return current;
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Evaluate whether a conditional field should be active (visible/required)
|
|
90
|
-
* based on the current config values.
|
|
91
|
-
*
|
|
92
|
-
* A field with conditionals is only required when at least one "show" or
|
|
93
|
-
* "require" condition is satisfied.
|
|
94
|
-
*/
|
|
95
|
-
function isFieldActive(field, config) {
|
|
96
|
-
if (!field.conditional || field.conditional.length === 0) {
|
|
97
|
-
return true;
|
|
98
|
-
}
|
|
99
|
-
// Check if any "show" or "require" condition is met
|
|
100
|
-
return field.conditional.some((cond) => {
|
|
101
|
-
if (cond.action !== 'show' && cond.action !== 'require') {
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
104
|
-
const fieldValue = getNestedValue(config, cond.field);
|
|
105
|
-
switch (cond.operator) {
|
|
106
|
-
case '==': return fieldValue === cond.value;
|
|
107
|
-
case '!=': return fieldValue !== cond.value;
|
|
108
|
-
case '>': return fieldValue > cond.value;
|
|
109
|
-
case '<': return fieldValue < cond.value;
|
|
110
|
-
case '>=': return fieldValue >= cond.value;
|
|
111
|
-
case '<=': return fieldValue <= cond.value;
|
|
112
|
-
case 'in': return Array.isArray(cond.value) && cond.value.includes(fieldValue);
|
|
113
|
-
case 'not_in': return Array.isArray(cond.value) && !cond.value.includes(fieldValue);
|
|
114
|
-
case 'contains':
|
|
115
|
-
return typeof fieldValue === 'string' && fieldValue.includes(cond.value);
|
|
116
|
-
default: return false;
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Determine the config completeness status of a workflow node.
|
|
122
|
-
*
|
|
123
|
-
* Status logic:
|
|
124
|
-
* - "valid" → All active required fields are filled (or no required fields exist)
|
|
125
|
-
* - "warning" → Some active required fields are missing, but at least one field has data
|
|
126
|
-
* - "error" → Has active required fields and none are filled, config is empty
|
|
127
|
-
* - "unconfigured" → Action definition not found (unknown action type)
|
|
128
|
-
*/
|
|
129
|
-
export function getNodeConfigStatus(node) {
|
|
130
|
-
// Some actions should never show a status indicator
|
|
131
|
-
if (HIDDEN_STATUS_ACTIONS.has(node.actionDefinitionId)) {
|
|
132
|
-
return {
|
|
133
|
-
status: 'hidden',
|
|
134
|
-
requiredTotal: 0,
|
|
135
|
-
requiredFilled: 0,
|
|
136
|
-
optionalTotal: 0,
|
|
137
|
-
optionalFilled: 0,
|
|
138
|
-
missingRequired: [],
|
|
139
|
-
filledOptional: [],
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
const definition = getActionById(node.actionDefinitionId);
|
|
143
|
-
if (!definition) {
|
|
144
|
-
return {
|
|
145
|
-
status: 'unconfigured',
|
|
146
|
-
requiredTotal: 0,
|
|
147
|
-
requiredFilled: 0,
|
|
148
|
-
optionalTotal: 0,
|
|
149
|
-
optionalFilled: 0,
|
|
150
|
-
missingRequired: [],
|
|
151
|
-
filledOptional: [],
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
const fields = definition.inputSchema?.fields ?? [];
|
|
155
|
-
const config = node.config ?? {};
|
|
156
|
-
// Filter to only active (visible) fields based on conditionals
|
|
157
|
-
const activeFields = fields.filter(f => !f.hidden && isFieldActive(f, config));
|
|
158
|
-
const requiredFields = activeFields.filter(f => f.validation?.required);
|
|
159
|
-
const optionalFields = activeFields.filter(f => !f.validation?.required);
|
|
160
|
-
const missingRequired = [];
|
|
161
|
-
let requiredFilled = 0;
|
|
162
|
-
for (const field of requiredFields) {
|
|
163
|
-
const value = getNestedValue(config, field.key);
|
|
164
|
-
if (isFieldFilled(value)) {
|
|
165
|
-
requiredFilled++;
|
|
166
|
-
}
|
|
167
|
-
else if (isFieldFilled(field.defaultValue)) {
|
|
168
|
-
// Field has a defaultValue — count as filled
|
|
169
|
-
requiredFilled++;
|
|
170
|
-
}
|
|
171
|
-
else if (isSatisfiedOutOfBand(node.actionDefinitionId, field.key, config)) {
|
|
172
|
-
// Field is configured out-of-band (e.g. Connector Trigger events live in
|
|
173
|
-
// the backend subscription store, mirrored here as an eventCount summary)
|
|
174
|
-
requiredFilled++;
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
missingRequired.push(field.key);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
const filledOptional = [];
|
|
181
|
-
let optionalFilled = 0;
|
|
182
|
-
for (const field of optionalFields) {
|
|
183
|
-
const value = getNestedValue(config, field.key);
|
|
184
|
-
if (isFieldFilled(value)) {
|
|
185
|
-
optionalFilled++;
|
|
186
|
-
filledOptional.push(field.key);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
const requiredTotal = requiredFields.length;
|
|
190
|
-
const optionalTotal = optionalFields.length;
|
|
191
|
-
let status;
|
|
192
|
-
if (requiredTotal === 0) {
|
|
193
|
-
// No required fields → always valid (e.g., manual_trigger)
|
|
194
|
-
status = 'valid';
|
|
195
|
-
}
|
|
196
|
-
else if (missingRequired.length === 0) {
|
|
197
|
-
// All required fields filled
|
|
198
|
-
status = 'valid';
|
|
199
|
-
}
|
|
200
|
-
else if (requiredFilled > 0 || optionalFilled > 0) {
|
|
201
|
-
// Partially configured — some required fields still missing
|
|
202
|
-
status = 'warning';
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
// Nothing configured at all but has required fields
|
|
206
|
-
status = 'error';
|
|
207
|
-
}
|
|
208
|
-
return {
|
|
209
|
-
status,
|
|
210
|
-
requiredTotal,
|
|
211
|
-
requiredFilled,
|
|
212
|
-
optionalTotal,
|
|
213
|
-
optionalFilled,
|
|
214
|
-
missingRequired,
|
|
215
|
-
filledOptional,
|
|
216
|
-
};
|
|
217
|
-
}
|