blaze-performance-tester 3.2.32 → 3.2.34
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/cli.js +182 -7
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5747,7 +5747,7 @@ var i18n = {
|
|
|
5747
5747
|
good: "(\u0905\u091A\u094D\u091B\u093E)"
|
|
5748
5748
|
},
|
|
5749
5749
|
verdict: "\u{1F916} \u090F\u0906\u0908 \u0938\u094D\u091F\u094D\u0930\u0947\u0938-\u091F\u0947\u0938\u094D\u091F\u093F\u0902\u0917 \u090F\u091C\u0947\u0902\u091F \u0915\u093E \u0928\u093F\u0930\u094D\u0923\u092F",
|
|
5750
|
-
health: { title: "\u092C\u094D\u0932\u0947\u091C\u093C \u0930\u0928 \u0939\u0947\u0932\u094D\u0925 \u0938\u094D\u0915\u094B\u0930", subtitle: "\u0915\u0902\u092A\u094B\u091C\u093F\u091F \u0930\u0928
|
|
5750
|
+
health: { title: "\u092C\u094D\u0932\u0947\u091C\u093C \u0930\u0928 \u0939\u0947\u0932\u094D\u0925 \u0938\u094D\u0915\u094B\u0930", subtitle: "\u0915\u0902\u092A\u094B\u091C\u093F\u091F \u0930\u0928 QUALITY \u0907\u0902\u091C\u0928 \u0930\u0947\u091F\u093F\u0902\u0917" },
|
|
5751
5751
|
matrix: {
|
|
5752
5752
|
title: "\u{1F4CB} HTTP \u0930\u093F\u0938\u094D\u092A\u0949\u0928\u094D\u0938 \u092E\u0948\u091F\u094D\u0930\u093F\u0915\u094D\u0938",
|
|
5753
5753
|
info: "\u0938\u0942\u091A\u0928\u093E\u0924\u094D\u092E\u0915",
|
|
@@ -5976,6 +5976,34 @@ ${JSON.stringify(metrics, null, 2)}
|
|
|
5976
5976
|
return null;
|
|
5977
5977
|
}
|
|
5978
5978
|
}
|
|
5979
|
+
async function generateWittyAudioBriefing(cards) {
|
|
5980
|
+
const apiKey = process.env.GEMINI_API_KEY;
|
|
5981
|
+
if (!apiKey) {
|
|
5982
|
+
return "Hey Product Manager! Here is your quick performance update. Actually, your Gemini API Key is missing, so I am improvising. Your health score is sitting at " + cards.healthScore + " out of 100. Check the logs, configure your credentials, and let's make it snappy next time!";
|
|
5983
|
+
}
|
|
5984
|
+
console.log("\u{1F9E0} Querying Gemini 2.5 Flash for a Witty PM Executive Briefing...");
|
|
5985
|
+
const prompt = `
|
|
5986
|
+
You are a fast-talking, highly witty, slightly sarcastic AI performance consultant reporting to a very busy Product Manager.
|
|
5987
|
+
Review these metrics:
|
|
5988
|
+
- Blaze Health Score: ${cards.healthScore}/100
|
|
5989
|
+
- Apdex: ${cards.apdex.toFixed(2)}
|
|
5990
|
+
- Throughput: ${cards.throughput.toFixed(1)} req/s
|
|
5991
|
+
- Error Rate: ${(cards.errorRate * 100).toFixed(2)}%
|
|
5992
|
+
- P95 Latency: ${cards.p95Latency.toFixed(1)}ms
|
|
5993
|
+
|
|
5994
|
+
Compose a witty, energetic daily audio update script that takes exactly 30 seconds to read aloud (around 65-75 words maximum). Focus on what the numbers mean for the business or the features. Return ONLY standard plain-text narrative string, free of markdown styling (*, #, bold tags) or technical headers, ready for immediate browser text-to-speech engine streaming. Make it punchy!
|
|
5995
|
+
`;
|
|
5996
|
+
try {
|
|
5997
|
+
const ai = new GoogleGenAI({});
|
|
5998
|
+
const response = await ai.models.generateContent({
|
|
5999
|
+
model: "gemini-2.5-flash",
|
|
6000
|
+
contents: prompt
|
|
6001
|
+
});
|
|
6002
|
+
return response.text?.replace(/["'**#]/g, "").trim() || "Performance matrix evaluated. Status operational.";
|
|
6003
|
+
} catch (error) {
|
|
6004
|
+
return `System alert PM. Your test achieved a health score of ${cards.healthScore} running at ${cards.throughput.toFixed(0)} requests per second. Check dashboard details for full diagnostic breakdowns.`;
|
|
6005
|
+
}
|
|
6006
|
+
}
|
|
5979
6007
|
async function generateGeminiRCA(history, finalSummary, errorLogs) {
|
|
5980
6008
|
const apiKey = process.env.GEMINI_API_KEY;
|
|
5981
6009
|
if (!apiKey) {
|
|
@@ -6424,6 +6452,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
6424
6452
|
};
|
|
6425
6453
|
generateFinalAgentReport(history, healthScore);
|
|
6426
6454
|
const geminiAnalysisHtml = await generateGeminiRCA(history, finalSummaryCards, aggregateErrorLogs);
|
|
6455
|
+
const wittyBriefingText = await generateWittyAudioBriefing(finalSummaryCards);
|
|
6427
6456
|
if (config.optionValue === "elif") {
|
|
6428
6457
|
const plainEnglishSummary = await generateElifExplanation(finalSummaryCards);
|
|
6429
6458
|
if (plainEnglishSummary) {
|
|
@@ -6443,7 +6472,7 @@ async function runIntelligentAgenticStressTest(config) {
|
|
|
6443
6472
|
breakdownRates[code] = totalRequestsAccumulator === 0 ? 0 : globalCodeCounts[code] / totalRequestsAccumulator * 100;
|
|
6444
6473
|
});
|
|
6445
6474
|
const baselineData = loadBaselineData(config.baselinePath);
|
|
6446
|
-
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, geminiAnalysisHtml, baselineData);
|
|
6475
|
+
exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, geminiAnalysisHtml, wittyBriefingText, baselineData);
|
|
6447
6476
|
}
|
|
6448
6477
|
async function runStandardStressTest(config) {
|
|
6449
6478
|
console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s | RampUp: ${config.rampUpSec}s | RampDown: ${config.rampDownSec}s]`);
|
|
@@ -6486,6 +6515,7 @@ async function runStandardStressTest(config) {
|
|
|
6486
6515
|
const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
|
|
6487
6516
|
const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
|
|
6488
6517
|
const geminiAnalysisHtml = await generateGeminiRCA(history, finalSummaryCards, rawErrors.length > 0 ? rawErrors : getFallbackClusterLogs());
|
|
6518
|
+
const wittyBriefingText = await generateWittyAudioBriefing(finalSummaryCards);
|
|
6489
6519
|
if (config.optionValue === "elif") {
|
|
6490
6520
|
const plainEnglishSummary = await generateElifExplanation(finalSummaryCards);
|
|
6491
6521
|
if (plainEnglishSummary) {
|
|
@@ -6511,7 +6541,7 @@ async function runStandardStressTest(config) {
|
|
|
6511
6541
|
total4xx: metrics.c4xx,
|
|
6512
6542
|
total5xx: metrics.c5xx,
|
|
6513
6543
|
breakdownRates
|
|
6514
|
-
}, finalSummaryCards, rawRequests, geminiAnalysisHtml, baselineData);
|
|
6544
|
+
}, finalSummaryCards, rawRequests, geminiAnalysisHtml, wittyBriefingText, baselineData);
|
|
6515
6545
|
}
|
|
6516
6546
|
function getFallbackClusterLogs() {
|
|
6517
6547
|
const logs = [];
|
|
@@ -6576,7 +6606,7 @@ function processMetricsTelemetry(requests, durationSec) {
|
|
|
6576
6606
|
const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
|
|
6577
6607
|
const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
|
|
6578
6608
|
let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
|
|
6579
|
-
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500:
|
|
6609
|
+
const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 502, 503: 0, 504: 0 };
|
|
6580
6610
|
[400, 401, 403, 404, 429, 500, 502, 503, 504].forEach((c) => codeCounts[c] = 0);
|
|
6581
6611
|
requests.forEach((r) => {
|
|
6582
6612
|
if (r.statusCode >= 100 && r.statusCode < 200)
|
|
@@ -6644,7 +6674,7 @@ function generateFinalAgentReport(history, score) {
|
|
|
6644
6674
|
console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
|
|
6645
6675
|
console.log("=======================================================\n");
|
|
6646
6676
|
}
|
|
6647
|
-
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], geminiAnalysisHtml = "", baselineData = null) {
|
|
6677
|
+
function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], geminiAnalysisHtml = "", wittyBriefingText = "", baselineData = null) {
|
|
6648
6678
|
const dict = i18n[config.locale] || i18n["en-US"];
|
|
6649
6679
|
const dir = dict.rtl ? "rtl" : "ltr";
|
|
6650
6680
|
const formatter = new Intl.DateTimeFormat(config.locale || "en-US", {
|
|
@@ -6749,9 +6779,14 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
6749
6779
|
</table>
|
|
6750
6780
|
</div>`;
|
|
6751
6781
|
let logClustersHtml = "";
|
|
6782
|
+
let formattedTicketLogs = "No structural error codes encountered.";
|
|
6752
6783
|
if (semanticReport) {
|
|
6753
6784
|
const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
|
|
6754
|
-
|
|
6785
|
+
formattedTicketLogs = semanticReport.clusters.slice(0, 5).map((c) => {
|
|
6786
|
+
const cleanBlueprint = c.template.replace(/\[\d{4}-\d{2}-\d{2}.*?\]\s*/, "");
|
|
6787
|
+
return `[${c.severity}] Count: ${c.count} | Cat: ${c.category}
|
|
6788
|
+
\u21B3 ${cleanBlueprint}`;
|
|
6789
|
+
}).join("\n\n");
|
|
6755
6790
|
logClustersHtml = `
|
|
6756
6791
|
<div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
|
|
6757
6792
|
<h3 style="border-bottom: none; padding-bottom: 0rem; margin-bottom: 0.25rem; display: flex; align-items: center; gap: 0.5rem; color: #ffffff; font-size: 1.2rem;">
|
|
@@ -6798,6 +6833,25 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
6798
6833
|
</table>
|
|
6799
6834
|
</div>`;
|
|
6800
6835
|
}
|
|
6836
|
+
const generatedTicketMarkdown = `## \u{1F6A8} Performance Degradation Ticket (Blaze Incident Framework)
|
|
6837
|
+
|
|
6838
|
+
### \u{1F4CA} 1. System Telemetry Metrics
|
|
6839
|
+
- **Blaze Core Health Score:** ${cards.healthScore}/100
|
|
6840
|
+
- **Target Threshold Apdex:** ${config.targetApdex} (Realized Apdex: ${cards.apdex.toFixed(2)})
|
|
6841
|
+
- **Peak Aggregated Throughput:** ${cards.throughput.toFixed(1)} req/sec
|
|
6842
|
+
- **P95 Latency Window:** ${cards.p95Latency.toFixed(1)} ms
|
|
6843
|
+
- **Observed System Error Rate:** ${(cards.errorRate * 100).toFixed(2)}%
|
|
6844
|
+
|
|
6845
|
+
### \u{1F9E0} 2. Architectural Sizing Recommendations
|
|
6846
|
+
- **Recommended Remediation Profile:** Upgrade capacity to a minimum configuration tier of **${recommendedCpuCores} CPU Cores** and **${recommendedRamGb} GB RAM**.
|
|
6847
|
+
- **Estimated OpEx Budget Shift:** ~$${estimatedMonthlyCost}/month based on system concurrency profiles.
|
|
6848
|
+
|
|
6849
|
+
### \u274C 3. Structural Log Blueprint Failures
|
|
6850
|
+
\`\`\`
|
|
6851
|
+
${formattedTicketLogs}
|
|
6852
|
+
\`\`\`
|
|
6853
|
+
|
|
6854
|
+
*Ticket generated autonomously via Blaze Fix-It Ticket Engine pipeline. Status: Pending Triage.*`;
|
|
6801
6855
|
const breakdownRates = responseMatrix.breakdownRates || {};
|
|
6802
6856
|
const breakdownGridHtml = [400, 401, 403, 404, 429, 500, 502, 503, 504].map((code) => {
|
|
6803
6857
|
const rate = breakdownRates[code] || 0;
|
|
@@ -6827,7 +6881,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
6827
6881
|
.metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
|
|
6828
6882
|
.card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
|
|
6829
6883
|
.card-value { font-size: 1.6rem; font-weight: 700; color: #ffffff; }
|
|
6830
|
-
.card-value .unit { font-size: 0.9rem; font-weight: 500; color: #94a3b8; margin-inline-start: 0.2rem; }
|
|
6884
|
+
.card-value .unit { font-size: 0.9rem; font-weight: 500; color: #94a3b8; margin-inline-start: 0.2rem; display: inline-block; }
|
|
6831
6885
|
.card-value.green { color: #10b981; }
|
|
6832
6886
|
.card-value.orange { color: #f97316; }
|
|
6833
6887
|
.card-value.purple { color: #a855f7; }
|
|
@@ -6881,6 +6935,28 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
6881
6935
|
<h1>\u{1F525} ${dict.title}</h1>
|
|
6882
6936
|
<div class="meta">${dict.targetScript}: <code>${config.targetScript}</code> | ${dict.rampUp}: ${config.rampUpSec}s | ${dict.rampDown}: ${config.rampDownSec}s | ${dict.generatedAt}: ${formattedDate}</div>
|
|
6883
6937
|
</div>
|
|
6938
|
+
|
|
6939
|
+
<!-- \u{1F399}\uFE0F Automated Executive Summary Audio Player Dashboard Widget Component -->
|
|
6940
|
+
<div class="card" style="margin-bottom: 2rem; background: #1e1b4b; border: 1px solid #6366f1; display: flex; align-items: center; gap: 1.5rem; padding: 1rem 1.5rem; border-radius: 8px;">
|
|
6941
|
+
<div style="background: #312e81; border-radius: 50%; width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; cursor: pointer; border: 2px solid #818cf8; transition: transform 0.2s; flex-shrink: 0;" id="audioPlayBtn" onclick="toggleBriefingAudio()">
|
|
6942
|
+
<svg id="playIcon" width="18" height="18" viewBox="0 0 24 24" fill="#818cf8"><path d="M8 5v14l11-7z"/></svg>
|
|
6943
|
+
<svg id="pauseIcon" width="18" height="18" viewBox="0 0 24 24" fill="#818cf8" style="display:none;"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>
|
|
6944
|
+
</div>
|
|
6945
|
+
<div style="flex-grow: 1; min-width: 0;">
|
|
6946
|
+
<div style="font-size: 0.85rem; font-weight: bold; color: #818cf8; text-transform: uppercase; letter-spacing: 0.05em; display: flex; align-items: center; gap: 0.5rem;">
|
|
6947
|
+
<span>\u{1F399}\uFE0F Executive Summary Briefing</span>
|
|
6948
|
+
<span id="audioStatus" style="font-size: 0.75rem; color: #94a3b8; text-transform: none; font-weight: normal;">(Ready to play)</span>
|
|
6949
|
+
</div>
|
|
6950
|
+
<div style="font-size: 0.9rem; color: #cbd5e1; font-style: italic; margin-top: 0.25rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" id="briefingTextPreview"></div>
|
|
6951
|
+
</div>
|
|
6952
|
+
<div style="display: flex; align-items: flex-end; gap: 3px; height: 20px; flex-shrink: 0;" id="visualizerBars">
|
|
6953
|
+
<div style="width: 3px; height: 8px; background: #6366f1; border-radius: 1px; transition: height 0.15s ease;"></div>
|
|
6954
|
+
<div style="width: 3px; height: 14px; background: #6366f1; border-radius: 1px; transition: height 0.15s ease;"></div>
|
|
6955
|
+
<div style="width: 3px; height: 6px; background: #6366f1; border-radius: 1px; transition: height 0.15s ease;"></div>
|
|
6956
|
+
<div style="width: 3px; height: 18px; background: #6366f1; border-radius: 1px; transition: height 0.15s ease;"></div>
|
|
6957
|
+
<div style="width: 3px; height: 10px; background: #6366f1; border-radius: 1px; transition: height 0.15s ease;"></div>
|
|
6958
|
+
</div>
|
|
6959
|
+
</div>
|
|
6884
6960
|
|
|
6885
6961
|
<div class="cards-wrapper">
|
|
6886
6962
|
<div class="metric-card">
|
|
@@ -6987,6 +7063,19 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
6987
7063
|
</div>
|
|
6988
7064
|
</div>
|
|
6989
7065
|
|
|
7066
|
+
<!-- \u{1F3AB} Generative Fix-It Tickets Feature UI Component -->
|
|
7067
|
+
<div class="card" style="margin-top: 2rem; background: #0c1c18; border: 1px solid #10b981;">
|
|
7068
|
+
<h3 style="color: #34d399; display: flex; align-items: center; justify-content: space-between; font-size: 1.2rem; border-bottom: 1px solid #1f2937; padding-bottom: 0.5rem;">
|
|
7069
|
+
<span>\u{1F3AB} Generative Fix-It Ticket Engine</span>
|
|
7070
|
+
<button id="btnCopyTicket" onclick="copyFixItTicketMarkdown()" style="background: #10b981; color: #0c1c18; border: none; padding: 0.4rem 0.9rem; border-radius: 4px; cursor: pointer; font-weight: bold; font-size: 0.85rem; transition: background 0.2s;">
|
|
7071
|
+
\u{1F4CB} Copy Ticket Markdown
|
|
7072
|
+
</button>
|
|
7073
|
+
</h3>
|
|
7074
|
+
<div style="background: #040d0a; border: 1px solid #14532d; border-radius: 6px; padding: 1rem; max-height: 300px; overflow-y: auto;">
|
|
7075
|
+
<pre id="ticketBodyPreview" style="margin: 0; color: #a7f3d0; font-family: monospace; font-size: 0.85rem; white-space: pre-wrap; word-break: break-all;"></pre>
|
|
7076
|
+
</div>
|
|
7077
|
+
</div>
|
|
7078
|
+
|
|
6990
7079
|
<div class="charts-grid" style="margin-top: 2rem;">
|
|
6991
7080
|
<div class="graph-card">
|
|
6992
7081
|
<div class="graph-title">${dict.charts.volume}</div>
|
|
@@ -7049,6 +7138,92 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
|
|
|
7049
7138
|
</div>
|
|
7050
7139
|
|
|
7051
7140
|
<script>
|
|
7141
|
+
// Inject the generated Briefing Text payload
|
|
7142
|
+
const textBriefingPayload = ${JSON.stringify(wittyBriefingText)};
|
|
7143
|
+
document.getElementById('briefingTextPreview').textContent = '"' + textBriefingPayload + '"';
|
|
7144
|
+
|
|
7145
|
+
let synthesisEngine = window.speechSynthesis;
|
|
7146
|
+
let textUtterance = null;
|
|
7147
|
+
let audioStateActive = false;
|
|
7148
|
+
let visualBarsTimer = null;
|
|
7149
|
+
|
|
7150
|
+
function toggleBriefingAudio() {
|
|
7151
|
+
if (!synthesisEngine) {
|
|
7152
|
+
alert("Speech synthesis metrics streaming unsupported on this browser platform.");
|
|
7153
|
+
return;
|
|
7154
|
+
}
|
|
7155
|
+
|
|
7156
|
+
if (audioStateActive) {
|
|
7157
|
+
synthesisEngine.cancel();
|
|
7158
|
+
terminateAudioVisuals();
|
|
7159
|
+
} else {
|
|
7160
|
+
synthesisEngine.cancel();
|
|
7161
|
+
textUtterance = new SpeechSynthesisUtterance(textBriefingPayload);
|
|
7162
|
+
|
|
7163
|
+
// Match specialized high quality voice parameters if dynamically present
|
|
7164
|
+
let targetVoices = synthesisEngine.getVoices();
|
|
7165
|
+
let activeVoice = targetVoices.find(v => v.lang.startsWith('en') && v.name.includes('Google')) || targetVoices.find(v => v.lang.startsWith('en'));
|
|
7166
|
+
if (activeVoice) textUtterance.voice = activeVoice;
|
|
7167
|
+
|
|
7168
|
+
textUtterance.rate = 1.08; // Snappy presentation delivery mapping
|
|
7169
|
+
textUtterance.pitch = 1.0;
|
|
7170
|
+
|
|
7171
|
+
textUtterance.onend = () => terminateAudioVisuals();
|
|
7172
|
+
textUtterance.onerror = () => terminateAudioVisuals();
|
|
7173
|
+
|
|
7174
|
+
synthesisEngine.speak(textUtterance);
|
|
7175
|
+
initializeAudioVisuals();
|
|
7176
|
+
}
|
|
7177
|
+
}
|
|
7178
|
+
|
|
7179
|
+
function initializeAudioVisuals() {
|
|
7180
|
+
audioStateActive = true;
|
|
7181
|
+
document.getElementById('playIcon').style.display = 'none';
|
|
7182
|
+
document.getElementById('pauseIcon').style.display = 'block';
|
|
7183
|
+
document.getElementById('audioStatus').textContent = '(Briefing playing...)';
|
|
7184
|
+
document.getElementById('audioPlayBtn').style.transform = 'scale(1.05)';
|
|
7185
|
+
|
|
7186
|
+
const bars = document.getElementById('visualizerBars').children;
|
|
7187
|
+
visualBarsTimer = setInterval(() => {
|
|
7188
|
+
for (let bar of bars) {
|
|
7189
|
+
bar.style.height = (Math.floor(Math.random() * 16) + 4) + 'px';
|
|
7190
|
+
}
|
|
7191
|
+
}, 120);
|
|
7192
|
+
}
|
|
7193
|
+
|
|
7194
|
+
function terminateAudioVisuals() {
|
|
7195
|
+
audioStateActive = false;
|
|
7196
|
+
document.getElementById('playIcon').style.display = 'block';
|
|
7197
|
+
document.getElementById('pauseIcon').style.display = 'none';
|
|
7198
|
+
document.getElementById('audioStatus').textContent = '(Paused / Finished)';
|
|
7199
|
+
document.getElementById('audioPlayBtn').style.transform = 'scale(1)';
|
|
7200
|
+
clearInterval(visualBarsTimer);
|
|
7201
|
+
|
|
7202
|
+
const defaultHeights = [8, 14, 6, 18, 10];
|
|
7203
|
+
const bars = document.getElementById('visualizerBars').children;
|
|
7204
|
+
for (let i = 0; i < bars.length; i++) {
|
|
7205
|
+
if(bars[i]) bars[i].style.height = defaultHeights[i] + 'px';
|
|
7206
|
+
}
|
|
7207
|
+
}
|
|
7208
|
+
|
|
7209
|
+
// Inject and expose the formatted Fix-It Ticket Markdown
|
|
7210
|
+
const rawTicketMarkdown = ${JSON.stringify(generatedTicketMarkdown)};
|
|
7211
|
+
document.getElementById('ticketBodyPreview').textContent = rawTicketMarkdown;
|
|
7212
|
+
|
|
7213
|
+
function copyFixItTicketMarkdown() {
|
|
7214
|
+
navigator.clipboard.writeText(rawTicketMarkdown).then(() => {
|
|
7215
|
+
const btn = document.getElementById('btnCopyTicket');
|
|
7216
|
+
btn.textContent = '\u2705 Copied!';
|
|
7217
|
+
btn.style.background = '#34d399';
|
|
7218
|
+
setTimeout(() => {
|
|
7219
|
+
btn.textContent = '\u{1F4CB} Copy Ticket Markdown';
|
|
7220
|
+
btn.style.background = '#10b981';
|
|
7221
|
+
}, 2000);
|
|
7222
|
+
}).catch(err => {
|
|
7223
|
+
console.error('Failed to copy ticket layout text blueprint: ', err);
|
|
7224
|
+
});
|
|
7225
|
+
}
|
|
7226
|
+
|
|
7052
7227
|
const labels = ${JSON.stringify(labels)};
|
|
7053
7228
|
const successRequestsData = ${JSON.stringify(successRequestsData)};
|
|
7054
7229
|
const failedWorkloadsData = ${JSON.stringify(failedWorkloadsData)};
|