@pipedream/linear_app 0.5.0 → 0.5.2

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.
@@ -5,7 +5,7 @@ export default {
5
5
  key: "linear_app-create-issue",
6
6
  name: "Create Issue",
7
7
  description: "Create an issue (API Key). See the docs [here](https://developers.linear.app/docs/graphql/working-with-the-graphql-api#creating-and-editing-issues)",
8
- version: "0.4.0",
8
+ version: "0.4.2",
9
9
  props: {
10
10
  linearApp,
11
11
  teamId: {
@@ -4,7 +4,7 @@ export default {
4
4
  key: "linear_app-get-issue",
5
5
  name: "Get Issue",
6
6
  description: "Get an issue by ID (API Key). See the docs [here](https://developers.linear.app/docs/graphql/working-with-the-graphql-api)",
7
- version: "0.1.0",
7
+ version: "0.1.2",
8
8
  type: "action",
9
9
  props: {
10
10
  linearApp,
@@ -4,7 +4,7 @@ export default {
4
4
  key: "linear_app-get-teams",
5
5
  name: "Get Teams",
6
6
  description: "Get all the teams (API Key). See the docs [here](https://developers.linear.app/docs/graphql/working-with-the-graphql-api)",
7
- version: "0.2.0",
7
+ version: "0.2.2",
8
8
  type: "action",
9
9
  props: {
10
10
  linearApp,
@@ -1,12 +1,12 @@
1
- import constants from "../../common/constants.mjs";
2
1
  import linearApp from "../../linear_app.app.mjs";
2
+ import utils from "../../common/utils.mjs";
3
3
 
4
4
  export default {
5
5
  key: "linear_app-search-issues",
6
6
  name: "Search Issues",
7
7
  description: "Search issues (API Key). See the docs [here](https://developers.linear.app/docs/graphql/working-with-the-graphql-api)",
8
8
  type: "action",
9
- version: "0.2.0",
9
+ version: "0.2.2",
10
10
  props: {
11
11
  linearApp,
12
12
  query: {
@@ -53,57 +53,27 @@ export default {
53
53
  ],
54
54
  },
55
55
  },
56
- methods: {
57
- buildFilter() {
58
- return {
59
- title: {
60
- containsIgnoreCase: this.query,
61
- },
62
- team: {
63
- id: {
64
- eq: this.teamId,
65
- },
66
- },
67
- project: {
68
- id: {
69
- eq: this.projectId,
70
- },
71
- },
72
- assignee: {
73
- id: {
74
- eq: this.assigneeId,
75
- },
76
- },
77
- labels: {
78
- name: {
79
- in: this.issueLabels,
80
- },
81
- },
82
- };
83
- },
84
- },
85
56
  async run({ $ }) {
86
- const {
87
- orderBy,
88
- includeArchived,
89
- } = this;
90
-
91
57
  const issues = [];
92
58
  let hasNextPage;
93
59
  let after;
94
- const filter = this.buildFilter();
95
60
 
96
61
  do {
62
+ const variables = utils.buildVariables(after, {
63
+ filter: {
64
+ query: this.query,
65
+ teamId: this.teamId,
66
+ projectId: this.projectId,
67
+ assigneeId: this.assigneeId,
68
+ issueLabels: this.issueLabels,
69
+ },
70
+ orderBy: this.orderBy,
71
+ includeArchived: this.includeArchived,
72
+ });
97
73
  const {
98
74
  nodes,
99
75
  pageInfo,
100
- } = await this.linearApp.searchIssues({
101
- filter,
102
- orderBy,
103
- after,
104
- includeArchived,
105
- first: constants.DEFAULT_LIMIT,
106
- });
76
+ } = await this.linearApp.listIssues(variables);
107
77
 
108
78
  issues.push(...nodes);
109
79
  after = pageInfo.endCursor;
@@ -5,7 +5,7 @@ export default {
5
5
  name: "Update Issue",
6
6
  description: "Update an issue (API Key). See the docs [here](https://developers.linear.app/docs/graphql/working-with-the-graphql-api#creating-and-editing-issues)",
7
7
  type: "action",
8
- version: "0.1.0",
8
+ version: "0.1.2",
9
9
  props: {
10
10
  linearApp,
11
11
  teamId: {
@@ -43,6 +43,65 @@ const ORDER_BY_OPTIONS = [
43
43
  },
44
44
  ];
45
45
 
46
+ const ISSUE_NODES = `
47
+ id
48
+ title
49
+ description
50
+ boardOrder
51
+ branchName
52
+ createdAt
53
+ customerTicketCount
54
+ identifier
55
+ number
56
+ priority
57
+ priorityLabel
58
+ sortOrder
59
+ updatedAt
60
+ url
61
+ assignee {
62
+ id
63
+ name
64
+ email
65
+ }
66
+ creator {
67
+ id
68
+ name
69
+ email
70
+ }
71
+ project {
72
+ id
73
+ name
74
+ }
75
+ state {
76
+ id
77
+ name
78
+ }
79
+ team {
80
+ id
81
+ name
82
+ }
83
+ `;
84
+
85
+ const COMMENT_NODES = `
86
+ id
87
+ body
88
+ createdAt
89
+ reactionData
90
+ updatedAt
91
+ issue {
92
+ id
93
+ title
94
+ project {
95
+ id
96
+ name
97
+ }
98
+ }
99
+ user {
100
+ id
101
+ name
102
+ }
103
+ `;
104
+
46
105
  export default {
47
106
  WEBHOOK_ID,
48
107
  LINEAR_DELIVERY_HEADER,
@@ -54,4 +113,6 @@ export default {
54
113
  CLIENT_IPS,
55
114
  ORDER_BY_OPTIONS,
56
115
  FIELD,
116
+ ISSUE_NODES,
117
+ COMMENT_NODES,
57
118
  };
package/common/utils.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import constants from "./constants.mjs";
2
+
1
3
  async function streamIterator(stream) {
2
4
  const resources = [];
3
5
  for await (const resource of stream) {
@@ -6,6 +8,49 @@ async function streamIterator(stream) {
6
8
  return resources;
7
9
  }
8
10
 
11
+ function buildVariables(endCursor, args) {
12
+ const title = args.filter.query
13
+ ? `title: { containsIgnoreCase: "${args.filter.query}" }`
14
+ : "";
15
+ const teamId = args.filter.teamId
16
+ ? `, team: { id: { eq: "${args.filter.teamId}" } }`
17
+ : "";
18
+ const projectId = args.filter.projectId
19
+ ? `, project: { id: { eq: "${args.filter.projectId}" } }`
20
+ : "";
21
+ const team = args.filter.team
22
+ ? `, team: { id: { in: ${JSON.stringify(args.filter.team.id.in)} } }`
23
+ : "";
24
+ const project = args.filter.project && args.filter.project.id.eq
25
+ ? `, project: { id: { eq: "${args.filter.project.id.eq}" } }`
26
+ : "";
27
+ const state = args.filter.state
28
+ ? `, state: { id: { eq: "${args.filter.state.id.eq}" } }`
29
+ : "";
30
+ const assigneeId = args.filter.assigneeId
31
+ ? `, assignee: { id: { eq: "${args.filter.assigneeId}" } }`
32
+ : "";
33
+ const issueLabels = args.filter.issueLabels
34
+ ? `, labels: { name: { in: ${JSON.stringify(args.filter.issueLabels)} } }`
35
+ : "";
36
+ let filter = `${title}${teamId}${projectId}${team}${project}${state}${assigneeId}${issueLabels}`;
37
+ if (filter[0] === ",") {
38
+ filter = filter.substring(2, filter.length);
39
+ }
40
+
41
+ const orderBy = args.orderBy
42
+ ? `, orderBy: ${args.orderBy}`
43
+ : "";
44
+ const includeArchived = args.includeArchived
45
+ ? `, includeArchived: ${args.includeArchived}`
46
+ : "";
47
+ const after = endCursor
48
+ ? `, after: "${endCursor}"`
49
+ : "";
50
+ return `filter: { ${filter} }, first: ${constants.DEFAULT_LIMIT}${orderBy}${includeArchived}${after}`;
51
+ }
52
+
9
53
  export default {
10
54
  streamIterator,
55
+ buildVariables,
11
56
  };
@@ -1,5 +1,6 @@
1
1
  import { LinearClient } from "@linear/sdk";
2
2
  import constants from "./common/constants.mjs";
3
+ import utils from "./common/utils.mjs";
3
4
  import { axios } from "@pipedream/platform";
4
5
 
5
6
  export default {
@@ -203,11 +204,51 @@ export default {
203
204
  }) {
204
205
  return this.client().updateIssue(issueId, input);
205
206
  },
206
- async searchIssues(variables) {
207
- return this.client().issues(variables);
207
+ async listIssues(variables) {
208
+ const { data: { issues } } = await this.makeAxiosRequest({
209
+ method: "POST",
210
+ data: {
211
+ query: `
212
+ {
213
+ issues(${variables}) {
214
+ nodes {
215
+ ${constants.ISSUE_NODES}
216
+ }
217
+ pageInfo {
218
+ hasNextPage
219
+ endCursor
220
+ }
221
+ }
222
+ }`,
223
+ },
224
+ });
225
+ return issues;
208
226
  },
209
227
  async getIssue(id) {
210
- return this.client().issue(id);
228
+ const { data: { issue } } = await this.makeAxiosRequest({
229
+ method: "POST",
230
+ data: {
231
+ query: `
232
+ {
233
+ issue(id: "${id}") {
234
+ ${constants.ISSUE_NODES}
235
+ }
236
+ }`,
237
+ },
238
+ });
239
+ return issue;
240
+ },
241
+ async getUser(id) {
242
+ return this.client().user(id);
243
+ },
244
+ async getProject(id) {
245
+ return this.client().project(id);
246
+ },
247
+ async getState(id) {
248
+ return this.client().workflowState(id);
249
+ },
250
+ async getTeam(id) {
251
+ return this.client().team(id);
211
252
  },
212
253
  async listTeams(variables = {}) {
213
254
  return this.client().teams(variables);
@@ -227,15 +268,26 @@ export default {
227
268
  async listStates(variables = {}) {
228
269
  return this.client().workflowStates(variables);
229
270
  },
230
- async listIssues(variables = {}) {
231
- return this.client().issues(variables);
232
- },
233
271
  async listIssueLabels(variables = {}) {
234
272
  return this.client().issueLabels(variables);
235
273
  },
236
274
  async listComments(variables = {}) {
237
275
  return this.client().comments(variables);
238
276
  },
277
+ async getComment(id) {
278
+ const { data: { comment } } = await this.makeAxiosRequest({
279
+ method: "POST",
280
+ data: {
281
+ query: `
282
+ {
283
+ comment(id: "${id}") {
284
+ ${constants.COMMENT_NODES}
285
+ }
286
+ }`,
287
+ },
288
+ });
289
+ return comment;
290
+ },
239
291
  async listResourcesOptions({
240
292
  prevContext, resourcesFn, resourcesArgs, resouceMapper,
241
293
  } = {}) {
@@ -270,19 +322,23 @@ export default {
270
322
  resourcesFn,
271
323
  resourcesFnArgs,
272
324
  max = constants.DEFAULT_MAX_RECORDS,
325
+ useGraphQl = true,
273
326
  }) {
274
327
  let counter = 0;
275
328
  let hasNextPage;
276
329
  let endCursor;
277
330
  do {
331
+ const variables = useGraphQl
332
+ ? utils.buildVariables(endCursor, resourcesFnArgs)
333
+ : {
334
+ after: endCursor,
335
+ first: constants.DEFAULT_LIMIT,
336
+ ...resourcesFnArgs,
337
+ };
278
338
  const {
279
339
  nodes,
280
340
  pageInfo,
281
- } = await resourcesFn({
282
- after: endCursor,
283
- first: constants.DEFAULT_LIMIT,
284
- ...resourcesFnArgs,
285
- });
341
+ } = await resourcesFn(variables);
286
342
  for (const node of nodes) {
287
343
  counter += 1;
288
344
  yield node;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipedream/linear_app",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Pipedream Linear_app Components",
5
5
  "main": "linear_app.app.mjs",
6
6
  "keywords": [
@@ -7,7 +7,7 @@ export default {
7
7
  name: "New Created Comment (Instant)",
8
8
  description: "Emit new event when a new comment is created. See the docs [here](https://developers.linear.app/docs/graphql/webhooks)",
9
9
  type: "source",
10
- version: "0.1.0",
10
+ version: "0.1.2",
11
11
  dedupe: "unique",
12
12
  methods: {
13
13
  ...common.methods,
@@ -22,6 +22,13 @@ export default {
22
22
  getResourcesFn() {
23
23
  return this.linearApp.listComments;
24
24
  },
25
+ useGraphQl() {
26
+ return false;
27
+ },
28
+ async isFromProject(body) {
29
+ const comment = await this.linearApp.getComment(body.data.id);
30
+ return !this.projectId || comment?.issue?.project?.id == this.projectId;
31
+ },
25
32
  getResourcesFnArgs() {
26
33
  return {
27
34
  sortBy: "createdAt",
@@ -38,6 +38,9 @@ export default {
38
38
  isRelevant() {
39
39
  return true;
40
40
  },
41
+ useGraphQl() {
42
+ return true;
43
+ },
41
44
  getResourceTypes() {
42
45
  throw new Error("getResourceTypes is not implemented");
43
46
  },
@@ -64,6 +67,7 @@ export default {
64
67
  const stream = this.linearApp.paginateResources({
65
68
  resourcesFn: this.getResourcesFn(),
66
69
  resourcesFnArgs: this.getResourcesFnArgs(),
70
+ useGraphQl: this.useGraphQl(),
67
71
  });
68
72
  const resources = await utils.streamIterator(stream);
69
73
 
@@ -74,7 +78,10 @@ export default {
74
78
  });
75
79
  },
76
80
  async activate() {
77
- for (const teamId of this.teamIds) {
81
+ const teamIds = this.teamIds || [
82
+ this.teamId,
83
+ ];
84
+ for (const teamId of teamIds) {
78
85
  const { _webhook: webhook } =
79
86
  await this.linearApp.createWebhook({
80
87
  teamId,
@@ -86,7 +93,10 @@ export default {
86
93
  }
87
94
  },
88
95
  async deactivate() {
89
- for (const teamId of this.teamIds) {
96
+ const teamIds = this.teamIds || [
97
+ this.teamId,
98
+ ];
99
+ for (const teamId of teamIds) {
90
100
  const webhookId = this.getWebhookId(teamId);
91
101
  if (webhookId) {
92
102
  await this.linearApp.deleteWebhook(webhookId);
@@ -113,7 +123,7 @@ export default {
113
123
  return;
114
124
  }
115
125
 
116
- if (!this.isFromProject(body) || !this.isRelevant(body)) {
126
+ if (!(await this.isFromProject(body)) || !this.isRelevant(body)) {
117
127
  return;
118
128
  }
119
129
 
@@ -7,7 +7,7 @@ export default {
7
7
  name: "New Created Issue (Instant)",
8
8
  description: "Emit new event when a new issue is created. See the docs [here](https://developers.linear.app/docs/graphql/webhooks)",
9
9
  type: "source",
10
- version: "0.3.0",
10
+ version: "0.3.2",
11
11
  dedupe: "unique",
12
12
  methods: {
13
13
  ...common.methods,
@@ -24,7 +24,7 @@ export default {
24
24
  },
25
25
  getResourcesFnArgs() {
26
26
  return {
27
- sortBy: "createdAt",
27
+ orderBy: "createdAt",
28
28
  filter: {
29
29
  team: {
30
30
  id: {
@@ -7,7 +7,7 @@ export default {
7
7
  name: "New Updated Issue (Instant)",
8
8
  description: "Emit new event when an issue is updated. See the docs [here](https://developers.linear.app/docs/graphql/webhooks)",
9
9
  type: "source",
10
- version: "0.3.0",
10
+ version: "0.3.2",
11
11
  dedupe: "unique",
12
12
  methods: {
13
13
  ...common.methods,
@@ -24,7 +24,7 @@ export default {
24
24
  },
25
25
  getResourcesFnArgs() {
26
26
  return {
27
- sortBy: "updatedAt",
27
+ orderBy: "updatedAt",
28
28
  filter: {
29
29
  team: {
30
30
  id: {
@@ -7,8 +7,37 @@ export default {
7
7
  name: "New Issue Status Updated (Instant)",
8
8
  description: "Emit new event when the status of an issue is updated. See the docs [here](https://developers.linear.app/docs/graphql/webhooks)",
9
9
  type: "source",
10
- version: "0.1.0",
10
+ version: "0.1.2",
11
11
  dedupe: "unique",
12
+ props: {
13
+ linearApp: common.props.linearApp,
14
+ http: common.props.http,
15
+ db: common.props.db,
16
+ teamId: {
17
+ label: "Team ID",
18
+ type: "string",
19
+ propDefinition: [
20
+ common.props.linearApp,
21
+ "teamId",
22
+ ],
23
+ },
24
+ projectId: {
25
+ propDefinition: [
26
+ common.props.linearApp,
27
+ "projectId",
28
+ ],
29
+ },
30
+ stateId: {
31
+ propDefinition: [
32
+ common.props.linearApp,
33
+ "stateId",
34
+ ({ teamId }) => ({
35
+ teamId,
36
+ }),
37
+ ],
38
+ description: "Emit issues that are updated to this state",
39
+ },
40
+ },
12
41
  methods: {
13
42
  ...common.methods,
14
43
  getResourceTypes() {
@@ -28,7 +57,9 @@ export default {
28
57
  filter: {
29
58
  team: {
30
59
  id: {
31
- in: this.teamIds,
60
+ in: [
61
+ this.teamId,
62
+ ],
32
63
  },
33
64
  },
34
65
  project: {
@@ -36,11 +67,16 @@ export default {
36
67
  eq: this.projectId,
37
68
  },
38
69
  },
70
+ state: {
71
+ id: {
72
+ eq: this.stateId,
73
+ },
74
+ },
39
75
  },
40
76
  };
41
77
  },
42
78
  isRelevant(body) {
43
- return body?.updatedFrom?.stateId;
79
+ return body?.updatedFrom?.stateId && (!this.stateId || body.data.stateId === this.stateId);
44
80
  },
45
81
  getMetadata(resource) {
46
82
  const {