Some checks failed
CI / Check / macos-latest (push) Has been cancelled
CI / Check / ubuntu-latest (push) Has been cancelled
CI / Check / windows-latest (push) Has been cancelled
CI / Test / macos-latest (push) Has been cancelled
CI / Test / ubuntu-latest (push) Has been cancelled
CI / Test / windows-latest (push) Has been cancelled
CI / Clippy (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Security Audit (push) Has been cancelled
CI / Secrets Scan (push) Has been cancelled
CI / Install Script Smoke Test (push) Has been cancelled
67 lines
1.9 KiB
JavaScript
67 lines
1.9 KiB
JavaScript
// OpenFang Approvals Page — Execution approval queue for sensitive agent actions
|
|
'use strict';
|
|
|
|
function approvalsPage() {
|
|
return {
|
|
approvals: [],
|
|
filterStatus: 'all',
|
|
loading: true,
|
|
loadError: '',
|
|
|
|
get filtered() {
|
|
var f = this.filterStatus;
|
|
if (f === 'all') return this.approvals;
|
|
return this.approvals.filter(function(a) { return a.status === f; });
|
|
},
|
|
|
|
get pendingCount() {
|
|
return this.approvals.filter(function(a) { return a.status === 'pending'; }).length;
|
|
},
|
|
|
|
async loadData() {
|
|
this.loading = true;
|
|
this.loadError = '';
|
|
try {
|
|
var data = await OpenFangAPI.get('/api/approvals');
|
|
this.approvals = data.approvals || [];
|
|
} catch(e) {
|
|
this.loadError = e.message || 'Could not load approvals.';
|
|
}
|
|
this.loading = false;
|
|
},
|
|
|
|
async approve(id) {
|
|
try {
|
|
await OpenFangAPI.post('/api/approvals/' + id + '/approve', {});
|
|
OpenFangToast.success('Approved');
|
|
await this.loadData();
|
|
} catch(e) {
|
|
OpenFangToast.error(e.message);
|
|
}
|
|
},
|
|
|
|
async reject(id) {
|
|
var self = this;
|
|
OpenFangToast.confirm('Reject Action', 'Are you sure you want to reject this action?', async function() {
|
|
try {
|
|
await OpenFangAPI.post('/api/approvals/' + id + '/reject', {});
|
|
OpenFangToast.success('Rejected');
|
|
await self.loadData();
|
|
} catch(e) {
|
|
OpenFangToast.error(e.message);
|
|
}
|
|
});
|
|
},
|
|
|
|
timeAgo(dateStr) {
|
|
if (!dateStr) return '';
|
|
var d = new Date(dateStr);
|
|
var secs = Math.floor((Date.now() - d.getTime()) / 1000);
|
|
if (secs < 60) return secs + 's ago';
|
|
if (secs < 3600) return Math.floor(secs / 60) + 'm ago';
|
|
if (secs < 86400) return Math.floor(secs / 3600) + 'h ago';
|
|
return Math.floor(secs / 86400) + 'd ago';
|
|
}
|
|
};
|
|
}
|