@pipedream/jira_service_desk 1.0.0 → 2.0.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.
@@ -4,7 +4,7 @@ export default {
4
4
  key: "jira_service_desk-create-comment-on-request",
5
5
  name: "Create Comment on Request",
6
6
  description: "Create a comment on a customer request. [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-comment-post)",
7
- version: "0.0.4",
7
+ version: "0.1.0",
8
8
  annotations: {
9
9
  destructiveHint: false,
10
10
  openWorldHint: true,
@@ -23,9 +23,6 @@ export default {
23
23
  propDefinition: [
24
24
  jiraServiceDesk,
25
25
  "requestId",
26
- ({ cloudId }) => ({
27
- cloudId,
28
- }),
29
26
  ],
30
27
  },
31
28
  body: {
@@ -1,11 +1,21 @@
1
+ // x-pd-ai: optimized
2
+ import { ConfigurationError } from "@pipedream/platform";
1
3
  import jiraServiceDesk from "../../jira_service_desk.app.mjs";
4
+ import constants from "../../common/constants.mjs";
2
5
 
3
6
  export default {
4
7
  key: "jira_service_desk-create-request",
5
8
  name: "Create Request",
6
9
  description:
7
- "Creates a new customer request. [See the documentation](https://docs.atlassian.com/jira-servicedesk/REST/3.6.2/#servicedeskapi/request-createCustomerRequest)",
8
- version: "0.1.3",
10
+ "Creates a customer request (ticket) in a Jira Service Management service desk."
11
+ + " This is the single tool for creating any kind of ticket (incident, service request, access request, hardware request, and so on)."
12
+ + " The kind of ticket is decided by `requestTypeId`, not by the wording of the summary, so always pick the request type deliberately."
13
+ + " Use **List Sites** to get `cloudId`, **List Service Desks** to get `serviceDeskId`, and **List Request Types** to choose the `requestTypeId` whose name and description match the user's intent."
14
+ + " Call **List Request Type Fields** to see which fields that request type requires; pass anything beyond summary and description in `additionalFieldValues`, keyed by Jira field ID."
15
+ + " Worked example: on service desk `1`, request type `4` (\"Onboard new employees\") requires `summary` and also accepts a `duedate`, so call with Summary `Joseph Wilson starts on September 1`, Description `Needs a laptop and an email account`, and Additional Field Values `{ \"duedate\": \"2026-09-01\" }`."
16
+ + " Returns the created request including its `issueKey` and `issueId`."
17
+ + " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-post)",
18
+ version: "1.0.0",
9
19
  annotations: {
10
20
  destructiveHint: false,
11
21
  openWorldHint: true,
@@ -24,95 +34,130 @@ export default {
24
34
  propDefinition: [
25
35
  jiraServiceDesk,
26
36
  "serviceDeskId",
27
- ({ cloudId }) => ({
28
- cloudId,
29
- }),
30
37
  ],
38
+ description: "The service desk to raise the request in. Use **List Service Desks** to find valid IDs (e.g. `1`).",
31
39
  },
32
40
  requestTypeId: {
33
41
  propDefinition: [
34
42
  jiraServiceDesk,
35
43
  "requestTypeId",
36
- ({
37
- cloudId, serviceDeskId,
38
- }) => ({
39
- cloudId,
40
- serviceDeskId,
41
- }),
42
44
  ],
43
- reloadProps: true,
45
+ description: "The request type that determines what kind of ticket this is. Use **List Request Types** to see the types this service desk offers and pick the one matching the user's intent (e.g. `8` for \"Report a system problem\").",
46
+ },
47
+ summary: {
48
+ type: "string",
49
+ label: "Summary",
50
+ description: "One-line title of the request, e.g. `Laptop won't boot after the latest update`. Required by virtually every request type.",
51
+ },
52
+ description: {
53
+ type: "string",
54
+ label: "Description",
55
+ description: "Body of the request, as plain text.",
56
+ optional: true,
57
+ },
58
+ additionalFieldValues: {
59
+ type: "object",
60
+ label: "Additional Field Values",
61
+ description:
62
+ "Any other fields the chosen request type requires or accepts, as a JSON object of Jira field ID to value, e.g. `{ \"duedate\": \"2026-09-01\", \"customfield_10052\": \"Laptop\" }`."
63
+ + " Run **List Request Type Fields** for the exact `fieldId`s, which are required, and their schemas."
64
+ + " Values that parse as JSON are converted (`[\"a\",\"b\"]` becomes a list, `5` becomes a number); to keep a numeric-looking value a string, wrap it in quotes (`\"\\\"123\\\"\"`)."
65
+ + " Keys `summary` and `description` given here override the props above.",
66
+ optional: true,
44
67
  },
45
68
  requestParticipants: {
46
69
  type: "string[]",
47
70
  label: "Request Participants",
48
- description:
49
- "Not available to users who only have the Service Desk Customer permission or if the feature is turned off for customers..",
71
+ description: "Atlassian account IDs to add as participants, e.g. `[\"5b10a2844c20165700ede21g\"]`. Not available to users who only have the Service Desk Customer permission, or if the feature is turned off for customers.",
50
72
  optional: true,
51
73
  },
52
74
  raiseOnBehalfOf: {
53
75
  type: "string",
54
76
  label: "Raise On Behalf Of",
55
- description:
56
- "Not available to users who only have the Service Desk Customer permission.",
77
+ description: "Atlassian account ID of the customer to raise this request for, e.g. `5b10a2844c20165700ede21g`. Not available to users who only have the Service Desk Customer permission.",
78
+ optional: true,
79
+ },
80
+ form: {
81
+ type: "object",
82
+ label: "Form",
83
+ description: "Answers to the form attached to the request type, as `{ \"answers\": { \"<questionId>\": { \"text\": \"...\" } } }`. Omit any Jira field from `additionalFieldValues` when it is linked to a form answer here. For answers in ADF, also set `isAdfRequest` to `true`.",
84
+ optional: true,
85
+ },
86
+ isAdfRequest: {
87
+ type: "boolean",
88
+ label: "Is ADF Request",
89
+ description: "Set to `true` to send rich-text fields (such as `description`) as Atlassian Document Format objects rather than plain text. Leave unset to send plain strings. When `true`, do not use the Description prop, which only sends plain text: pass the ADF object as a JSON string under the `description` key of `additionalFieldValues` instead. Marked experimental by Atlassian.",
90
+ optional: true,
91
+ },
92
+ channel: {
93
+ type: "string",
94
+ label: "Channel",
95
+ description: "Extra information about the channel the request came in on. Marked experimental by Atlassian.",
57
96
  optional: true,
58
97
  },
59
- },
60
- async additionalProps() {
61
- const {
62
- cloudId, serviceDeskId, requestTypeId,
63
- } = this;
64
- const types = await this.jiraServiceDesk.getRequestTypeFields({
65
- cloudId,
66
- serviceDeskId,
67
- requestTypeId,
68
- });
69
-
70
- return Object.fromEntries(
71
- types.map((field) => [
72
- field.fieldId,
73
- {
74
- type: "string",
75
- label: `Field: "${field.name}"`,
76
- description: `[See the documentation](https://docs.atlassian.com/jira-servicedesk/REST/3.6.2/#fieldformats) for info on specific fields. If the provided value is not a string, it will be parsed as JSON.${field.description
77
- ? `
78
- \\
79
- Field description: "${field.description}"`
80
- : ""}${field.jiraSchema
81
- ? `
82
- \\
83
- Field schema: \`${JSON.stringify(field.jiraSchema)}\``
84
- : ""}`,
85
- optional: !field.required,
86
- },
87
- ]),
88
- );
89
98
  },
90
99
  async run({ $ }) {
91
100
  const {
92
- // eslint-disable-next-line no-unused-vars
93
101
  jiraServiceDesk,
94
102
  cloudId,
95
103
  serviceDeskId,
96
104
  requestTypeId,
105
+ summary,
106
+ description,
107
+ additionalFieldValues,
97
108
  requestParticipants,
98
109
  raiseOnBehalfOf,
99
- ...requestFieldValues
110
+ form,
111
+ isAdfRequest,
112
+ channel,
100
113
  } = this;
101
114
 
102
- Object.entries(requestFieldValues).forEach(([
103
- key,
104
- value,
105
- ]) => {
115
+ let extraFields = additionalFieldValues;
116
+ if (typeof extraFields === "string") {
106
117
  try {
107
- const parsedValue = JSON.parse(value);
108
- requestFieldValues[key] = parsedValue;
118
+ extraFields = JSON.parse(extraFields);
119
+ } catch (error) {
120
+ throw new ConfigurationError(`Additional Field Values is not valid JSON: ${error.message}`);
109
121
  }
110
- catch (err) {
111
- // ignore non-serializable values
112
- }
113
- });
122
+ }
123
+ if (extraFields != null && (typeof extraFields !== "object" || Array.isArray(extraFields))) {
124
+ throw new ConfigurationError("Additional Field Values must be a JSON object of Jira field ID to value (not a list or a single value).");
125
+ }
114
126
 
115
- const response = await this.jiraServiceDesk.createCustomerRequest({
127
+ // Object props arrive from the UI with string values; parse the ones that carry
128
+ // non-string Jira field types (arrays, objects, numbers) and leave the rest as text.
129
+ const parsedExtraFields = Object.fromEntries(
130
+ Object.entries(extraFields ?? {}).map(([
131
+ fieldId,
132
+ value,
133
+ ]) => {
134
+ if (typeof value !== "string") {
135
+ return [
136
+ fieldId,
137
+ value,
138
+ ];
139
+ }
140
+ try {
141
+ return [
142
+ fieldId,
143
+ JSON.parse(value),
144
+ ];
145
+ } catch {
146
+ return [
147
+ fieldId,
148
+ value,
149
+ ];
150
+ }
151
+ }),
152
+ );
153
+
154
+ const requestFieldValues = {
155
+ [constants.REQUEST_FIELD.SUMMARY]: summary,
156
+ [constants.REQUEST_FIELD.DESCRIPTION]: description,
157
+ ...parsedExtraFields,
158
+ };
159
+
160
+ const response = await jiraServiceDesk.createCustomerRequest({
116
161
  $,
117
162
  cloudId,
118
163
  data: {
@@ -121,9 +166,13 @@ Field description: "${field.description}"`
121
166
  requestFieldValues,
122
167
  requestParticipants,
123
168
  raiseOnBehalfOf,
169
+ form,
170
+ isAdfRequest,
171
+ channel,
124
172
  },
125
173
  });
126
- $.export("$summary", "Successfully created request");
174
+
175
+ $.export("$summary", `Successfully created request ${response.issueKey}`);
127
176
  return response;
128
177
  },
129
178
  };
@@ -8,7 +8,7 @@ export default {
8
8
  + " Use this to identify who is logged in, or to filter requests by the current user's `account_id`."
9
9
  + " No `cloudId` required — this uses the Atlassian Identity API directly."
10
10
  + " [See the documentation](https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/)",
11
- version: "0.0.2",
11
+ version: "0.0.3",
12
12
  type: "action",
13
13
  annotations: {
14
14
  destructiveHint: false,
@@ -10,7 +10,7 @@ export default {
10
10
  + " Use **List Sites** first to obtain the required `cloudId`."
11
11
  + " Use **List My Requests** to find the `issueKey` of a request (e.g. `IT-42`)."
12
12
  + " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-get)",
13
- version: "0.1.0",
13
+ version: "0.2.0",
14
14
  type: "action",
15
15
  annotations: {
16
16
  destructiveHint: false,
@@ -11,7 +11,7 @@ export default {
11
11
  + " Use **List Sites** first to obtain the required `cloudId`."
12
12
  + " Use **List My Requests** to find the `issueKey` (e.g. `IT-42`)."
13
13
  + " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-status-get)",
14
- version: "1.0.0",
14
+ version: "1.1.0",
15
15
  type: "action",
16
16
  annotations: {
17
17
  destructiveHint: false,
@@ -3,8 +3,8 @@ import jira_service_desk from "../../jira_service_desk.app.mjs";
3
3
  export default {
4
4
  key: "jira_service_desk-list-cloud-id-options",
5
5
  name: "List Cloud ID Options",
6
- description: "Retrieves available options for the Cloud ID field.",
7
- version: "0.0.3",
6
+ description: "Lists the Atlassian sites you can raise requests on, as `{label, value}` options, to discover the `cloudId` every other Jira Service Desk tool needs. Takes no input beyond the account. Example: returns `[{ \"label\": \"acme\", \"value\": \"822faf0d-5427-420e-9016-999d3dc76918\" }]`. Use **List Sites** instead if you want the full site records. [See the documentation](https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/#3-1-get-the-cloudid-for-your-site)",
7
+ version: "0.1.0",
8
8
  type: "action",
9
9
  annotations: {
10
10
  destructiveHint: false,
@@ -15,8 +15,17 @@ export default {
15
15
  jira_service_desk,
16
16
  },
17
17
  async run({ $ }) {
18
- const options = await jira_service_desk.propDefinitions.cloudId.options
19
- .call(this.jira_service_desk);
18
+ const sites = await this.jira_service_desk.getSites({
19
+ $,
20
+ });
21
+ const options = sites
22
+ ?.filter?.(({ scopes }) => scopes?.includes("write:servicedesk-request"))
23
+ ?.map?.(({
24
+ id, name,
25
+ }) => ({
26
+ label: name,
27
+ value: id,
28
+ })) ?? [];
20
29
  $.export("$summary", `Successfully retrieved ${options.length} option${options.length === 1
21
30
  ? ""
22
31
  : "s"}`);
@@ -13,7 +13,7 @@ export default {
13
13
  + " `requestStatus`: `OPEN_REQUESTS` (default), `CLOSED_REQUESTS`, or `ALL_REQUESTS`."
14
14
  + " `requestOwnership`: `OWNED_REQUESTS` (default) or `PARTICIPATED_REQUESTS`."
15
15
  + " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-get)",
16
- version: "1.0.0",
16
+ version: "1.1.0",
17
17
  type: "action",
18
18
  annotations: {
19
19
  destructiveHint: false,
@@ -11,7 +11,7 @@ export default {
11
11
  + " Use **List Sites** first to obtain the required `cloudId`."
12
12
  + " Use **List My Requests** or **Get Request** to find the `issueKey` (e.g. `IT-42`)."
13
13
  + " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-transition-get)",
14
- version: "1.0.0",
14
+ version: "1.1.0",
15
15
  type: "action",
16
16
  annotations: {
17
17
  destructiveHint: false,
@@ -0,0 +1,87 @@
1
+ // x-pd-ai: optimized
2
+ import app from "../../jira_service_desk.app.mjs";
3
+
4
+ export default {
5
+ key: "jira_service_desk-list-request-type-fields",
6
+ name: "List Request Type Fields",
7
+ description:
8
+ "Lists the fields a given request type accepts, so you can build the `additionalFieldValues` argument for **Create Request** in a single pass."
9
+ + " Each entry gives the `fieldId` to use as the key, whether it is `required`, its `jiraSchema` (the value format), and any `validValues` for select-style fields."
10
+ + " Use **List Sites** for `cloudId`, **List Service Desks** for `serviceDeskId`, and **List Request Types** for `requestTypeId`."
11
+ + " Example: request type `4` (\"Onboard new employees\") on service desk `1` returns a required `summary` plus optional `duedate` (`jiraSchema.type` `date`, so pass `\"2026-09-01\"`), `description`, and `attachment`."
12
+ + " Also returns `canRaiseOnBehalfOf` and `canAddRequestParticipants`, which tell you whether the `raiseOnBehalfOf` and `requestParticipants` arguments of **Create Request** are usable with this account."
13
+ + " Hidden fields are only visible to service desk administrators."
14
+ + " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-servicedesk/#api-rest-servicedeskapi-servicedesk-servicedeskid-requesttype-requesttypeid-field-get)",
15
+ version: "0.0.1",
16
+ type: "action",
17
+ annotations: {
18
+ destructiveHint: false,
19
+ openWorldHint: true,
20
+ readOnlyHint: true,
21
+ },
22
+ props: {
23
+ app,
24
+ cloudId: {
25
+ propDefinition: [
26
+ app,
27
+ "cloudId",
28
+ ],
29
+ },
30
+ serviceDeskId: {
31
+ propDefinition: [
32
+ app,
33
+ "serviceDeskId",
34
+ ],
35
+ description: "The service desk the request type belongs to. Use **List Service Desks** to find valid IDs (e.g. `1`).",
36
+ },
37
+ requestTypeId: {
38
+ propDefinition: [
39
+ app,
40
+ "requestTypeId",
41
+ ],
42
+ description: "The request type whose fields to list. Use **List Request Types** to find valid IDs (e.g. `4`).",
43
+ },
44
+ expand: {
45
+ propDefinition: [
46
+ app,
47
+ "expand",
48
+ ],
49
+ description: "Extra data to include. Pass `[\"hiddenFields\"]` to also return fields hidden on the request type, which only a service desk administrator can see. `hiddenFields` is the only value this endpoint accepts.",
50
+ },
51
+ },
52
+ async run({ $ }) {
53
+ const {
54
+ requestTypeFields, canRaiseOnBehalfOf, canAddRequestParticipants,
55
+ } = await this.app.getRequestTypeCreateMeta({
56
+ $,
57
+ cloudId: this.cloudId,
58
+ serviceDeskId: this.serviceDeskId,
59
+ requestTypeId: this.requestTypeId,
60
+ params: {
61
+ expand: this.expand,
62
+ },
63
+ });
64
+
65
+ const fields = requestTypeFields?.map?.(({
66
+ fieldId, name, description, required, jiraSchema, validValues, defaultValues, visible,
67
+ }) => ({
68
+ fieldId,
69
+ name,
70
+ description,
71
+ required,
72
+ jiraSchema,
73
+ validValues,
74
+ defaultValues,
75
+ visible,
76
+ })) ?? [];
77
+
78
+ $.export("$summary", `Found ${fields.length} field${fields.length === 1
79
+ ? ""
80
+ : "s"}`);
81
+ return {
82
+ requestTypeFields: fields,
83
+ canRaiseOnBehalfOf,
84
+ canAddRequestParticipants,
85
+ };
86
+ },
87
+ };
@@ -0,0 +1,124 @@
1
+ // x-pd-ai: optimized
2
+ import app from "../../jira_service_desk.app.mjs";
3
+
4
+ export default {
5
+ key: "jira_service_desk-list-request-types",
6
+ name: "List Request Types",
7
+ description:
8
+ "Lists the customer request types a service desk offers, with the `id`, `name`, and `description` of each."
9
+ + " Call this before **Create Request** to choose the `requestTypeId` that matches what the user is asking for: the request type, not the summary wording, decides what kind of ticket gets created."
10
+ + " Names vary by desk, so match on meaning rather than assuming a type called \"Incident\" exists (an IT desk may instead offer \"Report a system problem\")."
11
+ + " Use **List Sites** for `cloudId` and **List Service Desks** for `serviceDeskId`."
12
+ + " Results are paginated automatically up to `maxResults`."
13
+ + " Returns `{ requestTypes, truncated }`, where `truncated` is `true` when more types remained unfetched."
14
+ + " Example: service desk `1` returns entries such as `{ \"id\": \"8\", \"name\": \"Report a system problem\", \"description\": \"Let us know if something isn't working properly\", \"canCreateRequest\": true }`."
15
+ + " Types with `canCreateRequest: false` cannot be used to raise a request."
16
+ + " Then call **List Request Type Fields** to see what the chosen type requires."
17
+ + " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-servicedesk/#api-rest-servicedeskapi-servicedesk-servicedeskid-requesttype-get)",
18
+ version: "0.0.1",
19
+ type: "action",
20
+ annotations: {
21
+ destructiveHint: false,
22
+ openWorldHint: true,
23
+ readOnlyHint: true,
24
+ },
25
+ props: {
26
+ app,
27
+ cloudId: {
28
+ propDefinition: [
29
+ app,
30
+ "cloudId",
31
+ ],
32
+ },
33
+ serviceDeskId: {
34
+ propDefinition: [
35
+ app,
36
+ "serviceDeskId",
37
+ ],
38
+ description: "The service desk whose request types to list. Use **List Service Desks** to find valid IDs (e.g. `1`).",
39
+ },
40
+ searchQuery: {
41
+ type: "string",
42
+ label: "Search Query",
43
+ description: "Filter results to request types matching this text, e.g. `hardware`. Omit to return every type the desk offers.",
44
+ optional: true,
45
+ },
46
+ groupId: {
47
+ type: "integer",
48
+ label: "Group ID",
49
+ description: "Filter results to a single request type group. Group IDs appear as `groupIds` on the request types returned by this action.",
50
+ optional: true,
51
+ },
52
+ restrictionStatus: {
53
+ type: "string",
54
+ label: "Restriction Status",
55
+ description: "Filter by whether the request type is open to all customers or restricted.",
56
+ options: [
57
+ "open",
58
+ "restricted",
59
+ ],
60
+ optional: true,
61
+ },
62
+ includeHiddenRequestTypesInSearch: {
63
+ type: "boolean",
64
+ label: "Include Hidden Request Types In Search",
65
+ description: "Whether to include hidden request types. Only applies together with `searchQuery`.",
66
+ optional: true,
67
+ },
68
+ maxResults: {
69
+ propDefinition: [
70
+ app,
71
+ "maxResults",
72
+ ],
73
+ },
74
+ expand: {
75
+ propDefinition: [
76
+ app,
77
+ "expand",
78
+ ],
79
+ description: "Extra data to include on each request type. Pass `[\"field\"]` to return the type's fields inline, which saves a follow-up **List Request Type Fields** call. `field` is the only value this endpoint accepts.",
80
+ },
81
+ },
82
+ async run({ $ }) {
83
+ const {
84
+ results, hasMore,
85
+ } = await this.app.getRequestTypes({
86
+ $,
87
+ cloudId: this.cloudId,
88
+ serviceDeskId: this.serviceDeskId,
89
+ maxResults: this.maxResults,
90
+ params: {
91
+ searchQuery: this.searchQuery,
92
+ groupId: this.groupId,
93
+ restrictionStatus: this.restrictionStatus,
94
+ includeHiddenRequestTypesInSearch: this.includeHiddenRequestTypesInSearch,
95
+ expand: this.expand,
96
+ },
97
+ });
98
+
99
+ const requestTypes = results.map(({
100
+ id, name, description, helpText, issueTypeId, serviceDeskId, groupIds, canCreateRequest,
101
+ fields,
102
+ }) => ({
103
+ id,
104
+ name,
105
+ description,
106
+ helpText,
107
+ issueTypeId,
108
+ serviceDeskId,
109
+ groupIds,
110
+ canCreateRequest,
111
+ fields,
112
+ }));
113
+
114
+ $.export("$summary", `Found ${requestTypes.length} request type${requestTypes.length === 1
115
+ ? ""
116
+ : "s"}${hasMore
117
+ ? ", truncated at Max Results; raise it to fetch more"
118
+ : ""}`);
119
+ return {
120
+ requestTypes,
121
+ truncated: hasMore,
122
+ };
123
+ },
124
+ };
@@ -0,0 +1,66 @@
1
+ // x-pd-ai: optimized
2
+ import app from "../../jira_service_desk.app.mjs";
3
+
4
+ export default {
5
+ key: "jira_service_desk-list-service-desks",
6
+ name: "List Service Desks",
7
+ description:
8
+ "Lists every service desk on an Atlassian site, with the `id` and project details of each."
9
+ + " Call this to discover the `serviceDeskId` required by **Create Request**, **List Request Types**, and **List My Requests** when you only know a project name or key."
10
+ + " Use **List Sites** first to obtain the required `cloudId`."
11
+ + " Results are paginated automatically up to `maxResults`."
12
+ + " Returns `{ serviceDesks, truncated }`, where `truncated` is `true` when more desks remained unfetched."
13
+ + " Example: a site with one desk returns `{ \"serviceDesks\": [{ \"id\": \"1\", \"projectName\": \"Support\", \"projectKey\": \"SUP\" }], \"truncated\": false }`."
14
+ + " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-servicedesk/#api-rest-servicedeskapi-servicedesk-get)",
15
+ version: "0.0.1",
16
+ type: "action",
17
+ annotations: {
18
+ destructiveHint: false,
19
+ openWorldHint: true,
20
+ readOnlyHint: true,
21
+ },
22
+ props: {
23
+ app,
24
+ cloudId: {
25
+ propDefinition: [
26
+ app,
27
+ "cloudId",
28
+ ],
29
+ },
30
+ maxResults: {
31
+ propDefinition: [
32
+ app,
33
+ "maxResults",
34
+ ],
35
+ },
36
+ },
37
+ async run({ $ }) {
38
+ const {
39
+ results, hasMore,
40
+ } = await this.app.getServiceDesks({
41
+ $,
42
+ cloudId: this.cloudId,
43
+ maxResults: this.maxResults,
44
+ });
45
+
46
+ const serviceDesks = results.map(({
47
+ id, projectId, projectName, projectKey, projectTypeKey,
48
+ }) => ({
49
+ id,
50
+ projectId,
51
+ projectName,
52
+ projectKey,
53
+ projectTypeKey,
54
+ }));
55
+
56
+ $.export("$summary", `Found ${serviceDesks.length} service desk${serviceDesks.length === 1
57
+ ? ""
58
+ : "s"}${hasMore
59
+ ? ", truncated at Max Results; raise it to fetch more"
60
+ : ""}`);
61
+ return {
62
+ serviceDesks,
63
+ truncated: hasMore,
64
+ };
65
+ },
66
+ };
@@ -8,7 +8,7 @@ export default {
8
8
  + " **Call this tool first** to obtain the `cloudId` (returned as `id`) required by every other Jira Service Desk tool."
9
9
  + " Each site includes its `id` (cloudId), `name`, and `url`."
10
10
  + " [See the documentation](https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/#3-1-get-the-cloudid-for-your-site)",
11
- version: "0.0.2",
11
+ version: "0.0.3",
12
12
  type: "action",
13
13
  annotations: {
14
14
  destructiveHint: false,
@@ -10,7 +10,7 @@ export default {
10
10
  + " Use **List My Requests** or **Get Request** to find the `issueKey` (e.g. `IT-42`)."
11
11
  + " Optionally include a comment to explain the transition."
12
12
  + " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-issueidorkey-transition-post)",
13
- version: "0.0.2",
13
+ version: "0.1.0",
14
14
  type: "action",
15
15
  annotations: {
16
16
  destructiveHint: false,
@@ -11,7 +11,7 @@ export default {
11
11
  + " `fields` is a JSON object of field name-value pairs."
12
12
  + " Example: `{\"summary\": \"Updated title\", \"priority\": {\"name\": \"High\"}}`."
13
13
  + " [See the documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-put)",
14
- version: "0.0.2",
14
+ version: "0.1.0",
15
15
  type: "action",
16
16
  annotations: {
17
17
  destructiveHint: false,
@@ -12,9 +12,15 @@ const MAX_RESULTS_DEFAULT = 100;
12
12
  const MAX_RESULTS_MIN = 1;
13
13
  const MAX_RESULTS_MAX = 1000;
14
14
 
15
+ const REQUEST_FIELD = {
16
+ SUMMARY: "summary",
17
+ DESCRIPTION: "description",
18
+ };
19
+
15
20
  export default {
16
21
  PAGE_SIZE,
17
22
  MAX_RESULTS_DEFAULT,
18
23
  MAX_RESULTS_MIN,
19
24
  MAX_RESULTS_MAX,
25
+ REQUEST_FIELD,
20
26
  };
@@ -1,3 +1,4 @@
1
+ // x-pd-ai: optimized
1
2
  import { axios } from "@pipedream/platform";
2
3
  import constants from "./common/constants.mjs";
3
4
 
@@ -8,70 +9,22 @@ export default {
8
9
  cloudId: {
9
10
  type: "string",
10
11
  label: "Cloud ID",
11
- description: "Select a site, or provide a custom ID.",
12
- async options() {
13
- const sites = await this.getSites();
14
- return sites?.filter?.(({ scopes }) => scopes?.includes("write:servicedesk-request")).map(({
15
- id, name,
16
- }) => ({
17
- label: name,
18
- value: id,
19
- }));
20
- },
12
+ description: "The Atlassian site (cloud) ID, e.g. `822faf0d-5427-420e-9016-999d3dc76918`. Run **List Sites** to get the `id` of every site you can access.",
21
13
  },
22
14
  serviceDeskId: {
23
15
  type: "string",
24
16
  label: "Service Desk ID",
25
- description: "Select a service desk, or provide a custom ID.",
26
- async options({ cloudId }) {
27
- const desks = await this.getServiceDesks({
28
- cloudId,
29
- });
30
- return desks?.map?.(({
31
- id, projectName,
32
- }) => ({
33
- label: projectName,
34
- value: id,
35
- }));
36
- },
17
+ description: "The numeric ID of the service desk, e.g. `1`. Run **List Service Desks** to find it from a project name or key.",
37
18
  },
38
19
  requestId: {
39
20
  type: "string",
40
21
  label: "Request ID",
41
- description: "Select a request, or provide a custom ID.",
42
- async options({ cloudId }) {
43
- const requests = await this.getCustomerRequests({
44
- cloudId,
45
- });
46
- return requests?.map?.(({
47
- issueId, issueKey, requestFieldValues,
48
- }) => {
49
- const summary = requestFieldValues?.find?.(({ fieldId }) => fieldId === "summary")?.value;
50
- return ({
51
- label: `(${issueKey}) ${summary}`,
52
- value: issueId,
53
- });
54
- });
55
- },
22
+ description: "The `issueId` of the customer request, e.g. `10288`. Run **List My Requests** to find it.",
56
23
  },
57
24
  requestTypeId: {
58
25
  type: "string",
59
26
  label: "Request Type ID",
60
- description: "Select a request type, or provide a custom ID.",
61
- async options({
62
- cloudId, serviceDeskId,
63
- }) {
64
- const types = await this.getRequestTypes({
65
- cloudId,
66
- serviceDeskId,
67
- });
68
- return types?.map?.(({
69
- id, name,
70
- }) => ({
71
- label: name,
72
- value: id,
73
- }));
74
- },
27
+ description: "The numeric ID of the request type, e.g. `4`. Run **List Request Types** to see what a service desk offers and pick the type matching the user's intent.",
75
28
  },
76
29
  issueIdOrKey: {
77
30
  type: "string",
@@ -87,6 +40,12 @@ export default {
87
40
  min: constants.MAX_RESULTS_MIN,
88
41
  max: constants.MAX_RESULTS_MAX,
89
42
  },
43
+ expand: {
44
+ type: "string[]",
45
+ label: "Expand",
46
+ description: "Additional data to include in the response, as a list of expansion names (e.g. `[\"field\"]`). Valid values differ per endpoint and are listed in the `_expands` property of that endpoint's response. Unrecognised names are ignored silently rather than rejected.",
47
+ optional: true,
48
+ },
90
49
  },
91
50
  methods: {
92
51
  _baseUrl() {
@@ -158,30 +117,34 @@ export default {
158
117
  });
159
118
  },
160
119
  async getServiceDesks({
161
- $, cloudId,
120
+ $, cloudId, maxResults,
162
121
  }) {
163
122
  const { results } = await this._paginate({
164
123
  $,
165
124
  path: `/ex/jira/${cloudId}/rest/servicedeskapi/servicedesk`,
125
+ maxResults,
166
126
  });
167
127
  return results;
168
128
  },
169
129
  async getRequestTypes({
170
- $, cloudId, serviceDeskId,
130
+ $, cloudId, serviceDeskId, params, maxResults,
171
131
  }) {
172
132
  const { results } = await this._paginate({
173
133
  $,
174
134
  path: `/ex/jira/${cloudId}/rest/servicedeskapi/servicedesk/${serviceDeskId}/requesttype`,
135
+ params,
136
+ maxResults,
175
137
  });
176
138
  return results;
177
139
  },
178
- async getRequestTypeFields({
179
- cloudId, serviceDeskId, requestTypeId,
140
+ async getRequestTypeCreateMeta({
141
+ $, cloudId, serviceDeskId, requestTypeId, params,
180
142
  }) {
181
- const response = await this._makeRequest({
143
+ return this._makeRequest({
144
+ $,
182
145
  path: `/ex/jira/${cloudId}/rest/servicedeskapi/servicedesk/${serviceDeskId}/requesttype/${requestTypeId}/field`,
146
+ params,
183
147
  });
184
- return response.requestTypeFields;
185
148
  },
186
149
  async getCustomerRequests({
187
150
  $, cloudId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipedream/jira_service_desk",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "Pipedream Jira Service Desk Components",
5
5
  "main": "jira_service_desk.app.mjs",
6
6
  "keywords": [
@@ -6,7 +6,7 @@ export default {
6
6
  name: "New Request Created",
7
7
  description:
8
8
  "Emit new event when a customer request is created. [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/#api-rest-servicedeskapi-request-get)",
9
- version: "0.0.3",
9
+ version: "0.1.0",
10
10
  type: "source",
11
11
  dedupe: "unique",
12
12
  methods: {
@@ -6,7 +6,7 @@ export default {
6
6
  name: "Request Status Updated",
7
7
  description:
8
8
  "Emit new event when a customer request is updated. [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/#api-rest-servicedeskapi-request-get)",
9
- version: "0.0.3",
9
+ version: "0.1.0",
10
10
  type: "source",
11
11
  dedupe: "unique",
12
12
  methods: {
@@ -1,107 +0,0 @@
1
- import app from "../../jira_service_desk.app.mjs";
2
-
3
- export default {
4
- key: "jira_service_desk-create-incident",
5
- name: "Create Incident",
6
- description:
7
- "Creates a new incident request in a Jira Service Desk."
8
- + " Auto-discovers the best-matching request type (prefers types named 'incident' or 'problem') and, if `serviceDeskId` is omitted, auto-discovers it from the user's existing requests."
9
- + " Use **List Sites** first to obtain the required `cloudId`."
10
- + " `serviceDeskId` is optional — if not provided, the tool calls **List My Requests** to discover it automatically."
11
- + " Returns the new request including its `issueKey` and `issueId`."
12
- + " [See the documentation](https://developer.atlassian.com/cloud/jira/service-desk/rest/api-group-request/#api-rest-servicedeskapi-request-post)",
13
- version: "0.0.2",
14
- type: "action",
15
- annotations: {
16
- destructiveHint: false,
17
- openWorldHint: true,
18
- readOnlyHint: false,
19
- },
20
- props: {
21
- app,
22
- cloudId: {
23
- propDefinition: [
24
- app,
25
- "cloudId",
26
- ],
27
- },
28
- serviceDeskId: {
29
- type: "string",
30
- label: "Service Desk ID",
31
- description: "The numeric ID of the service desk (e.g. `2`). If omitted, the tool auto-discovers it from your existing requests. You can also find it in your Jira Service Management project settings.",
32
- optional: true,
33
- },
34
- summary: {
35
- type: "string",
36
- label: "Summary",
37
- description: "The title/summary of the incident.",
38
- },
39
- description: {
40
- type: "string",
41
- label: "Description",
42
- description: "A detailed description of the incident.",
43
- },
44
- },
45
- async run({ $ }) {
46
- // Auto-discover serviceDeskId if not provided: extract from existing requests
47
- let serviceDeskId = this.serviceDeskId;
48
- if (!serviceDeskId) {
49
- const { results: existingRequests } = await this.app.listMyRequests({
50
- $,
51
- cloudId: this.cloudId,
52
- });
53
- if (!existingRequests?.length) {
54
- throw new Error("No existing requests found to auto-discover serviceDeskId. Please provide serviceDeskId explicitly.");
55
- }
56
- const uniqueIds = [
57
- ...new Set(existingRequests.map((r) => r.serviceDeskId)),
58
- ];
59
- if (uniqueIds.length > 1) {
60
- throw new Error(
61
- `Multiple service desks found (${uniqueIds.join(", ")}). Please provide serviceDeskId explicitly.`,
62
- );
63
- }
64
- serviceDeskId = uniqueIds[0];
65
- }
66
-
67
- // Auto-discover the best-matching request type for an incident.
68
- // Prefers types named "incident" or "problem"; falls back to first available.
69
- const requestTypes = await this.app.getRequestTypes({
70
- $,
71
- cloudId: this.cloudId,
72
- serviceDeskId,
73
- });
74
-
75
- if (!requestTypes?.length) {
76
- throw new Error(`No request types found in service desk ${serviceDeskId}.`);
77
- }
78
-
79
- const INCIDENT_KEYWORDS = [
80
- "incident",
81
- "problem",
82
- "system problem",
83
- "issue",
84
- ];
85
-
86
- const incidentType = requestTypes.find(({ name }) =>
87
- INCIDENT_KEYWORDS.some((kw) => name?.toLowerCase().includes(kw))) || requestTypes[0];
88
-
89
- const requestFieldValues = {
90
- summary: this.summary,
91
- description: this.description,
92
- };
93
-
94
- const response = await this.app.createCustomerRequest({
95
- $,
96
- cloudId: this.cloudId,
97
- data: {
98
- serviceDeskId,
99
- requestTypeId: incidentType.id,
100
- requestFieldValues,
101
- },
102
- });
103
-
104
- $.export("$summary", `Created ${incidentType.name} ${response.issueKey}: ${this.summary}`);
105
- return response;
106
- },
107
- };