feat: complete Epic 1 production foundation

This commit is contained in:
2026-08-25 01:24:11 +03:00
parent 767428436d
commit 182bde8ac0
298 changed files with 35719 additions and 5299 deletions
+36 -3
View File
@@ -44,6 +44,9 @@ function mapOperation(item) {
created_at: item.created_at,
updated_at: item.updated_at,
published_at: item.published_at,
current_draft_version: item.current_draft_version,
latest_published_version: item.latest_published_version,
can_delete: item.can_delete === true,
target_url: item.target_url || '',
method: item.target_action || '',
usage_summary: item.usage_summary || {
@@ -117,6 +120,7 @@ document.addEventListener('alpine:init', function() {
_agentsByOpIdCacheVersion: -1,
_activeAgentsCache: null,
_activeAgentsCacheVersion: -1,
_loadGeneration: 0,
async init() {
var self = this;
@@ -153,25 +157,31 @@ document.addEventListener('alpine:init', function() {
},
async reload() {
var generation = ++this._loadGeneration;
var requestedWorkspaceId = this.workspaceId;
this.loading = true;
this.loadError = '';
try {
var response = await window.CrankApi.listOperations(this.workspaceId);
var response = await window.CrankApi.listOperations(requestedWorkspaceId);
if (generation !== this._loadGeneration || requestedWorkspaceId !== this.workspaceId) return;
this.replaceOperations((response && response.items ? response.items : []).map(mapOperation));
this.categoryOptions = Array.from(new Set(this.operations.map(function(operation) {
return operation.category;
}).filter(Boolean))).sort();
this.stats = computeStats(this.operations);
} catch (error) {
if (generation !== this._loadGeneration || requestedWorkspaceId !== this.workspaceId) return;
this.replaceOperations([]);
this.categoryOptions = [];
this.stats = emptyStats();
this.loadError = error.message || 'Failed to load operations';
}
this.loading = false;
this.page = 1;
if (generation === this._loadGeneration && requestedWorkspaceId === this.workspaceId) {
this.loading = false;
this.page = 1;
}
},
replaceOperations(operations) {
@@ -453,6 +463,29 @@ document.addEventListener('alpine:init', function() {
}
},
async archiveOperation(operation) {
if (!operation || !confirm(this.tKey('ops.archive.confirm'))) return;
try {
await window.CrankApi.archiveOperation(this.workspaceId, operation.id);
await this.reload();
if (window.CrankUi) {
window.CrankUi.success(
this.tfKey('ops.archive.success.message', {
name: operation.display_name || operation.name
}),
this.tKey('ops.archive.success.title')
);
}
} catch (error) {
if (window.CrankUi) {
window.CrankUi.error(
error.message || this.tKey('ops.archive.error.message'),
this.tKey('ops.archive.error.title')
);
}
}
},
protocolLabel(operation) {
return operation.method ? ('REST · ' + operation.method) : 'REST';
},