-
Notifications
You must be signed in to change notification settings - Fork 3.5k
feat(trigger): add ServiceNow webhook triggers #4077
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
baa3dcf
feat(trigger): add ServiceNow webhook triggers
waleedlatif1 bb3aee3
fix(trigger): add webhook secret field and remove non-TSDoc comment
waleedlatif1 77712e6
feat(trigger): add ServiceNow provider handler with event matching
waleedlatif1 952cc69
lint
waleedlatif1 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import { ServiceNowIcon } from '@/components/icons' | ||
| import { buildTriggerSubBlocks } from '@/triggers' | ||
| import { | ||
| buildChangeRequestOutputs, | ||
| buildServiceNowExtraFields, | ||
| servicenowSetupInstructions, | ||
| servicenowTriggerOptions, | ||
| } from '@/triggers/servicenow/utils' | ||
| import type { TriggerConfig } from '@/triggers/types' | ||
|
|
||
| /** | ||
| * ServiceNow Change Request Created Trigger | ||
| */ | ||
| export const servicenowChangeRequestCreatedTrigger: TriggerConfig = { | ||
| id: 'servicenow_change_request_created', | ||
| name: 'ServiceNow Change Request Created', | ||
| provider: 'servicenow', | ||
| description: 'Trigger workflow when a new change request is created in ServiceNow', | ||
| version: '1.0.0', | ||
| icon: ServiceNowIcon, | ||
|
|
||
| subBlocks: buildTriggerSubBlocks({ | ||
| triggerId: 'servicenow_change_request_created', | ||
| triggerOptions: servicenowTriggerOptions, | ||
| setupInstructions: servicenowSetupInstructions('Insert (record creation)'), | ||
| extraFields: buildServiceNowExtraFields('servicenow_change_request_created'), | ||
| }), | ||
|
|
||
| outputs: buildChangeRequestOutputs(), | ||
|
|
||
| webhook: { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import { ServiceNowIcon } from '@/components/icons' | ||
| import { buildTriggerSubBlocks } from '@/triggers' | ||
| import { | ||
| buildChangeRequestOutputs, | ||
| buildServiceNowExtraFields, | ||
| servicenowSetupInstructions, | ||
| servicenowTriggerOptions, | ||
| } from '@/triggers/servicenow/utils' | ||
| import type { TriggerConfig } from '@/triggers/types' | ||
|
|
||
| /** | ||
| * ServiceNow Change Request Updated Trigger | ||
| */ | ||
| export const servicenowChangeRequestUpdatedTrigger: TriggerConfig = { | ||
| id: 'servicenow_change_request_updated', | ||
| name: 'ServiceNow Change Request Updated', | ||
| provider: 'servicenow', | ||
| description: 'Trigger workflow when a change request is updated in ServiceNow', | ||
| version: '1.0.0', | ||
| icon: ServiceNowIcon, | ||
|
|
||
| subBlocks: buildTriggerSubBlocks({ | ||
| triggerId: 'servicenow_change_request_updated', | ||
| triggerOptions: servicenowTriggerOptions, | ||
| setupInstructions: servicenowSetupInstructions('Update (record modification)'), | ||
| extraFields: buildServiceNowExtraFields('servicenow_change_request_updated'), | ||
| }), | ||
|
|
||
| outputs: buildChangeRequestOutputs(), | ||
|
|
||
| webhook: { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import { ServiceNowIcon } from '@/components/icons' | ||
| import { buildTriggerSubBlocks } from '@/triggers' | ||
| import { | ||
| buildIncidentOutputs, | ||
| buildServiceNowExtraFields, | ||
| servicenowSetupInstructions, | ||
| servicenowTriggerOptions, | ||
| } from '@/triggers/servicenow/utils' | ||
| import type { TriggerConfig } from '@/triggers/types' | ||
|
|
||
| /** | ||
| * ServiceNow Incident Created Trigger | ||
| * | ||
| * Primary trigger — includes the dropdown for selecting trigger type. | ||
| */ | ||
| export const servicenowIncidentCreatedTrigger: TriggerConfig = { | ||
| id: 'servicenow_incident_created', | ||
| name: 'ServiceNow Incident Created', | ||
| provider: 'servicenow', | ||
| description: 'Trigger workflow when a new incident is created in ServiceNow', | ||
| version: '1.0.0', | ||
| icon: ServiceNowIcon, | ||
|
|
||
| subBlocks: buildTriggerSubBlocks({ | ||
| triggerId: 'servicenow_incident_created', | ||
| triggerOptions: servicenowTriggerOptions, | ||
| includeDropdown: true, | ||
| setupInstructions: servicenowSetupInstructions('Insert (record creation)'), | ||
| extraFields: buildServiceNowExtraFields('servicenow_incident_created'), | ||
| }), | ||
|
|
||
| outputs: buildIncidentOutputs(), | ||
|
|
||
| webhook: { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import { ServiceNowIcon } from '@/components/icons' | ||
| import { buildTriggerSubBlocks } from '@/triggers' | ||
| import { | ||
| buildIncidentOutputs, | ||
| buildServiceNowExtraFields, | ||
| servicenowSetupInstructions, | ||
| servicenowTriggerOptions, | ||
| } from '@/triggers/servicenow/utils' | ||
| import type { TriggerConfig } from '@/triggers/types' | ||
|
|
||
| /** | ||
| * ServiceNow Incident Updated Trigger | ||
| */ | ||
| export const servicenowIncidentUpdatedTrigger: TriggerConfig = { | ||
| id: 'servicenow_incident_updated', | ||
| name: 'ServiceNow Incident Updated', | ||
| provider: 'servicenow', | ||
| description: 'Trigger workflow when an incident is updated in ServiceNow', | ||
| version: '1.0.0', | ||
| icon: ServiceNowIcon, | ||
|
|
||
| subBlocks: buildTriggerSubBlocks({ | ||
| triggerId: 'servicenow_incident_updated', | ||
| triggerOptions: servicenowTriggerOptions, | ||
| setupInstructions: servicenowSetupInstructions('Update (record modification)'), | ||
| extraFields: buildServiceNowExtraFields('servicenow_incident_updated'), | ||
| }), | ||
|
|
||
| outputs: buildIncidentOutputs(), | ||
|
|
||
| webhook: { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| export { servicenowChangeRequestCreatedTrigger } from './change_request_created' | ||
| export { servicenowChangeRequestUpdatedTrigger } from './change_request_updated' | ||
| export { servicenowIncidentCreatedTrigger } from './incident_created' | ||
| export { servicenowIncidentUpdatedTrigger } from './incident_updated' | ||
| export { servicenowWebhookTrigger } from './webhook' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| import type { SubBlockConfig } from '@/blocks/types' | ||
| import type { TriggerOutput } from '@/triggers/types' | ||
|
|
||
| /** | ||
| * Shared trigger dropdown options for all ServiceNow triggers | ||
| */ | ||
| export const servicenowTriggerOptions = [ | ||
| { label: 'Incident Created', id: 'servicenow_incident_created' }, | ||
| { label: 'Incident Updated', id: 'servicenow_incident_updated' }, | ||
| { label: 'Change Request Created', id: 'servicenow_change_request_created' }, | ||
| { label: 'Change Request Updated', id: 'servicenow_change_request_updated' }, | ||
| { label: 'Generic Webhook (All Events)', id: 'servicenow_webhook' }, | ||
| ] | ||
|
|
||
| /** | ||
| * Generates setup instructions for ServiceNow webhooks. | ||
| * ServiceNow uses Business Rules with RESTMessageV2 for outbound webhooks. | ||
| */ | ||
| export function servicenowSetupInstructions(eventType: string): string { | ||
| const instructions = [ | ||
| '<strong>Note:</strong> You need admin or developer permissions in your ServiceNow instance to create Business Rules.', | ||
| 'Navigate to <strong>System Definition > Business Rules</strong> and create a new Business Rule.', | ||
| `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>.`, | ||
| 'Check the <strong>Advanced</strong> checkbox to enable the script editor.', | ||
| `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>`, | ||
| 'Activate the Business Rule and click "Save" above to activate your trigger.', | ||
| ] | ||
|
|
||
| return instructions | ||
| .map( | ||
| (instruction, index) => | ||
| `<div class="mb-3">${index === 0 ? instruction : `<strong>${index}.</strong> ${instruction}`}</div>` | ||
| ) | ||
| .join('') | ||
| } | ||
|
|
||
| /** | ||
| * Extra fields for ServiceNow triggers (optional table filter) | ||
| */ | ||
| export function buildServiceNowExtraFields(triggerId: string): SubBlockConfig[] { | ||
| return [ | ||
| { | ||
| id: 'tableName', | ||
| title: 'Table Name (Optional)', | ||
| type: 'short-input', | ||
| placeholder: 'e.g., incident, change_request', | ||
| description: 'Optionally filter to a specific ServiceNow table', | ||
| mode: 'trigger', | ||
| condition: { field: 'selectedTriggerId', value: triggerId }, | ||
| }, | ||
|
waleedlatif1 marked this conversation as resolved.
|
||
| ] | ||
| } | ||
|
waleedlatif1 marked this conversation as resolved.
waleedlatif1 marked this conversation as resolved.
|
||
|
|
||
| /** | ||
| * Common record fields shared across ServiceNow trigger outputs | ||
| */ | ||
| function buildRecordOutputs(): Record<string, TriggerOutput> { | ||
| return { | ||
| sysId: { type: 'string', description: 'Unique system ID of the record' }, | ||
| number: { type: 'string', description: 'Record number (e.g., INC0010001, CHG0010001)' }, | ||
| tableName: { type: 'string', description: 'ServiceNow table name' }, | ||
| shortDescription: { type: 'string', description: 'Short description of the record' }, | ||
| description: { type: 'string', description: 'Full description of the record' }, | ||
| state: { type: 'string', description: 'Current state of the record' }, | ||
| priority: { | ||
| type: 'string', | ||
| description: 'Priority level (1=Critical, 2=High, 3=Moderate, 4=Low, 5=Planning)', | ||
| }, | ||
| assignedTo: { type: 'string', description: 'User assigned to this record' }, | ||
| assignmentGroup: { type: 'string', description: 'Group assigned to this record' }, | ||
| createdBy: { type: 'string', description: 'User who created the record' }, | ||
| createdOn: { type: 'string', description: 'When the record was created (ISO 8601)' }, | ||
| updatedBy: { type: 'string', description: 'User who last updated the record' }, | ||
| updatedOn: { type: 'string', description: 'When the record was last updated (ISO 8601)' }, | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Outputs for incident triggers | ||
| */ | ||
| export function buildIncidentOutputs(): Record<string, TriggerOutput> { | ||
| return { | ||
| ...buildRecordOutputs(), | ||
| urgency: { type: 'string', description: 'Urgency level (1=High, 2=Medium, 3=Low)' }, | ||
| impact: { type: 'string', description: 'Impact level (1=High, 2=Medium, 3=Low)' }, | ||
| category: { type: 'string', description: 'Incident category' }, | ||
| subcategory: { type: 'string', description: 'Incident subcategory' }, | ||
| caller: { type: 'string', description: 'Caller/requester of the incident' }, | ||
| resolvedBy: { type: 'string', description: 'User who resolved the incident' }, | ||
| resolvedAt: { type: 'string', description: 'When the incident was resolved' }, | ||
| closeNotes: { type: 'string', description: 'Notes added when the incident was closed' }, | ||
| record: { type: 'json', description: 'Full incident record data' }, | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Outputs for change request triggers | ||
| */ | ||
| export function buildChangeRequestOutputs(): Record<string, TriggerOutput> { | ||
| return { | ||
| ...buildRecordOutputs(), | ||
| type: { type: 'string', description: 'Change type (Normal, Standard, Emergency)' }, | ||
| risk: { type: 'string', description: 'Risk level of the change' }, | ||
| impact: { type: 'string', description: 'Impact level of the change' }, | ||
| approval: { type: 'string', description: 'Approval status' }, | ||
| startDate: { type: 'string', description: 'Planned start date' }, | ||
| endDate: { type: 'string', description: 'Planned end date' }, | ||
| category: { type: 'string', description: 'Change category' }, | ||
| record: { type: 'json', description: 'Full change request record data' }, | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Outputs for the generic webhook trigger (all events) | ||
| */ | ||
| export function buildServiceNowWebhookOutputs(): Record<string, TriggerOutput> { | ||
| return { | ||
| ...buildRecordOutputs(), | ||
| eventType: { | ||
| type: 'string', | ||
| description: 'The type of event that triggered this workflow (e.g., insert, update, delete)', | ||
| }, | ||
| category: { type: 'string', description: 'Record category' }, | ||
| record: { type: 'json', description: 'Full record data from the webhook payload' }, | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import { ServiceNowIcon } from '@/components/icons' | ||
| import { buildTriggerSubBlocks } from '@/triggers' | ||
| import { | ||
| buildServiceNowExtraFields, | ||
| buildServiceNowWebhookOutputs, | ||
| servicenowSetupInstructions, | ||
| servicenowTriggerOptions, | ||
| } from '@/triggers/servicenow/utils' | ||
| import type { TriggerConfig } from '@/triggers/types' | ||
|
|
||
| /** | ||
| * Generic ServiceNow Webhook Trigger | ||
| * Captures all ServiceNow webhook events | ||
| */ | ||
| export const servicenowWebhookTrigger: TriggerConfig = { | ||
| id: 'servicenow_webhook', | ||
| name: 'ServiceNow Webhook (All Events)', | ||
| provider: 'servicenow', | ||
| description: 'Trigger workflow on any ServiceNow webhook event', | ||
| version: '1.0.0', | ||
| icon: ServiceNowIcon, | ||
|
|
||
| subBlocks: buildTriggerSubBlocks({ | ||
| triggerId: 'servicenow_webhook', | ||
| triggerOptions: servicenowTriggerOptions, | ||
| setupInstructions: servicenowSetupInstructions('Insert, Update, or Delete'), | ||
| extraFields: buildServiceNowExtraFields('servicenow_webhook'), | ||
| }), | ||
|
|
||
| outputs: buildServiceNowWebhookOutputs(), | ||
|
|
||
| webhook: { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| }, | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.