mirror of
https://github.com/RightNow-AI/openfang.git
synced 2026-05-03 04:52:08 +02:00
Initial commit — OpenFang Agent Operating System
Open-source Agent OS built in Rust. - 14 crates, 1,767+ tests, zero clippy warnings - 7 autonomous Hands (Clip, Lead, Collector, Predictor, Researcher, Twitter, Browser) - 16 security systems (WASM sandbox, Merkle audit trail, taint tracking, Ed25519 signing, SSRF protection, secret zeroization, HMAC-SHA256 mutual auth, and more) - 30 pre-built agents across 4 performance tiers - 40 channel adapters (Telegram, Discord, Slack, WhatsApp, Teams, and 35 more) - 38 built-in tools + MCP client/server + A2A protocol - 26 LLM providers with intelligent routing and cost tracking - 60+ bundled skills with FangHub marketplace - Tauri 2.0 native desktop app - 140+ REST/WS/SSE API endpoints with Alpine.js dashboard - OpenAI-compatible /v1/chat/completions endpoint - One-command install, production-ready
This commit is contained in:
66
crates/openfang-api/static/js/pages/approvals.js
Normal file
66
crates/openfang-api/static/js/pages/approvals.js
Normal file
@@ -0,0 +1,66 @@
|
||||
// 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';
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user