Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
17 changes: 17 additions & 0 deletions apps/sim/blocks/blocks/servicenow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ServiceNowIcon } from '@/components/icons'
import type { BlockConfig } from '@/blocks/types'
import { IntegrationType } from '@/blocks/types'
import type { ServiceNowResponse } from '@/tools/servicenow/types'
import { getTrigger } from '@/triggers'

export const ServiceNowBlock: BlockConfig<ServiceNowResponse> = {
type: 'servicenow',
Expand Down Expand Up @@ -215,6 +216,12 @@ Output: {"state": "2", "assigned_to": "john.doe", "work_notes": "Assigned and st
condition: { field: 'operation', value: 'servicenow_delete_record' },
required: true,
},
// Trigger SubBlocks
Comment thread
waleedlatif1 marked this conversation as resolved.
Outdated
...getTrigger('servicenow_incident_created').subBlocks,
...getTrigger('servicenow_incident_updated').subBlocks,
...getTrigger('servicenow_change_request_created').subBlocks,
...getTrigger('servicenow_change_request_updated').subBlocks,
...getTrigger('servicenow_webhook').subBlocks,
],
tools: {
access: [
Expand Down Expand Up @@ -262,4 +269,14 @@ Output: {"state": "2", "assigned_to": "john.doe", "work_notes": "Assigned and st
success: { type: 'boolean', description: 'Operation success status' },
metadata: { type: 'json', description: 'Operation metadata' },
},
triggers: {
enabled: true,
available: [
'servicenow_incident_created',
'servicenow_incident_updated',
'servicenow_change_request_created',
'servicenow_change_request_updated',
'servicenow_webhook',
],
},
}
12 changes: 12 additions & 0 deletions apps/sim/triggers/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,13 @@ import {
salesforceRecordUpdatedTrigger,
salesforceWebhookTrigger,
} from '@/triggers/salesforce'
import {
servicenowChangeRequestCreatedTrigger,
servicenowChangeRequestUpdatedTrigger,
servicenowIncidentCreatedTrigger,
servicenowIncidentUpdatedTrigger,
servicenowWebhookTrigger,
} from '@/triggers/servicenow'
import { slackWebhookTrigger } from '@/triggers/slack'
import { stripeWebhookTrigger } from '@/triggers/stripe'
import { telegramWebhookTrigger } from '@/triggers/telegram'
Expand Down Expand Up @@ -437,6 +444,11 @@ export const TRIGGER_REGISTRY: TriggerRegistry = {
salesforce_opportunity_stage_changed: salesforceOpportunityStageChangedTrigger,
salesforce_case_status_changed: salesforceCaseStatusChangedTrigger,
salesforce_webhook: salesforceWebhookTrigger,
servicenow_incident_created: servicenowIncidentCreatedTrigger,
servicenow_incident_updated: servicenowIncidentUpdatedTrigger,
servicenow_change_request_created: servicenowChangeRequestCreatedTrigger,
servicenow_change_request_updated: servicenowChangeRequestUpdatedTrigger,
servicenow_webhook: servicenowWebhookTrigger,
stripe_webhook: stripeWebhookTrigger,
telegram_webhook: telegramWebhookTrigger,
typeform_webhook: typeformWebhookTrigger,
Expand Down
37 changes: 37 additions & 0 deletions apps/sim/triggers/servicenow/change_request_created.ts
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',
},
},
}
37 changes: 37 additions & 0 deletions apps/sim/triggers/servicenow/change_request_updated.ts
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',
},
},
}
40 changes: 40 additions & 0 deletions apps/sim/triggers/servicenow/incident_created.ts
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',
},
},
}
37 changes: 37 additions & 0 deletions apps/sim/triggers/servicenow/incident_updated.ts
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',
},
},
}
5 changes: 5 additions & 0 deletions apps/sim/triggers/servicenow/index.ts
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'
126 changes: 126 additions & 0 deletions apps/sim/triggers/servicenow/utils.ts
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("&lt;webhook_url&gt;");\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 },
},
Comment thread
waleedlatif1 marked this conversation as resolved.
]
}
Comment thread
waleedlatif1 marked this conversation as resolved.
Comment thread
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' },
}
}
38 changes: 38 additions & 0 deletions apps/sim/triggers/servicenow/webhook.ts
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',
},
},
}
Loading