feat: connect alpine operations and wizard to admin api

This commit is contained in:
a.tolmachev
2026-03-30 01:03:17 +03:00
parent 23ca2cda59
commit f45ace378a
9 changed files with 1213 additions and 520 deletions
+22 -16
View File
@@ -13,6 +13,7 @@
<script src="js/config.js"></script>
<script src="js/i18n.js"></script>
<script src="js/workspace.js"></script>
<script src="js/api.js"></script>
</head>
<body x-data="catalog()">
@@ -118,23 +119,23 @@
<div class="stats-row">
<div class="stat-card">
<div class="stat-label" data-i18n="stats.total">Total operations</div>
<div class="stat-value" x-text="operations.length"></div>
<div class="stat-delta up">+3 this month</div>
<div class="stat-value" x-text="formatMetricNumber(stats.total)"></div>
<div class="stat-delta" x-text="stats.total ? 'Catalog synced with backend' : 'No operations yet'"></div>
</div>
<div class="stat-card">
<div class="stat-label" data-i18n="stats.active">Active</div>
<div class="stat-value" x-text="operations.filter(o => o.status === 'active').length"></div>
<div class="stat-delta" x-text="operations.length ? Math.round(operations.filter(o=>o.status==='active').length/operations.length*100)+'% of total' : ''"></div>
<div class="stat-value" x-text="formatMetricNumber(stats.active)"></div>
<div class="stat-delta" x-text="stats.total ? Math.round((stats.active / stats.total) * 100) + '% of total' : 'No published tools yet'"></div>
</div>
<div class="stat-card">
<div class="stat-label" data-i18n="stats.requests">Requests today</div>
<div class="stat-value">4,821</div>
<div class="stat-delta up">+12% vs yesterday</div>
<div class="stat-value" x-text="formatMetricNumber(stats.requestsToday)"></div>
<div class="stat-delta" x-text="stats.requestsToday ? 'Summed from operation usage' : 'No traffic recorded today'"></div>
</div>
<div class="stat-card">
<div class="stat-label" data-i18n="stats.latency">Avg. latency</div>
<div class="stat-value">187ms</div>
<div class="stat-delta down">+23ms this week</div>
<div class="stat-value" x-text="stats.averageLatencyMs ? stats.averageLatencyMs + 'ms' : '—'"></div>
<div class="stat-delta" x-text="stats.averageLatencyMs ? 'Weighted by today\\'s calls' : 'Waiting for runtime samples'"></div>
</div>
</div>
@@ -233,15 +234,15 @@
:class="{ 'has-value': filterAgent, open: openDropdown === 'agent' }"
@click="toggleDropdown('agent')"
>
<span x-text="filterAgent ? activeAgents.find(a => a.id === filterAgent)?.display_name : 'Agent'"></span>
<span x-text="filterAgent ? activeAgents.find(a => a.agent_id === filterAgent)?.display_name : 'Agent'"></span>
<svg class="chevron" width="10" height="10"><use href="icons/general/chevron-down.svg#icon"/></svg>
</button>
<div class="dropdown-menu" x-show="openDropdown === 'agent'" x-transition>
<template x-for="a in activeAgents" :key="a.id">
<template x-for="a in activeAgents" :key="a.agent_id">
<button
class="dropdown-item"
:class="{ selected: filterAgent === a.id }"
@click="setAgent(a.id)"
:class="{ selected: filterAgent === a.agent_id }"
@click="setAgent(a.agent_id)"
>
<span x-text="a.display_name"></span>
<svg class="check" width="12" height="12"><use href="icons/general/check.svg#icon"/></svg>
@@ -321,8 +322,13 @@
<p data-i18n="ops.empty.sub">Try adjusting your search or filters.</p>
</div>
<div class="empty-state" x-show="!loading && loadError">
<h3>Backend connection failed</h3>
<p x-text="loadError"></p>
</div>
<!-- Table itself -->
<table x-show="!loading && totalFiltered > 0">
<table x-show="!loading && totalFiltered > 0 && !loadError">
<thead>
<tr>
<th class="th-sortable" :class="{ 'sort-active': sort.startsWith('name') }" @click="setSort(sort === 'name_asc' ? 'name_desc' : 'name_asc')">
@@ -350,7 +356,7 @@
<div class="op-name" x-text="op.name"></div>
<div class="op-display" x-text="op.display_name"></div>
<div class="op-agent-badges" x-show="(agentsByOpId[op.id] || []).length > 0">
<template x-for="a in (agentsByOpId[op.id] || [])" :key="a.id">
<template x-for="a in (agentsByOpId[op.id] || [])" :key="a.agent_id">
<span class="op-agent-badge" x-text="a.display_name"></span>
</template>
</div>
@@ -368,7 +374,7 @@
<td class="col-url">
<div class="target-url-cell">
<span x-text="truncateUrl(op.target_url)" :title="op.target_url"></span>
<a :href="op.target_url && op.target_url.startsWith('http') ? op.target_url : '#'" target="_blank" rel="noopener">
<a :href="op.target_url && op.target_url.startsWith('http') ? op.target_url : '#'" target="_blank" rel="noopener" :style="!op.target_url ? 'opacity:.35;pointer-events:none;' : ''">
<svg width="11" height="11"><use href="icons/general/external.svg#icon"/></svg>
</a>
</div>
@@ -389,7 +395,7 @@
</table>
<!-- Footer / pagination -->
<div class="table-footer" x-show="!loading && totalFiltered > 0">
<div class="table-footer" x-show="!loading && totalFiltered > 0 && !loadError">
<span class="table-footer-info">
Showing <span x-text="pageStart"></span><span x-text="pageEnd"></span> of <span x-text="totalFiltered"></span> operations
</span>