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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
import React from 'dom-chef';
import cache from 'webext-storage-cache';
import select from 'select-dom';
import TagIcon from 'octicon/tag.svg';
import elementReady from 'element-ready';
import * as pageDetect from 'github-url-detection';
import features from '.';
import * as api from '../github-helpers/api';
import looseParseInt from '../helpers/loose-parse-int';
import {appendBefore} from '../helpers/dom-utils';
import {createDropdownItem} from './more-dropdown';
import {buildRepoURL, getRepo} from '../github-helpers';
const getCacheKey = (): string => `releases-count:${getRepo()!.nameWithOwner}`;
function parseCountFromDom(): number {
const releasesCountElement = select('.numbers-summary a[href$="/releases"] .num');
if (releasesCountElement) {
return looseParseInt(releasesCountElement);
}
// In "Repository refresh" layout, look for the releases link in the sidebar
const moreReleasesCountElement = select('[href$="/tags"] strong');
if (moreReleasesCountElement) {
return looseParseInt(moreReleasesCountElement);
}
return 0;
}
async function fetchFromApi(): Promise<number> {
const {repository} = await api.v4(`
repository() {
refs(refPrefix: "refs/tags/") {
totalCount
}
}
`);
return repository.refs.totalCount;
}
const getReleaseCount = cache.function(async () => pageDetect.isRepoRoot() ? parseCountFromDom() : fetchFromApi(), {
maxAge: {hours: 1},
staleWhileRevalidate: {days: 3},
cacheKey: getCacheKey
});
async function init(): Promise<false | void> {
// Always prefer the information in the DOM
if (pageDetect.isRepoRoot()) {
await cache.delete(getCacheKey());
}
const count = await getReleaseCount();
if (count === 0) {
return false;
}
// Wait for the tab bar to be loaded
await elementReady([
'.pagehead + *', // Pre "Repository refresh" layout
'.UnderlineNav-body + *'
].join());
const repoNavigationBar = select('.js-responsive-underlinenav');
if (repoNavigationBar) {
// "Repository refresh" layout
const releasesTab = (
<a
href={buildRepoURL('releases')}
className="js-selected-navigation-item UnderlineNav-item hx_underlinenav-item no-wrap js-responsive-underlinenav-item"
data-hotkey="g r"
data-selected-links="repo_releases"
data-tab-item="rgh-releases-item"
>
<TagIcon className="UnderlineNav-octicon"/>
<span data-content="Releases">Releases</span>
{count && <span className="Counter">{count}</span>}
</a>
);
select(':scope > ul', repoNavigationBar)!.append(
<li className="d-flex">
{releasesTab}
</li>
);
// This re-triggers the overflow listener forcing it to also hide this tab if necessary #3347
repoNavigationBar.replaceWith(repoNavigationBar);
// Update "selected" tab mark
if (pageDetect.isReleasesOrTags()) {
const selected = select('.UnderlineNav-item.selected');
if (selected) {
selected.classList.remove('selected');
selected.removeAttribute('aria-current');
}
releasesTab.classList.add('selected');
releasesTab.setAttribute('aria-current', 'page');
}
appendBefore(
select('.js-responsive-underlinenav .dropdown-menu ul')!,
'.dropdown-divider', // Won't exist if `more-dropdown` is disabled
createDropdownItem('Releases', buildRepoURL('releases'), {
'data-menu-item': 'rgh-releases-item'
})
);
// Hide redundant 'Releases' section from repo sidebar
if (pageDetect.isRepoRoot()) {
const sidebarReleases = await elementReady('.BorderGrid-cell a[href$="/releases"]');
sidebarReleases!.closest('.BorderGrid-row')!.setAttribute('hidden', '');
}
return;
}
const releasesTab = (
<a href={buildRepoURL('releases')} className="reponav-item" data-hotkey="g r">
<TagIcon/>
<span> Releases </span>
{count && <span className="Counter">{count}</span>}
</a>
);
appendBefore(
// GHE doesn't have `.reponav > ul`
select('.reponav > ul') ?? select('.reponav')!,
'.reponav-dropdown, [data-selected-links^="repo_settings"]',
releasesTab
);
// Update "selected" tab mark
if (pageDetect.isReleasesOrTags()) {
select('.reponav-item.selected')?.classList.remove('js-selected-navigation-item', 'selected');
releasesTab.classList.add('js-selected-navigation-item', 'selected');
releasesTab.dataset.selectedLinks = 'repo_releases'; // Required for ajaxLoad
}
}
void features.add(__filebasename, {
shortcuts: {
'g r': 'Go to Releases'
},
include: [
pageDetect.isRepo
],
awaitDomReady: false,
init
});
|