viberadar 0.3.225 → 0.3.226
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ui/dashboard.html +64 -40
- package/package.json +1 -1
package/dist/ui/dashboard.html
CHANGED
|
@@ -8473,7 +8473,7 @@ function updateLoadLiveStats() {
|
|
|
8473
8473
|
}
|
|
8474
8474
|
|
|
8475
8475
|
function formatLoadMetricMs(value) {
|
|
8476
|
-
return value == null || !Number.isFinite(Number(value)) ? '
|
|
8476
|
+
return value == null || !Number.isFinite(Number(value)) ? '-' : `${Math.round(Number(value))} ms`;
|
|
8477
8477
|
}
|
|
8478
8478
|
|
|
8479
8479
|
function loadEndpointLatencyColor(endpoint, summary) {
|
|
@@ -8525,33 +8525,40 @@ function renderLoadEndpointBreakdown(summary) {
|
|
|
8525
8525
|
</div>`;
|
|
8526
8526
|
}
|
|
8527
8527
|
|
|
8528
|
-
async function
|
|
8529
|
-
|
|
8530
|
-
|
|
8528
|
+
async function copyTextToClipboard(text) {
|
|
8529
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
8530
|
+
await navigator.clipboard.writeText(text);
|
|
8531
|
+
return;
|
|
8532
|
+
}
|
|
8533
|
+
const ta = document.createElement('textarea');
|
|
8534
|
+
ta.value = text;
|
|
8535
|
+
ta.style.position = 'fixed';
|
|
8536
|
+
ta.style.left = '-9999px';
|
|
8537
|
+
document.body.appendChild(ta);
|
|
8538
|
+
ta.focus();
|
|
8539
|
+
ta.select();
|
|
8540
|
+
document.execCommand('copy');
|
|
8541
|
+
ta.remove();
|
|
8542
|
+
}
|
|
8543
|
+
|
|
8544
|
+
async function copyLoadText(btn, text, fallbackLabel, errorPrefix) {
|
|
8545
|
+
if (!String(text || '').trim()) return;
|
|
8531
8546
|
const original = btn ? btn.textContent : '';
|
|
8532
8547
|
try {
|
|
8533
|
-
|
|
8534
|
-
await navigator.clipboard.writeText(text);
|
|
8535
|
-
} else {
|
|
8536
|
-
const ta = document.createElement('textarea');
|
|
8537
|
-
ta.value = text;
|
|
8538
|
-
ta.style.position = 'fixed';
|
|
8539
|
-
ta.style.left = '-9999px';
|
|
8540
|
-
document.body.appendChild(ta);
|
|
8541
|
-
ta.focus();
|
|
8542
|
-
ta.select();
|
|
8543
|
-
document.execCommand('copy');
|
|
8544
|
-
ta.remove();
|
|
8545
|
-
}
|
|
8548
|
+
await copyTextToClipboard(text);
|
|
8546
8549
|
if (btn) {
|
|
8547
8550
|
btn.textContent = 'Скопировано';
|
|
8548
|
-
setTimeout(() => { btn.textContent = original ||
|
|
8551
|
+
setTimeout(() => { btn.textContent = original || fallbackLabel; }, 1400);
|
|
8549
8552
|
}
|
|
8550
8553
|
} catch (e) {
|
|
8551
|
-
alert(
|
|
8554
|
+
alert(errorPrefix + ': ' + e.message);
|
|
8552
8555
|
}
|
|
8553
8556
|
}
|
|
8554
8557
|
|
|
8558
|
+
async function copyLoadLog(btn) {
|
|
8559
|
+
await copyLoadText(btn, (loadLogLines || []).join('\n'), 'Копировать лог', 'Не удалось скопировать лог');
|
|
8560
|
+
}
|
|
8561
|
+
|
|
8555
8562
|
function drawLoadChart(id, buckets, valFn, color, label) {
|
|
8556
8563
|
const canvas = document.getElementById(id);
|
|
8557
8564
|
if (!canvas) return;
|
|
@@ -9070,6 +9077,7 @@ function renderLoad(c) {
|
|
|
9070
9077
|
</div>
|
|
9071
9078
|
${renderLoadEndpointBreakdown(summary)}
|
|
9072
9079
|
<div class="load-btns" style="margin-top:12px">
|
|
9080
|
+
<button class="load-btn" onclick="copyLoadAnalysisPrompt(this)">Копировать отчёт для агента</button>
|
|
9073
9081
|
<button class="load-btn" style="background:#1a2a3a;border-color:var(--blue);color:var(--blue)" onclick="loadAiAnalysis()">🤖 AI-анализ результатов</button>
|
|
9074
9082
|
</div>
|
|
9075
9083
|
</div>` : ''}
|
|
@@ -9191,32 +9199,31 @@ async function runLoadTest() {
|
|
|
9191
9199
|
}
|
|
9192
9200
|
}
|
|
9193
9201
|
|
|
9194
|
-
async function stopLoadTest() {
|
|
9195
|
-
try { await fetch('/api/load/stop', { method: 'POST' }); } catch {}
|
|
9196
|
-
}
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
if (!loadState || !loadState.summary) return;
|
|
9202
|
+
async function stopLoadTest() {
|
|
9203
|
+
try { await fetch('/api/load/stop', { method: 'POST' }); } catch {}
|
|
9204
|
+
}
|
|
9205
|
+
|
|
9206
|
+
function buildLoadAnalysisPrompt() {
|
|
9207
|
+
if (!loadState || !loadState.summary) return '';
|
|
9200
9208
|
const summary = loadState.summary;
|
|
9201
9209
|
const logs = loadState.logs || [];
|
|
9202
9210
|
const totalRequests = Number(summary.totalRequests || loadState.totalRequests || 0);
|
|
9203
9211
|
if (totalRequests <= 0 && logs.length === 0) {
|
|
9204
|
-
|
|
9205
|
-
return;
|
|
9212
|
+
return '';
|
|
9206
9213
|
}
|
|
9207
9214
|
const endpointLines = Array.isArray(summary.endpoints) && summary.endpoints.length
|
|
9208
9215
|
? summary.endpoints.slice(0, 30).map(endpoint =>
|
|
9209
|
-
`- ${endpoint.endpoint}: requests=${Math.round(endpoint.requests || 0)}, errors=${endpoint.errorPct == null ? '
|
|
9216
|
+
`- ${endpoint.endpoint}: requests=${Math.round(endpoint.requests || 0)}, errors=${endpoint.errorPct == null ? '-' : Number(endpoint.errorPct || 0).toFixed(2) + '%'}, avg=${Math.round(endpoint.avgDuration || 0)}ms, p90=${Math.round(endpoint.p90Duration || 0)}ms, p95=${Math.round(endpoint.p95Duration || 0)}ms, p99=${Math.round(endpoint.p99Duration || 0)}ms, max=${Math.round(endpoint.maxDuration || 0)}ms`
|
|
9210
9217
|
).join('\n')
|
|
9211
9218
|
: '(нет разбивки: в k6-скрипте нет тега endpoint или metrics.ndjson недоступен)';
|
|
9212
|
-
|
|
9219
|
+
return `Проанализируй результаты нагрузочного тестирования k6:
|
|
9213
9220
|
|
|
9214
|
-
Run ID: ${loadState.runId || '
|
|
9215
|
-
Status: ${loadState.status || '
|
|
9216
|
-
Result path: ${loadState.config?.resultPath || '
|
|
9217
|
-
Script: ${loadState.config?.scriptName || '
|
|
9218
|
-
VUs: ${loadState.config?.vus || '
|
|
9219
|
-
Duration: ${loadState.config?.duration || '
|
|
9221
|
+
Run ID: ${loadState.runId || '-'}
|
|
9222
|
+
Status: ${loadState.status || '-'}
|
|
9223
|
+
Result path: ${loadState.config?.resultPath || '-'}
|
|
9224
|
+
Script: ${loadState.config?.scriptName || '-'}
|
|
9225
|
+
VUs: ${loadState.config?.vus || '-'}
|
|
9226
|
+
Duration: ${loadState.config?.duration || '-'}
|
|
9220
9227
|
|
|
9221
9228
|
RPS: ${(summary.rps||0).toFixed(2)}
|
|
9222
9229
|
avg latency: ${Math.round(summary.avgDuration||0)}ms
|
|
@@ -9225,8 +9232,8 @@ p95 latency: ${Math.round(summary.p95Duration||0)}ms
|
|
|
9225
9232
|
p99 latency: ${Math.round(summary.p99Duration||0)}ms
|
|
9226
9233
|
Total requests: ${totalRequests}
|
|
9227
9234
|
Error rate: ${(summary.errorPct||0).toFixed(2)}%
|
|
9228
|
-
Checks failed: ${summary.checksFailed ?? '
|
|
9229
|
-
Exit code: ${summary.exitCode ?? '
|
|
9235
|
+
Checks failed: ${summary.checksFailed ?? '-'}
|
|
9236
|
+
Exit code: ${summary.exitCode ?? '-'}
|
|
9230
9237
|
|
|
9231
9238
|
Разбивка по endpoint:
|
|
9232
9239
|
${endpointLines}
|
|
@@ -9235,9 +9242,26 @@ ${endpointLines}
|
|
|
9235
9242
|
${logs.slice(-120).join('\n') || '(лог пустой)'}
|
|
9236
9243
|
|
|
9237
9244
|
Оцени: производительность, узкие места, рекомендации по оптимизации.`;
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9245
|
+
}
|
|
9246
|
+
|
|
9247
|
+
async function copyLoadAnalysisPrompt(btn) {
|
|
9248
|
+
const prompt = buildLoadAnalysisPrompt();
|
|
9249
|
+
if (!prompt) {
|
|
9250
|
+
alert('Для копирования нет данных: в выбранном прогоне 0 запросов и пустой лог k6. Открой завершённый run с результатами или скопируй лог ошибки вручную.');
|
|
9251
|
+
return;
|
|
9252
|
+
}
|
|
9253
|
+
await copyLoadText(btn, prompt, 'Копировать отчёт для агента', 'Не удалось скопировать отчёт');
|
|
9254
|
+
}
|
|
9255
|
+
|
|
9256
|
+
async function loadAiAnalysis() {
|
|
9257
|
+
const prompt = buildLoadAnalysisPrompt();
|
|
9258
|
+
if (!prompt) {
|
|
9259
|
+
alert('Для AI-анализа нет данных: в выбранном прогоне 0 запросов и пустой лог k6. Открой завершённый run с результатами или скопируй лог ошибки вручную.');
|
|
9260
|
+
return;
|
|
9261
|
+
}
|
|
9262
|
+
|
|
9263
|
+
// Open agent terminal and send task
|
|
9264
|
+
document.getElementById('agentPanel').classList.add('open');
|
|
9241
9265
|
document.getElementById('termBtn').classList.add('term-active');
|
|
9242
9266
|
|
|
9243
9267
|
try {
|