swiftbar-github 1.0.0 → 1.1.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 +2 -0
- package/assets/github.svg +1 -1
- package/dist/swiftbar-github.js +74 -18
- package/package.json +1 -1
- package/swiftbar-github.3m.sh +5 -0
package/README.md
CHANGED
|
@@ -17,3 +17,5 @@ Download [swiftbar-github.3m.sh](https://cdn.jsdelivr.net/npm/swiftbar-github@la
|
|
|
17
17
|
Run `chmod +x swiftbar-github.3m.sh`. Updates resolve through `@latest` on each refresh; downloaded versions are cached. For authentication without `gh`, set `GH_TOKEN` or `GITHUB_TOKEN` in SwiftBar's environment.
|
|
18
18
|
|
|
19
19
|
Allow notifications for the bundled terminal-notifier in macOS System Settings. Click entries to open them on GitHub.
|
|
20
|
+
|
|
21
|
+
Use **Mark as read** to clear unread threads by type or reason. This does not complete pending review requests. Option-click the menu to access SwiftBar's hidden controls.
|
package/assets/github.svg
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
2
|
-
<path d="
|
|
2
|
+
<path transform="translate(4 4)" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"/>
|
|
3
3
|
</svg>
|
package/dist/swiftbar-github.js
CHANGED
|
@@ -83,13 +83,14 @@ function notify(item) {
|
|
|
83
83
|
notifier.notify(notification, (error) => resolve(!error));
|
|
84
84
|
});
|
|
85
85
|
}
|
|
86
|
-
function action(label,
|
|
86
|
+
function action(label, args, refresh = false) {
|
|
87
87
|
if (!launcher)
|
|
88
88
|
return `${label} | href=${inbox}`;
|
|
89
|
-
|
|
89
|
+
const params = args.map((arg, index) => `param${index + 1}=${arg}`).join(" ");
|
|
90
|
+
return `${label} | bash="${launcher.replaceAll('"', '\\"')}" ${params} terminal=false${refresh ? " refresh=true" : ""}`;
|
|
90
91
|
}
|
|
91
|
-
async function
|
|
92
|
-
|
|
92
|
+
async function client() {
|
|
93
|
+
return new Octokit({
|
|
93
94
|
auth: await token(),
|
|
94
95
|
userAgent: "swiftbar-github",
|
|
95
96
|
request: {
|
|
@@ -103,6 +104,9 @@ async function fetchActivity(argument) {
|
|
|
103
104
|
},
|
|
104
105
|
log: { debug() { }, info() { }, warn() { }, error() { } },
|
|
105
106
|
});
|
|
107
|
+
}
|
|
108
|
+
async function fetchActivity(argument) {
|
|
109
|
+
const github = await client();
|
|
106
110
|
const { data: user } = await github.rest.users.getAuthenticated();
|
|
107
111
|
const requested = await github.paginate(github.rest.search.issuesAndPullRequests, {
|
|
108
112
|
q: `is:pr is:open archived:false review-requested:${user.login}`,
|
|
@@ -127,7 +131,7 @@ async function fetchActivity(argument) {
|
|
|
127
131
|
};
|
|
128
132
|
});
|
|
129
133
|
if (argument === "open-reviews")
|
|
130
|
-
return { reviews, notifications: [] };
|
|
134
|
+
return { reviews, notifications: [], unread: [] };
|
|
131
135
|
const reviewURLs = new Set(reviews.map((item) => item.url));
|
|
132
136
|
const unread = await github.paginate(github.rest.activity.listNotificationsForAuthenticatedUser, {
|
|
133
137
|
all: false,
|
|
@@ -151,21 +155,21 @@ async function fetchActivity(argument) {
|
|
|
151
155
|
reason,
|
|
152
156
|
};
|
|
153
157
|
});
|
|
154
|
-
return { reviews, notifications };
|
|
158
|
+
return { reviews, notifications, unread };
|
|
155
159
|
}
|
|
156
|
-
function renderMenu(reviews, notifications) {
|
|
160
|
+
function renderMenu(reviews, notifications, unread) {
|
|
157
161
|
const total = reviews.length + notifications.length;
|
|
158
162
|
if (!total)
|
|
159
163
|
return "";
|
|
160
164
|
const menu = [
|
|
161
|
-
`${total} | templateImage=${icon}`,
|
|
165
|
+
`${process.env.SWIFTBAR_GITHUB_DEV ? "Dev " : ""}${total} | templateImage=${icon}`,
|
|
162
166
|
"---",
|
|
163
167
|
`Review requests (${reviews.length}) | color=gray`,
|
|
164
168
|
];
|
|
165
169
|
if (reviews.length) {
|
|
166
170
|
for (const item of reviews)
|
|
167
171
|
menu.push(`${item.repository} ${item.title} | href=${item.url}`);
|
|
168
|
-
menu.push(action("Open all review requests", "open-reviews"));
|
|
172
|
+
menu.push(action("Open all review requests", ["open-reviews"]));
|
|
169
173
|
}
|
|
170
174
|
else
|
|
171
175
|
menu.push("No reviews requested | color=gray");
|
|
@@ -173,37 +177,89 @@ function renderMenu(reviews, notifications) {
|
|
|
173
177
|
if (notifications.length) {
|
|
174
178
|
for (const item of notifications)
|
|
175
179
|
menu.push(`${item.repository} [${item.reason}]: ${item.title} | href=${item.url}`);
|
|
176
|
-
menu.push(action("Open all notifications", "open-notifications"));
|
|
180
|
+
menu.push(action("Open all notifications", ["open-notifications"]));
|
|
177
181
|
}
|
|
178
182
|
else
|
|
179
183
|
menu.push("No unread notifications | color=gray");
|
|
184
|
+
if (unread.length) {
|
|
185
|
+
const types = {
|
|
186
|
+
PullRequest: "Pull requests",
|
|
187
|
+
Issue: "Issues",
|
|
188
|
+
Discussion: "Discussions",
|
|
189
|
+
Commit: "Commits",
|
|
190
|
+
Release: "Releases",
|
|
191
|
+
};
|
|
192
|
+
menu.push("---", "Mark as read");
|
|
193
|
+
menu.push(`--${action(`All notifications (${unread.length})`, ["mark-read", unread.map((item) => item.id).join(",")], true)}`);
|
|
194
|
+
for (const [heading, labelFor] of [
|
|
195
|
+
[
|
|
196
|
+
"By type",
|
|
197
|
+
(item) => text(types[item.subject.type] || item.subject.type),
|
|
198
|
+
],
|
|
199
|
+
[
|
|
200
|
+
"By reason",
|
|
201
|
+
(item) => text(item.reason).replaceAll("_", " "),
|
|
202
|
+
],
|
|
203
|
+
]) {
|
|
204
|
+
const groups = new Map();
|
|
205
|
+
for (const item of unread) {
|
|
206
|
+
const label = labelFor(item);
|
|
207
|
+
const ids = groups.get(label) || [];
|
|
208
|
+
ids.push(item.id);
|
|
209
|
+
groups.set(label, ids);
|
|
210
|
+
}
|
|
211
|
+
menu.push("-----", `--${heading} | color=gray`);
|
|
212
|
+
for (const [label, ids] of [...groups].sort(([a], [b]) => a.localeCompare(b)))
|
|
213
|
+
menu.push(`--${action(`${label} (${ids.length})`, ["mark-read", ids.join(",")], true)}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
180
216
|
return menu.join("\n");
|
|
181
217
|
}
|
|
182
|
-
async function deliverAlerts(file, items) {
|
|
218
|
+
async function deliverAlerts(file, items, represented = []) {
|
|
183
219
|
await mkdir(cache, { recursive: true });
|
|
184
220
|
const path = join(cache, file);
|
|
185
221
|
const seen = await state(path);
|
|
186
|
-
const current =
|
|
222
|
+
const current = new Set(represented);
|
|
187
223
|
for (const item of items) {
|
|
224
|
+
if (current.has(item.key))
|
|
225
|
+
continue;
|
|
188
226
|
if (!seen || seen.has(item.key) || (await notify(item)))
|
|
189
|
-
current.
|
|
227
|
+
current.add(item.key);
|
|
190
228
|
}
|
|
191
|
-
await save(path, current);
|
|
229
|
+
await save(path, [...current]);
|
|
192
230
|
}
|
|
193
231
|
async function main() {
|
|
194
232
|
const argument = process.argv[2];
|
|
195
|
-
if (argument &&
|
|
233
|
+
if (argument &&
|
|
234
|
+
!["open-reviews", "open-notifications", "mark-read"].includes(argument))
|
|
196
235
|
throw new Error("Usage: swiftbar-github");
|
|
197
|
-
|
|
236
|
+
if (argument === "mark-read") {
|
|
237
|
+
const ids = (process.argv[3] || "").split(",").map(Number);
|
|
238
|
+
if (ids.some((id) => !Number.isSafeInteger(id) || id <= 0))
|
|
239
|
+
throw new Error("Usage: swiftbar-github mark-read <thread-ids>");
|
|
240
|
+
const github = await client();
|
|
241
|
+
for (const id of ids)
|
|
242
|
+
await github.rest.activity.markThreadAsRead({ thread_id: id });
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const { reviews, notifications, unread } = await fetchActivity(argument);
|
|
198
246
|
if (argument) {
|
|
199
247
|
const items = argument === "open-reviews" ? reviews : notifications;
|
|
200
248
|
for (const item of items)
|
|
201
249
|
await exec("/usr/bin/open", ["-g", item.url]);
|
|
202
250
|
return;
|
|
203
251
|
}
|
|
204
|
-
const menu = renderMenu(reviews, notifications);
|
|
252
|
+
const menu = renderMenu(reviews, notifications, unread);
|
|
253
|
+
const previousReviews = await state(join(cache, "requested-prs"));
|
|
254
|
+
const reviewURLs = new Set([
|
|
255
|
+
...reviews.map((item) => item.url),
|
|
256
|
+
...(previousReviews || []),
|
|
257
|
+
]);
|
|
258
|
+
const represented = unread
|
|
259
|
+
.filter((item) => item.reason === "review_requested" && reviewURLs.has(webURL(item)))
|
|
260
|
+
.map((item) => `${item.id}:${item.updated_at}`);
|
|
205
261
|
await deliverAlerts("requested-prs", reviews);
|
|
206
|
-
await deliverAlerts("inbox-notifications", notifications);
|
|
262
|
+
await deliverAlerts("inbox-notifications", notifications, represented);
|
|
207
263
|
if (menu)
|
|
208
264
|
console.log(menu);
|
|
209
265
|
}
|
package/package.json
CHANGED
package/swiftbar-github.3m.sh
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
+
# <swiftbar.hideAbout>true</swiftbar.hideAbout>
|
|
3
|
+
# <swiftbar.hideRunInTerminal>true</swiftbar.hideRunInTerminal>
|
|
4
|
+
# <swiftbar.hideLastUpdated>true</swiftbar.hideLastUpdated>
|
|
5
|
+
# <swiftbar.hideDisablePlugin>true</swiftbar.hideDisablePlugin>
|
|
6
|
+
# <swiftbar.hideSwiftBar>true</swiftbar.hideSwiftBar>
|
|
2
7
|
|
|
3
8
|
if output=$(npx --yes swiftbar-github@latest "$@" 2>/dev/null); then
|
|
4
9
|
[[ -z "$output" ]] || printf '%s\n' "$output"
|