|
| 1 | +import type { SubBlockConfig } from '@/blocks/types' |
| 2 | +import type { TriggerOutput } from '@/triggers/types' |
| 3 | + |
| 4 | +/** |
| 5 | + * Shared trigger dropdown options for all ServiceNow triggers |
| 6 | + */ |
| 7 | +export const servicenowTriggerOptions = [ |
| 8 | + { label: 'Incident Created', id: 'servicenow_incident_created' }, |
| 9 | + { label: 'Incident Updated', id: 'servicenow_incident_updated' }, |
| 10 | + { label: 'Change Request Created', id: 'servicenow_change_request_created' }, |
| 11 | + { label: 'Change Request Updated', id: 'servicenow_change_request_updated' }, |
| 12 | + { label: 'Generic Webhook (All Events)', id: 'servicenow_webhook' }, |
| 13 | +] |
| 14 | + |
| 15 | +/** |
| 16 | + * Generates setup instructions for ServiceNow webhooks. |
| 17 | + * ServiceNow uses Business Rules with RESTMessageV2 for outbound webhooks. |
| 18 | + */ |
| 19 | +export function servicenowSetupInstructions(eventType: string): string { |
| 20 | + const instructions = [ |
| 21 | + '<strong>Note:</strong> You need admin or developer permissions in your ServiceNow instance to create Business Rules.', |
| 22 | + 'Navigate to <strong>System Definition > Business Rules</strong> and create a new Business Rule.', |
| 23 | + `Set the table (e.g., <strong>incident</strong>, <strong>change_request</strong>), set <strong>When</strong> to <strong>after</strong>, and check <strong>${eventType}</strong>.`, |
| 24 | + 'Check the <strong>Advanced</strong> checkbox to enable the script editor.', |
| 25 | + `In the script, use <strong>RESTMessageV2</strong> to POST the record data as JSON to the <strong>Webhook URL</strong> above. Example:<br/><code style="font-size: 0.85em; display: block; margin-top: 4px; white-space: pre-wrap;">var r = new sn_ws.RESTMessageV2();\nr.setEndpoint("<webhook_url>");\nr.setHttpMethod("POST");\nr.setRequestHeader("Content-Type", "application/json");\nr.setRequestBody(JSON.stringify({\n sysId: current.sys_id.toString(),\n number: current.number.toString(),\n shortDescription: current.short_description.toString(),\n state: current.state.toString(),\n priority: current.priority.toString()\n}));\nr.execute();</code>`, |
| 26 | + 'Activate the Business Rule and click "Save" above to activate your trigger.', |
| 27 | + ] |
| 28 | + |
| 29 | + return instructions |
| 30 | + .map( |
| 31 | + (instruction, index) => |
| 32 | + `<div class="mb-3">${index === 0 ? instruction : `<strong>${index}.</strong> ${instruction}`}</div>` |
| 33 | + ) |
| 34 | + .join('') |
| 35 | +} |
| 36 | + |
| 37 | +/** |
| 38 | + * Extra fields for ServiceNow triggers (optional table filter) |
| 39 | + */ |
| 40 | +export function buildServiceNowExtraFields(triggerId: string): SubBlockConfig[] { |
| 41 | + return [ |
| 42 | + { |
| 43 | + id: 'tableName', |
| 44 | + title: 'Table Name (Optional)', |
| 45 | + type: 'short-input', |
| 46 | + placeholder: 'e.g., incident, change_request', |
| 47 | + description: 'Optionally filter to a specific ServiceNow table', |
| 48 | + mode: 'trigger', |
| 49 | + condition: { field: 'selectedTriggerId', value: triggerId }, |
| 50 | + }, |
| 51 | + ] |
| 52 | +} |
| 53 | + |
| 54 | +/** |
| 55 | + * Common record fields shared across ServiceNow trigger outputs |
| 56 | + */ |
| 57 | +function buildRecordOutputs(): Record<string, TriggerOutput> { |
| 58 | + return { |
| 59 | + sysId: { type: 'string', description: 'Unique system ID of the record' }, |
| 60 | + number: { type: 'string', description: 'Record number (e.g., INC0010001, CHG0010001)' }, |
| 61 | + tableName: { type: 'string', description: 'ServiceNow table name' }, |
| 62 | + shortDescription: { type: 'string', description: 'Short description of the record' }, |
| 63 | + description: { type: 'string', description: 'Full description of the record' }, |
| 64 | + state: { type: 'string', description: 'Current state of the record' }, |
| 65 | + priority: { |
| 66 | + type: 'string', |
| 67 | + description: 'Priority level (1=Critical, 2=High, 3=Moderate, 4=Low, 5=Planning)', |
| 68 | + }, |
| 69 | + assignedTo: { type: 'string', description: 'User assigned to this record' }, |
| 70 | + assignmentGroup: { type: 'string', description: 'Group assigned to this record' }, |
| 71 | + createdBy: { type: 'string', description: 'User who created the record' }, |
| 72 | + createdOn: { type: 'string', description: 'When the record was created (ISO 8601)' }, |
| 73 | + updatedBy: { type: 'string', description: 'User who last updated the record' }, |
| 74 | + updatedOn: { type: 'string', description: 'When the record was last updated (ISO 8601)' }, |
| 75 | + } |
| 76 | +} |
| 77 | + |
| 78 | +/** |
| 79 | + * Outputs for incident triggers |
| 80 | + */ |
| 81 | +export function buildIncidentOutputs(): Record<string, TriggerOutput> { |
| 82 | + return { |
| 83 | + ...buildRecordOutputs(), |
| 84 | + urgency: { type: 'string', description: 'Urgency level (1=High, 2=Medium, 3=Low)' }, |
| 85 | + impact: { type: 'string', description: 'Impact level (1=High, 2=Medium, 3=Low)' }, |
| 86 | + category: { type: 'string', description: 'Incident category' }, |
| 87 | + subcategory: { type: 'string', description: 'Incident subcategory' }, |
| 88 | + caller: { type: 'string', description: 'Caller/requester of the incident' }, |
| 89 | + resolvedBy: { type: 'string', description: 'User who resolved the incident' }, |
| 90 | + resolvedAt: { type: 'string', description: 'When the incident was resolved' }, |
| 91 | + closeNotes: { type: 'string', description: 'Notes added when the incident was closed' }, |
| 92 | + record: { type: 'json', description: 'Full incident record data' }, |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +/** |
| 97 | + * Outputs for change request triggers |
| 98 | + */ |
| 99 | +export function buildChangeRequestOutputs(): Record<string, TriggerOutput> { |
| 100 | + return { |
| 101 | + ...buildRecordOutputs(), |
| 102 | + type: { type: 'string', description: 'Change type (Normal, Standard, Emergency)' }, |
| 103 | + risk: { type: 'string', description: 'Risk level of the change' }, |
| 104 | + impact: { type: 'string', description: 'Impact level of the change' }, |
| 105 | + approval: { type: 'string', description: 'Approval status' }, |
| 106 | + startDate: { type: 'string', description: 'Planned start date' }, |
| 107 | + endDate: { type: 'string', description: 'Planned end date' }, |
| 108 | + category: { type: 'string', description: 'Change category' }, |
| 109 | + record: { type: 'json', description: 'Full change request record data' }, |
| 110 | + } |
| 111 | +} |
| 112 | + |
| 113 | +/** |
| 114 | + * Outputs for the generic webhook trigger (all events) |
| 115 | + */ |
| 116 | +export function buildServiceNowWebhookOutputs(): Record<string, TriggerOutput> { |
| 117 | + return { |
| 118 | + ...buildRecordOutputs(), |
| 119 | + eventType: { |
| 120 | + type: 'string', |
| 121 | + description: 'The type of event that triggered this workflow (e.g., insert, update, delete)', |
| 122 | + }, |
| 123 | + category: { type: 'string', description: 'Record category' }, |
| 124 | + record: { type: 'json', description: 'Full record data from the webhook payload' }, |
| 125 | + } |
| 126 | +} |
0 commit comments