feat(automation): complete unified automation system redesign

Phase 4 completion:
- Add ApprovalQueue component for managing pending approvals
- Add ExecutionResult component for displaying hand/workflow results
- Update Sidebar navigation to use unified AutomationPanel
- Replace separate 'hands' and 'workflow' tabs with single 'automation' tab
- Fix TypeScript type safety issues with unknown types in JSX expressions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-03-18 17:12:05 +08:00
parent 3a7631e035
commit 3518fc8ece
74 changed files with 4984 additions and 687 deletions

View File

@@ -958,15 +958,27 @@ export class GatewayClient {
private async restPost<T>(path: string, body?: unknown): Promise<T> {
const baseUrl = this.getRestBaseUrl();
const response = await fetch(`${baseUrl}${path}`, {
const url = `${baseUrl}${path}`;
console.log(`[GatewayClient] POST ${url}`, body);
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: body ? JSON.stringify(body) : undefined,
});
if (!response.ok) {
throw new Error(`REST API error: ${response.status} ${response.statusText}`);
const errorBody = await response.text().catch(() => '');
console.error(`[GatewayClient] POST ${url} failed: ${response.status} ${response.statusText}`, errorBody);
const error = new Error(`REST API error: ${response.status} ${response.statusText}${errorBody ? ` - ${errorBody}` : ''}`);
(error as any).status = response.status;
(error as any).body = errorBody;
throw error;
}
return response.json();
const result = await response.json();
console.log(`[GatewayClient] POST ${url} response:`, result);
return result;
}
private async restPut<T>(path: string, body?: unknown): Promise<T> {
@@ -1318,12 +1330,19 @@ export class GatewayClient {
/** Trigger a Hand */
async triggerHand(name: string, params?: Record<string, unknown>): Promise<{ runId: string; status: string }> {
console.log(`[GatewayClient] Triggering hand: ${name}`, params);
// OpenFang uses /activate endpoint, not /trigger
const result = await this.restPost<{
instance_id: string;
status: string;
}>(`/api/hands/${name}/activate`, params || {});
return { runId: result.instance_id, status: result.status };
try {
const result = await this.restPost<{
instance_id: string;
status: string;
}>(`/api/hands/${name}/activate`, params || {});
console.log(`[GatewayClient] Hand trigger response:`, result);
return { runId: result.instance_id, status: result.status };
} catch (err) {
console.error(`[GatewayClient] Hand trigger failed for ${name}:`, err);
throw err;
}
}
/** Get Hand execution status */