Files
mars3142_collection/plugin/actions/GiteaAction.js
T
2026-04-10 12:25:38 +02:00

133 lines
4.1 KiB
JavaScript

class GiteaAction extends ActionBase {
constructor($UD, context) {
super($UD, context);
this.config = {
url: '',
owner: '',
repo: '',
token: '',
refreshRate: '4',
};
}
setActive() {}
setParams(jsn) {
this.config = Object.assign(this.config, (jsn && jsn.param) || {});
this.startTimer(() => this.fetchRun(), this.config.refreshRate);
}
onRun() {
if (this.config.url && this.config.owner && this.config.repo) {
this.$UD.openUrl(`${this.config.url}/${this.config.owner}/${this.config.repo}/actions`);
}
}
semverAtLeast(version, major, minor) {
const parts = version.replace(/[^0-9.]/g, '').split('.').map(Number);
if (parts[0] !== major) return parts[0] > major;
return (parts[1] || 0) >= minor;
}
fetchRun() {
this.debounce(async () => {
if (!this.config.url || !this.config.owner || !this.config.repo) {
this.renderButton(null, false);
return;
}
try {
const headers = this.config.token ? { Authorization: `token ${this.config.token}` } : {};
const versionRes = await fetch(`${this.config.url}/api/v1/version`, { headers });
if (!versionRes.ok) {
this.renderButton({ error: versionRes.status }, false);
return;
}
const { version } = await versionRes.json();
if (!this.semverAtLeast(version, 1, 23)) {
this.renderButton(null, true);
return;
}
const response = await fetch(
`${this.config.url}/api/v1/repos/${this.config.owner}/${this.config.repo}/actions/runs?limit=20`,
{ headers }
);
if (!response.ok) {
this.renderButton({ error: response.status }, false);
return;
}
const data = await response.json();
const runs = data.workflow_runs || [];
const activeStatuses = ['in_progress', 'queued', 'waiting', 'requested', 'action_required'];
const runningRun = runs.find(r => activeStatuses.includes(r.status));
this.renderButton(runningRun || runs[0] || null, false);
} catch (e) {
this.renderButton({ error: 'ERR' }, false);
}
});
}
renderButton(run, unsupported) {
const { canvas, ctx } = this.createCanvas();
// Owner — top
const ownerLabel = this.config.owner || '?';
ctx.fillStyle = '#888888';
ctx.font = '18px "Source Han Sans SC"';
ctx.fillText(ownerLabel.length > 14 ? ownerLabel.slice(0, 13) + '…' : ownerLabel, 98, 22);
// Repo name — below owner
const repoLabel = this.config.repo || '?';
ctx.fillStyle = '#7ec8e3';
ctx.font = 'bold 22px "Source Han Sans SC"';
ctx.fillText(repoLabel.length > 12 ? repoLabel.slice(0, 11) + '…' : repoLabel, 98, 46);
// Status symbol — center
let symbol, color;
if (unsupported) {
symbol = '⊘';
color = '#555555';
} else if (!run) {
symbol = '?';
color = '#666666';
} else if (run.error) {
symbol = '✗';
color = '#ff6b6b';
} else if (['in_progress', 'queued', 'waiting', 'requested', 'action_required'].includes(run.status)) {
symbol = '⟳';
color = '#f0c040';
} else if (run.conclusion === 'success' || run.status === 'success') {
symbol = '✓';
color = '#6bff6b';
} else if (run.conclusion === 'failure' || run.status === 'failure') {
symbol = '✗';
color = '#ff6b6b';
} else if (['cancelled', 'skipped', 'timed_out', 'neutral'].includes(run.conclusion || run.status)) {
symbol = '⊘';
color = '#aaaaaa';
} else {
symbol = '?';
color = '#666666';
}
ctx.fillStyle = color;
ctx.font = 'bold 76px "Source Han Sans SC"';
ctx.fillText(symbol, 98, 115);
// Run info — bottom, single line
if (run && !run.error) {
const branch = run.head_branch || '';
const num = `#${run.run_number}`;
const info = branch ? `${num} · ${branch}` : num;
ctx.fillStyle = '#aaaaaa';
ctx.font = 'bold 20px "Source Han Sans SC"';
ctx.fillText(info.length > 16 ? info.slice(0, 15) + '…' : info, 98, 172);
}
this.setIcon(canvas);
}
}