@pipedream/servicenow 0.6.0 → 0.8.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/README.md CHANGED
@@ -31,13 +31,14 @@ First, sign into your [ServiceNow Developer Portal](https://developer.servicenow
31
31
  ### Create the OAuth Validator app
32
32
 
33
33
  1. Copy the client ID and secret from the `Pipedream` app you created above.
34
- 2. Name this app `Pipedream OAuth Validator` and add the previously copied client ID and secret.
35
- 3. Set the grant type to **Authorization Code** and the **Token URL** to `oauth_token.do`.
36
- 4. Use the same **Redirect URL** as before.
34
+ 2. Go back to the **System OAuth > Application Registry > New** and select **Connect to an OAuth Provider (simplified)**
35
+ 3. Name this app `Pipedream OAuth Validator` and add the previously copied client ID and secret.
36
+ 4. Set the grant type to **Authorization Code** and the **Token URL** to `oauth_token.do`.
37
+ 5. Use the same **Redirect URL** as before.
37
38
 
38
- 5. Visit [Pipedream's account page](https://pipedream.com/accounts), and click **Click Here to Connect An App**. Search for **ServiceNow** and select it. Enter the client ID, client secret, and your instance name (e.g., `dev98042` from `https://dev98042.service-now.com/`).
39
+ 6. Visit [Pipedream's account page](https://pipedream.com/accounts), and click **Click Here to Connect An App**. Search for **ServiceNow** and select it. Enter the client ID, client secret, and your instance name (e.g., `dev98042` from `https://dev98042.service-now.com/`).
39
40
 
40
- 6. Press **Connect**. A new window will prompt you to login to your ServiceNow instance, authorizing Pipedream's access to the ServiceNow REST API.
41
+ 7. Press **Connect**. A new window will prompt you to login to your ServiceNow instance, authorizing Pipedream's access to the ServiceNow REST API.
41
42
 
42
43
  ## ServiceNow Authorization Reference
43
44
 
@@ -1,123 +1,77 @@
1
- // legacy_hash_id: a_k6irW7
2
- import { axios } from "@pipedream/platform";
1
+ import servicenow from "../../servicenow.app.mjs";
2
+ import { parseObject } from "../../common/utils.mjs";
3
3
 
4
4
  export default {
5
5
  key: "servicenow-create-table-record",
6
6
  name: "Create Table Record",
7
- description: "Inserts one record in the specified table.",
8
- version: "0.1.1",
7
+ description: "Inserts one record in the specified table. [See the documentation](https://www.servicenow.com/docs/bundle/zurich-api-reference/page/integrate/inbound-rest/concept/c_TableAPI.html#title_table-POST)",
8
+ version: "1.0.0",
9
+ annotations: {
10
+ destructiveHint: false,
11
+ openWorldHint: true,
12
+ readOnlyHint: false,
13
+ },
9
14
  type: "action",
10
15
  props: {
11
- servicenow: {
12
- type: "app",
13
- app: "servicenow",
14
- },
15
- table_name: {
16
- type: "string",
17
- description: "The name of the table where the record will be created.",
16
+ servicenow,
17
+ table: {
18
+ propDefinition: [
19
+ servicenow,
20
+ "table",
21
+ ],
18
22
  },
19
- table_record: {
23
+ recordData: {
24
+ label: "Record Data",
20
25
  type: "object",
21
- description: "The table record object. Use name-value pairs for each field of the record.",
26
+ description: "The data to create the record with, as key-value pairs (e.g. `{ \"name\": \"John Doe\", \"email\": \"john.doe@example.com\" }`)",
22
27
  },
23
- api_version: {
24
- type: "string",
25
- description: "API version number. Version numbers identify the endpoint version that a URI accesses. By specifying a version number in your URIs, you can ensure that future updates to the REST API do not negatively impact your integration. Use `lastest` to use the latest REST endpoint for your instance version.",
26
- optional: true,
27
- options: [
28
- "lastest",
29
- "v1",
30
- "v2",
28
+ responseDataFormat: {
29
+ propDefinition: [
30
+ servicenow,
31
+ "responseDataFormat",
31
32
  ],
32
33
  },
33
- request_format: {
34
- type: "string",
35
- description: "Format of REST request body",
36
- optional: true,
37
- options: [
38
- "application/json",
39
- "application/xml",
34
+ excludeReferenceLinks: {
35
+ propDefinition: [
36
+ servicenow,
37
+ "excludeReferenceLinks",
40
38
  ],
41
39
  },
42
- response_format: {
43
- type: "string",
44
- description: "Format of REST response body.",
45
- optional: true,
46
- options: [
47
- "application/json",
48
- "application/xml",
40
+ responseFields: {
41
+ propDefinition: [
42
+ servicenow,
43
+ "responseFields",
49
44
  ],
50
45
  },
51
- x_no_response_body: {
52
- type: "boolean",
53
- description: "By default, responses include body content detailing the modified record. Set this request header to true to suppress the response body.",
54
- optional: true,
55
- },
56
- sysparm_display_value: {
57
- type: "string",
58
- description: "Return field display values (true), actual values (false), or both (all) (default: false).",
59
- optional: true,
60
- options: [
61
- "true",
62
- "false",
63
- "all",
46
+ inputDisplayValue: {
47
+ propDefinition: [
48
+ servicenow,
49
+ "inputDisplayValue",
64
50
  ],
65
51
  },
66
- sysparm_exclude_reference_link: {
67
- type: "boolean",
68
- description: "Flag that indicates whether to exclude Table API links for reference fields.\n* `true`: Exclude Table API links for reference fields.\n* `false`: Include Table API links for reference fields.",
69
- optional: true,
70
- },
71
- sysparm_fields: {
72
- type: "string",
73
- description: "A comma-separated list of fields to return in the response.",
74
- optional: true,
75
- },
76
- sysparm_input_display_value: {
77
- type: "boolean",
78
- description: "Flag that indicates whether to set field values using the display value or the actual value.\n* `true`: Treats input values as display values and they are manipulated so they can be stored properly in the database.\n* `false`: Treats input values as actual values and stored them in the database without manipulation.",
79
- optional: true,
80
- },
81
- sysparm_view: {
82
- type: "string",
83
- description: "Render the response according to the specified UI view (overridden by sysparm_fields).",
84
- optional: true,
85
- options: [
86
- "desktop",
87
- "mobile",
88
- "both",
52
+ responseView: {
53
+ propDefinition: [
54
+ servicenow,
55
+ "responseView",
89
56
  ],
90
57
  },
91
58
  },
92
59
  async run({ $ }) {
93
- // See the API docs: https://docs.servicenow.com/bundle/paris-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html#table-POST
94
-
95
- if (!this.table_name || !this.table_record) {
96
- throw new Error("Must provide table_name, and table_record parameters.");
97
- }
98
-
99
- var apiVersion = "";
100
- if (this.api_version == "v1" || this.api_version == "v2") {
101
- apiVersion = this.api_version + "/";
102
- }
103
-
104
- return await axios($, {
105
- method: "post",
106
- url: `https://${this.servicenow.$auth.instance_name}.service-now.com/api/now/${apiVersion}table/${this.table_name}`,
107
- headers: {
108
- "Authorization": `Bearer ${this.servicenow.$auth.oauth_access_token}`,
109
- "Accept": this.request_format || "application/json",
110
- "Content-Type": this.response_format || "application/json",
111
- "X-no-response-body": this.x_no_response_body,
112
- },
60
+ const response = await this.servicenow.createTableRecord({
61
+ $,
62
+ table: this.table,
63
+ data: parseObject(this.recordData),
113
64
  params: {
114
- sysparm_display_value: this.sysparm_display_value,
115
- sysparm_exclude_reference_link: this.sysparm_exclude_reference_link,
116
- sysparm_fields: this.sysparm_fields,
117
- sysparm_input_display_value: this.sysparm_input_display_value,
118
- sysparm_view: this.sysparm_view,
65
+ sysparm_display_value: this.responseDataFormat,
66
+ sysparm_exclude_reference_link: this.excludeReferenceLinks,
67
+ sysparm_fields: this.responseFields?.join?.() || this.responseFields,
68
+ sysparm_input_display_value: this.inputDisplayValue,
69
+ sysparm_view: this.responseView,
119
70
  },
120
- data: this.table_record,
121
71
  });
72
+
73
+ $.export("$summary", `Successfully created record in table "${this.table}"`);
74
+
75
+ return response;
122
76
  },
123
77
  };
@@ -0,0 +1,53 @@
1
+ import servicenow from "../../servicenow.app.mjs";
2
+
3
+ export default {
4
+ key: "servicenow-delete-table-record",
5
+ name: "Delete Table Record",
6
+ description: "Deletes the specified record from a table. [See the documentation](https://www.servicenow.com/docs/bundle/zurich-api-reference/page/integrate/inbound-rest/concept/c_TableAPI.html#title_table-DELETE)",
7
+ version: "0.0.1",
8
+ annotations: {
9
+ destructiveHint: true,
10
+ openWorldHint: true,
11
+ readOnlyHint: false,
12
+ },
13
+ type: "action",
14
+ props: {
15
+ servicenow,
16
+ table: {
17
+ propDefinition: [
18
+ servicenow,
19
+ "table",
20
+ ],
21
+ },
22
+ recordId: {
23
+ propDefinition: [
24
+ servicenow,
25
+ "recordId",
26
+ ],
27
+ },
28
+ queryNoDomain: {
29
+ propDefinition: [
30
+ servicenow,
31
+ "queryNoDomain",
32
+ ],
33
+ },
34
+ },
35
+ async run({ $ }) {
36
+ await this.servicenow.deleteTableRecord({
37
+ $,
38
+ table: this.table,
39
+ recordId: this.recordId,
40
+ params: {
41
+ sysparm_query_no_domain: this.queryNoDomain,
42
+ },
43
+ });
44
+
45
+ $.export("$summary", `Successfully deleted record ${this.recordId} from table "${this.table}"`);
46
+
47
+ return {
48
+ success: true,
49
+ recordId: this.recordId,
50
+ table: this.table,
51
+ };
52
+ },
53
+ };
@@ -0,0 +1,133 @@
1
+ import { ConfigurationError } from "@pipedream/platform";
2
+ import servicenow from "../../servicenow.app.mjs";
3
+
4
+ export default {
5
+ key: "servicenow-get-record-counts-by-field",
6
+ name: "Get Record Counts by Field",
7
+ description: "Retrieves the count of records grouped by a specified field from a ServiceNow table. [See the documentation](https://www.servicenow.com/docs/bundle/zurich-api-reference/page/integrate/inbound-rest/concept/c_AggregateAPI.html#title_aggregate-GET-stats)",
8
+ version: "0.0.1",
9
+ annotations: {
10
+ destructiveHint: false,
11
+ openWorldHint: true,
12
+ readOnlyHint: true,
13
+ },
14
+ type: "action",
15
+ props: {
16
+ servicenow,
17
+ table: {
18
+ propDefinition: [
19
+ servicenow,
20
+ "table",
21
+ ],
22
+ },
23
+ groupByField: {
24
+ type: "string",
25
+ label: "Group By Field",
26
+ description: "The field to group records by (e.g., `priority`, `state`, `category`)",
27
+ },
28
+ count: {
29
+ type: "boolean",
30
+ label: "Count",
31
+ description: "If true, returns the number of records returned by the query",
32
+ optional: true,
33
+ default: true,
34
+ },
35
+ query: {
36
+ label: "Query",
37
+ type: "string",
38
+ description: "An [encoded query string](https://www.servicenow.com/docs/bundle/zurich-platform-user-interface/page/use/using-lists/concept/c_EncodedQueryStrings.html) to filter records before aggregation (e.g., `active=true^priority=1`)",
39
+ optional: true,
40
+ },
41
+ aggregateInfo: {
42
+ type: "alert",
43
+ alertType: "info",
44
+ content: "You must provide at least one Aggregate Field. [See the documentation](https://www.servicenow.com/docs/bundle/zurich-api-reference/page/integrate/inbound-rest/concept/c_AggregateAPI.html#title_aggregate-GET-stats) for more information.",
45
+ },
46
+ avgFields: {
47
+ type: "string[]",
48
+ label: "Average Aggregate Fields",
49
+ description: "Numeric fields to calculate averages for (e.g., `reassignment_count`, `reopen_count`)",
50
+ optional: true,
51
+ },
52
+ minFields: {
53
+ type: "string[]",
54
+ label: "Minimum Aggregate Fields",
55
+ description: "Numeric fields to find minimum values for",
56
+ optional: true,
57
+ },
58
+ maxFields: {
59
+ type: "string[]",
60
+ label: "Maximum Aggregate Fields",
61
+ description: "Numeric fields to find maximum values for",
62
+ optional: true,
63
+ },
64
+ sumFields: {
65
+ type: "string[]",
66
+ label: "Sum Aggregate Fields",
67
+ description: "Numeric fields to calculate sums for",
68
+ optional: true,
69
+ },
70
+ havingQuery: {
71
+ type: "string",
72
+ label: "Having Query",
73
+ description: "Filter the aggregated results (e.g., `COUNT>10` to only show groups with more than 10 records)",
74
+ optional: true,
75
+ },
76
+ responseDataFormat: {
77
+ propDefinition: [
78
+ servicenow,
79
+ "responseDataFormat",
80
+ ],
81
+ },
82
+ orderBy: {
83
+ type: "string",
84
+ label: "Order By",
85
+ description: "Field to sort results by. Prefix with `^ORDER_BY` for ascending or `^ORDER_BYDESC` for descending (e.g., `^ORDER_BYDESC` + field name)",
86
+ optional: true,
87
+ },
88
+ },
89
+ async run({ $ }) {
90
+ const params = {
91
+ sysparm_count: this.count,
92
+ sysparm_query: this.query,
93
+ sysparm_group_by: this.groupByField,
94
+ sysparm_display_value: this.responseDataFormat,
95
+ sysparm_having: this.havingQuery,
96
+ sysparm_order_by: this.orderBy,
97
+ };
98
+
99
+ let hasAggregateFields = false;
100
+
101
+ // Add aggregate functions for each field type
102
+ if (this.avgFields?.length) {
103
+ params.sysparm_avg_fields = this.avgFields.join?.() || this.avgFields;
104
+ hasAggregateFields = true;
105
+ }
106
+ if (this.minFields?.length) {
107
+ params.sysparm_min_fields = this.minFields.join?.() || this.minFields;
108
+ hasAggregateFields = true;
109
+ }
110
+ if (this.maxFields?.length) {
111
+ params.sysparm_max_fields = this.maxFields.join?.() || this.maxFields;
112
+ hasAggregateFields = true;
113
+ }
114
+ if (this.sumFields?.length) {
115
+ params.sysparm_sum_fields = this.sumFields.join?.() || this.sumFields;
116
+ hasAggregateFields = true;
117
+ }
118
+
119
+ if (!hasAggregateFields) {
120
+ throw new ConfigurationError("You must provide at least one Aggregate Field. [See the documentation](https://www.servicenow.com/docs/bundle/zurich-api-reference/page/integrate/inbound-rest/concept/c_AggregateAPI.html#title_aggregate-GET-stats) for more information.");
121
+ }
122
+
123
+ const response = await this.servicenow.getRecordCountsByField({
124
+ $,
125
+ table: this.table,
126
+ params,
127
+ });
128
+
129
+ $.export("$summary", `Successfully retrieved ${response?.length || 0} records grouped by field "${this.groupByField}"`);
130
+
131
+ return response;
132
+ },
133
+ };
@@ -0,0 +1,77 @@
1
+ import servicenow from "../../servicenow.app.mjs";
2
+
3
+ export default {
4
+ key: "servicenow-get-table-record-by-id",
5
+ name: "Get Table Record by ID",
6
+ description: "Retrieves a single record from a table by its ID. [See the documentation](https://www.servicenow.com/docs/bundle/zurich-api-reference/page/integrate/inbound-rest/concept/c_TableAPI.html#title_table-GET-id)",
7
+ version: "1.0.0",
8
+ annotations: {
9
+ destructiveHint: false,
10
+ openWorldHint: true,
11
+ readOnlyHint: true,
12
+ },
13
+ type: "action",
14
+ props: {
15
+ servicenow,
16
+ table: {
17
+ propDefinition: [
18
+ servicenow,
19
+ "table",
20
+ ],
21
+ },
22
+ recordId: {
23
+ propDefinition: [
24
+ servicenow,
25
+ "recordId",
26
+ ],
27
+ },
28
+ responseDataFormat: {
29
+ propDefinition: [
30
+ servicenow,
31
+ "responseDataFormat",
32
+ ],
33
+ },
34
+ excludeReferenceLinks: {
35
+ propDefinition: [
36
+ servicenow,
37
+ "excludeReferenceLinks",
38
+ ],
39
+ },
40
+ responseFields: {
41
+ propDefinition: [
42
+ servicenow,
43
+ "responseFields",
44
+ ],
45
+ },
46
+ responseView: {
47
+ propDefinition: [
48
+ servicenow,
49
+ "responseView",
50
+ ],
51
+ },
52
+ queryNoDomain: {
53
+ propDefinition: [
54
+ servicenow,
55
+ "queryNoDomain",
56
+ ],
57
+ },
58
+ },
59
+ async run({ $ }) {
60
+ const response = await this.servicenow.getTableRecordById({
61
+ $,
62
+ table: this.table,
63
+ recordId: this.recordId,
64
+ params: {
65
+ sysparm_display_value: this.responseDataFormat,
66
+ sysparm_exclude_reference_link: this.excludeReferenceLinks,
67
+ sysparm_fields: this.responseFields?.join?.() || this.responseFields,
68
+ sysparm_view: this.responseView,
69
+ sysparm_query_no_domain: this.queryNoDomain,
70
+ },
71
+ });
72
+
73
+ $.export("$summary", `Successfully retrieved record ${this.recordId} from table "${this.table}"`);
74
+
75
+ return response;
76
+ },
77
+ };
@@ -1,137 +1,135 @@
1
- // legacy_hash_id: a_wdid84
2
- import { axios } from "@pipedream/platform";
1
+ import { ConfigurationError } from "@pipedream/platform";
2
+ import servicenow from "../../servicenow.app.mjs";
3
3
 
4
4
  export default {
5
5
  key: "servicenow-get-table-records",
6
6
  name: "Get Table Records",
7
- description: "Retrieves multiple records for the specified table.",
8
- version: "0.3.1",
7
+ description: "Retrieves multiple records for the specified table. [See the documentation](https://www.servicenow.com/docs/bundle/zurich-api-reference/page/integrate/inbound-rest/concept/c_TableAPI.html#title_table-GET)",
8
+ version: "1.0.0",
9
+ annotations: {
10
+ destructiveHint: false,
11
+ openWorldHint: true,
12
+ readOnlyHint: true,
13
+ },
9
14
  type: "action",
10
15
  props: {
11
- servicenow: {
12
- type: "app",
13
- app: "servicenow",
14
- },
15
- table_name: {
16
- type: "string",
17
- description: "The name of the table containing the records to retrieve.",
18
- },
19
- api_version: {
20
- type: "string",
21
- description: "API version number. Version numbers identify the endpoint version that a URI accesses. By specifying a version number in your URIs, you can ensure that future updates to the REST API do not negatively impact your integration. Use `lastest` to use the latest REST endpoint for your instance version.",
22
- optional: true,
23
- options: [
24
- "lastest",
25
- "v1",
26
- "v2",
16
+ servicenow,
17
+ table: {
18
+ propDefinition: [
19
+ servicenow,
20
+ "table",
27
21
  ],
28
22
  },
29
- request_format: {
30
- type: "string",
31
- description: "Format of REST request body",
32
- optional: true,
33
- options: [
34
- "application/json",
35
- "application/xml",
36
- "text/xml",
37
- ],
23
+ filterInfo: {
24
+ type: "alert",
25
+ alertType: "info",
26
+ content: "You must provide either a `Query` or at least one `Filter` prop. ",
38
27
  },
39
- response_format: {
28
+ query: {
29
+ label: "Query",
40
30
  type: "string",
41
- description: "Format of REST response body.",
31
+ description: "An [encoded query string](https://www.servicenow.com/docs/bundle/zurich-platform-user-interface/page/use/using-lists/concept/c_EncodedQueryStrings.html) to filter records by (e.g., `active=true^priority=1`). This overrides any other filters set.",
42
32
  optional: true,
43
- options: [
44
- "application/json",
45
- "application/xml",
46
- "text/xml",
47
- ],
48
33
  },
49
- sysparm_query: {
34
+ filterCreatedAtDate: {
50
35
  type: "string",
36
+ label: "Filter by Date Created",
37
+ description: "Return records created only after the given date, in the format `YYYY-MM-DD HH:MM:SS` (e.g. `2026-01-01 00:00:00`).",
51
38
  optional: true,
52
39
  },
53
- sysparm_display_value: {
40
+ filterUpdatedAtDate: {
54
41
  type: "string",
55
- description: "Return field display values (true), actual values (false), or both (all) (default: false).",
42
+ label: "Filter by Date Updated",
43
+ description: "Return records updated only after the given date, in the format `YYYY-MM-DD HH:MM:SS` (e.g. `2026-01-01 00:00:00`).",
56
44
  optional: true,
57
- options: [
58
- "true",
59
- "false",
60
- "all",
61
- ],
62
45
  },
63
- sysparm_exclude_reference_link: {
46
+ filterActive: {
64
47
  type: "boolean",
65
- description: "True to exclude Table API links for reference fields (default: false).",
48
+ label: "Filter by Active",
49
+ description: "If set to `true`, only return records that are active. If set to `false`, only return records that are inactive. May not be available for all tables.",
66
50
  optional: true,
67
51
  },
68
- sysparm_suppress_pagination_header: {
69
- type: "boolean",
70
- description: "True to supress pagination header (default: false).",
71
- optional: true,
72
- },
73
- sysparm_fields: {
74
- type: "string",
75
- description: "A comma-separated list of fields to return in the response.",
76
- optional: true,
52
+ responseDataFormat: {
53
+ propDefinition: [
54
+ servicenow,
55
+ "responseDataFormat",
56
+ ],
77
57
  },
78
- sysparm_limit: {
79
- type: "string",
80
- description: "The maximum number of results returned per page (default: 10,000).",
81
- optional: true,
58
+ excludeReferenceLinks: {
59
+ propDefinition: [
60
+ servicenow,
61
+ "excludeReferenceLinks",
62
+ ],
82
63
  },
83
- sysparm_view: {
84
- type: "string",
85
- description: "Render the response according to the specified UI view (overridden by sysparm_fields).",
86
- optional: true,
64
+ responseFields: {
65
+ propDefinition: [
66
+ servicenow,
67
+ "responseFields",
68
+ ],
87
69
  },
88
- sysparm_query_category: {
89
- type: "string",
90
- description: "Name of the query category (read replica category) to use for queries.",
70
+ limit: {
71
+ type: "integer",
72
+ label: "Limit",
73
+ description: "The maximum number of results to return",
74
+ min: 1,
75
+ default: 10000,
91
76
  optional: true,
92
77
  },
93
- sysparm_query_no_domain: {
94
- type: "boolean",
95
- description: "True to access data across domains if authorized (default: false).",
96
- optional: true,
78
+ responseView: {
79
+ propDefinition: [
80
+ servicenow,
81
+ "responseView",
82
+ ],
97
83
  },
98
- sysparm_no_count: {
99
- type: "boolean",
100
- description: "Do not execute a select count(*) on table (default: false).",
101
- optional: true,
84
+ queryNoDomain: {
85
+ propDefinition: [
86
+ servicenow,
87
+ "queryNoDomain",
88
+ ],
102
89
  },
103
90
  },
104
91
  async run({ $ }) {
105
- // See the API docs: https://docs.servicenow.com/bundle/paris-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html#table-GET-id */
92
+ let query = this.query;
106
93
 
107
- if (!this.table_name) {
108
- throw new Error("Must provide table_name parameter.");
109
- }
94
+ // If no query is provided, build one from the filters
95
+ if (!query) {
96
+ const filters = [];
97
+
98
+ if (this.filterCreatedAtDate) {
99
+ filters.push(`sys_created_on>=${this.filterCreatedAtDate}`);
100
+ }
101
+
102
+ if (this.filterUpdatedAtDate) {
103
+ filters.push(`sys_updated_on>=${this.filterUpdatedAtDate}`);
104
+ }
105
+
106
+ if (this.filterActive !== undefined) {
107
+ filters.push(`active=${this.filterActive}`);
108
+ }
110
109
 
111
- var apiVersion = "";
112
- if (this.api_version == "v1" || this.api_version == "v2") {
113
- apiVersion = this.api_version + "/";
110
+ if (!filters.length) {
111
+ throw new ConfigurationError("You must provide either a `Query` or at least one `Filter` prop.");
112
+ }
113
+
114
+ query = filters.join("^");
114
115
  }
115
116
 
116
- return await axios($, {
117
- url: `https://${this.servicenow.$auth.instance_name}.service-now.com/api/now/${apiVersion}table/${this.table_name}`,
118
- headers: {
119
- "Authorization": `Bearer ${this.servicenow.$auth.oauth_access_token}`,
120
- "Accept": this.request_format || "application/json",
121
- "Content-Type": this.response_format || "application/json",
122
- },
117
+ const response = await this.servicenow.getTableRecords({
118
+ $,
119
+ table: this.table,
123
120
  params: {
124
- sysparm_query: this.sysparm_query,
125
- sysparm_display_value: this.sysparm_display_value,
126
- sysparm_exclude_reference_link: this.sysparm_exclude_reference_link,
127
- sysparm_suppress_pagination_header: this.sysparm_suppress_pagination_header,
128
- sysparm_fields: this.sysparm_fields,
129
- sysparm_limit: this.sysparm_limit,
130
- sysparm_view: this.sysparm_view,
131
- sysparm_query_category: this.sysparm_query_category,
132
- sysparm_query_no_domain: this.sysparm_query_no_domain,
133
- sysparm_no_count: this.sysparm_no_count,
121
+ sysparm_query: query,
122
+ sysparm_display_value: this.responseDataFormat,
123
+ sysparm_exclude_reference_link: this.excludeReferenceLinks,
124
+ sysparm_fields: this.responseFields?.join?.() || this.responseFields,
125
+ sysparm_limit: this.limit,
126
+ sysparm_view: this.responseView,
127
+ sysparm_query_no_domain: this.queryNoDomain,
134
128
  },
135
129
  });
130
+
131
+ $.export("$summary", `Successfully retrieved ${response?.length || 0} record(s) from table "${this.table}"`);
132
+
133
+ return response;
136
134
  },
137
135
  };
@@ -1,130 +1,94 @@
1
- // legacy_hash_id: a_4riE2J
2
- import { axios } from "@pipedream/platform";
1
+ import servicenow from "../../servicenow.app.mjs";
2
+ import { parseObject } from "../../common/utils.mjs";
3
3
 
4
4
  export default {
5
5
  key: "servicenow-update-table-record",
6
6
  name: "Update Table Record",
7
- description: "Updates the specified record with the name-value pairs included in the request body.",
8
- version: "0.1.1",
7
+ description: "Updates the specified record with the name-value pairs included in the request body. [See the documentation](https://www.servicenow.com/docs/bundle/zurich-api-reference/page/integrate/inbound-rest/concept/c_TableAPI.html#title_table-PATCH)",
8
+ version: "1.0.0",
9
+ annotations: {
10
+ destructiveHint: true,
11
+ openWorldHint: true,
12
+ readOnlyHint: false,
13
+ },
9
14
  type: "action",
10
15
  props: {
11
- servicenow: {
12
- type: "app",
13
- app: "servicenow",
14
- },
15
- table_name: {
16
- type: "string",
17
- description: "The name of the table containing the record to update.",
18
- },
19
- sys_id: {
20
- type: "string",
21
- description: "Unique identifier of the record to update.",
22
- },
23
- update_fields: {
24
- type: "object",
25
- description: "An object with name-value pairs with the fields to update in the specified record.\n**Note:** All fields within a record may not be available for update. For example, fields that have a prefix of \"sys_\" are typically system parameters that are automatically generated and cannot be updated.",
26
- },
27
- api_version: {
28
- type: "string",
29
- description: "API version number. Version numbers identify the endpoint version that a URI accesses. By specifying a version number in your URIs, you can ensure that future updates to the REST API do not negatively impact your integration. Use `lastest` to use the latest REST endpoint for your instance version.",
30
- optional: true,
31
- options: [
32
- "lastest",
33
- "v1",
34
- "v2",
16
+ servicenow,
17
+ table: {
18
+ propDefinition: [
19
+ servicenow,
20
+ "table",
35
21
  ],
36
22
  },
37
- request_format: {
38
- type: "string",
39
- description: "Format of REST request body",
40
- optional: true,
41
- options: [
42
- "application/json",
43
- "application/xml",
44
- "text/xml",
23
+ recordId: {
24
+ propDefinition: [
25
+ servicenow,
26
+ "recordId",
45
27
  ],
46
28
  },
47
- response_format: {
48
- type: "string",
49
- description: "Format of REST response body.",
50
- optional: true,
51
- options: [
52
- "application/json",
53
- "application/xml",
54
- "text/xml",
55
- ],
29
+ updateFields: {
30
+ label: "Update Fields",
31
+ type: "object",
32
+ description: "The fields to update in the record, as key-value pairs (e.g. `{ \"name\": \"Jane Doe\", \"status\": \"active\" }`). **Note:** System fields (prefixed with `sys_`) are typically auto-generated and cannot be updated.",
56
33
  },
57
- x_no_response_body: {
34
+ replaceRecord: {
58
35
  type: "boolean",
59
- description: "By default, responses include body content detailing the modified record. Set this request header to true to suppress the response body.",
36
+ label: "Replace Record",
37
+ description: "If true, replaces the entire record with the provided fields (uses PUT instead of PATCH). Any fields not provided will be cleared.",
60
38
  optional: true,
61
39
  },
62
- sysparm_display_value: {
63
- type: "string",
64
- description: "Return field display values (true), actual values (false), or both (all) (default: false).",
65
- optional: true,
66
- options: [
67
- "true",
68
- "false",
69
- "all",
40
+ responseDataFormat: {
41
+ propDefinition: [
42
+ servicenow,
43
+ "responseDataFormat",
70
44
  ],
71
45
  },
72
- sysparm_fields: {
73
- type: "string",
74
- description: "A comma-separated list of fields to return in the response.",
75
- optional: true,
46
+ responseFields: {
47
+ propDefinition: [
48
+ servicenow,
49
+ "responseFields",
50
+ ],
76
51
  },
77
- sysparm_input_display_value: {
78
- type: "boolean",
79
- description: "Flag that indicates whether to set field values using the display value or the actual value.\n* `true`: Treats input values as display values and they are manipulated so they can be stored properly in the database.\n* `false`: Treats input values as actual values and stored them in the database without manipulation.",
80
- optional: true,
52
+ inputDisplayValue: {
53
+ propDefinition: [
54
+ servicenow,
55
+ "inputDisplayValue",
56
+ ],
81
57
  },
82
- sysparm_view: {
83
- type: "string",
84
- description: "Render the response according to the specified UI view (overridden by sysparm_fields).",
85
- optional: true,
86
- options: [
87
- "desktop",
88
- "mobile",
89
- "both",
58
+ responseView: {
59
+ propDefinition: [
60
+ servicenow,
61
+ "responseView",
90
62
  ],
91
63
  },
92
- sysparm_query_no_domain: {
93
- type: "boolean",
94
- description: "True to access data across domains if authorized (default: false).",
95
- optional: true,
64
+ queryNoDomain: {
65
+ propDefinition: [
66
+ servicenow,
67
+ "queryNoDomain",
68
+ ],
96
69
  },
97
70
  },
98
71
  async run({ $ }) {
99
- /* See the API docs: https://docs.servicenow.com/bundle/paris-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html#c_TableAPI
100
- Section Table - PATCH /now/table/{tableName}/{sys_id} */
101
-
102
- if (!this.table_name || !this.sys_id || !this.update_fields) {
103
- throw new Error("Must provide table_name, sys_id, and update_fields parameters.");
104
- }
105
-
106
- var apiVersion = "";
107
- if (this.api_version == "v1" || this.api_version == "v2") {
108
- apiVersion = this.api_version + "/";
109
- }
110
-
111
- return await axios($, {
112
- method: "patch",
113
- url: `https://${this.servicenow.$auth.instance_name}.service-now.com/api/now/${apiVersion}table/${this.table_name}/${this.sys_id}`,
114
- headers: {
115
- "Authorization": `Bearer ${this.servicenow.$auth.oauth_access_token}`,
116
- "Accept": this.request_format || "application/json",
117
- "Content-Type": this.response_format || "application/json",
118
- "X-no-response-body": this.x_no_response_body,
119
- },
72
+ const response = await this.servicenow.updateTableRecord({
73
+ $,
74
+ table: this.table,
75
+ recordId: this.recordId,
76
+ replace: this.replaceRecord,
77
+ data: parseObject(this.updateFields),
120
78
  params: {
121
- sysparm_display_value: this.sysparm_display_value,
122
- sysparm_fields: this.sysparm_fields,
123
- sysparm_input_display_value: this.sysparm_input_display_value,
124
- sysparm_view: this.sysparm_view,
125
- sysparm_query_no_domain: this.sysparm_query_no_domain,
79
+ sysparm_display_value: this.responseDataFormat,
80
+ sysparm_fields: this.responseFields?.join?.() || this.responseFields,
81
+ sysparm_input_display_value: this.inputDisplayValue,
82
+ sysparm_view: this.responseView,
83
+ sysparm_query_no_domain: this.queryNoDomain,
126
84
  },
127
- data: this.update_fields,
128
85
  });
86
+
87
+ const action = this.replaceRecord
88
+ ? "replaced"
89
+ : "updated";
90
+ $.export("$summary", `Successfully ${action} record ${this.recordId} in table "${this.table}"`);
91
+
92
+ return response;
129
93
  },
130
94
  };
@@ -0,0 +1,31 @@
1
+ const DEFAULT_SEVERITY_OPTIONS = [
2
+ {
3
+ label: "Critical",
4
+ value: "1",
5
+ },
6
+ {
7
+ label: "High",
8
+ value: "2",
9
+ },
10
+ {
11
+ label: "Moderate",
12
+ value: "3",
13
+ },
14
+ {
15
+ label: "Low",
16
+ value: "4",
17
+ },
18
+ ];
19
+
20
+ const INCIDENT_SEVERITY_OPTIONS = [
21
+ ...DEFAULT_SEVERITY_OPTIONS,
22
+ {
23
+ label: "Planning",
24
+ value: "5",
25
+ },
26
+ ];
27
+
28
+ export default {
29
+ DEFAULT_SEVERITY_OPTIONS,
30
+ INCIDENT_SEVERITY_OPTIONS,
31
+ };
@@ -0,0 +1,15 @@
1
+ import { ConfigurationError } from "@pipedream/platform";
2
+
3
+ export function parseObject(value) {
4
+ if (!value) return undefined;
5
+
6
+ if (typeof value === "string") {
7
+ try {
8
+ return JSON.parse(value);
9
+ } catch (e) {
10
+ throw new ConfigurationError(`Invalid JSON: ${value}`);
11
+ }
12
+ }
13
+
14
+ return value;
15
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pipedream/servicenow",
3
- "version": "0.6.0",
4
- "description": "Pipedream servicenow Components",
3
+ "version": "0.8.0",
4
+ "description": "Pipedream ServiceNow Components",
5
5
  "main": "servicenow.app.mjs",
6
6
  "keywords": [
7
7
  "pipedream",
@@ -13,6 +13,6 @@
13
13
  "access": "public"
14
14
  },
15
15
  "dependencies": {
16
- "@pipedream/platform": "^3.0.0"
16
+ "@pipedream/platform": "^3.1.1"
17
17
  }
18
18
  }
@@ -1,11 +1,169 @@
1
+ import { axios } from "@pipedream/platform";
2
+
1
3
  export default {
2
4
  type: "app",
3
5
  app: "servicenow",
4
- propDefinitions: {},
6
+ propDefinitions: {
7
+ table: {
8
+ type: "string",
9
+ label: "Table",
10
+ description: "Search for a table or provide a table name (not label)",
11
+ useQuery: true,
12
+ async options({ query }) {
13
+ if (!(query?.length > 1)) {
14
+ console.log("Please input a search term");
15
+ return [];
16
+ }
17
+ const data = await this.getTableRecords({
18
+ table: "sys_db_object",
19
+ params: {
20
+ sysparm_query: `nameLIKE${query}^ORlabelLIKE${query}`,
21
+ sysparm_fields: "name,label",
22
+ },
23
+ });
24
+ return data.map(({
25
+ label, name,
26
+ }) => ({
27
+ label,
28
+ value: name,
29
+ }));
30
+ },
31
+ },
32
+ recordId: {
33
+ type: "string",
34
+ label: "Record ID",
35
+ description: "The ID (`sys_id` field) of the record",
36
+ },
37
+ responseDataFormat: {
38
+ label: "Response Data Format",
39
+ type: "string",
40
+ description: "The format to return response fields in",
41
+ optional: true,
42
+ options: [
43
+ {
44
+ value: "true",
45
+ label: "Returns the display values for all fields",
46
+ },
47
+ {
48
+ value: "false",
49
+ label: "Returns the actual values from the database",
50
+ },
51
+ {
52
+ value: "all",
53
+ label: "Returns both actual and display values",
54
+ },
55
+ ],
56
+ },
57
+ excludeReferenceLinks: {
58
+ type: "boolean",
59
+ label: "Exclude Reference Links",
60
+ description: "If true, the response excludes Table API links for reference fields",
61
+ optional: true,
62
+ },
63
+ responseFields: {
64
+ type: "string[]",
65
+ label: "Response Fields",
66
+ description: "The fields to return in the response. By default, all fields are returned",
67
+ optional: true,
68
+ },
69
+ inputDisplayValue: {
70
+ label: "Input Display Value",
71
+ type: "boolean",
72
+ description: "If true, the input values are treated as display values (and are manipulated so they can be stored properly in the database)",
73
+ optional: true,
74
+ },
75
+ responseView: {
76
+ label: "Response View",
77
+ type: "string",
78
+ description: "Render the response according to the specified UI view (overridden by `Response Fields`)",
79
+ optional: true,
80
+ options: [
81
+ "desktop",
82
+ "mobile",
83
+ "both",
84
+ ],
85
+ },
86
+ queryNoDomain: {
87
+ type: "boolean",
88
+ label: "Query Across Domains",
89
+ description: "If true, allows access to data across domains (if authorized)",
90
+ optional: true,
91
+ },
92
+ },
5
93
  methods: {
6
- // this.$auth contains connected account data
7
- authKeys() {
8
- console.log(Object.keys(this.$auth));
94
+ async _makeRequest({
95
+ $ = this,
96
+ headers,
97
+ ...args
98
+ }) {
99
+ const response = await axios($, {
100
+ baseURL: `https://${this.$auth.instance_name}.service-now.com/api/now`,
101
+ headers: {
102
+ ...headers,
103
+ "Authorization": `Bearer ${this.$auth.oauth_access_token}`,
104
+ },
105
+ ...args,
106
+ });
107
+ return response.result;
108
+ },
109
+ async createTableRecord({
110
+ table, ...args
111
+ }) {
112
+ return this._makeRequest({
113
+ method: "post",
114
+ url: `/table/${table}`,
115
+ headers: {
116
+ "Content-Type": "application/json",
117
+ },
118
+ ...args,
119
+ });
120
+ },
121
+ async updateTableRecord({
122
+ table, recordId, replace, ...args
123
+ }) {
124
+ return this._makeRequest({
125
+ method: replace
126
+ ? "put"
127
+ : "patch",
128
+ url: `/table/${table}/${recordId}`,
129
+ headers: {
130
+ "Content-Type": "application/json",
131
+ },
132
+ ...args,
133
+ });
134
+ },
135
+ async deleteTableRecord({
136
+ table, recordId, ...args
137
+ }) {
138
+ return this._makeRequest({
139
+ method: "delete",
140
+ url: `/table/${table}/${recordId}`,
141
+ ...args,
142
+ });
143
+ },
144
+ async getTableRecordById({
145
+ table, recordId, ...args
146
+ }) {
147
+ return this._makeRequest({
148
+ url: `/table/${table}/${recordId}`,
149
+ ...args,
150
+ });
151
+ },
152
+ async getTableRecords({
153
+ table, ...args
154
+ }) {
155
+ return this._makeRequest({
156
+ url: `/table/${table}`,
157
+ ...args,
158
+ });
159
+ },
160
+ async getRecordCountsByField({
161
+ table, ...args
162
+ }) {
163
+ return this._makeRequest({
164
+ url: `/stats/${table}`,
165
+ ...args,
166
+ });
9
167
  },
10
168
  },
11
169
  };
@@ -1,112 +0,0 @@
1
- // legacy_hash_id: a_rJid2e
2
- import { axios } from "@pipedream/platform";
3
-
4
- export default {
5
- key: "servicenow-get-table-record-by-sysid",
6
- name: "Get Table Record By SysId",
7
- description: "Retrieves the record identified by the specified sys_id from the specified table.",
8
- version: "0.3.1",
9
- type: "action",
10
- props: {
11
- servicenow: {
12
- type: "app",
13
- app: "servicenow",
14
- },
15
- table_name: {
16
- type: "string",
17
- description: "The name of the table containing the record to retrieve.",
18
- },
19
- sys_id: {
20
- type: "string",
21
- description: "Unique identifier of the record to retrieve.",
22
- },
23
- api_version: {
24
- type: "string",
25
- description: "API version number. Version numbers identify the endpoint version that a URI accesses. By specifying a version number in your URIs, you can ensure that future updates to the REST API do not negatively impact your integration. Use `lastest` to use the latest REST endpoint for your instance version.",
26
- optional: true,
27
- options: [
28
- "lastest",
29
- "v1",
30
- "v2",
31
- ],
32
- },
33
- request_format: {
34
- type: "string",
35
- description: "Format of REST request body",
36
- optional: true,
37
- options: [
38
- "application/json",
39
- "application/xml",
40
- "text/xml",
41
- ],
42
- },
43
- response_format: {
44
- type: "string",
45
- description: "Format of REST response body.",
46
- optional: true,
47
- options: [
48
- "application/json",
49
- "application/xml",
50
- "text/xml",
51
- ],
52
- },
53
- sysparm_display_value: {
54
- type: "string",
55
- description: "Return field display values (true), actual values (false), or both (all) (default: false).",
56
- optional: true,
57
- options: [
58
- "true",
59
- "false",
60
- "all",
61
- ],
62
- },
63
- sysparm_exclude_reference_link: {
64
- type: "boolean",
65
- description: "True to exclude Table API links for reference fields (default: false).",
66
- optional: true,
67
- },
68
- sysparm_fields: {
69
- type: "string",
70
- description: "A comma-separated list of fields to return in the response.",
71
- optional: true,
72
- },
73
- sysparm_view: {
74
- type: "string",
75
- description: "Render the response according to the specified UI view (overridden by sysparm_fields).",
76
- optional: true,
77
- },
78
- sysparm_query_no_domain: {
79
- type: "boolean",
80
- description: "True to access data across domains if authorized (default: false).",
81
- optional: true,
82
- },
83
- },
84
- async run({ $ }) {
85
- // See the API docs: https://docs.servicenow.com/bundle/paris-application-development/page/integrate/inbound-rest/concept/c_TableAPI.html#table-GET-id */
86
-
87
- if (!this.table_name || !this.sys_id) {
88
- throw new Error("Must provide table_name, and sys_id parameters.");
89
- }
90
-
91
- var apiVersion = "";
92
- if (this.api_version == "v1" || this.api_version == "v2") {
93
- apiVersion = this.api_version + "/";
94
- }
95
-
96
- return await axios($, {
97
- url: `https://${this.servicenow.$auth.instance_name}.service-now.com/api/now/${apiVersion}table/${this.table_name}/${this.sys_id}`,
98
- headers: {
99
- "Authorization": `Bearer ${this.servicenow.$auth.oauth_access_token}`,
100
- "Accept": this.request_format || "application/json",
101
- "Content-Type": this.response_format || "application/json",
102
- },
103
- params: {
104
- sysparm_display_value: this.sysparm_display_value,
105
- sysparm_exclude_reference_link: this.sysparm_exclude_reference_link,
106
- sysparm_fields: this.sysparm_fields,
107
- sysparm_view: this.sysparm_view,
108
- sysparm_query_no_domain: this.sysparm_query_no_domain,
109
- },
110
- });
111
- },
112
- };