/
pull.ts
132 lines (115 loc) · 4.24 KB
/
pull.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
(() => {
let creds = new Credentials();
var action = new PlugIn.Action(async () => {
try {
let req = URL.FetchRequest.fromString("https://api.linear.app/graphql");
if (!req?.url?.host) {
throw "could not parse the URL for Linear's API";
}
/////////////////////////////////////
// Step 1: make sure we have creds //
/////////////////////////////////////
let stored = creds.read(req.url.host);
let key = null;
if (stored === null || app.optionKeyDown) {
let credsForm = new Form();
credsForm.addField(new Form.Field.Password("key", "API Key"));
await credsForm.show(
"Please create a personal API key in the Linear settings and paste it here\n(hold option while activating this workflow in the future to reset this)",
"Save Key"
);
key = (credsForm.values as { key: string }).key;
creds.write(req.url.host, "-", key);
} else {
key = stored.password;
}
///////////////////////////
// Step 2: get the tasks //
///////////////////////////
req.method = "POST";
req.bodyString =
'{"query":"{ viewer { assignedIssues(filter: {state: {type: {nin: [\\"completed\\",\\"canceled\\"]}}}) { nodes { identifier title url dueDate team { name } project { name url } } } } }"}';
req.headers = {
"Content-Type": "application/json",
Authorization: key,
};
let resp = await req.fetch().catch((err) => {
console.error("Problem fetching tasks:", err);
let alert = new Alert("Problem fetching from Linear", err);
alert.show();
throw err;
});
if (resp.bodyString === null) {
throw "body string was null. Did the request succeed?";
}
let body = JSON.parse(resp.bodyString);
//////////////////////////////////
// Step 3: make the tasks in OF //
//////////////////////////////////
let toFocus: Array<Project> = [];
for (let linearTask of body.data.viewer.assignedIssues.nodes) {
let teamsTag = flattenedTags.byName("teams") || new Tag("teams");
let teamTag =
teamsTag.tagNamed(linearTask.team.name) ||
new Tag(linearTask.team.name, teamsTag);
let linearTag =
flattenedTags.byName("from Linear") || new Tag("from Linear");
let projectName = `${linearTask.team.name} Non-Project Tasks`;
if (linearTask.project !== null) {
projectName = linearTask.project.name;
}
let project =
flattenedProjects.byName(projectName) || new Project(projectName);
project.addTag(teamTag);
project.addTag(linearTag);
project.containsSingletonActions = true;
project.status = Project.Status.Active;
toFocus.push(project);
if (
linearTask.project &&
project.note.indexOf(linearTask.project.url) === -1
) {
if (project.note !== "") {
project.appendStringToNote(`\n\n${linearTask.project.url}`);
} else {
project.appendStringToNote(linearTask.project.url);
}
}
let taskName = `${linearTask.identifier}: ${linearTask.title}`;
let task =
project.flattenedTasks.byName(taskName) ||
new Task(taskName, project);
task.addTag(teamTag);
task.addTag(linearTag);
task.markIncomplete();
if (task.note.indexOf(linearTask.url) === -1) {
if (task.note !== "") {
task.appendStringToNote(`\n\n${linearTask.url}`);
} else {
task.appendStringToNote(linearTask.url);
}
}
if (linearTask.dueDate) {
// set the date but strip off the time component
let date = new Date(linearTask.dueDate);
task.dueDate = new Date(
date.getFullYear(),
date.getMonth(),
date.getDate(),
0,
0,
0
);
}
}
if (app.platformName === "macOS") {
document.windows[0].perspective = Perspective.BuiltIn.Projects;
document.windows[0].focus = toFocus as SectionArray;
}
} catch (err) {
console.error(err);
throw err;
}
});
return action;
})();