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
|
import {CachedFunction} from 'webext-storage-cache';
import {elementExists} from 'select-dom';
import elementReady from 'element-ready';
import * as pageDetect from 'github-url-detection';
import features from '../feature-manager.js';
import api, {expectTokenScope} from '../github-helpers/api.js';
import {cacheByRepo} from '../github-helpers/index.js';
import HasAnyProjects from './clean-conversation-filters.gql';
const hasAnyProjects = new CachedFunction('has-projects', {
async updater(): Promise<boolean> {
const activeProjectsCounter = await elementReady('[data-hotkey="g b"] .Counter');
if (activeProjectsCounter && getCount(activeProjectsCounter) > 0) {
return true;
}
const isOrganization = elementExists('[rel=author][data-hovercard-type="organization"]');
if (!activeProjectsCounter && !isOrganization) {
// No tab = Projects disabled in repo
// No organization = no Projects in organization
return false;
}
await expectTokenScope('read:project');
const {repository, organization} = await api.v4(HasAnyProjects, {
allowErrors: true,
});
return Boolean(repository.projects.totalCount)
|| Boolean(repository.projectsV2.totalCount)
|| Boolean(organization?.projects?.totalCount)
|| Boolean(organization?.projectsV2?.totalCount);
},
maxAge: {days: 1},
staleWhileRevalidate: {days: 20},
cacheKey: cacheByRepo,
});
function getCount(element: HTMLElement): number {
return Number(element.textContent.trim());
}
async function hideMilestones(): Promise<void> {
const milestones = await elementReady('[data-selected-links^="repo_milestones"] .Counter');
if (getCount(milestones!) === 0) {
(await elementReady('[data-hotkey="m"]'))!.parentElement!.remove();
}
}
async function hideProjects(): Promise<void> {
const projectsDropdown = await elementReady('[data-hotkey="p"]');
projectsDropdown?.parentElement!.remove();
}
// Toolbar is shown only if the repo has ever had an issue/PR
async function hasConversations(): Promise<boolean> {
return Boolean(elementReady('#js-issues-toolbar', {waitForChildren: false}));
}
void features.add(import.meta.url, {
asLongAs: [
hasConversations,
],
include: [
pageDetect.isRepoIssueOrPRList,
],
deduplicate: 'has-rgh-inner',
init: hideMilestones,
}, {
asLongAs: [
hasConversations,
],
include: [
pageDetect.isRepoIssueOrPRList,
],
exclude: [
async () => hasAnyProjects.get(),
],
deduplicate: 'has-rgh-inner',
init: hideProjects,
});
/*
Test URLs:
- Has conversations: https://github.com/refined-github/refined-github/pulls
- No conversations: https://github.com/fregante/empty/pulls
*/
|