03468d4ca4
Signed-off-by: Peter Siegmund <developer@mars3142.org>
113 lines
3.8 KiB
JavaScript
113 lines
3.8 KiB
JavaScript
class GiteaPRAction extends ActionBase {
|
|
constructor($UD, context) {
|
|
super($UD, context);
|
|
this.config = {
|
|
url: '',
|
|
token: '',
|
|
filter: 'review_requested',
|
|
refreshRate: '4',
|
|
};
|
|
}
|
|
|
|
setActive() {}
|
|
|
|
setParams(jsn) {
|
|
this.config = Object.assign(this.config, (jsn && jsn.param) || {});
|
|
this.startTimer(() => this.fetchPRs(), this.config.refreshRate);
|
|
}
|
|
|
|
onRun() {
|
|
if (this.config.url) {
|
|
this.$UD.openUrl(`${this.config.url}/pulls?type=your_repositories&sort=&state=open&q=`);
|
|
}
|
|
}
|
|
|
|
fetchPRs() {
|
|
this.debounce(async () => {
|
|
if (!this.config.url || !this.config.token) {
|
|
this.renderButton(null, false);
|
|
return;
|
|
}
|
|
try {
|
|
const headers = { Authorization: `token ${this.config.token}` };
|
|
const filter = this.config.filter || 'review_requested';
|
|
const base = `${this.config.url}/api/v1/repos/issues/search?type=pullrequest&state=open&limit=50`;
|
|
|
|
const fetchIds = async (url) => {
|
|
const r = await fetch(url, { headers, signal: AbortSignal.timeout(8000) });
|
|
console.log('GiteaPR status:', r.status, url);
|
|
if (!r.ok) {
|
|
const body = await r.text();
|
|
console.log('GiteaPR error body:', body);
|
|
return null;
|
|
}
|
|
const data = await r.json();
|
|
return Array.isArray(data) ? data.map(i => i.id) : [];
|
|
};
|
|
|
|
let ids;
|
|
if (filter === 'both') {
|
|
const [a, b] = await Promise.all([
|
|
fetchIds(`${base}&assigned=true`),
|
|
fetchIds(`${base}&review_requested=true`),
|
|
]);
|
|
if (a === null || b === null) { this.renderButton(null, true); return; }
|
|
ids = [...new Set([...a, ...b])];
|
|
} else {
|
|
const param = filter === 'assigned' ? '&assigned=true' : '&review_requested=true';
|
|
ids = await fetchIds(`${base}${param}`);
|
|
if (ids === null) { this.renderButton(null, true); return; }
|
|
}
|
|
|
|
this.renderButton(ids.length, false);
|
|
} catch (e) {
|
|
// timeout or network error = VPN likely down
|
|
this.renderButton(null, false);
|
|
}
|
|
});
|
|
}
|
|
|
|
renderButton(count, isError) {
|
|
const { canvas, ctx } = this.createCanvas();
|
|
|
|
// Label — top
|
|
ctx.fillStyle = '#7ec8e3';
|
|
ctx.font = 'bold 22px "Source Han Sans SC"';
|
|
ctx.fillText('Pull Requests', 98, 30);
|
|
|
|
if (count === null) {
|
|
// No connection — show plug/disconnected icon
|
|
ctx.fillStyle = isError ? '#ff6b6b' : '#888888';
|
|
ctx.font = '70px "Source Han Sans SC"';
|
|
ctx.textBaseline = 'alphabetic';
|
|
const bm = ctx.measureText('⚡');
|
|
ctx.fillText('⚡', 98, 98 + (bm.actualBoundingBoxAscent - bm.actualBoundingBoxDescent) / 2);
|
|
ctx.textBaseline = 'middle';
|
|
|
|
ctx.fillStyle = isError ? '#ff6b6b' : '#888888';
|
|
ctx.font = 'bold 22px "Source Han Sans SC"';
|
|
ctx.fillText(isError ? 'API Error' : 'Offline', 98, 166);
|
|
} else {
|
|
// Count — large center number (visually centered using actual bounding box)
|
|
const color = count === 0 ? '#6bff6b' : count < 5 ? '#f0c040' : '#ff6b6b';
|
|
ctx.fillStyle = color;
|
|
const fSize = count > 99 ? 60 : count > 9 ? 80 : 96;
|
|
ctx.font = `bold ${fSize}px "Source Han Sans SC"`;
|
|
const text = count > 999 ? '999+' : String(count);
|
|
ctx.textBaseline = 'alphabetic';
|
|
const m = ctx.measureText(text);
|
|
ctx.fillText(text, 98, 98 + (m.actualBoundingBoxAscent - m.actualBoundingBoxDescent) / 2);
|
|
ctx.textBaseline = 'middle';
|
|
|
|
// Subtext
|
|
const filter = this.config.filter || 'review_requested';
|
|
const label = filter === 'assigned' ? 'assigned' : filter === 'review_requested' ? 'review req.' : 'open';
|
|
ctx.fillStyle = '#888888';
|
|
ctx.font = '18px "Source Han Sans SC"';
|
|
ctx.fillText(label, 98, 166);
|
|
}
|
|
|
|
this.setIcon(canvas);
|
|
}
|
|
}
|