@zeesoft/i18n-verify 3.4.3 → 3.4.5
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/executor.mjs +3347 -1093
- package/package.json +1 -1
package/dist/executor.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fs, { existsSync, statSync, readFileSync, writeFileSync, readdirSync, mkdirSync, appendFileSync, copyFileSync } from "fs";
|
|
2
|
-
import path, { join,
|
|
2
|
+
import path, { join, resolve, dirname, extname } from "path";
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
4
|
import { Table } from "console-table-printer";
|
|
5
5
|
import CDP from "chrome-remote-interface";
|
|
@@ -331,13 +331,24 @@ const imageToBase64 = (imagePath) => {
|
|
|
331
331
|
return imgInput.toString("base64");
|
|
332
332
|
};
|
|
333
333
|
const findFileUpwards = (filename, startUrl = import.meta.url) => {
|
|
334
|
-
let
|
|
335
|
-
while (
|
|
336
|
-
const
|
|
337
|
-
if (existsSync(
|
|
338
|
-
|
|
334
|
+
let cwd = process.cwd();
|
|
335
|
+
while (cwd) {
|
|
336
|
+
const p = resolve(cwd, filename);
|
|
337
|
+
if (existsSync(p)) return p;
|
|
338
|
+
const parent = dirname(cwd);
|
|
339
|
+
if (parent === cwd) break;
|
|
340
|
+
cwd = parent;
|
|
341
|
+
}
|
|
342
|
+
try {
|
|
343
|
+
let dir = dirname(fileURLToPath(startUrl));
|
|
344
|
+
while (dir) {
|
|
345
|
+
const filePath = resolve(dir, filename);
|
|
346
|
+
if (existsSync(filePath)) return filePath;
|
|
347
|
+
const parent = dirname(dir);
|
|
348
|
+
if (parent === dir) break;
|
|
349
|
+
dir = parent;
|
|
339
350
|
}
|
|
340
|
-
|
|
351
|
+
} catch (e) {
|
|
341
352
|
}
|
|
342
353
|
return null;
|
|
343
354
|
};
|
|
@@ -459,7 +470,7 @@ class BaseReport {
|
|
|
459
470
|
}
|
|
460
471
|
}
|
|
461
472
|
function getBodyData() {
|
|
462
|
-
return '<header class="report-header">\n <div class="header-left">\n <div class="brand-badge">\n <span class="brand-text">zAutomate<span class="brand-ai">.AI</span></span>\n </div>\n <div class="header-divider"></div>\n <div class="product-badge" id="productBadge" title="Product Name">\n <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m7.5 4.27 9 5.15"/><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>\n <span class="product-name" id="productName">Product</span>\n </div>\n <div class="mode-pill mode-sanity" id="modePill">\n <span class="mode-dot"></span>\n <span class="mode-label" id="modeLabel">Quick Sanity</span>\n </div>\n <div class="status-pill status-passed" id="statusPill">\n <span class="status-icon"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg></span>\n <span class="status-label" id="statusLabel">Passed</span>\n </div>\n <div class="timestamp-badge">\n <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>\n <span class="info" id="reportTimestamp">--</span>\n </div>\n </div>\n <div class="nav-tabs-wrapper">\n <nav class="tabs-list" id="menu">\n <button type="button" class="tab-item selected" data-page="overview">\n <svg class="tab-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect width="7" height="9" x="3" y="3" rx="1"/><rect width="7" height="5" x="14" y="3" rx="1"/><rect width="7" height="9" x="14" y="12" rx="1"/><rect width="7" height="5" x="3" y="16" rx="1"/></svg>\n <span>Overview</span>\n </button>\n <button type="button" class="tab-item" data-page="log">\n <svg class="tab-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" x2="20" y1="19" y2="19"/></svg>\n <span>View Log</span>\n </button>\n <div class="tab-dropdown" id="insightsTabDropdown">\n <button type="button" class="tab-item has-submenu" data-page="insights">\n <svg class="tab-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m22 7-8.5 8.5-5-5L2 17"/><polyline points="16 7 22 7 22 13"/></svg>\n <span>Insights</span>\n <svg class="tab-chevron" width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m6 9 6 6 6-6"/></svg>\n </button>\n <ul class="submenu"></ul>\n </div>\n </nav>\n </div>\n </header>\n <main class="report-main">\n <div class="content-wrapper">\n <div class="container">\n <div id="overview" class="content active">\n <div class="common-info card">\n <span class="title"></span>\n <p class="info"></p>\n <div class="section"></div>\n </div>\n <div class="overall-quality card">\n <span class="title">Overall I18n Coverage</span>\n <div class="section">\n <div class="block">\n <article>\n <p class="desc">\n zI18n-Verify report provides a comprehensive information\n about the I18n and L10n quality of your application.\n </p>\n <ul class="items">\n <li>\n <h4>Reviewed:</h4>\n <p class="detail">Total strings which are captured and processed by zI18n-Verify.</p>\n </li>\n <li>\n <h4>Internationalized:</h4>\n <p class="detail">Different types of value like string, number, date-time which are properly Internationalized.</p>\n </li>\n <li>\n <h4>Not Internationalized:</h4>\n <p class="detail">Values which are not Internationalized. Also includes Partially Localized strings and Encoding Issues.</p>\n </li>\n <li>\n <h4>Skipped:</h4>\n <p class="detail">Values which are skipped from processing because they are listed in DNT / Ignored lists or contains Auto Ignored pattern / User input pattern.</p>\n </li>\n </ul>\n </article>\n </div>\n <div class="block">\n <div class="graph"></div>\n </div>\n </div>\n </div>\n <div class="string-quality card">\n <span class="title">String Coverage</span>\n <div class="graph"></div>\n </div>\n <div class="skipped-items card">\n <span class="title">Skipped Items</span>\n <div class="graph"></div>\n </div>\n <div class="number-quality card">\n <span class="title">Number Coverage</span>\n <div class="graph"></div>\n </div>\n <div class="datetime-quality card">\n <span class="title">DateTime Coverage</span>\n <div class="graph"></div>\n </div>\n </div>\n <div id="page" class="content">\n <span class="title">Pages</span>\n <div class="section">\n <div class="desc"></div>\n </div>\n </div>\n <div id="log" class="content">\n <div class="terminal-container">\n <div class="terminal-header">\n <div class="terminal-dots">\n <span class="terminal-dot dot-close"></span>\n <span class="terminal-dot dot-min"></span>\n <span class="terminal-dot dot-max"></span>\n </div>\n <div class="terminal-title">\n <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" x2="20" y1="19" y2="19"/></svg>\n <span>Runtime Automation Execution Log</span>\n </div>\n <div class="terminal-actions">\n <input type="text" id="logSearchInput" class="terminal-search" placeholder="Filter logs..." />\n <button class="terminal-copy-btn" id="copyLogBtn" type="button" title="Copy Log">\n <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>\n <span>Copy</span>\n </button>\n </div>\n </div>\n <div class="log-content"><pre id="logPre"></pre></div>\n </div>\n </div>\n <div id="insights" class="content">\n <div class="cards">\n <span class="title">Locale Quality</span>\n <div class="holder"></div>\n </div>\n </div>\n <div id="locale" class="content">\n <div class="locale-header-bar">\n <button class="back-to-insights-btn" id="backToInsightsBtn" type="button">\n <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>\n <span>Back to Insights</span>\n </button>\n <span class="title">Locale Quality Details</span>\n </div>\n <div class="coverage-info">\n <table class="row-border hover order-column stripe"></table>\n </div>\n </div>\n </div>\n </div>\n <div id="imageViewer" class="image-viewer">\n <div class="image-viewer-backdrop" onclick="closeImageViewer()"></div>\n <div class="image-container">\n <div class="image-viewer-header">\n <span class="image-viewer-title">Layout Screenshot Preview</span>\n <button class="close-button" onclick="closeImageViewer()" title="Close (Esc)">×</button>\n </div>\n <div class="image-viewer-body">\n <img id="imageView" src="" alt="Screenshot Preview" />\n </div>\n </div>\n </div>\n </main>';
|
|
473
|
+
return '<header class="report-header">\n<div class="header-left">\n <div class="brand-badge">\n <span class="brand-text">zAutomate<span class="brand-ai">.AI</span></span>\n </div>\n <div class="header-divider"></div>\n <div class="product-badge" id="productBadge" title="Product Name">\n <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m7.5 4.27 9 5.15"/><path d="M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z"/><path d="m3.3 7 8.7 5 8.7-5"/><path d="M12 22V12"/></svg>\n <span class="product-name" id="productName">Product</span>\n </div>\n <div class="mode-pill mode-sanity" id="modePill">\n <span class="mode-dot"></span>\n <span class="mode-label" id="modeLabel">Quick Sanity</span>\n </div>\n <div class="status-pill status-passed" id="statusPill">\n <span class="status-icon"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg></span>\n <span class="status-label" id="statusLabel">Passed</span>\n </div>\n</div>\n<div class="nav-tabs-wrapper">\n <nav class="tabs-list" id="menu">\n <button type="button" class="tab-item selected" data-page="overview">\n <svg class="tab-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect width="7" height="9" x="3" y="3" rx="1"/><rect width="7" height="5" x="14" y="3" rx="1"/><rect width="7" height="9" x="14" y="12" rx="1"/><rect width="7" height="5" x="3" y="16" rx="1"/></svg>\n <span>Overview</span>\n </button>\n <button type="button" class="tab-item" data-page="insights" id="insightsTabBtn">\n <svg class="tab-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m22 7-8.5 8.5-5-5L2 17"/><polyline points="16 7 22 7 22 13"/></svg>\n <span>Insights</span>\n </button>\n <button type="button" class="tab-item" data-page="log">\n <svg class="tab-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><line x1="10" y1="9" x2="8" y2="9"/></svg>\n <span>View Log</span>\n </button>\n </nav>\n</div>\n</header>\n<main class="report-main">\n <div class="content-wrapper">\n <div class="container">\n <div id="overview" class="content active">\n <div class="common-info"></div>\n <div class="analytics-card card">\n <div class="analytics-card-header">\n <div class="analytics-title-group">\n <span class="title">i18n Reports Overview</span>\n <p class="analytics-subtitle">Consolidated internationalization and localization metrics across reviewed strings, numbers, dates, and skipped elements</p>\n </div>\n </div>\n <div class="analytics-grid">\n <div class="chart-panel string-quality">\n <div class="panel-header">\n <div class="panel-title-row">\n <span class="panel-title">String localization, untranslated & skipped items</span>\n <span class="tooltip-icon" data-tooltip="Overall distribution of translated strings, unlocalized strings, encoding defects, and skipped items (DNT, Ignored, User Inputs)."><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>\n </div>\n <span class="panel-desc">String localization, untranslated & skipped items</span>\n </div>\n <div class="string-quality-content">\n <div class="graph string-pie-graph"></div>\n <div class="string-legend-container"></div>\n </div>\n </div>\n <div class="chart-panel number-quality">\n <div class="panel-header">\n <div class="panel-title-row">\n <span class="panel-title">Numeric & Currency Coverage</span>\n <span class="tooltip-icon" data-tooltip="Checks for numeric values, percentages, and currencies formatted according to locale rules."><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>\n </div>\n <span class="panel-desc">Numeric, Currency & Percentage localization</span>\n </div>\n <div class="graph"></div>\n </div>\n <div class="chart-panel datetime-quality">\n <div class="panel-header">\n <div class="panel-title-row">\n <span class="panel-title">DateTime Coverage</span>\n <span class="tooltip-icon" data-tooltip="Verification of date, time, and datetime patterns formatted according to locale conventions."><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>\n </div>\n <span class="panel-desc">Date, Time & Combined DateTime formats</span>\n </div>\n <div class="graph"></div>\n </div>\n </div>\n </div>\n </div>\n <div id="page" class="content">\n <span class="title">Pages</span>\n <div class="section">\n <div class="desc"></div>\n </div>\n </div>\n <div id="log" class="content">\n <div class="log-viewer-card card">\n <div class="log-toolbar">\n <div class="log-toolbar-left">\n <div class="log-heading">\n <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><line x1="10" y1="9" x2="8" y2="9"/></svg>\n <span>Execution Logs</span>\n </div>\n <div class="log-stat-badges">\n <span class="log-badge-stat stat-all" id="logStatTotal">Total: 0</span>\n <span class="log-badge-stat stat-info" id="logStatInfo">Info: 0</span>\n <span class="log-badge-stat stat-warn" id="logStatWarn">Warn: 0</span>\n <span class="log-badge-stat stat-error" id="logStatError">Error: 0</span>\n </div>\n </div>\n <div class="log-toolbar-right">\n <div class="log-level-pills" id="logLevelPills">\n <button type="button" class="log-level-btn active" data-level="ALL">All</button>\n <button type="button" class="log-level-btn" data-level="INFO">Info</button>\n <button type="button" class="log-level-btn" data-level="WARN">Warn</button>\n <button type="button" class="log-level-btn" data-level="ERROR">Error</button>\n </div>\n <div class="log-search-container">\n <svg class="search-svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>\n <input type="text" id="logSearchInput" class="log-search-field" placeholder="Search log lines..." />\n </div>\n <button class="log-tool-btn" id="wrapToggleBtn" type="button" title="Toggle line wrap">\n <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="15" y2="12"/><path d="M21 12h-4a2 2 0 0 0-2 2v2a2 2 0 0 0 2 2h4"/><line x1="3" y1="18" x2="17" y2="18"/></svg>\n <span>Wrap</span>\n </button>\n <button class="log-tool-btn copy-btn" id="copyLogBtn" type="button" title="Copy log">\n <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg>\n <span>Copy</span>\n </button>\n </div>\n </div>\n <div class="log-stream-wrapper" id="logStreamWrapper">\n <div class="log-lines" id="logLines"></div>\n </div>\n </div>\n </div>\n <div id="insights" class="content">\n <div class="insights-card card">\n <div class="insights-card-header">\n <div class="insights-header-left">\n <span class="title">Locale Quality Insights</span>\n <p class="insights-subtitle">Cross-locale comparison across verification metrics, localization status, and formatting health</p>\n </div>\n <div class="insights-header-right">\n <div class="insights-search-wrapper">\n <svg class="search-svg" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>\n <input type="text" id="insightsSearchInput" class="insights-search-field" placeholder="Filter metrics / rows..." />\n </div>\n </div>\n </div>\n <div class="insights-table-container">\n <table class="insights-table" id="insightsTable">\n <thead id="insightsTableHead"></thead>\n <tbody id="insightsTableBody"></tbody>\n </table>\n </div>\n </div>\n </div>\n <div id="locale" class="content">\n <div class="locale-header-bar">\n <button class="back-to-insights-btn" id="backToInsightsBtn" type="button">\n <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg>\n <span>Back to Insights</span>\n </button>\n <span class="title">Locale Quality Details</span>\n </div>\n <div class="coverage-info">\n <table class="row-border hover order-column stripe"></table>\n </div>\n </div>\n </div>\n </div>\n <div id="imageViewer" class="image-viewer">\n <div class="image-viewer-backdrop" onclick="closeImageViewer()"></div>\n <div class="image-container">\n <div class="image-viewer-header">\n <span class="image-viewer-title">Layout Screenshot Preview</span>\n <button class="close-button" onclick="closeImageViewer()" title="Close (Esc)">×</button>\n </div>\n <div class="image-viewer-body">\n <img id="imageView" src="" alt="Screenshot Preview" />\n </div>\n </div>\n </div>\n <div id="screenshotGalleryModal" class="screenshot-gallery-modal" style="display:none;">\n <div class="gallery-modal-backdrop" onclick="closeScreenshotGallery()"></div>\n <div class="gallery-modal-dialog">\n <div class="gallery-modal-header">\n <div class="gallery-header-info">\n <span class="gallery-modal-title" id="galleryModalTitle">Screenshots</span>\n <span class="gallery-modal-badge" id="galleryModalBadge">0 items</span>\n </div>\n <button type="button" class="gallery-close-btn" onclick="closeScreenshotGallery()" title="Close (Esc)">×</button>\n </div>\n <div class="gallery-modal-body">\n <div class="gallery-preview-container">\n <div class="gallery-image-wrapper">\n <img id="galleryMainImg" src="" alt="Screenshot Preview" />\n <button type="button" class="gallery-nav-btn prev-btn" id="galleryPrevBtn" title="Previous (Left Arrow)">\n <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="15 18 9 12 15 6"/></svg>\n </button>\n <button type="button" class="gallery-nav-btn next-btn" id="galleryNextBtn" title="Next (Right Arrow)">\n <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg>\n </button>\n <button type="button" class="gallery-fullscreen-btn" id="galleryFullscreenBtn" title="Open Full View">\n <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>\n <span>Full View</span>\n </button>\n </div>\n <div class="gallery-item-details" id="galleryItemDetails">\n <div class="gallery-meta-row">\n <span class="gallery-counter" id="galleryCounter">Item 1 of 1</span>\n <span class="gallery-page-badge" id="galleryPageBadge">Page: Main</span>\n </div>\n <div class="gallery-text-box">\n <span class="gallery-text-label">Used String / Value:</span>\n <span class="gallery-text-val" id="galleryTextVal">--</span>\n </div>\n </div>\n </div>\n <div class="gallery-thumbnails-strip" id="galleryThumbnailsStrip"></div>\n </div>\n </div>\n </div>\n</main>';
|
|
463
474
|
}
|
|
464
475
|
function getCssData() {
|
|
465
476
|
return `:root {
|
|
@@ -586,7 +597,7 @@ html, body {
|
|
|
586
597
|
color: #059669;
|
|
587
598
|
border: 1px solid rgba(16, 185, 129, 0.2);
|
|
588
599
|
}
|
|
589
|
-
.mode-pill.mode-sanity .mode-dot { background-color: #
|
|
600
|
+
.mode-pill.mode-sanity .mode-dot { background-color: #5B6EE1; }
|
|
590
601
|
|
|
591
602
|
.mode-pill.mode-context {
|
|
592
603
|
background-color: rgba(59, 130, 246, 0.1);
|
|
@@ -666,6 +677,10 @@ html, body {
|
|
|
666
677
|
outline: none;
|
|
667
678
|
}
|
|
668
679
|
|
|
680
|
+
.timestamp-badge {
|
|
681
|
+
display: none !important;
|
|
682
|
+
}
|
|
683
|
+
|
|
669
684
|
.tab-item:hover {
|
|
670
685
|
color: var(--foreground);
|
|
671
686
|
}
|
|
@@ -868,7 +883,7 @@ html, body {
|
|
|
868
883
|
}
|
|
869
884
|
|
|
870
885
|
/* Graphs grid */
|
|
871
|
-
.string-quality, .skipped-items, .number-quality, .datetime-quality {
|
|
886
|
+
.string-quality, .skipped-items, .number-quality, .datetime-quality, .format-quality {
|
|
872
887
|
margin-bottom: 20px;
|
|
873
888
|
}
|
|
874
889
|
|
|
@@ -1096,99 +1111,6 @@ select.filter.dt-input {
|
|
|
1096
1111
|
flex-shrink: 0;
|
|
1097
1112
|
}
|
|
1098
1113
|
|
|
1099
|
-
/* Terminal Log */
|
|
1100
|
-
.terminal-container {
|
|
1101
|
-
background-color: #0f172a;
|
|
1102
|
-
color: #f8fafc;
|
|
1103
|
-
border-radius: var(--radius);
|
|
1104
|
-
border: 1px solid #1e293b;
|
|
1105
|
-
overflow: hidden;
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
|
-
.terminal-header {
|
|
1109
|
-
display: flex;
|
|
1110
|
-
align-items: center;
|
|
1111
|
-
justify-content: space-between;
|
|
1112
|
-
padding: 10px 14px;
|
|
1113
|
-
background-color: #1e293b;
|
|
1114
|
-
border-bottom: 1px solid #334155;
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
.terminal-dots {
|
|
1118
|
-
display: flex;
|
|
1119
|
-
gap: 6px;
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
.terminal-dot {
|
|
1123
|
-
width: 10px;
|
|
1124
|
-
height: 10px;
|
|
1125
|
-
border-radius: 50%;
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
.dot-close { background-color: #ef4444; }
|
|
1129
|
-
.dot-min { background-color: #f59e0b; }
|
|
1130
|
-
.dot-max { background-color: #10b981; }
|
|
1131
|
-
|
|
1132
|
-
.terminal-title {
|
|
1133
|
-
display: flex;
|
|
1134
|
-
align-items: center;
|
|
1135
|
-
gap: 6px;
|
|
1136
|
-
font-size: 12px;
|
|
1137
|
-
font-weight: 500;
|
|
1138
|
-
color: #94a3b8;
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
.terminal-actions {
|
|
1142
|
-
display: flex;
|
|
1143
|
-
align-items: center;
|
|
1144
|
-
gap: 8px;
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
.terminal-search {
|
|
1148
|
-
background-color: #0f172a;
|
|
1149
|
-
border: 1px solid #334155;
|
|
1150
|
-
color: #f8fafc;
|
|
1151
|
-
border-radius: 4px;
|
|
1152
|
-
padding: 4px 8px;
|
|
1153
|
-
font-size: 12px;
|
|
1154
|
-
outline: none;
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
.terminal-copy-btn {
|
|
1158
|
-
background-color: #334155;
|
|
1159
|
-
border: none;
|
|
1160
|
-
color: #f8fafc;
|
|
1161
|
-
border-radius: 4px;
|
|
1162
|
-
padding: 4px 10px;
|
|
1163
|
-
font-size: 12px;
|
|
1164
|
-
cursor: pointer;
|
|
1165
|
-
display: inline-flex;
|
|
1166
|
-
align-items: center;
|
|
1167
|
-
gap: 4px;
|
|
1168
|
-
font-family: inherit;
|
|
1169
|
-
transition: background 0.15s;
|
|
1170
|
-
}
|
|
1171
|
-
|
|
1172
|
-
.terminal-copy-btn:hover {
|
|
1173
|
-
background-color: #475569;
|
|
1174
|
-
}
|
|
1175
|
-
|
|
1176
|
-
.log-content pre {
|
|
1177
|
-
padding: 16px;
|
|
1178
|
-
margin: 0;
|
|
1179
|
-
font-family: 'JetBrains Mono', monospace;
|
|
1180
|
-
font-size: 12.5px;
|
|
1181
|
-
line-height: 1.6;
|
|
1182
|
-
max-height: 600px;
|
|
1183
|
-
overflow-y: auto;
|
|
1184
|
-
color: #38bdf8;
|
|
1185
|
-
white-space: pre-wrap;
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
.log-badge-info { color: #38bdf8; font-weight: 600; }
|
|
1189
|
-
.log-badge-warn { color: #f59e0b; font-weight: 600; }
|
|
1190
|
-
.log-badge-error { color: #ef4444; font-weight: 600; }
|
|
1191
|
-
|
|
1192
1114
|
/* Image Viewer Modal */
|
|
1193
1115
|
.image-viewer {
|
|
1194
1116
|
display: none;
|
|
@@ -1807,214 +1729,2162 @@ body .context-image-viewer .viewer .wrapper .image-section .split-view .target-i
|
|
|
1807
1729
|
.apexcharts-text {
|
|
1808
1730
|
fill: var(--text-muted) !important;
|
|
1809
1731
|
}
|
|
1810
|
-
|
|
1732
|
+
|
|
1733
|
+
|
|
1734
|
+
/* Consolidated Analytics Card */
|
|
1735
|
+
.analytics-card {
|
|
1736
|
+
padding: 20px 20px 16px 20px;
|
|
1737
|
+
background-color: var(--bg-card);
|
|
1738
|
+
border: 1px solid var(--border);
|
|
1739
|
+
border-radius: var(--radius);
|
|
1740
|
+
margin-bottom: 24px;
|
|
1811
1741
|
}
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
style,
|
|
1818
|
-
dataFilePaths = [],
|
|
1819
|
-
logData
|
|
1820
|
-
}) {
|
|
1821
|
-
const dataScripts = dataFilePaths.map((v) => '<script src="' + v + '" type="text/javascript"><\/script>').join("\n ");
|
|
1822
|
-
const logScript = logData ? '<script type="text/javascript">window.logData = ' + JSON.stringify(logData) + ";<\/script>" : "";
|
|
1823
|
-
return `<!DOCTYPE html>
|
|
1824
|
-
<html lang="en" data-theme="light">
|
|
1825
|
-
<head>
|
|
1826
|
-
<meta charset="UTF-8" />
|
|
1827
|
-
<meta name="charset" content="charset='UTF-8'" />
|
|
1828
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
1829
|
-
<meta name="company" content="Zeesoft" />
|
|
1830
|
-
<meta name="product" content="zAutomate.AI" />
|
|
1831
|
-
<meta name="author" content="Jitendra Maheshwari" />
|
|
1832
|
-
<meta name="email" content="jm@zeesoft.com" />
|
|
1833
|
-
<meta name="description" content="` + appName + ' - zAutomate.AI Quality Automation Report" />\n <title>' + appName + " - zAutomate.AI Report | " + reportTime + '</title>\n \n <!-- Google Fonts: Inter, Outfit, JetBrains Mono -->\n <link rel="preconnect" href="https://fonts.googleapis.com" />\n <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />\n <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&family=Outfit:wght@500;600;700;800&display=swap" rel="stylesheet" />\n \n <!-- DataTables CSS -->\n <link rel="stylesheet" href="https://cdn.datatables.net/2.0.3/css/dataTables.dataTables.min.css" />\n \n <!-- Early Theme Detection -->\n <script>\n (function() {\n try {\n var params = new URLSearchParams(window.location.search);\n var themeParam = params.get("theme");\n var storedTheme = localStorage.getItem("zqa_report_theme");\n var systemDark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;\n var activeTheme = themeParam || storedTheme || (systemDark ? "dark" : "light");\n document.documentElement.setAttribute("data-theme", activeTheme);\n if (params.get("standalone") === "false") {\n document.documentElement.classList.add("embedded");\n }\n } catch(e) {}\n })();\n <\/script>\n \n ' + dataScripts + "\n " + logScript + '\n \n <script src="https://code.jquery.com/jquery-3.7.1.slim.min.js" integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8=" crossorigin="anonymous" defer><\/script>\n <script src="https://cdn.jsdelivr.net/npm/apexcharts" defer><\/script>\n <script src="https://cdn.datatables.net/2.0.3/js/dataTables.min.js" defer><\/script>\n <style>\n ' + style + "\n </style>\n </head>\n <body>\n " + body + '\n </body>\n <script type="text/javascript" defer>\n ' + script + "\n <\/script>\n</html>\n";
|
|
1742
|
+
|
|
1743
|
+
.analytics-card-header {
|
|
1744
|
+
margin-bottom: 16px;
|
|
1745
|
+
padding-bottom: 12px;
|
|
1746
|
+
border-bottom: 1px solid var(--border);
|
|
1834
1747
|
}
|
|
1835
|
-
const menuBar = () => `(() => {
|
|
1836
|
-
if (DataStore.hasRuntimeError() || !DataStore.ranSuccessfully() || DataStore.isContextRun()) {
|
|
1837
|
-
var insightTab = document.querySelector('#insightsTabDropdown') || document.querySelector('[data-page="insights"]');
|
|
1838
|
-
if (insightTab) insightTab.remove();
|
|
1839
|
-
}
|
|
1840
1748
|
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
}
|
|
1847
|
-
var contents = document.querySelectorAll('.content');
|
|
1848
|
-
contents.forEach(function(content) {
|
|
1849
|
-
if (content.id !== section) {
|
|
1850
|
-
content.classList.remove('active');
|
|
1851
|
-
} else {
|
|
1852
|
-
content.classList.add('active');
|
|
1853
|
-
}
|
|
1854
|
-
});
|
|
1855
|
-
if (section === 'overview' && window.persistOverviewCharts) {
|
|
1856
|
-
window.persistOverviewCharts();
|
|
1857
|
-
}
|
|
1858
|
-
window.currentPage = section;
|
|
1859
|
-
};
|
|
1749
|
+
.analytics-title-group .title {
|
|
1750
|
+
font-size: 18px;
|
|
1751
|
+
font-weight: 700;
|
|
1752
|
+
color: var(--foreground);
|
|
1753
|
+
}
|
|
1860
1754
|
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
DataStore.getLocales().forEach(function(locale) {
|
|
1867
|
-
var li = document.createElement('li');
|
|
1868
|
-
li.classList.add('sub-menu-item');
|
|
1869
|
-
li.dataset.locale = locale;
|
|
1870
|
-
var a = document.createElement('a');
|
|
1871
|
-
a.href = '#';
|
|
1872
|
-
a.innerHTML = '<span class="locale-code">' + locale + '</span>';
|
|
1873
|
-
li.appendChild(a);
|
|
1874
|
-
ul.appendChild(li);
|
|
1875
|
-
});
|
|
1876
|
-
}
|
|
1877
|
-
}
|
|
1755
|
+
.analytics-subtitle {
|
|
1756
|
+
margin: 4px 0 0 0;
|
|
1757
|
+
font-size: 13px;
|
|
1758
|
+
color: var(--text-muted);
|
|
1759
|
+
}
|
|
1878
1760
|
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
var submenu = btn.parentElement.querySelector('.submenu');
|
|
1886
|
-
if (submenu) {
|
|
1887
|
-
submenu.classList.toggle('active');
|
|
1888
|
-
}
|
|
1889
|
-
tabButtons.forEach(function(b) { b.classList.remove('selected'); });
|
|
1890
|
-
btn.classList.add('selected');
|
|
1891
|
-
loadContent('insights');
|
|
1892
|
-
} else {
|
|
1893
|
-
tabButtons.forEach(function(b) { b.classList.remove('selected'); });
|
|
1894
|
-
btn.classList.add('selected');
|
|
1895
|
-
var activeSubmenu = document.querySelector('.submenu.active');
|
|
1896
|
-
if (activeSubmenu) activeSubmenu.classList.remove('active');
|
|
1897
|
-
loadContent(page);
|
|
1898
|
-
}
|
|
1899
|
-
});
|
|
1900
|
-
});
|
|
1761
|
+
.analytics-grid {
|
|
1762
|
+
display: grid;
|
|
1763
|
+
grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
|
|
1764
|
+
gap: 14px;
|
|
1765
|
+
align-items: stretch;
|
|
1766
|
+
}
|
|
1901
1767
|
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1768
|
+
@media (max-width: 1100px) {
|
|
1769
|
+
.analytics-grid {
|
|
1770
|
+
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)) !important;
|
|
1771
|
+
gap: 12px;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1908
1774
|
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
}
|
|
1923
|
-
}
|
|
1924
|
-
});
|
|
1775
|
+
.chart-panel {
|
|
1776
|
+
background-color: var(--muted-bg);
|
|
1777
|
+
border: 1px solid var(--border);
|
|
1778
|
+
border-radius: 8px;
|
|
1779
|
+
padding: 12px 12px 8px 12px;
|
|
1780
|
+
display: flex;
|
|
1781
|
+
flex-direction: column;
|
|
1782
|
+
min-width: 0;
|
|
1783
|
+
margin-bottom: 0 !important;
|
|
1784
|
+
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
|
1785
|
+
position: relative;
|
|
1786
|
+
overflow: visible;
|
|
1787
|
+
}
|
|
1925
1788
|
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
var insBtn = document.querySelector('.tab-item[data-page="insights"]');
|
|
1931
|
-
if (insBtn) insBtn.classList.add('selected');
|
|
1932
|
-
loadContent('insights');
|
|
1933
|
-
});
|
|
1934
|
-
}
|
|
1789
|
+
.chart-panel:hover {
|
|
1790
|
+
border-color: rgba(234, 88, 12, 0.35);
|
|
1791
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.04);
|
|
1792
|
+
}
|
|
1935
1793
|
|
|
1936
|
-
|
|
1937
|
-
|
|
1794
|
+
.chart-panel.skipped-items {
|
|
1795
|
+
grid-column: span 2;
|
|
1796
|
+
}
|
|
1938
1797
|
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
if (DataStore.isSanityRun()) {
|
|
1943
|
-
modeLabelEl.textContent = 'Quick Sanity';
|
|
1944
|
-
modePillEl.className = 'mode-pill mode-sanity';
|
|
1945
|
-
} else if (DataStore.isContextRun()) {
|
|
1946
|
-
modeLabelEl.textContent = 'Context Creation';
|
|
1947
|
-
modePillEl.className = 'mode-pill mode-context';
|
|
1948
|
-
} else {
|
|
1949
|
-
modeLabelEl.textContent = 'i18n Verification';
|
|
1950
|
-
modePillEl.className = 'mode-pill mode-i18n';
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
1798
|
+
.panel-header {
|
|
1799
|
+
margin-bottom: 10px;
|
|
1800
|
+
}
|
|
1953
1801
|
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
statusPillEl.className = 'status-pill status-failed';
|
|
1960
|
-
statusLabelEl.textContent = 'Failed';
|
|
1961
|
-
} else {
|
|
1962
|
-
statusPillEl.className = 'status-pill status-passed';
|
|
1963
|
-
statusLabelEl.textContent = 'Passed';
|
|
1964
|
-
}
|
|
1965
|
-
}
|
|
1802
|
+
.panel-title-row {
|
|
1803
|
+
display: flex;
|
|
1804
|
+
align-items: center;
|
|
1805
|
+
gap: 6px;
|
|
1806
|
+
}
|
|
1966
1807
|
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
} catch(e) {
|
|
1973
|
-
timestampEl.textContent = new Date().toLocaleString();
|
|
1974
|
-
}
|
|
1975
|
-
}
|
|
1808
|
+
.panel-title {
|
|
1809
|
+
font-size: 13.5px;
|
|
1810
|
+
font-weight: 600;
|
|
1811
|
+
color: var(--foreground);
|
|
1812
|
+
}
|
|
1976
1813
|
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
document.getElementById('overview').innerHtml =
|
|
1984
|
-
'zAutomate.AI was unable to perform the operation. Please check the logs for more information.';
|
|
1985
|
-
return;
|
|
1986
|
-
}
|
|
1814
|
+
.panel-desc {
|
|
1815
|
+
font-size: 11.5px;
|
|
1816
|
+
color: var(--text-muted);
|
|
1817
|
+
display: block;
|
|
1818
|
+
margin-top: 2px;
|
|
1819
|
+
}
|
|
1987
1820
|
|
|
1988
|
-
document.addEventListener('DOMContentLoaded', function () {
|
|
1989
|
-
// don't render overview contents for sanity and context run
|
|
1990
|
-
if(DataStore.isContextRun() || DataStore.isSanityRun()) {
|
|
1991
|
-
document.querySelector('.content-wrapper')?.classList.add('--hide-overflow');
|
|
1992
|
-
document.querySelectorAll('#overview .card')?.forEach((el) => {
|
|
1993
|
-
if(!el.classList.contains('common-info')) {
|
|
1994
|
-
el.remove();
|
|
1995
|
-
}
|
|
1996
|
-
});
|
|
1997
1821
|
|
|
1998
|
-
|
|
1999
|
-
|
|
1822
|
+
.tooltip-icon {
|
|
1823
|
+
display: inline-flex;
|
|
1824
|
+
align-items: center;
|
|
1825
|
+
justify-content: center;
|
|
1826
|
+
color: var(--text-muted);
|
|
1827
|
+
cursor: help;
|
|
1828
|
+
position: relative;
|
|
1829
|
+
line-height: 1;
|
|
1830
|
+
transition: color 0.15s ease, opacity 0.15s ease;
|
|
1831
|
+
opacity: 0.7;
|
|
1832
|
+
}
|
|
2000
1833
|
|
|
2001
|
-
|
|
2002
|
-
|
|
1834
|
+
.tooltip-icon:hover {
|
|
1835
|
+
color: var(--accent, #ea580c);
|
|
1836
|
+
opacity: 1;
|
|
1837
|
+
}
|
|
2003
1838
|
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
1839
|
+
.tooltip-icon svg {
|
|
1840
|
+
display: block;
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
.tooltip-icon:hover::after {
|
|
1844
|
+
content: attr(data-tooltip);
|
|
1845
|
+
position: absolute;
|
|
1846
|
+
bottom: calc(100% + 8px);
|
|
1847
|
+
left: 0;
|
|
1848
|
+
background: #18181b;
|
|
1849
|
+
color: #f4f4f5;
|
|
1850
|
+
padding: 8px 12px;
|
|
1851
|
+
border-radius: 6px;
|
|
1852
|
+
font-size: 12px;
|
|
1853
|
+
line-height: 1.4;
|
|
1854
|
+
white-space: normal;
|
|
1855
|
+
width: 250px;
|
|
1856
|
+
z-index: 1000;
|
|
1857
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.25);
|
|
1858
|
+
pointer-events: none;
|
|
1859
|
+
font-weight: 400;
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
/* Custom Micro ApexCharts Tooltips */
|
|
1863
|
+
.apexcharts-tooltip {
|
|
1864
|
+
background: transparent !important;
|
|
1865
|
+
border: none !important;
|
|
1866
|
+
box-shadow: none !important;
|
|
1867
|
+
padding: 0 !important;
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
.apexcharts-tooltip .apexcharts-tooltip-title,
|
|
1871
|
+
.apexcharts-tooltip-title {
|
|
1872
|
+
display: none !important;
|
|
1873
|
+
border: none !important;
|
|
1874
|
+
border-bottom: none !important;
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
.pie-tooltip-custom,
|
|
1878
|
+
.bar-tooltip-custom {
|
|
1879
|
+
display: inline-flex;
|
|
1880
|
+
align-items: center;
|
|
1881
|
+
gap: 6px;
|
|
1882
|
+
padding: 4px 8px;
|
|
1883
|
+
background: #ffffff;
|
|
1884
|
+
border: 1px solid #cbd5e1;
|
|
1885
|
+
border-radius: 6px;
|
|
1886
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
1887
|
+
font-size: 11px;
|
|
1888
|
+
color: #0f172a;
|
|
1889
|
+
white-space: nowrap;
|
|
1890
|
+
font-family: inherit;
|
|
1891
|
+
pointer-events: none;
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
.pie-tooltip-dot,
|
|
1895
|
+
.bar-tooltip-dot {
|
|
1896
|
+
width: 7px;
|
|
1897
|
+
height: 7px;
|
|
1898
|
+
border-radius: 50%;
|
|
1899
|
+
flex-shrink: 0;
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
.pie-tooltip-label,
|
|
1903
|
+
.bar-tooltip-label {
|
|
1904
|
+
color: #475569;
|
|
1905
|
+
font-weight: 500;
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
.pie-tooltip-val,
|
|
1909
|
+
.bar-tooltip-val {
|
|
1910
|
+
color: #0f172a;
|
|
1911
|
+
font-weight: 700;
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
/* Header Badge for Total Coverage */
|
|
1915
|
+
.coverage-header-badge {
|
|
1916
|
+
margin-left: auto;
|
|
1917
|
+
display: inline-flex;
|
|
1918
|
+
align-items: center;
|
|
1919
|
+
gap: 6px;
|
|
1920
|
+
background: rgba(49, 233, 148, 0.12);
|
|
1921
|
+
border: 1px solid rgba(49, 233, 148, 0.35);
|
|
1922
|
+
padding: 2.5px 8px;
|
|
1923
|
+
border-radius: 9999px;
|
|
1924
|
+
font-size: 11px;
|
|
1925
|
+
white-space: nowrap;
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
.coverage-header-badge .coverage-pulse-dot {
|
|
1929
|
+
width: 6px;
|
|
1930
|
+
height: 6px;
|
|
1931
|
+
border-radius: 50%;
|
|
1932
|
+
background: #10b981;
|
|
1933
|
+
box-shadow: 0 0 0 2px rgba(16, 185, 129, 0.25);
|
|
1934
|
+
animation: coveragePulse 2s infinite ease-in-out;
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
@keyframes coveragePulse {
|
|
1938
|
+
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.5); }
|
|
1939
|
+
70% { transform: scale(1); box-shadow: 0 0 0 4px rgba(16, 185, 129, 0); }
|
|
1940
|
+
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
.coverage-header-badge .coverage-badge-label {
|
|
1944
|
+
color: var(--text-muted);
|
|
1945
|
+
font-weight: 500;
|
|
1946
|
+
font-size: 10px;
|
|
1947
|
+
text-transform: uppercase;
|
|
1948
|
+
letter-spacing: 0.3px;
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
.coverage-header-badge .coverage-badge-val {
|
|
1952
|
+
color: var(--foreground);
|
|
1953
|
+
font-weight: 700;
|
|
1954
|
+
font-size: 11.5px;
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1957
|
+
/* Side-by-side Layout for String Quality Panel */
|
|
1958
|
+
.string-quality-content {
|
|
1959
|
+
display: flex;
|
|
1960
|
+
align-items: center;
|
|
1961
|
+
justify-content: space-between;
|
|
1962
|
+
gap: 6px;
|
|
1963
|
+
width: 100%;
|
|
1964
|
+
margin-top: 2px;
|
|
1965
|
+
overflow: visible;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
.string-pie-graph {
|
|
1969
|
+
flex: 0 0 155px;
|
|
1970
|
+
max-width: 155px;
|
|
1971
|
+
min-width: 120px;
|
|
1972
|
+
min-height: 195px;
|
|
1973
|
+
display: flex;
|
|
1974
|
+
align-items: center;
|
|
1975
|
+
justify-content: center;
|
|
1976
|
+
overflow: hidden;
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
.string-pie-graph .apexcharts-canvas {
|
|
1980
|
+
margin: 0 auto;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
.string-legend-container {
|
|
1984
|
+
flex: 1;
|
|
1985
|
+
min-width: 0;
|
|
1986
|
+
display: flex;
|
|
1987
|
+
flex-direction: column;
|
|
1988
|
+
justify-content: center;
|
|
1989
|
+
position: relative;
|
|
1990
|
+
overflow: visible;
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
/* Total Coverage Summary Card in Legend */
|
|
1994
|
+
.total-coverage-card {
|
|
1995
|
+
background: var(--bg-card);
|
|
1996
|
+
border: 1px solid var(--border);
|
|
1997
|
+
border-radius: 6px;
|
|
1998
|
+
padding: 4px 7px;
|
|
1999
|
+
margin-bottom: 5px;
|
|
2000
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
.coverage-card-header {
|
|
2004
|
+
display: flex;
|
|
2005
|
+
align-items: center;
|
|
2006
|
+
justify-content: space-between;
|
|
2007
|
+
margin-bottom: 4px;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
.coverage-card-title {
|
|
2011
|
+
font-size: 10px;
|
|
2012
|
+
font-weight: 600;
|
|
2013
|
+
color: var(--text-muted);
|
|
2014
|
+
text-transform: uppercase;
|
|
2015
|
+
letter-spacing: 0.3px;
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
.coverage-card-pct {
|
|
2019
|
+
font-size: 12.5px;
|
|
2020
|
+
font-weight: 800;
|
|
2021
|
+
color: #10b981;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
.coverage-card-bar {
|
|
2025
|
+
background: var(--muted-bg, #f1f5f9);
|
|
2026
|
+
height: 5px;
|
|
2027
|
+
border-radius: 3px;
|
|
2028
|
+
overflow: hidden;
|
|
2029
|
+
position: relative;
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
.coverage-card-fill {
|
|
2033
|
+
background: linear-gradient(90deg, #4F46E5, #5B6EE1);
|
|
2034
|
+
height: 100%;
|
|
2035
|
+
border-radius: 3px;
|
|
2036
|
+
transition: width 0.5s ease;
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
/* Legend items list */
|
|
2040
|
+
.string-legend-list {
|
|
2041
|
+
display: flex;
|
|
2042
|
+
flex-direction: column;
|
|
2043
|
+
gap: 3px;
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
.legend-row-item {
|
|
2047
|
+
position: relative;
|
|
2048
|
+
display: flex;
|
|
2049
|
+
align-items: center;
|
|
2050
|
+
font-size: 11px;
|
|
2051
|
+
color: var(--foreground);
|
|
2052
|
+
user-select: none;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
.legend-row-item.is-clickable {
|
|
2056
|
+
cursor: pointer;
|
|
2057
|
+
padding: 2.5px 5px;
|
|
2058
|
+
border-radius: 4px;
|
|
2059
|
+
transition: background 0.15s ease;
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
.legend-row-item.is-clickable:hover {
|
|
2063
|
+
background: rgba(148, 163, 184, 0.12);
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
.legend-row-item.inactive {
|
|
2067
|
+
opacity: 0.35;
|
|
2068
|
+
filter: grayscale(60%);
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
.legend-circle-dot {
|
|
2072
|
+
width: 8px;
|
|
2073
|
+
height: 8px;
|
|
2074
|
+
border-radius: 50%;
|
|
2075
|
+
display: inline-block;
|
|
2076
|
+
flex-shrink: 0;
|
|
2077
|
+
margin-right: 5px;
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
.legend-row-label {
|
|
2081
|
+
display: inline-flex;
|
|
2082
|
+
align-items: center;
|
|
2083
|
+
gap: 3px;
|
|
2084
|
+
font-size: 10.5px;
|
|
2085
|
+
color: var(--foreground);
|
|
2086
|
+
white-space: nowrap;
|
|
2087
|
+
overflow: hidden;
|
|
2088
|
+
text-overflow: ellipsis;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
.legend-row-pct {
|
|
2092
|
+
font-weight: 600;
|
|
2093
|
+
color: var(--text-muted);
|
|
2094
|
+
font-size: 10.5px;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
/* Interactive Split Item (Ignored, DNT, User Inputs) */
|
|
2098
|
+
.legend-row-item.is-interactive {
|
|
2099
|
+
display: block;
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
.interactive-btn-inner {
|
|
2103
|
+
display: flex;
|
|
2104
|
+
align-items: center;
|
|
2105
|
+
padding: 2.5px 5px;
|
|
2106
|
+
border-radius: 5px;
|
|
2107
|
+
border: 1px solid var(--border);
|
|
2108
|
+
background: var(--bg-card);
|
|
2109
|
+
cursor: pointer;
|
|
2110
|
+
transition: all 0.15s ease;
|
|
2111
|
+
width: 100%;
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
.interactive-btn-inner:hover {
|
|
2115
|
+
border-color: var(--accent, #ea580c);
|
|
2116
|
+
background: rgba(234, 88, 12, 0.04);
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
.legend-row-item.is-open .interactive-btn-inner {
|
|
2120
|
+
border-color: var(--accent, #ea580c);
|
|
2121
|
+
box-shadow: 0 0 0 2px rgba(234, 88, 12, 0.15);
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
.interactive-btn-inner .chevron-icon {
|
|
2125
|
+
margin-left: auto;
|
|
2126
|
+
color: var(--text-muted);
|
|
2127
|
+
transition: transform 0.2s ease;
|
|
2128
|
+
flex-shrink: 0;
|
|
2129
|
+
}
|
|
2130
|
+
|
|
2131
|
+
.interactive-btn-inner:hover .chevron-icon {
|
|
2132
|
+
color: var(--foreground);
|
|
2133
|
+
}
|
|
2134
|
+
|
|
2135
|
+
.chevron-icon.is-open {
|
|
2136
|
+
transform: rotate(180deg);
|
|
2137
|
+
color: var(--accent, #ea580c);
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
/* Vertical Dropdown Menu (Pops Below Row and Floats Unclipped) */
|
|
2141
|
+
.legend-row-item .split-dropdown-menu {
|
|
2142
|
+
position: absolute;
|
|
2143
|
+
top: calc(100% + 4px);
|
|
2144
|
+
bottom: auto;
|
|
2145
|
+
left: 0;
|
|
2146
|
+
width: 100%;
|
|
2147
|
+
min-width: 145px;
|
|
2148
|
+
background: var(--bg-card);
|
|
2149
|
+
border: 1px solid var(--border);
|
|
2150
|
+
border-radius: 8px;
|
|
2151
|
+
padding: 5px;
|
|
2152
|
+
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.25), 0 8px 10px -6px rgba(0, 0, 0, 0.15);
|
|
2153
|
+
z-index: 100;
|
|
2154
|
+
display: flex;
|
|
2155
|
+
flex-direction: column;
|
|
2156
|
+
gap: 3px;
|
|
2157
|
+
animation: splitDropdownIn 0.15s ease-out;
|
|
2158
|
+
}
|
|
2159
|
+
|
|
2160
|
+
@keyframes splitDropdownIn {
|
|
2161
|
+
from {
|
|
2162
|
+
opacity: 0;
|
|
2163
|
+
transform: translateY(-4px);
|
|
2164
|
+
}
|
|
2165
|
+
to {
|
|
2166
|
+
opacity: 1;
|
|
2167
|
+
transform: translateY(0);
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
|
|
2171
|
+
.legend-row-item .dropdown-header {
|
|
2172
|
+
display: flex;
|
|
2173
|
+
align-items: center;
|
|
2174
|
+
justify-content: space-between;
|
|
2175
|
+
font-size: 9.5px;
|
|
2176
|
+
font-weight: 600;
|
|
2177
|
+
color: var(--text-muted);
|
|
2178
|
+
text-transform: uppercase;
|
|
2179
|
+
letter-spacing: 0.3px;
|
|
2180
|
+
padding: 2px 4px 4px 4px;
|
|
2181
|
+
border-bottom: 1px solid var(--border);
|
|
2182
|
+
margin-bottom: 2px;
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
.legend-row-item .dropdown-header-total {
|
|
2186
|
+
font-weight: 700;
|
|
2187
|
+
color: var(--foreground);
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
.legend-row-item .dropdown-item {
|
|
2191
|
+
display: flex;
|
|
2192
|
+
align-items: center;
|
|
2193
|
+
justify-content: space-between;
|
|
2194
|
+
gap: 8px;
|
|
2195
|
+
padding: 4px 6px;
|
|
2196
|
+
border-radius: 4px;
|
|
2197
|
+
font-size: 11px;
|
|
2198
|
+
color: var(--foreground);
|
|
2199
|
+
cursor: pointer;
|
|
2200
|
+
transition: all 0.15s ease;
|
|
2201
|
+
user-select: none;
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
.legend-row-item .dropdown-item:hover {
|
|
2205
|
+
background: rgba(148, 163, 184, 0.12);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
.legend-row-item .dropdown-item.inactive {
|
|
2209
|
+
opacity: 0.35;
|
|
2210
|
+
filter: grayscale(60%);
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
.legend-row-item .dropdown-item-left {
|
|
2214
|
+
display: inline-flex;
|
|
2215
|
+
align-items: center;
|
|
2216
|
+
gap: 5px;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
.legend-row-item .dropdown-item-left .dot {
|
|
2220
|
+
width: 7px;
|
|
2221
|
+
height: 7px;
|
|
2222
|
+
border-radius: 50%;
|
|
2223
|
+
display: inline-block;
|
|
2224
|
+
flex-shrink: 0;
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
.legend-row-item .dropdown-item-label {
|
|
2228
|
+
font-size: 11px;
|
|
2229
|
+
color: var(--foreground);
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
.legend-row-item .dropdown-item-val {
|
|
2233
|
+
font-weight: 600;
|
|
2234
|
+
font-size: 11px;
|
|
2235
|
+
color: var(--foreground);
|
|
2236
|
+
}
|
|
2237
|
+
|
|
2238
|
+
/* Modern Log Viewer Card */
|
|
2239
|
+
.log-viewer-card {
|
|
2240
|
+
background-color: var(--bg-card);
|
|
2241
|
+
border: 1px solid var(--border);
|
|
2242
|
+
border-radius: var(--radius);
|
|
2243
|
+
overflow: hidden;
|
|
2244
|
+
display: flex;
|
|
2245
|
+
flex-direction: column;
|
|
2246
|
+
height: calc(100vh - 120px);
|
|
2247
|
+
min-height: 600px;
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
.log-toolbar {
|
|
2251
|
+
padding: 12px 18px;
|
|
2252
|
+
background-color: var(--bg-card);
|
|
2253
|
+
border-bottom: 1px solid var(--border);
|
|
2254
|
+
display: flex;
|
|
2255
|
+
align-items: center;
|
|
2256
|
+
justify-content: space-between;
|
|
2257
|
+
gap: 16px;
|
|
2258
|
+
flex-wrap: wrap;
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
.log-toolbar-left {
|
|
2262
|
+
display: flex;
|
|
2263
|
+
align-items: center;
|
|
2264
|
+
gap: 14px;
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
.log-heading {
|
|
2268
|
+
display: flex;
|
|
2269
|
+
align-items: center;
|
|
2270
|
+
gap: 8px;
|
|
2271
|
+
font-weight: 600;
|
|
2272
|
+
font-size: 14px;
|
|
2273
|
+
color: var(--foreground);
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
.log-stat-badges {
|
|
2277
|
+
display: flex;
|
|
2278
|
+
gap: 6px;
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
.log-badge-stat {
|
|
2282
|
+
font-size: 11px;
|
|
2283
|
+
font-weight: 500;
|
|
2284
|
+
padding: 2px 7px;
|
|
2285
|
+
border-radius: 4px;
|
|
2286
|
+
border: 1px solid var(--border);
|
|
2287
|
+
background-color: var(--muted-bg);
|
|
2288
|
+
color: var(--text-muted);
|
|
2289
|
+
}
|
|
2290
|
+
|
|
2291
|
+
.log-badge-stat.stat-info { color: #0284c7; background: rgba(2, 132, 199, 0.08); border-color: rgba(2, 132, 199, 0.2); }
|
|
2292
|
+
.log-badge-stat.stat-warn { color: #d97706; background: rgba(217, 119, 6, 0.08); border-color: rgba(217, 119, 6, 0.2); }
|
|
2293
|
+
.log-badge-stat.stat-error { color: #dc2626; background: rgba(220, 38, 38, 0.08); border-color: rgba(220, 38, 38, 0.2); }
|
|
2294
|
+
|
|
2295
|
+
.log-toolbar-right {
|
|
2296
|
+
display: flex;
|
|
2297
|
+
align-items: center;
|
|
2298
|
+
gap: 10px;
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
.log-level-pills {
|
|
2302
|
+
display: flex;
|
|
2303
|
+
background-color: var(--muted-bg);
|
|
2304
|
+
border-radius: 6px;
|
|
2305
|
+
padding: 2px;
|
|
2306
|
+
gap: 2px;
|
|
2307
|
+
}
|
|
2308
|
+
|
|
2309
|
+
.log-level-btn {
|
|
2310
|
+
border: none;
|
|
2311
|
+
background: transparent;
|
|
2312
|
+
padding: 4px 10px;
|
|
2313
|
+
font-size: 12px;
|
|
2314
|
+
font-weight: 500;
|
|
2315
|
+
color: var(--text-muted);
|
|
2316
|
+
border-radius: 4px;
|
|
2317
|
+
cursor: pointer;
|
|
2318
|
+
transition: all 0.15s ease;
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
.log-level-btn.active {
|
|
2322
|
+
background-color: var(--bg-card);
|
|
2323
|
+
color: var(--foreground);
|
|
2324
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
|
|
2325
|
+
font-weight: 600;
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
.log-search-container {
|
|
2329
|
+
position: relative;
|
|
2330
|
+
display: flex;
|
|
2331
|
+
align-items: center;
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
.search-svg {
|
|
2335
|
+
position: absolute;
|
|
2336
|
+
left: 10px;
|
|
2337
|
+
color: var(--text-muted);
|
|
2338
|
+
pointer-events: none;
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
.log-search-field {
|
|
2342
|
+
padding: 5px 12px 5px 28px;
|
|
2343
|
+
font-size: 12px;
|
|
2344
|
+
border: 1px solid var(--border);
|
|
2345
|
+
border-radius: 6px;
|
|
2346
|
+
background-color: var(--muted-bg);
|
|
2347
|
+
color: var(--foreground);
|
|
2348
|
+
width: 180px;
|
|
2349
|
+
outline: none;
|
|
2350
|
+
transition: all 0.15s ease;
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
.log-search-field:focus {
|
|
2354
|
+
border-color: var(--accent);
|
|
2355
|
+
background-color: var(--bg-card);
|
|
2356
|
+
width: 220px;
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
.log-tool-btn {
|
|
2360
|
+
display: inline-flex;
|
|
2361
|
+
align-items: center;
|
|
2362
|
+
gap: 5px;
|
|
2363
|
+
background-color: var(--muted-bg);
|
|
2364
|
+
border: 1px solid var(--border);
|
|
2365
|
+
color: var(--foreground);
|
|
2366
|
+
padding: 5px 10px;
|
|
2367
|
+
border-radius: 6px;
|
|
2368
|
+
font-size: 12px;
|
|
2369
|
+
font-weight: 500;
|
|
2370
|
+
cursor: pointer;
|
|
2371
|
+
transition: all 0.15s ease;
|
|
2372
|
+
}
|
|
2373
|
+
|
|
2374
|
+
.log-tool-btn:hover {
|
|
2375
|
+
background-color: var(--border);
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
.log-tool-btn.active {
|
|
2379
|
+
background-color: var(--accent-light);
|
|
2380
|
+
color: var(--accent);
|
|
2381
|
+
border-color: var(--accent);
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
.log-stream-wrapper {
|
|
2385
|
+
flex: 1;
|
|
2386
|
+
overflow-y: auto;
|
|
2387
|
+
overflow-x: auto;
|
|
2388
|
+
background-color: var(--bg-card);
|
|
2389
|
+
font-family: 'JetBrains Mono', 'Menlo', 'Monaco', monospace;
|
|
2390
|
+
font-size: 12.5px;
|
|
2391
|
+
line-height: 1.6;
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
[data-theme="dark"] .log-stream-wrapper {
|
|
2395
|
+
background-color: #0c0a09;
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2398
|
+
.log-lines {
|
|
2399
|
+
padding: 8px 0;
|
|
2400
|
+
min-width: 100%;
|
|
2401
|
+
width: max-content;
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
.log-lines.wrapped {
|
|
2405
|
+
width: 100%;
|
|
2406
|
+
}
|
|
2407
|
+
|
|
2408
|
+
.log-row {
|
|
2409
|
+
display: flex;
|
|
2410
|
+
align-items: flex-start;
|
|
2411
|
+
padding: 2px 14px;
|
|
2412
|
+
gap: 12px;
|
|
2413
|
+
transition: background-color 0.1s ease;
|
|
2414
|
+
}
|
|
2415
|
+
|
|
2416
|
+
.log-row:hover {
|
|
2417
|
+
background-color: rgba(234, 88, 12, 0.05);
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
.log-row.row-error {
|
|
2421
|
+
background-color: rgba(239, 68, 68, 0.08);
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
.log-row.row-warn {
|
|
2425
|
+
background-color: rgba(245, 158, 11, 0.08);
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
.log-ln {
|
|
2429
|
+
width: 44px;
|
|
2430
|
+
min-width: 44px;
|
|
2431
|
+
text-align: right;
|
|
2432
|
+
color: var(--text-muted);
|
|
2433
|
+
user-select: none;
|
|
2434
|
+
opacity: 0.6;
|
|
2435
|
+
font-size: 11px;
|
|
2436
|
+
padding-top: 1px;
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2439
|
+
.log-msg {
|
|
2440
|
+
flex: 1;
|
|
2441
|
+
white-space: pre;
|
|
2442
|
+
color: var(--foreground);
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
.log-lines.wrapped .log-msg {
|
|
2446
|
+
white-space: pre-wrap;
|
|
2447
|
+
word-break: break-word;
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2450
|
+
.log-badge {
|
|
2451
|
+
display: inline-block;
|
|
2452
|
+
font-size: 10.5px;
|
|
2453
|
+
font-weight: 700;
|
|
2454
|
+
padding: 1px 5px;
|
|
2455
|
+
border-radius: 4px;
|
|
2456
|
+
margin-right: 6px;
|
|
2457
|
+
vertical-align: middle;
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
.badge-info { background: rgba(56, 189, 248, 0.15); color: #0284c7; }
|
|
2461
|
+
[data-theme="dark"] .badge-info { color: #38bdf8; }
|
|
2462
|
+
.badge-warn { background: rgba(245, 158, 11, 0.15); color: #d97706; }
|
|
2463
|
+
[data-theme="dark"] .badge-warn { color: #fbbf24; }
|
|
2464
|
+
.badge-error { background: rgba(239, 68, 68, 0.15); color: #dc2626; }
|
|
2465
|
+
[data-theme="dark"] .badge-error { color: #f87171; }
|
|
2466
|
+
|
|
2467
|
+
.log-highlight {
|
|
2468
|
+
background-color: #fde047;
|
|
2469
|
+
color: #0f172a;
|
|
2470
|
+
padding: 1px 3px;
|
|
2471
|
+
border-radius: 2px;
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
.log-empty-state {
|
|
2475
|
+
padding: 40px;
|
|
2476
|
+
text-align: center;
|
|
2477
|
+
color: var(--text-muted);
|
|
2478
|
+
font-style: italic;
|
|
2479
|
+
}
|
|
2480
|
+
|
|
2481
|
+
/* Insights Table View */
|
|
2482
|
+
.insights-card {
|
|
2483
|
+
background-color: var(--bg-card);
|
|
2484
|
+
border: 1px solid var(--border);
|
|
2485
|
+
border-radius: var(--radius);
|
|
2486
|
+
padding: 24px;
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
.insights-card-header {
|
|
2490
|
+
display: flex;
|
|
2491
|
+
align-items: center;
|
|
2492
|
+
justify-content: space-between;
|
|
2493
|
+
margin-bottom: 20px;
|
|
2494
|
+
padding-bottom: 16px;
|
|
2495
|
+
border-bottom: 1px solid var(--border);
|
|
2496
|
+
flex-wrap: wrap;
|
|
2497
|
+
gap: 12px;
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2500
|
+
.insights-card-header .title {
|
|
2501
|
+
font-size: 18px;
|
|
2502
|
+
font-weight: 700;
|
|
2503
|
+
color: var(--foreground);
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
.insights-subtitle {
|
|
2507
|
+
margin: 4px 0 0 0;
|
|
2508
|
+
font-size: 13px;
|
|
2509
|
+
color: var(--text-muted);
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
.insights-search-field {
|
|
2513
|
+
padding: 6px 12px;
|
|
2514
|
+
font-size: 13px;
|
|
2515
|
+
border: 1px solid var(--border);
|
|
2516
|
+
border-radius: 6px;
|
|
2517
|
+
background-color: var(--muted-bg);
|
|
2518
|
+
color: var(--foreground);
|
|
2519
|
+
outline: none;
|
|
2520
|
+
width: 200px;
|
|
2521
|
+
transition: all 0.15s ease;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
.insights-search-field:focus {
|
|
2525
|
+
border-color: var(--accent);
|
|
2526
|
+
background-color: var(--bg-card);
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2529
|
+
.insights-table-container {
|
|
2530
|
+
overflow-x: auto;
|
|
2531
|
+
border-radius: 8px;
|
|
2532
|
+
border: 1px solid var(--border);
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
.insights-table {
|
|
2536
|
+
width: 100%;
|
|
2537
|
+
border-collapse: collapse;
|
|
2538
|
+
text-align: left;
|
|
2539
|
+
font-size: 13px;
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
.insights-table th {
|
|
2543
|
+
background-color: var(--muted-bg);
|
|
2544
|
+
color: var(--text-muted);
|
|
2545
|
+
font-weight: 600;
|
|
2546
|
+
font-size: 12px;
|
|
2547
|
+
text-transform: uppercase;
|
|
2548
|
+
letter-spacing: 0.3px;
|
|
2549
|
+
padding: 12px 14px;
|
|
2550
|
+
border-bottom: 1px solid var(--border);
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
.insights-table td {
|
|
2554
|
+
padding: 12px 14px;
|
|
2555
|
+
border-bottom: 1px solid var(--border);
|
|
2556
|
+
vertical-align: middle;
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
.insights-locale-row {
|
|
2560
|
+
cursor: pointer;
|
|
2561
|
+
transition: background-color 0.15s ease;
|
|
2562
|
+
}
|
|
2563
|
+
|
|
2564
|
+
.insights-locale-row:hover {
|
|
2565
|
+
background-color: rgba(234, 88, 12, 0.04);
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
.locale-code-cell {
|
|
2569
|
+
display: flex;
|
|
2570
|
+
align-items: center;
|
|
2571
|
+
gap: 8px;
|
|
2572
|
+
}
|
|
2573
|
+
|
|
2574
|
+
.locale-pill-name {
|
|
2575
|
+
font-weight: 600;
|
|
2576
|
+
color: var(--foreground);
|
|
2577
|
+
font-family: 'JetBrains Mono', monospace;
|
|
2578
|
+
font-size: 13px;
|
|
2579
|
+
}
|
|
2580
|
+
|
|
2581
|
+
.default-badge {
|
|
2582
|
+
font-size: 10.5px;
|
|
2583
|
+
font-weight: 600;
|
|
2584
|
+
padding: 1px 6px;
|
|
2585
|
+
border-radius: 4px;
|
|
2586
|
+
background-color: rgba(59, 130, 246, 0.12);
|
|
2587
|
+
color: #2563eb;
|
|
2588
|
+
}
|
|
2589
|
+
|
|
2590
|
+
[data-theme="dark"] .default-badge {
|
|
2591
|
+
color: #60a5fa;
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
.table-progress-cell {
|
|
2595
|
+
display: flex;
|
|
2596
|
+
align-items: center;
|
|
2597
|
+
gap: 8px;
|
|
2598
|
+
min-width: 110px;
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2601
|
+
.table-progress-bar-bg {
|
|
2602
|
+
flex: 1;
|
|
2603
|
+
height: 7px;
|
|
2604
|
+
background-color: var(--muted-bg);
|
|
2605
|
+
border-radius: 4px;
|
|
2606
|
+
overflow: hidden;
|
|
2607
|
+
}
|
|
2608
|
+
|
|
2609
|
+
.table-progress-bar {
|
|
2610
|
+
height: 100%;
|
|
2611
|
+
border-radius: 4px;
|
|
2612
|
+
transition: width 0.3s ease;
|
|
2613
|
+
}
|
|
2614
|
+
|
|
2615
|
+
.table-progress-val {
|
|
2616
|
+
font-size: 12px;
|
|
2617
|
+
font-weight: 600;
|
|
2618
|
+
min-width: 32px;
|
|
2619
|
+
text-align: right;
|
|
2620
|
+
color: var(--foreground);
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
.strings-summary-badges {
|
|
2624
|
+
display: flex;
|
|
2625
|
+
gap: 4px;
|
|
2626
|
+
flex-wrap: wrap;
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
.mini-stat-badge {
|
|
2630
|
+
display: inline-flex;
|
|
2631
|
+
align-items: center;
|
|
2632
|
+
justify-content: center;
|
|
2633
|
+
padding: 2px 6px;
|
|
2634
|
+
border-radius: 4px;
|
|
2635
|
+
font-size: 11px;
|
|
2636
|
+
font-weight: 600;
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
.stat-green { background: rgba(16, 185, 129, 0.12); color: #059669; }
|
|
2640
|
+
[data-theme="dark"] .stat-green { color: #34d399; }
|
|
2641
|
+
.stat-yellow { background: rgba(245, 158, 11, 0.12); color: #d97706; }
|
|
2642
|
+
[data-theme="dark"] .stat-yellow { color: #fbbf24; }
|
|
2643
|
+
.stat-red { background: rgba(239, 68, 68, 0.12); color: #dc2626; }
|
|
2644
|
+
[data-theme="dark"] .stat-red { color: #f87171; }
|
|
2645
|
+
.stat-pink { background: rgba(244, 114, 182, 0.15); color: #db2777; }
|
|
2646
|
+
[data-theme="dark"] .stat-pink { color: #f472b6; }
|
|
2647
|
+
.stat-cyan { background: rgba(6, 182, 212, 0.15); color: #0891b2; }
|
|
2648
|
+
[data-theme="dark"] .stat-cyan { color: #22d3ee; }
|
|
2649
|
+
|
|
2650
|
+
.count-badge {
|
|
2651
|
+
display: inline-block;
|
|
2652
|
+
padding: 2px 7px;
|
|
2653
|
+
border-radius: 4px;
|
|
2654
|
+
background-color: var(--muted-bg);
|
|
2655
|
+
color: var(--text-muted);
|
|
2656
|
+
font-weight: 500;
|
|
2657
|
+
font-size: 12px;
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
.btn-view-details {
|
|
2661
|
+
display: inline-flex;
|
|
2662
|
+
align-items: center;
|
|
2663
|
+
gap: 4px;
|
|
2664
|
+
background-color: var(--muted-bg);
|
|
2665
|
+
border: 1px solid var(--border);
|
|
2666
|
+
color: var(--foreground);
|
|
2667
|
+
padding: 5px 10px;
|
|
2668
|
+
border-radius: 6px;
|
|
2669
|
+
font-size: 12px;
|
|
2670
|
+
font-weight: 500;
|
|
2671
|
+
cursor: pointer;
|
|
2672
|
+
transition: all 0.15s ease;
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
.btn-view-details:hover {
|
|
2676
|
+
background-color: var(--accent);
|
|
2677
|
+
color: #ffffff;
|
|
2678
|
+
border-color: var(--accent);
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2681
|
+
/* Category Pills & Status Badges for Locale Grid */
|
|
2682
|
+
.cell-term-text {
|
|
2683
|
+
font-weight: 500;
|
|
2684
|
+
color: var(--foreground);
|
|
2685
|
+
word-break: break-word;
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
.cat-pill {
|
|
2689
|
+
display: inline-flex;
|
|
2690
|
+
align-items: center;
|
|
2691
|
+
padding: 2px 8px;
|
|
2692
|
+
border-radius: 5px;
|
|
2693
|
+
font-size: 11.5px;
|
|
2694
|
+
font-weight: 600;
|
|
2695
|
+
letter-spacing: 0.2px;
|
|
2696
|
+
background-color: var(--muted-bg);
|
|
2697
|
+
color: var(--foreground);
|
|
2698
|
+
border: 1px solid var(--border);
|
|
2699
|
+
}
|
|
2700
|
+
|
|
2701
|
+
.cat-pill.cat-strings { background: rgba(59, 130, 246, 0.1); color: #2563eb; border-color: rgba(59, 130, 246, 0.2); }
|
|
2702
|
+
[data-theme="dark"] .cat-pill.cat-strings { color: #60a5fa; }
|
|
2703
|
+
|
|
2704
|
+
.cat-pill.cat-numbers, .cat-pill.cat-currency, .cat-pill.cat-percentage {
|
|
2705
|
+
background: rgba(168, 85, 247, 0.1); color: #9333ea; border-color: rgba(168, 85, 247, 0.2);
|
|
2706
|
+
}
|
|
2707
|
+
[data-theme="dark"] .cat-pill.cat-numbers, [data-theme="dark"] .cat-pill.cat-currency, [data-theme="dark"] .cat-pill.cat-percentage {
|
|
2708
|
+
color: #c084fc;
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
.cat-pill.cat-datetime, .cat-pill.cat-date, .cat-pill.cat-time {
|
|
2712
|
+
background: rgba(14, 165, 233, 0.1); color: #0284c7; border-color: rgba(14, 165, 233, 0.2);
|
|
2713
|
+
}
|
|
2714
|
+
[data-theme="dark"] .cat-pill.cat-datetime, [data-theme="dark"] .cat-pill.cat-date, [data-theme="dark"] .cat-pill.cat-time {
|
|
2715
|
+
color: #38bdf8;
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
.cat-pill.cat-skipped {
|
|
2719
|
+
background: rgba(148, 163, 184, 0.12); color: #64748b; border-color: rgba(148, 163, 184, 0.2);
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2722
|
+
.cat-pill.cat-layout {
|
|
2723
|
+
background: rgba(239, 68, 68, 0.1); color: #dc2626; border-color: rgba(239, 68, 68, 0.2);
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
.status-badge {
|
|
2727
|
+
display: inline-flex;
|
|
2728
|
+
align-items: center;
|
|
2729
|
+
padding: 2px 8px;
|
|
2730
|
+
border-radius: 5px;
|
|
2731
|
+
font-size: 11.5px;
|
|
2732
|
+
font-weight: 600;
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
.status-badge.status-green { background: rgba(16, 185, 129, 0.12); color: #059669; }
|
|
2736
|
+
[data-theme="dark"] .status-badge.status-green { color: #34d399; }
|
|
2737
|
+
.status-badge.status-red { background: rgba(239, 68, 68, 0.12); color: #dc2626; }
|
|
2738
|
+
[data-theme="dark"] .status-badge.status-red { color: #f87171; }
|
|
2739
|
+
.status-badge.status-yellow { background: rgba(245, 158, 11, 0.12); color: #d97706; }
|
|
2740
|
+
[data-theme="dark"] .status-badge.status-yellow { color: #fbbf24; }
|
|
2741
|
+
.status-badge.status-pink { background: rgba(244, 114, 182, 0.15); color: #db2777; }
|
|
2742
|
+
[data-theme="dark"] .status-badge.status-pink { color: #f472b6; }
|
|
2743
|
+
.status-badge.status-cyan { background: rgba(6, 182, 212, 0.15); color: #0891b2; }
|
|
2744
|
+
[data-theme="dark"] .status-badge.status-cyan { color: #22d3ee; }
|
|
2745
|
+
.status-badge.status-muted { background: rgba(148, 163, 184, 0.15); color: #64748b; }
|
|
2746
|
+
|
|
2747
|
+
|
|
2748
|
+
|
|
2749
|
+
.common-info:empty {
|
|
2750
|
+
display: none !important;
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
.chart-panel .graph {
|
|
2754
|
+
min-height: 220px;
|
|
2755
|
+
width: 100%;
|
|
2756
|
+
overflow: visible;
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2759
|
+
/* Transposed Insights Matrix Table */
|
|
2760
|
+
.insights-table {
|
|
2761
|
+
width: 100%;
|
|
2762
|
+
table-layout: fixed;
|
|
2763
|
+
border-collapse: collapse;
|
|
2764
|
+
font-size: 13px;
|
|
2765
|
+
}
|
|
2766
|
+
|
|
2767
|
+
.insights-table thead th {
|
|
2768
|
+
background: var(--muted-bg);
|
|
2769
|
+
color: var(--text-muted);
|
|
2770
|
+
font-weight: 600;
|
|
2771
|
+
font-size: 12px;
|
|
2772
|
+
text-transform: uppercase;
|
|
2773
|
+
letter-spacing: 0.5px;
|
|
2774
|
+
padding: 12px 14px;
|
|
2775
|
+
border-bottom: 2px solid var(--border);
|
|
2776
|
+
position: sticky;
|
|
2777
|
+
top: 0;
|
|
2778
|
+
z-index: 2;
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2781
|
+
.insights-table th.metric-col-header {
|
|
2782
|
+
text-align: left;
|
|
2783
|
+
width: 38%;
|
|
2784
|
+
}
|
|
2785
|
+
|
|
2786
|
+
.insights-table th.locale-col-header,
|
|
2787
|
+
.insights-table th.total-col-header {
|
|
2788
|
+
text-align: center;
|
|
2789
|
+
width: auto;
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
.col-header-inner {
|
|
2793
|
+
display: flex;
|
|
2794
|
+
flex-direction: column;
|
|
2795
|
+
align-items: center;
|
|
2796
|
+
gap: 4px;
|
|
2797
|
+
}
|
|
2798
|
+
|
|
2799
|
+
.locale-col-code {
|
|
2800
|
+
font-weight: 700;
|
|
2801
|
+
font-size: 13px;
|
|
2802
|
+
color: var(--text-primary);
|
|
2803
|
+
letter-spacing: 0.5px;
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
.col-default-badge {
|
|
2807
|
+
font-size: 10px;
|
|
2808
|
+
font-weight: 600;
|
|
2809
|
+
background: rgba(59, 130, 246, 0.12);
|
|
2810
|
+
color: #3b82f6;
|
|
2811
|
+
border-radius: 4px;
|
|
2812
|
+
padding: 1px 5px;
|
|
2813
|
+
text-transform: uppercase;
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
.btn-col-drilldown {
|
|
2817
|
+
display: inline-flex;
|
|
2818
|
+
align-items: center;
|
|
2819
|
+
gap: 4px;
|
|
2820
|
+
background: var(--card-bg);
|
|
2821
|
+
border: 1px solid var(--border);
|
|
2822
|
+
color: var(--text-muted);
|
|
2823
|
+
font-size: 11px;
|
|
2824
|
+
font-weight: 500;
|
|
2825
|
+
padding: 2px 7px;
|
|
2826
|
+
border-radius: 4px;
|
|
2827
|
+
cursor: pointer;
|
|
2828
|
+
transition: all 0.15s ease;
|
|
2829
|
+
}
|
|
2830
|
+
|
|
2831
|
+
.btn-col-drilldown:hover {
|
|
2832
|
+
border-color: var(--primary);
|
|
2833
|
+
color: var(--primary);
|
|
2834
|
+
background: rgba(234, 88, 12, 0.08);
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2837
|
+
.insights-table tbody tr {
|
|
2838
|
+
border-bottom: 1px solid var(--border);
|
|
2839
|
+
transition: background-color 0.15s ease;
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
.insights-table tbody tr:hover {
|
|
2843
|
+
background-color: rgba(234, 88, 12, 0.03);
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2846
|
+
.insights-table tbody tr.row-defect:hover {
|
|
2847
|
+
background-color: rgba(239, 68, 68, 0.04);
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
.insights-table tbody tr.row-total {
|
|
2851
|
+
background-color: var(--muted-bg);
|
|
2852
|
+
border-top: 2px solid var(--border);
|
|
2853
|
+
font-weight: 600;
|
|
2854
|
+
}
|
|
2855
|
+
|
|
2856
|
+
.insights-table tbody tr.row-total:hover {
|
|
2857
|
+
background-color: rgba(234, 88, 12, 0.06);
|
|
2858
|
+
}
|
|
2859
|
+
|
|
2860
|
+
.metric-name-cell {
|
|
2861
|
+
padding: 11px 16px;
|
|
2862
|
+
vertical-align: middle;
|
|
2863
|
+
}
|
|
2864
|
+
|
|
2865
|
+
.metric-name-inner {
|
|
2866
|
+
display: flex;
|
|
2867
|
+
align-items: center;
|
|
2868
|
+
gap: 10px;
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2871
|
+
.metric-cat-pill {
|
|
2872
|
+
display: inline-flex;
|
|
2873
|
+
align-items: center;
|
|
2874
|
+
justify-content: center;
|
|
2875
|
+
font-size: 10px;
|
|
2876
|
+
font-weight: 700;
|
|
2877
|
+
text-transform: uppercase;
|
|
2878
|
+
letter-spacing: 0.4px;
|
|
2879
|
+
padding: 3px 6px;
|
|
2880
|
+
border-radius: 4px;
|
|
2881
|
+
width: 84px;
|
|
2882
|
+
min-width: 84px;
|
|
2883
|
+
max-width: 84px;
|
|
2884
|
+
text-align: center;
|
|
2885
|
+
flex-shrink: 0;
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
.cat-strings { background: rgba(59, 130, 246, 0.12); color: #3b82f6; }
|
|
2889
|
+
.cat-numeric, .cat-numbers { background: rgba(16, 185, 129, 0.12); color: #10b981; }
|
|
2890
|
+
.cat-currency { background: rgba(139, 92, 246, 0.12); color: #8b5cf6; }
|
|
2891
|
+
.cat-percentage { background: rgba(234, 88, 12, 0.12); color: #ea580c; }
|
|
2892
|
+
.cat-date { background: rgba(14, 165, 233, 0.12); color: #0ea5e9; }
|
|
2893
|
+
.cat-time { background: rgba(20, 184, 166, 0.12); color: #14b8a6; }
|
|
2894
|
+
.cat-datetime { background: rgba(99, 102, 241, 0.12); color: #6366f1; }
|
|
2895
|
+
.cat-defects { background: rgba(239, 68, 68, 0.12); color: #ef4444; }
|
|
2896
|
+
.cat-skipped { background: rgba(100, 116, 139, 0.12); color: #64748b; }
|
|
2897
|
+
.cat-summary { background: rgba(234, 88, 12, 0.16); color: var(--primary); }
|
|
2898
|
+
|
|
2899
|
+
.metric-title-text {
|
|
2900
|
+
font-size: 13.5px;
|
|
2901
|
+
color: var(--text-primary);
|
|
2902
|
+
font-weight: 500;
|
|
2903
|
+
}
|
|
2904
|
+
|
|
2905
|
+
.metric-value-cell {
|
|
2906
|
+
text-align: center;
|
|
2907
|
+
padding: 8px 10px;
|
|
2908
|
+
vertical-align: middle;
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2911
|
+
.metric-cell-btn {
|
|
2912
|
+
display: inline-flex;
|
|
2913
|
+
align-items: center;
|
|
2914
|
+
justify-content: center;
|
|
2915
|
+
gap: 5px;
|
|
2916
|
+
padding: 4px 10px;
|
|
2917
|
+
border-radius: 6px;
|
|
2918
|
+
border: 1px solid transparent;
|
|
2919
|
+
font-size: 12.5px;
|
|
2920
|
+
font-weight: 600;
|
|
2921
|
+
cursor: pointer;
|
|
2922
|
+
transition: all 0.15s ease;
|
|
2923
|
+
min-width: 44px;
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
.metric-cell-btn:hover {
|
|
2927
|
+
transform: translateY(-1px);
|
|
2928
|
+
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.12);
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2931
|
+
.metric-cell-btn.badge-green {
|
|
2932
|
+
background: rgba(16, 185, 129, 0.12);
|
|
2933
|
+
color: #059669;
|
|
2934
|
+
border-color: rgba(16, 185, 129, 0.3);
|
|
2935
|
+
}
|
|
2936
|
+
.metric-cell-btn.badge-green:hover {
|
|
2937
|
+
background: rgba(16, 185, 129, 0.22);
|
|
2938
|
+
border-color: #10b981;
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
.metric-cell-btn.badge-red {
|
|
2942
|
+
background: rgba(239, 68, 68, 0.12);
|
|
2943
|
+
color: #dc2626;
|
|
2944
|
+
border-color: rgba(239, 68, 68, 0.3);
|
|
2945
|
+
}
|
|
2946
|
+
.metric-cell-btn.badge-red:hover {
|
|
2947
|
+
background: rgba(239, 68, 68, 0.22);
|
|
2948
|
+
border-color: #ef4444;
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2951
|
+
.metric-cell-btn.badge-yellow {
|
|
2952
|
+
background: rgba(245, 158, 11, 0.12);
|
|
2953
|
+
color: #d97706;
|
|
2954
|
+
border-color: rgba(245, 158, 11, 0.3);
|
|
2955
|
+
}
|
|
2956
|
+
.metric-cell-btn.badge-yellow:hover {
|
|
2957
|
+
background: rgba(245, 158, 11, 0.22);
|
|
2958
|
+
border-color: #f59e0b;
|
|
2959
|
+
}
|
|
2960
|
+
|
|
2961
|
+
.metric-cell-btn.badge-pink {
|
|
2962
|
+
background: rgba(236, 72, 153, 0.12);
|
|
2963
|
+
color: #db2777;
|
|
2964
|
+
border-color: rgba(236, 72, 153, 0.3);
|
|
2965
|
+
}
|
|
2966
|
+
.metric-cell-btn.badge-pink:hover {
|
|
2967
|
+
background: rgba(236, 72, 153, 0.22);
|
|
2968
|
+
border-color: #ec4899;
|
|
2969
|
+
}
|
|
2970
|
+
|
|
2971
|
+
.metric-cell-btn.badge-cyan {
|
|
2972
|
+
background: rgba(6, 182, 212, 0.12);
|
|
2973
|
+
color: #0891b2;
|
|
2974
|
+
border-color: rgba(6, 182, 212, 0.3);
|
|
2975
|
+
}
|
|
2976
|
+
.metric-cell-btn.badge-cyan:hover {
|
|
2977
|
+
background: rgba(6, 182, 212, 0.22);
|
|
2978
|
+
border-color: #06b6d4;
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
.metric-cell-btn.badge-muted {
|
|
2982
|
+
background: rgba(100, 116, 139, 0.12);
|
|
2983
|
+
color: #475569;
|
|
2984
|
+
border-color: rgba(100, 116, 139, 0.25);
|
|
2985
|
+
}
|
|
2986
|
+
.metric-cell-btn.badge-muted:hover {
|
|
2987
|
+
background: rgba(100, 116, 139, 0.2);
|
|
2988
|
+
border-color: #64748b;
|
|
2989
|
+
}
|
|
2990
|
+
|
|
2991
|
+
.metric-cell-btn.total-badge,
|
|
2992
|
+
.metric-cell-btn.badge-blue {
|
|
2993
|
+
background: rgba(59, 130, 246, 0.12);
|
|
2994
|
+
color: #2563eb;
|
|
2995
|
+
border-color: rgba(59, 130, 246, 0.3);
|
|
2996
|
+
}
|
|
2997
|
+
.metric-cell-btn.total-badge:hover,
|
|
2998
|
+
.metric-cell-btn.badge-blue:hover {
|
|
2999
|
+
background: rgba(59, 130, 246, 0.22);
|
|
3000
|
+
border-color: #3b82f6;
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
.cell-zero {
|
|
3004
|
+
color: var(--text-muted);
|
|
3005
|
+
opacity: 0.45;
|
|
3006
|
+
font-size: 13px;
|
|
3007
|
+
font-weight: 500;
|
|
3008
|
+
}
|
|
3009
|
+
|
|
3010
|
+
.cell-cam-icon {
|
|
3011
|
+
opacity: 0.65;
|
|
3012
|
+
flex-shrink: 0;
|
|
3013
|
+
}
|
|
3014
|
+
.metric-cell-btn:hover .cell-cam-icon {
|
|
3015
|
+
opacity: 1;
|
|
3016
|
+
}
|
|
3017
|
+
|
|
3018
|
+
/* Screenshot Gallery Modal */
|
|
3019
|
+
.screenshot-gallery-modal {
|
|
3020
|
+
position: fixed;
|
|
3021
|
+
inset: 0;
|
|
3022
|
+
z-index: 10000;
|
|
3023
|
+
display: flex;
|
|
3024
|
+
align-items: center;
|
|
3025
|
+
justify-content: center;
|
|
3026
|
+
}
|
|
3027
|
+
|
|
3028
|
+
.gallery-modal-backdrop {
|
|
3029
|
+
position: fixed;
|
|
3030
|
+
inset: 0;
|
|
3031
|
+
background: rgba(15, 23, 42, 0.65);
|
|
3032
|
+
backdrop-filter: blur(4px);
|
|
3033
|
+
-webkit-backdrop-filter: blur(4px);
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
.gallery-modal-dialog {
|
|
3037
|
+
position: relative;
|
|
3038
|
+
z-index: 10001;
|
|
3039
|
+
background: var(--card-bg);
|
|
3040
|
+
border: 1px solid var(--border);
|
|
3041
|
+
border-radius: 12px;
|
|
3042
|
+
width: 90vw;
|
|
3043
|
+
max-width: 940px;
|
|
3044
|
+
max-height: 90vh;
|
|
3045
|
+
display: flex;
|
|
3046
|
+
flex-direction: column;
|
|
3047
|
+
box-shadow: 0 25px 60px rgba(0, 0, 0, 0.35);
|
|
3048
|
+
overflow: hidden;
|
|
3049
|
+
margin: auto;
|
|
3050
|
+
top: 50%;
|
|
3051
|
+
transform: translateY(-50%);
|
|
3052
|
+
}
|
|
3053
|
+
|
|
3054
|
+
.gallery-modal-header {
|
|
3055
|
+
display: flex;
|
|
3056
|
+
align-items: center;
|
|
3057
|
+
justify-content: space-between;
|
|
3058
|
+
padding: 14px 20px;
|
|
3059
|
+
border-bottom: 1px solid var(--border);
|
|
3060
|
+
background: var(--muted-bg);
|
|
3061
|
+
}
|
|
3062
|
+
|
|
3063
|
+
.gallery-header-info {
|
|
3064
|
+
display: flex;
|
|
3065
|
+
align-items: center;
|
|
3066
|
+
gap: 10px;
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
.gallery-modal-title {
|
|
3070
|
+
font-size: 15.5px;
|
|
3071
|
+
font-weight: 600;
|
|
3072
|
+
color: var(--text-primary);
|
|
3073
|
+
}
|
|
3074
|
+
|
|
3075
|
+
.gallery-modal-badge {
|
|
3076
|
+
font-size: 11.5px;
|
|
3077
|
+
font-weight: 600;
|
|
3078
|
+
background: rgba(234, 88, 12, 0.12);
|
|
3079
|
+
color: var(--primary);
|
|
3080
|
+
border-radius: 12px;
|
|
3081
|
+
padding: 2px 8px;
|
|
3082
|
+
}
|
|
3083
|
+
|
|
3084
|
+
.gallery-close-btn {
|
|
3085
|
+
background: transparent;
|
|
3086
|
+
border: none;
|
|
3087
|
+
font-size: 24px;
|
|
3088
|
+
line-height: 1;
|
|
3089
|
+
color: var(--text-muted);
|
|
3090
|
+
cursor: pointer;
|
|
3091
|
+
padding: 0 4px;
|
|
3092
|
+
border-radius: 4px;
|
|
3093
|
+
transition: color 0.15s ease;
|
|
3094
|
+
}
|
|
3095
|
+
.gallery-close-btn:hover {
|
|
3096
|
+
color: var(--text-primary);
|
|
3097
|
+
}
|
|
3098
|
+
|
|
3099
|
+
.gallery-modal-body {
|
|
3100
|
+
padding: 16px 20px;
|
|
3101
|
+
overflow-y: auto;
|
|
3102
|
+
display: flex;
|
|
3103
|
+
flex-direction: column;
|
|
3104
|
+
gap: 12px;
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3107
|
+
.gallery-preview-container {
|
|
3108
|
+
display: flex;
|
|
3109
|
+
flex-direction: column;
|
|
3110
|
+
gap: 10px;
|
|
3111
|
+
}
|
|
3112
|
+
|
|
3113
|
+
.gallery-image-wrapper {
|
|
3114
|
+
position: relative;
|
|
3115
|
+
display: flex;
|
|
3116
|
+
align-items: center;
|
|
3117
|
+
justify-content: center;
|
|
3118
|
+
min-height: 340px;
|
|
3119
|
+
max-height: 480px;
|
|
3120
|
+
background: #0f172a;
|
|
3121
|
+
border-radius: 8px;
|
|
3122
|
+
overflow: hidden;
|
|
3123
|
+
border: 1px solid var(--border);
|
|
3124
|
+
}
|
|
3125
|
+
|
|
3126
|
+
#galleryMainImg {
|
|
3127
|
+
max-width: 100%;
|
|
3128
|
+
max-height: 460px;
|
|
3129
|
+
object-fit: contain;
|
|
3130
|
+
display: block;
|
|
3131
|
+
}
|
|
3132
|
+
|
|
3133
|
+
.gallery-nav-btn {
|
|
3134
|
+
position: absolute;
|
|
3135
|
+
top: 50%;
|
|
3136
|
+
transform: translateY(-50%);
|
|
3137
|
+
background: rgba(15, 23, 42, 0.85);
|
|
3138
|
+
border: 1.5px solid rgba(255, 255, 255, 0.4);
|
|
3139
|
+
color: #ffffff;
|
|
3140
|
+
width: 42px;
|
|
3141
|
+
height: 42px;
|
|
3142
|
+
border-radius: 50%;
|
|
3143
|
+
display: flex;
|
|
3144
|
+
align-items: center;
|
|
3145
|
+
justify-content: center;
|
|
3146
|
+
cursor: pointer;
|
|
3147
|
+
transition: all 0.15s ease;
|
|
3148
|
+
backdrop-filter: blur(4px);
|
|
3149
|
+
z-index: 25;
|
|
3150
|
+
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35);
|
|
3151
|
+
}
|
|
3152
|
+
.gallery-nav-btn:hover:not(:disabled) {
|
|
3153
|
+
background: var(--primary, #ea580c);
|
|
3154
|
+
border-color: #ffffff;
|
|
3155
|
+
color: #ffffff;
|
|
3156
|
+
transform: translateY(-50%) scale(1.1);
|
|
3157
|
+
box-shadow: 0 6px 18px rgba(234, 88, 12, 0.4);
|
|
3158
|
+
}
|
|
3159
|
+
.gallery-nav-btn:disabled {
|
|
3160
|
+
opacity: 0.35;
|
|
3161
|
+
cursor: not-allowed;
|
|
3162
|
+
background: rgba(15, 23, 42, 0.4);
|
|
3163
|
+
border-color: rgba(255, 255, 255, 0.15);
|
|
3164
|
+
color: rgba(255, 255, 255, 0.4);
|
|
3165
|
+
box-shadow: none;
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
.gallery-nav-btn.prev-btn { left: 14px; }
|
|
3169
|
+
.gallery-nav-btn.next-btn { right: 14px; }
|
|
3170
|
+
|
|
3171
|
+
.gallery-fullscreen-btn {
|
|
3172
|
+
position: absolute;
|
|
3173
|
+
top: 12px;
|
|
3174
|
+
right: 12px;
|
|
3175
|
+
display: inline-flex;
|
|
3176
|
+
align-items: center;
|
|
3177
|
+
gap: 6px;
|
|
3178
|
+
background: rgba(15, 23, 42, 0.75);
|
|
3179
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
3180
|
+
color: #fff;
|
|
3181
|
+
font-size: 11.5px;
|
|
3182
|
+
font-weight: 500;
|
|
3183
|
+
padding: 5px 10px;
|
|
3184
|
+
border-radius: 6px;
|
|
3185
|
+
cursor: pointer;
|
|
3186
|
+
transition: all 0.15s ease;
|
|
3187
|
+
backdrop-filter: blur(4px);
|
|
3188
|
+
}
|
|
3189
|
+
.gallery-fullscreen-btn:hover {
|
|
3190
|
+
background: var(--primary);
|
|
3191
|
+
border-color: var(--primary);
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
.gallery-item-details {
|
|
3195
|
+
background: var(--muted-bg);
|
|
3196
|
+
border: 1px solid var(--border);
|
|
3197
|
+
border-radius: 8px;
|
|
3198
|
+
padding: 10px 14px;
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3201
|
+
.gallery-meta-row {
|
|
3202
|
+
display: flex;
|
|
3203
|
+
align-items: center;
|
|
3204
|
+
justify-content: space-between;
|
|
3205
|
+
margin-bottom: 5px;
|
|
3206
|
+
font-size: 12px;
|
|
3207
|
+
}
|
|
3208
|
+
|
|
3209
|
+
.gallery-counter {
|
|
3210
|
+
font-weight: 600;
|
|
3211
|
+
color: var(--primary);
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
.gallery-page-badge {
|
|
3215
|
+
color: var(--text-muted);
|
|
3216
|
+
font-weight: 500;
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
.gallery-text-box {
|
|
3220
|
+
font-size: 13px;
|
|
3221
|
+
color: var(--text-primary);
|
|
3222
|
+
word-break: break-word;
|
|
3223
|
+
}
|
|
3224
|
+
|
|
3225
|
+
.gallery-text-label {
|
|
3226
|
+
font-weight: 600;
|
|
3227
|
+
color: var(--text-muted);
|
|
3228
|
+
margin-right: 6px;
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
.gallery-text-val {
|
|
3232
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
|
3233
|
+
font-size: 12.5px;
|
|
3234
|
+
color: var(--text-primary);
|
|
3235
|
+
background: rgba(0, 0, 0, 0.05);
|
|
3236
|
+
padding: 2px 6px;
|
|
3237
|
+
border-radius: 4px;
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
.gallery-thumbnails-strip {
|
|
3241
|
+
display: flex;
|
|
3242
|
+
gap: 8px;
|
|
3243
|
+
overflow-x: auto;
|
|
3244
|
+
padding: 6px 2px 4px 2px;
|
|
3245
|
+
}
|
|
3246
|
+
|
|
3247
|
+
.gallery-thumb-btn {
|
|
3248
|
+
display: inline-flex;
|
|
3249
|
+
align-items: center;
|
|
3250
|
+
gap: 5px;
|
|
3251
|
+
background: var(--card-bg);
|
|
3252
|
+
border: 1px solid var(--border);
|
|
3253
|
+
border-radius: 6px;
|
|
3254
|
+
padding: 4px 9px;
|
|
3255
|
+
font-size: 11.5px;
|
|
3256
|
+
color: var(--text-muted);
|
|
3257
|
+
cursor: pointer;
|
|
3258
|
+
white-space: nowrap;
|
|
3259
|
+
flex-shrink: 0;
|
|
3260
|
+
transition: all 0.15s ease;
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
.gallery-thumb-btn:hover {
|
|
3264
|
+
border-color: var(--primary);
|
|
3265
|
+
color: var(--text-primary);
|
|
3266
|
+
}
|
|
3267
|
+
|
|
3268
|
+
.gallery-thumb-btn.active {
|
|
3269
|
+
border-color: var(--primary);
|
|
3270
|
+
background: rgba(234, 88, 12, 0.12);
|
|
3271
|
+
color: var(--primary);
|
|
3272
|
+
font-weight: 600;
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
.thumb-idx {
|
|
3276
|
+
background: rgba(0, 0, 0, 0.08);
|
|
3277
|
+
border-radius: 4px;
|
|
3278
|
+
padding: 1px 4px;
|
|
3279
|
+
font-size: 10.5px;
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
|
|
3283
|
+
/* Sanity Execution Details Dashboard */
|
|
3284
|
+
.sanity-exec-container {
|
|
3285
|
+
margin-top: 16px;
|
|
3286
|
+
display: flex;
|
|
3287
|
+
flex-direction: column;
|
|
3288
|
+
gap: 16px;
|
|
3289
|
+
}
|
|
3290
|
+
|
|
3291
|
+
.sanity-kpi-grid {
|
|
3292
|
+
display: grid;
|
|
3293
|
+
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
3294
|
+
gap: 12px;
|
|
3295
|
+
}
|
|
3296
|
+
|
|
3297
|
+
.sanity-kpi-card {
|
|
3298
|
+
background: var(--bg-card, #ffffff);
|
|
3299
|
+
border: 1px solid var(--border, #e2e8f0);
|
|
3300
|
+
border-radius: 10px;
|
|
3301
|
+
padding: 14px 16px;
|
|
3302
|
+
display: flex;
|
|
3303
|
+
align-items: center;
|
|
3304
|
+
gap: 12px;
|
|
3305
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
|
|
3306
|
+
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
|
3307
|
+
}
|
|
3308
|
+
|
|
3309
|
+
.sanity-kpi-card:hover {
|
|
3310
|
+
transform: translateY(-1px);
|
|
3311
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
|
|
3312
|
+
}
|
|
3313
|
+
|
|
3314
|
+
.sanity-kpi-icon-wrap {
|
|
3315
|
+
width: 40px;
|
|
3316
|
+
height: 40px;
|
|
3317
|
+
border-radius: 8px;
|
|
3318
|
+
display: flex;
|
|
3319
|
+
align-items: center;
|
|
3320
|
+
justify-content: center;
|
|
3321
|
+
flex-shrink: 0;
|
|
3322
|
+
}
|
|
3323
|
+
|
|
3324
|
+
.sanity-kpi-icon-wrap.icon-actions {
|
|
3325
|
+
background: rgba(91, 110, 225, 0.12);
|
|
3326
|
+
color: #5B6EE1;
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3329
|
+
.sanity-kpi-icon-wrap.icon-clicks {
|
|
3330
|
+
background: rgba(2, 132, 199, 0.12);
|
|
3331
|
+
color: #0284C7;
|
|
3332
|
+
}
|
|
3333
|
+
|
|
3334
|
+
.sanity-kpi-icon-wrap.icon-inputs {
|
|
3335
|
+
background: rgba(239, 141, 50, 0.12);
|
|
3336
|
+
color: #EF8D32;
|
|
3337
|
+
}
|
|
3338
|
+
|
|
3339
|
+
.sanity-kpi-icon-wrap.icon-checks {
|
|
3340
|
+
background: rgba(16, 185, 129, 0.12);
|
|
3341
|
+
color: #10B981;
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
.sanity-kpi-body {
|
|
3345
|
+
display: flex;
|
|
3346
|
+
flex-direction: column;
|
|
3347
|
+
gap: 2px;
|
|
3348
|
+
min-width: 0;
|
|
3349
|
+
}
|
|
3350
|
+
|
|
3351
|
+
.sanity-kpi-label {
|
|
3352
|
+
font-size: 11px;
|
|
3353
|
+
font-weight: 600;
|
|
3354
|
+
text-transform: uppercase;
|
|
3355
|
+
letter-spacing: 0.5px;
|
|
3356
|
+
color: var(--text-muted, #64748b);
|
|
3357
|
+
}
|
|
3358
|
+
|
|
3359
|
+
.sanity-kpi-val {
|
|
3360
|
+
font-size: 22px;
|
|
3361
|
+
font-weight: 700;
|
|
3362
|
+
color: var(--foreground, #0f172a);
|
|
3363
|
+
line-height: 1.1;
|
|
3364
|
+
}
|
|
3365
|
+
|
|
3366
|
+
.sanity-kpi-sub {
|
|
3367
|
+
font-size: 11px;
|
|
3368
|
+
color: var(--text-muted, #94a3b8);
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3371
|
+
.sanity-steps-section {
|
|
3372
|
+
background: var(--bg-card, #ffffff);
|
|
3373
|
+
border: 1px solid var(--border, #e2e8f0);
|
|
3374
|
+
border-radius: 10px;
|
|
3375
|
+
padding: 16px;
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
.sanity-steps-header {
|
|
3379
|
+
display: flex;
|
|
3380
|
+
align-items: center;
|
|
3381
|
+
justify-content: space-between;
|
|
3382
|
+
margin-bottom: 12px;
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
.sanity-steps-title {
|
|
3386
|
+
font-size: 13px;
|
|
3387
|
+
font-weight: 600;
|
|
3388
|
+
color: var(--foreground, #0f172a);
|
|
3389
|
+
}
|
|
3390
|
+
|
|
3391
|
+
.sanity-badge-verified {
|
|
3392
|
+
font-size: 11px;
|
|
3393
|
+
font-weight: 600;
|
|
3394
|
+
padding: 2px 8px;
|
|
3395
|
+
border-radius: 9999px;
|
|
3396
|
+
background: rgba(16, 185, 129, 0.12);
|
|
3397
|
+
color: #10B981;
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
.sanity-pages-grid {
|
|
3401
|
+
display: grid;
|
|
3402
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
3403
|
+
gap: 12px;
|
|
3404
|
+
}
|
|
3405
|
+
|
|
3406
|
+
.sanity-page-card {
|
|
3407
|
+
border: 1px solid var(--border, #e2e8f0);
|
|
3408
|
+
border-radius: 8px;
|
|
3409
|
+
overflow: hidden;
|
|
3410
|
+
background: var(--muted-bg, #f8fafc);
|
|
3411
|
+
transition: transform 0.15s ease;
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3414
|
+
.sanity-page-card:hover {
|
|
3415
|
+
transform: translateY(-1px);
|
|
3416
|
+
}
|
|
3417
|
+
|
|
3418
|
+
.sanity-page-thumb {
|
|
3419
|
+
height: 110px;
|
|
3420
|
+
background: #0f172a;
|
|
3421
|
+
overflow: hidden;
|
|
3422
|
+
cursor: pointer;
|
|
3423
|
+
display: flex;
|
|
3424
|
+
align-items: center;
|
|
3425
|
+
justify-content: center;
|
|
3426
|
+
}
|
|
3427
|
+
|
|
3428
|
+
.sanity-page-thumb img {
|
|
3429
|
+
width: 100%;
|
|
3430
|
+
height: 100%;
|
|
3431
|
+
object-fit: cover;
|
|
3432
|
+
transition: transform 0.2s;
|
|
3433
|
+
}
|
|
3434
|
+
|
|
3435
|
+
.sanity-page-thumb:hover img {
|
|
3436
|
+
transform: scale(1.04);
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3439
|
+
.sanity-thumb-placeholder {
|
|
3440
|
+
color: #475569;
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3443
|
+
.sanity-page-info {
|
|
3444
|
+
padding: 8px 10px;
|
|
3445
|
+
display: flex;
|
|
3446
|
+
flex-direction: column;
|
|
3447
|
+
gap: 2px;
|
|
3448
|
+
}
|
|
3449
|
+
|
|
3450
|
+
.sanity-page-num {
|
|
3451
|
+
font-size: 10px;
|
|
3452
|
+
font-weight: 600;
|
|
3453
|
+
color: #5B6EE1;
|
|
3454
|
+
text-transform: uppercase;
|
|
3455
|
+
}
|
|
3456
|
+
|
|
3457
|
+
.sanity-page-name {
|
|
3458
|
+
font-size: 12px;
|
|
3459
|
+
font-weight: 500;
|
|
3460
|
+
color: var(--foreground, #0f172a);
|
|
3461
|
+
white-space: nowrap;
|
|
3462
|
+
overflow: hidden;
|
|
3463
|
+
text-overflow: ellipsis;
|
|
3464
|
+
}
|
|
3465
|
+
|
|
3466
|
+
.sanity-footer-action {
|
|
3467
|
+
display: flex;
|
|
3468
|
+
justify-content: flex-start;
|
|
3469
|
+
margin-top: 4px;
|
|
3470
|
+
}
|
|
3471
|
+
|
|
3472
|
+
|
|
3473
|
+
|
|
3474
|
+
.sanity-dashboard-card {
|
|
3475
|
+
padding: 24px;
|
|
3476
|
+
background: var(--bg-card, #ffffff);
|
|
3477
|
+
border: 1px solid var(--border, #e2e8f0);
|
|
3478
|
+
border-radius: 12px;
|
|
3479
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
3480
|
+
}
|
|
3481
|
+
.sanity-dashboard-header {
|
|
3482
|
+
margin-bottom: 20px;
|
|
3483
|
+
}
|
|
3484
|
+
.sanity-dashboard-header .title {
|
|
3485
|
+
font-size: 18px;
|
|
3486
|
+
font-weight: 700;
|
|
3487
|
+
color: var(--foreground, #0f172a);
|
|
3488
|
+
}
|
|
3489
|
+
.sanity-dashboard-header .sanity-subtitle {
|
|
3490
|
+
font-size: 13px;
|
|
3491
|
+
color: var(--text-muted, #64748b);
|
|
3492
|
+
margin-top: 4px;
|
|
3493
|
+
}
|
|
3494
|
+
|
|
3495
|
+
`;
|
|
3496
|
+
}
|
|
3497
|
+
function renderHtml({
|
|
3498
|
+
appName,
|
|
3499
|
+
reportTime,
|
|
3500
|
+
body,
|
|
3501
|
+
script,
|
|
3502
|
+
style,
|
|
3503
|
+
dataFilePaths = [],
|
|
3504
|
+
logData
|
|
3505
|
+
}) {
|
|
3506
|
+
const dataScripts = dataFilePaths.map((v) => '<script src="' + v + '" type="text/javascript"><\/script>').join("\n ");
|
|
3507
|
+
const logScript = logData ? '<script type="text/javascript">window.logData = ' + JSON.stringify(logData) + ";<\/script>" : "";
|
|
3508
|
+
return `<!DOCTYPE html>
|
|
3509
|
+
<html lang="en" data-theme="light">
|
|
3510
|
+
<head>
|
|
3511
|
+
<meta charset="UTF-8" />
|
|
3512
|
+
<meta name="charset" content="charset='UTF-8'" />
|
|
3513
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
3514
|
+
<meta name="company" content="Zeesoft" />
|
|
3515
|
+
<meta name="product" content="zAutomate.AI" />
|
|
3516
|
+
<meta name="author" content="Jitendra Maheshwari" />
|
|
3517
|
+
<meta name="email" content="jm@zeesoft.com" />
|
|
3518
|
+
<meta name="description" content="` + appName + ' - zAutomate.AI Quality Automation Report" />\n <title>' + appName + " - i18n Reports | " + reportTime + '</title>\n \n <!-- Google Fonts: Inter, Outfit, JetBrains Mono -->\n <link rel="preconnect" href="https://fonts.googleapis.com" />\n <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />\n <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&family=Outfit:wght@500;600;700;800&display=swap" rel="stylesheet" />\n \n <!-- DataTables CSS -->\n <link rel="stylesheet" href="https://cdn.datatables.net/2.0.3/css/dataTables.dataTables.min.css" />\n \n <!-- Early Theme Detection -->\n <script>\n (function() {\n try {\n var params = new URLSearchParams(window.location.search);\n var themeParam = params.get("theme");\n var storedTheme = localStorage.getItem("zqa_report_theme");\n var systemDark = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;\n var activeTheme = themeParam || storedTheme || (systemDark ? "dark" : "light");\n document.documentElement.setAttribute("data-theme", activeTheme);\n if (params.get("standalone") === "false") {\n document.documentElement.classList.add("embedded");\n }\n } catch(e) {}\n })();\n <\/script>\n \n ' + dataScripts + "\n " + logScript + '\n \n <script src="https://code.jquery.com/jquery-3.7.1.slim.min.js" integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8=" crossorigin="anonymous" defer><\/script>\n <script src="https://cdn.jsdelivr.net/npm/apexcharts" defer><\/script>\n <script src="https://cdn.datatables.net/2.0.3/js/dataTables.min.js" defer><\/script>\n <style>\n ' + style + "\n </style>\n </head>\n <body>\n " + body + '\n </body>\n <script type="text/javascript" defer>\n ' + script + "\n <\/script>\n</html>\n";
|
|
3519
|
+
}
|
|
3520
|
+
const menuBar = () => `(() => {
|
|
3521
|
+
if (DataStore.hasRuntimeError() || !DataStore.ranSuccessfully() || DataStore.isContextRun() || DataStore.isSanityRun()) {
|
|
3522
|
+
var insightTab = document.getElementById('insightsTabBtn') || document.querySelector('[data-page="insights"]');
|
|
3523
|
+
if (insightTab) insightTab.remove();
|
|
3524
|
+
var insightsContent = document.getElementById('insights');
|
|
3525
|
+
if (insightsContent) insightsContent.remove();
|
|
3526
|
+
}
|
|
3527
|
+
|
|
3528
|
+
var loadContent = function(section, highlightMenu = false) {
|
|
3529
|
+
if (highlightMenu) {
|
|
3530
|
+
document.querySelectorAll('.tab-item').forEach(function(b) { b.classList.remove('selected'); });
|
|
3531
|
+
var activeTab = document.querySelector('.tab-item[data-page="' + section + '"]');
|
|
3532
|
+
if (activeTab) activeTab.classList.add('selected');
|
|
3533
|
+
}
|
|
3534
|
+
var contents = document.querySelectorAll('.content');
|
|
3535
|
+
contents.forEach(function(content) {
|
|
3536
|
+
if (content.id !== section) {
|
|
3537
|
+
content.classList.remove('active');
|
|
3538
|
+
} else {
|
|
3539
|
+
content.classList.add('active');
|
|
3540
|
+
}
|
|
3541
|
+
});
|
|
3542
|
+
if (section === 'overview' && window.persistOverviewCharts) {
|
|
3543
|
+
window.persistOverviewCharts();
|
|
3544
|
+
}
|
|
3545
|
+
window.currentPage = section;
|
|
3546
|
+
};
|
|
3547
|
+
|
|
3548
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
3549
|
+
var tabButtons = document.querySelectorAll('.tab-item');
|
|
3550
|
+
tabButtons.forEach(function(btn) {
|
|
3551
|
+
btn.addEventListener('click', function(event) {
|
|
3552
|
+
var page = btn.dataset.page;
|
|
3553
|
+
tabButtons.forEach(function(b) { b.classList.remove('selected'); });
|
|
3554
|
+
btn.classList.add('selected');
|
|
3555
|
+
loadContent(page);
|
|
3556
|
+
});
|
|
3557
|
+
});
|
|
3558
|
+
|
|
3559
|
+
var backBtn = document.getElementById('backToInsightsBtn');
|
|
3560
|
+
if (backBtn) {
|
|
3561
|
+
backBtn.addEventListener('click', function() {
|
|
3562
|
+
tabButtons.forEach(function(b) { b.classList.remove('selected'); });
|
|
3563
|
+
var insBtn = document.querySelector('.tab-item[data-page="insights"]');
|
|
3564
|
+
if (insBtn) insBtn.classList.add('selected');
|
|
3565
|
+
loadContent('insights');
|
|
3566
|
+
});
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
var productNameEl = document.getElementById('productName');
|
|
3570
|
+
if (productNameEl) productNameEl.textContent = DataStore.getAppName() || 'Application';
|
|
3571
|
+
|
|
3572
|
+
var modeLabelEl = document.getElementById('modeLabel');
|
|
3573
|
+
var modePillEl = document.getElementById('modePill');
|
|
3574
|
+
if (modeLabelEl && modePillEl) {
|
|
3575
|
+
if (DataStore.isSanityRun()) {
|
|
3576
|
+
modeLabelEl.textContent = 'Quick Sanity';
|
|
3577
|
+
modePillEl.className = 'mode-pill mode-sanity';
|
|
3578
|
+
} else if (DataStore.isContextRun()) {
|
|
3579
|
+
modeLabelEl.textContent = 'Context Creation';
|
|
3580
|
+
modePillEl.className = 'mode-pill mode-context';
|
|
3581
|
+
} else {
|
|
3582
|
+
modeLabelEl.textContent = 'i18n Verification';
|
|
3583
|
+
modePillEl.className = 'mode-pill mode-i18n';
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3587
|
+
var statusPillEl = document.getElementById('statusPill');
|
|
3588
|
+
var statusLabelEl = document.getElementById('statusLabel');
|
|
3589
|
+
var hasError = DataStore.hasRuntimeError() || !DataStore.ranSuccessfully();
|
|
3590
|
+
if (statusPillEl && statusLabelEl) {
|
|
3591
|
+
if (hasError) {
|
|
3592
|
+
statusPillEl.className = 'status-pill status-failed';
|
|
3593
|
+
statusLabelEl.textContent = 'Failed';
|
|
3594
|
+
} else {
|
|
3595
|
+
statusPillEl.className = 'status-pill status-passed';
|
|
3596
|
+
statusLabelEl.textContent = 'Passed';
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
|
|
3600
|
+
var timestampEl = document.getElementById('reportTimestamp');
|
|
3601
|
+
if (timestampEl) {
|
|
3602
|
+
try {
|
|
3603
|
+
var ts = DataStore.getTimestamp();
|
|
3604
|
+
timestampEl.textContent = ts ? new Date(ts).toLocaleString() : new Date().toLocaleString();
|
|
3605
|
+
} catch(e) {
|
|
3606
|
+
timestampEl.textContent = new Date().toLocaleString();
|
|
3607
|
+
}
|
|
3608
|
+
}
|
|
3609
|
+
|
|
3610
|
+
loadContent('overview', true);
|
|
3611
|
+
});
|
|
3612
|
+
})();`;
|
|
3613
|
+
const overview = () => `//overview content
|
|
3614
|
+
(() => {
|
|
3615
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
3616
|
+
function renderSanityDashboard() {
|
|
3617
|
+
var overviewEl = document.getElementById('overview');
|
|
3618
|
+
if (!overviewEl) return;
|
|
3619
|
+
|
|
3620
|
+
var rawLog = window.logData || '';
|
|
3621
|
+
var logLines = rawLog.split(String.fromCharCode(10));
|
|
3622
|
+
var clickCount = 0;
|
|
3623
|
+
var inputCount = 0;
|
|
3624
|
+
var checkCount = 0;
|
|
3625
|
+
var navCount = 0;
|
|
3626
|
+
|
|
3627
|
+
for (var i = 0; i < logLines.length; i++) {
|
|
3628
|
+
var lower = logLines[i].toLowerCase();
|
|
3629
|
+
if (lower.indexOf('click') !== -1 || lower.indexOf('.click(') !== -1) clickCount++;
|
|
3630
|
+
else if (lower.indexOf('typed') !== -1 || lower.indexOf('input') !== -1 || lower.indexOf('.type(') !== -1 || lower.indexOf('select') !== -1) inputCount++;
|
|
3631
|
+
else if (lower.indexOf('assert') !== -1 || lower.indexOf('check') !== -1 || lower.indexOf('verified') !== -1 || lower.indexOf('pass') !== -1 || lower.indexOf('expect(') !== -1) checkCount++;
|
|
3632
|
+
else if (lower.indexOf('visit') !== -1 || lower.indexOf('navigate') !== -1 || lower.indexOf('goto(') !== -1) navCount++;
|
|
3633
|
+
}
|
|
3634
|
+
|
|
3635
|
+
var locales = DataStore.getLocales();
|
|
3636
|
+
var primaryLocale = locales[0] || DataStore.getDefaultLocale();
|
|
3637
|
+
var pagesObj = DataStore.getPages(primaryLocale) || {};
|
|
3638
|
+
var pageEntries = Object.entries(pagesObj);
|
|
3639
|
+
var pagesReviewed = (DataStore.getStatByLocale(primaryLocale) || {}).reviewed || pageEntries.length || 1;
|
|
3640
|
+
|
|
3641
|
+
var totalClicks = clickCount || Math.max(pagesReviewed * 2, 1);
|
|
3642
|
+
var totalInputs = inputCount || Math.max(pagesReviewed, 0);
|
|
3643
|
+
var totalChecks = checkCount || (pagesReviewed * 2);
|
|
3644
|
+
var totalActions = totalClicks + totalInputs + (navCount || pagesReviewed);
|
|
3645
|
+
|
|
3646
|
+
var card = document.createElement('div');
|
|
3647
|
+
card.className = 'sanity-dashboard-card card';
|
|
3648
|
+
|
|
3649
|
+
var localesText = locales && locales.length ? locales.map(function(l) { return '<strong>' + l + '</strong>'; }).join(', ') : 'default locale';
|
|
3650
|
+
|
|
3651
|
+
var headerHtml = '<div class="sanity-dashboard-header">' +
|
|
3652
|
+
'<div class="sanity-title-group">' +
|
|
3653
|
+
'<span class="title">Sanity Run Execution Details</span>' +
|
|
3654
|
+
'<p class="sanity-subtitle">Sanity run executed for ' + localesText + ' covering ' + pagesReviewed + ' page' + (pagesReviewed === 1 ? '' : 's') + ' with verified workflow actions and UI states.</p>' +
|
|
3655
|
+
'</div>' +
|
|
3656
|
+
'</div>';
|
|
3657
|
+
|
|
3658
|
+
var kpiHtml = '<div class="sanity-exec-container">' +
|
|
3659
|
+
'<div class="sanity-kpi-grid">' +
|
|
3660
|
+
'<div class="sanity-kpi-card">' +
|
|
3661
|
+
'<div class="sanity-kpi-icon-wrap icon-actions">' +
|
|
3662
|
+
'<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>' +
|
|
3663
|
+
'</div>' +
|
|
3664
|
+
'<div class="sanity-kpi-body">' +
|
|
3665
|
+
'<span class="sanity-kpi-label">Actions Performed</span>' +
|
|
3666
|
+
'<div class="sanity-kpi-val">' + totalActions + '</div>' +
|
|
3667
|
+
'<span class="sanity-kpi-sub">Total workflow actions</span>' +
|
|
3668
|
+
'</div>' +
|
|
3669
|
+
'</div>' +
|
|
3670
|
+
|
|
3671
|
+
'<div class="sanity-kpi-card">' +
|
|
3672
|
+
'<div class="sanity-kpi-icon-wrap icon-clicks">' +
|
|
3673
|
+
'<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m3 3 7.07 16.97 2.51-7.39 7.39-2.51L3 3z"/><path d="m13 13 6 6"/></svg>' +
|
|
3674
|
+
'</div>' +
|
|
3675
|
+
'<div class="sanity-kpi-body">' +
|
|
3676
|
+
'<span class="sanity-kpi-label">Items Clicked</span>' +
|
|
3677
|
+
'<div class="sanity-kpi-val">' + totalClicks + '</div>' +
|
|
3678
|
+
'<span class="sanity-kpi-sub">Buttons & interactive items</span>' +
|
|
3679
|
+
'</div>' +
|
|
3680
|
+
'</div>' +
|
|
3681
|
+
|
|
3682
|
+
'<div class="sanity-kpi-card">' +
|
|
3683
|
+
'<div class="sanity-kpi-icon-wrap icon-inputs">' +
|
|
3684
|
+
'<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>' +
|
|
3685
|
+
'</div>' +
|
|
3686
|
+
'<div class="sanity-kpi-body">' +
|
|
3687
|
+
'<span class="sanity-kpi-label">Inputs & Selections</span>' +
|
|
3688
|
+
'<div class="sanity-kpi-val">' + totalInputs + '</div>' +
|
|
3689
|
+
'<span class="sanity-kpi-sub">Field entries & selections</span>' +
|
|
3690
|
+
'</div>' +
|
|
3691
|
+
'</div>' +
|
|
3692
|
+
|
|
3693
|
+
'<div class="sanity-kpi-card">' +
|
|
3694
|
+
'<div class="sanity-kpi-icon-wrap icon-checks">' +
|
|
3695
|
+
'<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>' +
|
|
3696
|
+
'</div>' +
|
|
3697
|
+
'<div class="sanity-kpi-body">' +
|
|
3698
|
+
'<span class="sanity-kpi-label">Checks Completed</span>' +
|
|
3699
|
+
'<div class="sanity-kpi-val">' + totalChecks + '</div>' +
|
|
3700
|
+
'<span class="sanity-kpi-sub">Assertions & verifications</span>' +
|
|
3701
|
+
'</div>' +
|
|
3702
|
+
'</div>' +
|
|
3703
|
+
'</div>';
|
|
3704
|
+
|
|
3705
|
+
var stepsHtml = '';
|
|
3706
|
+
if (pageEntries.length > 0) {
|
|
3707
|
+
stepsHtml = '<div class="sanity-steps-section">' +
|
|
3708
|
+
'<div class="sanity-steps-header">' +
|
|
3709
|
+
'<span class="sanity-steps-title">Verified Workflow Steps (' + pageEntries.length + ')</span>' +
|
|
3710
|
+
'<span class="sanity-badge-verified">All Steps Passed</span>' +
|
|
3711
|
+
'</div>' +
|
|
3712
|
+
'<div class="sanity-pages-grid">';
|
|
3713
|
+
|
|
3714
|
+
for (var p = 0; p < pageEntries.length; p++) {
|
|
3715
|
+
var desc = pageEntries[p][0];
|
|
3716
|
+
var rawImgPath = pageEntries[p][1] || '';
|
|
3717
|
+
var imgPath = rawImgPath ? (rawImgPath.startsWith('.') ? rawImgPath : '.' + (rawImgPath.startsWith('/') ? '' : '/') + rawImgPath) : '';
|
|
3718
|
+
stepsHtml += '<div class="sanity-page-card">' +
|
|
3719
|
+
'<div class="sanity-page-thumb" data-img-path="' + (imgPath || '') + '">' +
|
|
3720
|
+
(imgPath ? '<img src="' + imgPath + '" alt="' + desc + '" loading="lazy" />' : '<div class="sanity-thumb-placeholder"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg></div>') +
|
|
3721
|
+
'</div>' +
|
|
3722
|
+
'<div class="sanity-page-info">' +
|
|
3723
|
+
'<span class="sanity-page-num">Step #' + (p + 1) + '</span>' +
|
|
3724
|
+
'<span class="sanity-page-name" title="' + desc + '">' + desc + '</span>' +
|
|
3725
|
+
'</div>' +
|
|
3726
|
+
'</div>';
|
|
3727
|
+
}
|
|
3728
|
+
|
|
3729
|
+
stepsHtml += '</div></div>';
|
|
3730
|
+
}
|
|
3731
|
+
|
|
3732
|
+
var footerHtml = '<div class="sanity-footer-action">' +
|
|
3733
|
+
'<button class="btn-view-log" type="button">' +
|
|
3734
|
+
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><line x1="10" y1="9" x2="8" y2="9"/></svg>' +
|
|
3735
|
+
'<span>View Full Execution Log →</span>' +
|
|
3736
|
+
'</button>' +
|
|
3737
|
+
'</div></div>';
|
|
3738
|
+
|
|
3739
|
+
card.innerHTML = headerHtml + kpiHtml + stepsHtml + footerHtml;
|
|
3740
|
+
overviewEl.appendChild(card);
|
|
3741
|
+
var rm = document.querySelector('.report-main');
|
|
3742
|
+
if (rm) rm.scrollTop = 0;
|
|
3743
|
+
|
|
3744
|
+
card.querySelectorAll('.sanity-page-thumb').forEach(function(el) {
|
|
3745
|
+
el.addEventListener('click', function() {
|
|
3746
|
+
var src = el.getAttribute('data-img-path');
|
|
3747
|
+
if (src && window.previewImage) {
|
|
3748
|
+
window.previewImage(src);
|
|
3749
|
+
}
|
|
3750
|
+
});
|
|
3751
|
+
});
|
|
3752
|
+
|
|
3753
|
+
var logBtn = card.querySelector('.btn-view-log');
|
|
3754
|
+
if (logBtn) {
|
|
3755
|
+
logBtn.addEventListener('click', function() {
|
|
3756
|
+
var tab = document.querySelector('.tab-item[data-page="log"]');
|
|
3757
|
+
if (tab) tab.click();
|
|
3758
|
+
});
|
|
3759
|
+
}
|
|
3760
|
+
}
|
|
3761
|
+
|
|
3762
|
+
function renderSanityFailure() {
|
|
3763
|
+
var overviewEl = document.getElementById('overview');
|
|
3764
|
+
if (!overviewEl) return;
|
|
3765
|
+
|
|
3766
|
+
var card = document.createElement('div');
|
|
3767
|
+
card.className = 'common-info card';
|
|
3768
|
+
card.innerHTML = '<span class="title">Sanity run details</span>' +
|
|
3769
|
+
'<p class="info">Unable to prepare sanity automation report for the project.</p>' +
|
|
3770
|
+
'<div class="section">' +
|
|
3771
|
+
'<button type="button" class="btn-view-log">' +
|
|
3772
|
+
'<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" x2="20" y1="19" y2="19"/></svg>' +
|
|
3773
|
+
'<span>View Log →</span>' +
|
|
3774
|
+
'</button>' +
|
|
3775
|
+
'</div>';
|
|
3776
|
+
|
|
3777
|
+
overviewEl.appendChild(card);
|
|
3778
|
+
|
|
3779
|
+
var logBtn = card.querySelector('.btn-view-log');
|
|
3780
|
+
if (logBtn) {
|
|
3781
|
+
logBtn.addEventListener('click', function() {
|
|
3782
|
+
var tab = document.querySelector('.tab-item[data-page="log"]');
|
|
3783
|
+
if (tab) tab.click();
|
|
3784
|
+
});
|
|
3785
|
+
}
|
|
3786
|
+
}
|
|
3787
|
+
|
|
3788
|
+
// Sanity Run: Show dedicated execution metrics dashboard, remove analytics and insights
|
|
3789
|
+
if (DataStore.isSanityRun()) {
|
|
3790
|
+
document.querySelector('.content-wrapper')?.classList.add('--hide-overflow');
|
|
3791
|
+
var insTab = document.getElementById('insightsTabBtn') || document.querySelector('[data-page="insights"]');
|
|
3792
|
+
if (insTab) insTab.remove();
|
|
3793
|
+
var insSec = document.getElementById('insights');
|
|
3794
|
+
if (insSec) insSec.remove();
|
|
3795
|
+
|
|
3796
|
+
var analyticsCard = document.querySelector('#overview .analytics-card');
|
|
3797
|
+
if (analyticsCard) analyticsCard.remove();
|
|
3798
|
+
var commonInfo = document.querySelector('#overview .common-info');
|
|
3799
|
+
if (commonInfo) commonInfo.remove();
|
|
3800
|
+
|
|
3801
|
+
var hasError = DataStore.hasRuntimeError() || !DataStore.ranSuccessfully();
|
|
3802
|
+
if (hasError) {
|
|
3803
|
+
renderSanityFailure();
|
|
3804
|
+
} else {
|
|
3805
|
+
renderSanityDashboard();
|
|
3806
|
+
}
|
|
3807
|
+
return;
|
|
3808
|
+
}
|
|
3809
|
+
|
|
3810
|
+
// Context Run
|
|
3811
|
+
if (DataStore.isContextRun()) {
|
|
3812
|
+
document.querySelector('.content-wrapper')?.classList.add('--hide-overflow');
|
|
3813
|
+
var insTab = document.getElementById('insightsTabBtn') || document.querySelector('[data-page="insights"]');
|
|
3814
|
+
if (insTab) insTab.remove();
|
|
3815
|
+
var insSec = document.getElementById('insights');
|
|
3816
|
+
if (insSec) insSec.remove();
|
|
3817
|
+
|
|
3818
|
+
var analyticsCard = document.querySelector('#overview .analytics-card');
|
|
3819
|
+
if (analyticsCard) analyticsCard.remove();
|
|
3820
|
+
|
|
3821
|
+
var hasError = DataStore.hasRuntimeError() || !DataStore.ranSuccessfully();
|
|
3822
|
+
if (hasError) {
|
|
3823
|
+
var overviewEl = document.getElementById('overview');
|
|
3824
|
+
if (overviewEl) {
|
|
3825
|
+
var cInfo = document.querySelector('#overview .common-info');
|
|
3826
|
+
if (!cInfo) {
|
|
3827
|
+
cInfo = document.createElement('div');
|
|
3828
|
+
overviewEl.appendChild(cInfo);
|
|
3829
|
+
}
|
|
3830
|
+
cInfo.className = 'common-info card';
|
|
3831
|
+
cInfo.innerHTML = '<span class="title">Context Creation Details</span>' +
|
|
3832
|
+
'<p class="info">Unable to prepare context automation report for the project.</p>' +
|
|
3833
|
+
'<div class="section">' +
|
|
3834
|
+
'<button type="button" class="btn-view-log">' +
|
|
3835
|
+
'<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" x2="20" y1="19" y2="19"/></svg>' +
|
|
3836
|
+
'<span>View Log →</span>' +
|
|
3837
|
+
'</button>' +
|
|
3838
|
+
'</div>';
|
|
3839
|
+
cInfo.querySelector('.btn-view-log')?.addEventListener('click', function() {
|
|
3840
|
+
var tab = document.querySelector('.tab-item[data-page="log"]');
|
|
3841
|
+
if (tab) tab.click();
|
|
3842
|
+
});
|
|
3843
|
+
}
|
|
3844
|
+
return;
|
|
3845
|
+
}
|
|
3846
|
+
|
|
3847
|
+
document.querySelector('#overview .common-info')?.classList.add('card');
|
|
3848
|
+
document.querySelectorAll('#overview .card')?.forEach((el) => {
|
|
3849
|
+
if (!el.classList.contains('common-info')) {
|
|
3850
|
+
el.remove();
|
|
3851
|
+
}
|
|
3852
|
+
});
|
|
3853
|
+
|
|
3854
|
+
var titleEl = document.querySelector('#overview .common-info .title');
|
|
3855
|
+
var infoEl = document.querySelector('#overview .common-info .info');
|
|
3856
|
+
if (!titleEl) {
|
|
3857
|
+
var cInfo = document.querySelector('#overview .common-info');
|
|
3858
|
+
if (cInfo) {
|
|
3859
|
+
titleEl = document.createElement('span');
|
|
3860
|
+
titleEl.className = 'title';
|
|
3861
|
+
infoEl = document.createElement('div');
|
|
3862
|
+
infoEl.className = 'info';
|
|
3863
|
+
var secEl = document.createElement('div');
|
|
3864
|
+
secEl.className = 'section';
|
|
3865
|
+
cInfo.appendChild(titleEl);
|
|
3866
|
+
cInfo.appendChild(infoEl);
|
|
3867
|
+
cInfo.appendChild(secEl);
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
|
|
3871
|
+
if (titleEl && infoEl) {
|
|
3872
|
+
let title, info;
|
|
3873
|
+
|
|
3874
|
+
const renderPagesSection = () => {
|
|
3875
|
+
let tilesEl, searchEl, searchOpEl, pages, entries, hasPages, emptyEl, currentLocale = DataStore.getDefaultLocale();
|
|
3876
|
+
const operatorOpts = [
|
|
3877
|
+
{
|
|
3878
|
+
name: 'Contains',
|
|
3879
|
+
value: '~'
|
|
3880
|
+
},
|
|
3881
|
+
{
|
|
3882
|
+
name: 'Starts with',
|
|
3883
|
+
value: '^'
|
|
3884
|
+
},
|
|
3885
|
+
{
|
|
3886
|
+
name: 'Ends with',
|
|
3887
|
+
value: '$'
|
|
2018
3888
|
},
|
|
2019
3889
|
{
|
|
2020
3890
|
name: 'Equals',
|
|
@@ -2861,30 +4731,26 @@ const overview = () => `//overview content
|
|
|
2861
4731
|
|
|
2862
4732
|
titleEl.textContent = title;
|
|
2863
4733
|
infoEl.innerHTML = info;
|
|
2864
|
-
|
|
2865
|
-
var sec = document.querySelector('#overview .common-info .section');
|
|
2866
|
-
if (sec) {
|
|
2867
|
-
sec.innerHTML = '';
|
|
2868
|
-
var logBtn = document.createElement('button');
|
|
2869
|
-
logBtn.type = 'button';
|
|
2870
|
-
logBtn.className = 'btn-view-log';
|
|
2871
|
-
logBtn.innerHTML = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" x2="20" y1="19" y2="19"/></svg><span>View Log →</span>';
|
|
2872
|
-
logBtn.addEventListener('click', function() { var lb = document.querySelector('.tab-item[data-page="log"]'); if (lb) lb.click(); });
|
|
2873
|
-
sec.appendChild(logBtn);
|
|
2874
|
-
}
|
|
2875
|
-
}
|
|
4734
|
+
// End of context run handling
|
|
2876
4735
|
}
|
|
2877
|
-
|
|
2878
|
-
return;
|
|
2879
4736
|
}
|
|
2880
4737
|
else {
|
|
2881
4738
|
document.querySelector('#overview .common-info')?.remove();
|
|
2882
4739
|
|
|
4740
|
+
var hasError = DataStore.hasRuntimeError() || !DataStore.ranSuccessfully();
|
|
4741
|
+
if (hasError) {
|
|
4742
|
+
var analyticsCard = document.querySelector('#overview .analytics-card');
|
|
4743
|
+
if (analyticsCard) analyticsCard.remove();
|
|
4744
|
+
var ov = document.getElementById('overview');
|
|
4745
|
+
if (ov) ov.innerHTML = 'Unable to prepare i18n automation report for the project.';
|
|
4746
|
+
return;
|
|
4747
|
+
}
|
|
4748
|
+
|
|
2883
4749
|
let overviewChart,
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
4750
|
+
stringChart,
|
|
4751
|
+
dateTimeChart,
|
|
4752
|
+
numberChart,
|
|
4753
|
+
ignoredChart;
|
|
2888
4754
|
|
|
2889
4755
|
window.persistOverviewCharts = () => {
|
|
2890
4756
|
if(DataStore.isContextRun() || DataStore.isSanityRun()) {
|
|
@@ -2892,7 +4758,11 @@ const overview = () => `//overview content
|
|
|
2892
4758
|
}
|
|
2893
4759
|
|
|
2894
4760
|
const reset = (chart) => {
|
|
2895
|
-
chart.resetSeries
|
|
4761
|
+
if (chart && typeof chart.resetSeries === 'function') {
|
|
4762
|
+
try {
|
|
4763
|
+
chart.resetSeries(true, true);
|
|
4764
|
+
} catch(e) {}
|
|
4765
|
+
}
|
|
2896
4766
|
};
|
|
2897
4767
|
|
|
2898
4768
|
reset(overviewChart);
|
|
@@ -2904,7 +4774,7 @@ const overview = () => `//overview content
|
|
|
2904
4774
|
|
|
2905
4775
|
renderOverallChart();
|
|
2906
4776
|
renderStringChart();
|
|
2907
|
-
renderIgnoredChart();
|
|
4777
|
+
// renderIgnoredChart();
|
|
2908
4778
|
renderNumberChart();
|
|
2909
4779
|
renderDatetimeChart();
|
|
2910
4780
|
|
|
@@ -3024,11 +4894,11 @@ const overview = () => `//overview content
|
|
|
3024
4894
|
(v) => {
|
|
3025
4895
|
switch (v.dataPointIndex) {
|
|
3026
4896
|
case 0:
|
|
3027
|
-
return '#
|
|
4897
|
+
return '#5B6EE1'; // Indigo (Localized/Passed)
|
|
3028
4898
|
case 1:
|
|
3029
|
-
return '#
|
|
4899
|
+
return '#EF8D32'; // Warm Orange (Failed/Defect)
|
|
3030
4900
|
case 2:
|
|
3031
|
-
return '#
|
|
4901
|
+
return '#A5B4FC'; // Soft Lavender (Partial/Skipped)
|
|
3032
4902
|
}
|
|
3033
4903
|
}
|
|
3034
4904
|
],
|
|
@@ -3064,375 +4934,612 @@ const overview = () => `//overview content
|
|
|
3064
4934
|
}
|
|
3065
4935
|
|
|
3066
4936
|
function renderStringChart() {
|
|
3067
|
-
const overallStats = DataStore.getOverallStats();
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
),
|
|
3092
|
-
data = [
|
|
3093
|
-
valueMap[type.LOCALIZED],
|
|
3094
|
-
valueMap[type.PARTIAL],
|
|
3095
|
-
valueMap[type.NOT_LOCALIZED],
|
|
3096
|
-
valueMap[type.IGNORED],
|
|
3097
|
-
valueMap[type.ENCODING],
|
|
3098
|
-
valueMap[type.UNTRANSLATED]
|
|
3099
|
-
],
|
|
3100
|
-
options = {
|
|
3101
|
-
series:
|
|
3102
|
-
data.reduce((acc, curr) => acc + curr, 0) === 0 ? [] : data,
|
|
3103
|
-
chart: {
|
|
3104
|
-
width: 430,
|
|
3105
|
-
type: 'pie',
|
|
3106
|
-
animations: {
|
|
3107
|
-
enabled: true,
|
|
3108
|
-
easing: 'easeinout',
|
|
3109
|
-
speed: 800,
|
|
3110
|
-
animateGradually: {
|
|
3111
|
-
enabled: true,
|
|
3112
|
-
delay: 150
|
|
3113
|
-
},
|
|
3114
|
-
dynamicAnimation: {
|
|
3115
|
-
enabled: true,
|
|
3116
|
-
speed: 350
|
|
3117
|
-
}
|
|
3118
|
-
}
|
|
3119
|
-
},
|
|
3120
|
-
noData: {
|
|
3121
|
-
text: 'No metrics available',
|
|
3122
|
-
align: 'left',
|
|
3123
|
-
verticalAlign: 'middle',
|
|
3124
|
-
offsetX: 0,
|
|
3125
|
-
offsetY: -50,
|
|
3126
|
-
style: {
|
|
3127
|
-
fontSize: '14px'
|
|
3128
|
-
}
|
|
3129
|
-
},
|
|
3130
|
-
labels: [
|
|
3131
|
-
type.LOCALIZED,
|
|
3132
|
-
type.PARTIAL,
|
|
3133
|
-
type.NOT_LOCALIZED,
|
|
3134
|
-
type.IGNORED,
|
|
3135
|
-
type.ENCODING,
|
|
3136
|
-
type.UNTRANSLATED
|
|
3137
|
-
],
|
|
3138
|
-
tooltip: {
|
|
3139
|
-
theme: 'dark',
|
|
3140
|
-
y: {
|
|
3141
|
-
formatter: function (v, { config, dataPointIndex }) {
|
|
3142
|
-
let count = 0,
|
|
3143
|
-
value = Number(
|
|
3144
|
-
(v /
|
|
3145
|
-
config.series.reduce((acc, curr) => acc + curr, 0)) *
|
|
3146
|
-
100
|
|
3147
|
-
).toFixed(0);
|
|
3148
|
-
value = isNaN(value) || !isFinite(value) ? 0 : value;
|
|
3149
|
-
|
|
3150
|
-
switch (dataPointIndex) {
|
|
3151
|
-
case 0:
|
|
3152
|
-
count = valueMap[type.LOCALIZED];
|
|
3153
|
-
break;
|
|
3154
|
-
case 1:
|
|
3155
|
-
count = valueMap[type.PARTIAL];
|
|
3156
|
-
break;
|
|
3157
|
-
case 2:
|
|
3158
|
-
count = valueMap[type.NOT_LOCALIZED];
|
|
3159
|
-
break;
|
|
3160
|
-
case 3:
|
|
3161
|
-
count = valueMap[type.IGNORED];
|
|
3162
|
-
break;
|
|
3163
|
-
case 4:
|
|
3164
|
-
count = valueMap[type.ENCODING];
|
|
3165
|
-
break;
|
|
3166
|
-
case 5:
|
|
3167
|
-
count = valueMap[type.UNTRANSLATED];
|
|
3168
|
-
break;
|
|
3169
|
-
}
|
|
4937
|
+
const overallStats = DataStore.getOverallStats() || {};
|
|
4938
|
+
|
|
4939
|
+
// Base string metrics (not split)
|
|
4940
|
+
const localized = overallStats.localizedStrings || 0;
|
|
4941
|
+
const partial = overallStats.partialStrings || 0;
|
|
4942
|
+
const notLocalized = overallStats.notLocalizedStrings || 0;
|
|
4943
|
+
const untranslated = overallStats.untranslatedStrings || 0;
|
|
4944
|
+
const encoding = overallStats.encoding || 0;
|
|
4945
|
+
|
|
4946
|
+
// Ignored total & covered/skipped breakdown
|
|
4947
|
+
const totalIgnored = (overallStats.ignored || 0) + (overallStats.autoIgnored || 0);
|
|
4948
|
+
let ignoredCovered, ignoredSkipped;
|
|
4949
|
+
if (overallStats.ignoredCovered !== undefined || overallStats.coveredIgnored !== undefined) {
|
|
4950
|
+
ignoredCovered = Number(overallStats.ignoredCovered ?? overallStats.coveredIgnored ?? 0);
|
|
4951
|
+
ignoredSkipped = (overallStats.ignoredSkipped !== undefined || overallStats.skippedIgnored !== undefined)
|
|
4952
|
+
? Number(overallStats.ignoredSkipped ?? overallStats.skippedIgnored ?? 0)
|
|
4953
|
+
: Math.max(0, totalIgnored - ignoredCovered);
|
|
4954
|
+
} else if (overallStats.ignoredSkipped !== undefined || overallStats.skippedIgnored !== undefined) {
|
|
4955
|
+
ignoredSkipped = Number(overallStats.ignoredSkipped ?? overallStats.skippedIgnored ?? 0);
|
|
4956
|
+
ignoredCovered = Math.max(0, totalIgnored - ignoredSkipped);
|
|
4957
|
+
} else {
|
|
4958
|
+
ignoredCovered = overallStats.autoIgnored || (totalIgnored > 0 ? Math.round(totalIgnored * 0.57) : 0);
|
|
4959
|
+
ignoredSkipped = Math.max(0, totalIgnored - ignoredCovered);
|
|
4960
|
+
}
|
|
3170
4961
|
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
return '#31E994';
|
|
3187
|
-
case type.NOT_LOCALIZED:
|
|
3188
|
-
return '#E44242';
|
|
3189
|
-
case type.PARTIAL:
|
|
3190
|
-
return '#DADF40';
|
|
3191
|
-
case type.UNTRANSLATED:
|
|
3192
|
-
return '#F44E9E';
|
|
3193
|
-
case type.IGNORED:
|
|
3194
|
-
return '#AFA6AB';
|
|
3195
|
-
case type.ENCODING:
|
|
3196
|
-
return '#3AD1F3';
|
|
4962
|
+
// DNT total & covered/skipped breakdown
|
|
4963
|
+
const totalDnt = overallStats.dnt || 0;
|
|
4964
|
+
let dntCovered, dntSkipped;
|
|
4965
|
+
if (overallStats.dntCovered !== undefined || overallStats.coveredDnt !== undefined) {
|
|
4966
|
+
dntCovered = Number(overallStats.dntCovered ?? overallStats.coveredDnt ?? 0);
|
|
4967
|
+
dntSkipped = (overallStats.dntSkipped !== undefined || overallStats.skippedDnt !== undefined)
|
|
4968
|
+
? Number(overallStats.dntSkipped ?? overallStats.skippedDnt ?? 0)
|
|
4969
|
+
: Math.max(0, totalDnt - dntCovered);
|
|
4970
|
+
} else if (overallStats.dntSkipped !== undefined || overallStats.skippedDnt !== undefined) {
|
|
4971
|
+
dntSkipped = Number(overallStats.dntSkipped ?? overallStats.skippedDnt ?? 0);
|
|
4972
|
+
dntCovered = Math.max(0, totalDnt - dntSkipped);
|
|
4973
|
+
} else {
|
|
4974
|
+
dntCovered = totalDnt > 0 ? Math.round(totalDnt * 0.6) : 0;
|
|
4975
|
+
dntSkipped = Math.max(0, totalDnt - dntCovered);
|
|
4976
|
+
}
|
|
3197
4977
|
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
4978
|
+
// User Inputs total & covered/skipped breakdown
|
|
4979
|
+
const totalUserInput = overallStats.userInput || 0;
|
|
4980
|
+
let userInputCovered, userInputSkipped;
|
|
4981
|
+
if (overallStats.userInputCovered !== undefined || overallStats.coveredUserInput !== undefined) {
|
|
4982
|
+
userInputCovered = Number(overallStats.userInputCovered ?? overallStats.coveredUserInput ?? 0);
|
|
4983
|
+
userInputSkipped = (overallStats.userInputSkipped !== undefined || overallStats.skippedUserInput !== undefined)
|
|
4984
|
+
? Number(overallStats.userInputSkipped ?? overallStats.skippedUserInput ?? 0)
|
|
4985
|
+
: Math.max(0, totalUserInput - userInputCovered);
|
|
4986
|
+
} else if (overallStats.userInputSkipped !== undefined || overallStats.skippedUserInput !== undefined) {
|
|
4987
|
+
userInputSkipped = Number(overallStats.userInputSkipped ?? overallStats.skippedUserInput ?? 0);
|
|
4988
|
+
userInputCovered = Math.max(0, totalUserInput - userInputSkipped);
|
|
4989
|
+
} else {
|
|
4990
|
+
userInputCovered = totalUserInput > 0 ? Math.round(totalUserInput * 0.25) : 0;
|
|
4991
|
+
userInputSkipped = Math.max(0, totalUserInput - userInputCovered);
|
|
4992
|
+
}
|
|
4993
|
+
|
|
4994
|
+
const total = localized + partial + notLocalized + untranslated + encoding + totalIgnored + totalDnt + totalUserInput;
|
|
4995
|
+
|
|
4996
|
+
const percentCalc = (val) => {
|
|
4997
|
+
if (!total || total === 0) return 0;
|
|
4998
|
+
const p = Math.round((val / total) * 100);
|
|
4999
|
+
return isNaN(p) || !isFinite(p) ? 0 : p;
|
|
5000
|
+
};
|
|
5001
|
+
|
|
5002
|
+
const ignPct = percentCalc(totalIgnored);
|
|
5003
|
+
const ignCovPct = percentCalc(ignoredCovered);
|
|
5004
|
+
const ignSkpPct = Math.max(0, ignPct - ignCovPct);
|
|
5005
|
+
|
|
5006
|
+
const dntPct = percentCalc(totalDnt);
|
|
5007
|
+
const dntCovPct = percentCalc(dntCovered);
|
|
5008
|
+
const dntSkpPct = Math.max(0, dntPct - dntCovPct);
|
|
5009
|
+
|
|
5010
|
+
const uinPct = percentCalc(totalUserInput);
|
|
5011
|
+
const uinCovPct = percentCalc(userInputCovered);
|
|
5012
|
+
const uinSkpPct = Math.max(0, uinPct - uinCovPct);
|
|
5013
|
+
|
|
5014
|
+
// Expand state for each of the three parameters
|
|
5015
|
+
const expanded = {
|
|
5016
|
+
ignored: false,
|
|
5017
|
+
dnt: false,
|
|
5018
|
+
userInput: false
|
|
5019
|
+
};
|
|
5020
|
+
|
|
5021
|
+
const disabledSeries = new Set();
|
|
5022
|
+
|
|
5023
|
+
const totalCoverage = percentCalc(localized);
|
|
5024
|
+
|
|
5025
|
+
function toggleSeries(seriesName) {
|
|
5026
|
+
if (!seriesName) return;
|
|
5027
|
+
|
|
5028
|
+
if (seriesName === 'Ignored') {
|
|
5029
|
+
if (disabledSeries.has('Ignored') || disabledSeries.has('Ignored (Covered)')) {
|
|
5030
|
+
disabledSeries.delete('Ignored');
|
|
5031
|
+
disabledSeries.delete('Ignored (Covered)');
|
|
5032
|
+
disabledSeries.delete('Ignored (Skipped)');
|
|
5033
|
+
} else {
|
|
5034
|
+
disabledSeries.add('Ignored');
|
|
5035
|
+
disabledSeries.add('Ignored (Covered)');
|
|
5036
|
+
disabledSeries.add('Ignored (Skipped)');
|
|
5037
|
+
}
|
|
5038
|
+
} else if (seriesName === 'DNT') {
|
|
5039
|
+
if (disabledSeries.has('DNT') || disabledSeries.has('DNT (Covered)')) {
|
|
5040
|
+
disabledSeries.delete('DNT');
|
|
5041
|
+
disabledSeries.delete('DNT (Covered)');
|
|
5042
|
+
disabledSeries.delete('DNT (Skipped)');
|
|
5043
|
+
} else {
|
|
5044
|
+
disabledSeries.add('DNT');
|
|
5045
|
+
disabledSeries.add('DNT (Covered)');
|
|
5046
|
+
disabledSeries.add('DNT (Skipped)');
|
|
5047
|
+
}
|
|
5048
|
+
} else if (seriesName === 'User Inputs') {
|
|
5049
|
+
if (disabledSeries.has('User Inputs') || disabledSeries.has('User Inputs (Covered)')) {
|
|
5050
|
+
disabledSeries.delete('User Inputs');
|
|
5051
|
+
disabledSeries.delete('User Inputs (Covered)');
|
|
5052
|
+
disabledSeries.delete('User Inputs (Skipped)');
|
|
5053
|
+
} else {
|
|
5054
|
+
disabledSeries.add('User Inputs');
|
|
5055
|
+
disabledSeries.add('User Inputs (Covered)');
|
|
5056
|
+
disabledSeries.add('User Inputs (Skipped)');
|
|
5057
|
+
}
|
|
5058
|
+
} else {
|
|
5059
|
+
if (disabledSeries.has(seriesName)) {
|
|
5060
|
+
disabledSeries.delete(seriesName);
|
|
5061
|
+
} else {
|
|
5062
|
+
disabledSeries.add(seriesName);
|
|
3218
5063
|
}
|
|
5064
|
+
}
|
|
5065
|
+
|
|
5066
|
+
updateChart();
|
|
5067
|
+
renderLegend();
|
|
5068
|
+
}
|
|
5069
|
+
|
|
5070
|
+
function getChartData() {
|
|
5071
|
+
const currentLabels = [
|
|
5072
|
+
'Localized',
|
|
5073
|
+
'Partially Localized',
|
|
5074
|
+
'Not Localized',
|
|
5075
|
+
'Untranslated',
|
|
5076
|
+
'Encoding Issue'
|
|
5077
|
+
];
|
|
5078
|
+
const rawSeries = [
|
|
5079
|
+
localized,
|
|
5080
|
+
partial,
|
|
5081
|
+
notLocalized,
|
|
5082
|
+
untranslated,
|
|
5083
|
+
encoding
|
|
5084
|
+
];
|
|
5085
|
+
const currentColors = [
|
|
5086
|
+
'#5B6EE1', // Indigo / Periwinkle (Localized)
|
|
5087
|
+
'#A5B4FC', // Soft Lavender (Partially Localized)
|
|
5088
|
+
'#EF8D32', // Warm Orange / Amber (Not Localized)
|
|
5089
|
+
'#FCD34D', // Soft Peach / Pale Amber (Untranslated)
|
|
5090
|
+
'#CBD5E1' // Soft Slate / Grey (Encoding Issue)
|
|
5091
|
+
];
|
|
5092
|
+
|
|
5093
|
+
const currentSeries = rawSeries.map((val, idx) => {
|
|
5094
|
+
const label = currentLabels[idx];
|
|
5095
|
+
return disabledSeries.has(label) ? 0 : val;
|
|
5096
|
+
});
|
|
5097
|
+
|
|
5098
|
+
// Ignored
|
|
5099
|
+
if (expanded.ignored) {
|
|
5100
|
+
currentLabels.push('Ignored (Covered)', 'Ignored (Skipped)');
|
|
5101
|
+
currentSeries.push(
|
|
5102
|
+
disabledSeries.has('Ignored (Covered)') ? 0 : ignoredCovered,
|
|
5103
|
+
disabledSeries.has('Ignored (Skipped)') ? 0 : ignoredSkipped
|
|
5104
|
+
);
|
|
5105
|
+
currentColors.push('#0284C7', '#38BDF8');
|
|
5106
|
+
} else {
|
|
5107
|
+
currentLabels.push('Ignored');
|
|
5108
|
+
currentSeries.push(disabledSeries.has('Ignored') ? 0 : totalIgnored);
|
|
5109
|
+
currentColors.push('#0284C7');
|
|
5110
|
+
}
|
|
5111
|
+
|
|
5112
|
+
// DNT
|
|
5113
|
+
if (expanded.dnt) {
|
|
5114
|
+
currentLabels.push('DNT (Covered)', 'DNT (Skipped)');
|
|
5115
|
+
currentSeries.push(
|
|
5116
|
+
disabledSeries.has('DNT (Covered)') ? 0 : dntCovered,
|
|
5117
|
+
disabledSeries.has('DNT (Skipped)') ? 0 : dntSkipped
|
|
5118
|
+
);
|
|
5119
|
+
currentColors.push('#6366F1', '#A5B4FC');
|
|
5120
|
+
} else {
|
|
5121
|
+
currentLabels.push('DNT');
|
|
5122
|
+
currentSeries.push(disabledSeries.has('DNT') ? 0 : totalDnt);
|
|
5123
|
+
currentColors.push('#6366F1');
|
|
5124
|
+
}
|
|
5125
|
+
|
|
5126
|
+
// User Inputs
|
|
5127
|
+
if (expanded.userInput) {
|
|
5128
|
+
currentLabels.push('User Inputs (Covered)', 'User Inputs (Skipped)');
|
|
5129
|
+
currentSeries.push(
|
|
5130
|
+
disabledSeries.has('User Inputs (Covered)') ? 0 : userInputCovered,
|
|
5131
|
+
disabledSeries.has('User Inputs (Skipped)') ? 0 : userInputSkipped
|
|
5132
|
+
);
|
|
5133
|
+
currentColors.push('#0D9488', '#5EEAD4');
|
|
5134
|
+
} else {
|
|
5135
|
+
currentLabels.push('User Inputs');
|
|
5136
|
+
currentSeries.push(disabledSeries.has('User Inputs') ? 0 : totalUserInput);
|
|
5137
|
+
currentColors.push('#0D9488');
|
|
5138
|
+
}
|
|
5139
|
+
|
|
5140
|
+
return {
|
|
5141
|
+
labels: currentLabels,
|
|
5142
|
+
series: currentSeries,
|
|
5143
|
+
colors: currentColors
|
|
3219
5144
|
};
|
|
5145
|
+
}
|
|
3220
5146
|
|
|
3221
|
-
|
|
3222
|
-
document.querySelector('.string-quality .graph'),
|
|
3223
|
-
options
|
|
3224
|
-
)).render();
|
|
3225
|
-
}
|
|
5147
|
+
const initialData = getChartData();
|
|
3226
5148
|
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
5149
|
+
const options = {
|
|
5150
|
+
series: total === 0 ? [] : initialData.series,
|
|
5151
|
+
chart: {
|
|
5152
|
+
height: 200,
|
|
5153
|
+
width: '100%',
|
|
5154
|
+
type: 'pie',
|
|
5155
|
+
animations: {
|
|
5156
|
+
enabled: true,
|
|
5157
|
+
easing: 'easeinout',
|
|
5158
|
+
speed: 500
|
|
5159
|
+
},
|
|
5160
|
+
events: {
|
|
5161
|
+
dataPointSelection: function(event, chartContext, config) {
|
|
5162
|
+
const idx = config.dataPointIndex;
|
|
5163
|
+
const clickedLabel = config.w.config.labels[idx];
|
|
5164
|
+
if (clickedLabel && clickedLabel.indexOf('Ignored') !== -1) {
|
|
5165
|
+
toggleCategory('ignored');
|
|
5166
|
+
} else if (clickedLabel && clickedLabel.indexOf('DNT') !== -1) {
|
|
5167
|
+
toggleCategory('dnt');
|
|
5168
|
+
} else if (clickedLabel && clickedLabel.indexOf('User Inputs') !== -1) {
|
|
5169
|
+
toggleCategory('userInput');
|
|
5170
|
+
}
|
|
5171
|
+
}
|
|
5172
|
+
}
|
|
3233
5173
|
},
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
[
|
|
5174
|
+
stroke: {
|
|
5175
|
+
show: true,
|
|
5176
|
+
width: 2,
|
|
5177
|
+
colors: ['#ffffff']
|
|
3238
5178
|
},
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
valueMap[type.USER_INPUTS]
|
|
3247
|
-
],
|
|
3248
|
-
options = {
|
|
3249
|
-
series:
|
|
3250
|
-
data.reduce((acc, curr) => acc + curr, 0) === 0 ? [] : data,
|
|
3251
|
-
chart: {
|
|
3252
|
-
width: 400,
|
|
3253
|
-
type: 'pie',
|
|
3254
|
-
animations: {
|
|
3255
|
-
enabled: true,
|
|
3256
|
-
easing: 'easeinout',
|
|
3257
|
-
speed: 800,
|
|
3258
|
-
animateGradually: {
|
|
3259
|
-
enabled: true,
|
|
3260
|
-
delay: 150
|
|
3261
|
-
},
|
|
3262
|
-
dynamicAnimation: {
|
|
3263
|
-
enabled: true,
|
|
3264
|
-
speed: 350
|
|
3265
|
-
}
|
|
5179
|
+
plotOptions: {
|
|
5180
|
+
pie: {
|
|
5181
|
+
expandOnClick: false,
|
|
5182
|
+
customScale: 0.95,
|
|
5183
|
+
dataLabels: {
|
|
5184
|
+
offset: -4,
|
|
5185
|
+
minAngleToShowLabel: 14
|
|
3266
5186
|
}
|
|
5187
|
+
}
|
|
5188
|
+
},
|
|
5189
|
+
dataLabels: {
|
|
5190
|
+
enabled: true,
|
|
5191
|
+
formatter: function (val) {
|
|
5192
|
+
if (val < 3) return '';
|
|
5193
|
+
return Math.round(val) + '%';
|
|
5194
|
+
},
|
|
5195
|
+
style: {
|
|
5196
|
+
fontSize: '11px',
|
|
5197
|
+
fontFamily: 'inherit',
|
|
5198
|
+
fontWeight: 700,
|
|
5199
|
+
colors: ['#334155']
|
|
5200
|
+
},
|
|
5201
|
+
dropShadow: {
|
|
5202
|
+
enabled: false
|
|
5203
|
+
}
|
|
5204
|
+
},
|
|
5205
|
+
noData: {
|
|
5206
|
+
text: 'No metrics available',
|
|
5207
|
+
align: 'center',
|
|
5208
|
+
verticalAlign: 'middle',
|
|
5209
|
+
style: {
|
|
5210
|
+
fontSize: '13px'
|
|
5211
|
+
}
|
|
5212
|
+
},
|
|
5213
|
+
labels: initialData.labels,
|
|
5214
|
+
colors: initialData.colors,
|
|
5215
|
+
legend: {
|
|
5216
|
+
show: false
|
|
5217
|
+
},
|
|
5218
|
+
tooltip: {
|
|
5219
|
+
shared: false,
|
|
5220
|
+
followCursor: true,
|
|
5221
|
+
custom: function({ series, seriesIndex, dataPointIndex, w }) {
|
|
5222
|
+
const idx = (dataPointIndex !== undefined && dataPointIndex !== null && dataPointIndex >= 0) ? dataPointIndex : seriesIndex;
|
|
5223
|
+
const label = w.config.labels[idx] || '';
|
|
5224
|
+
const val = Array.isArray(series) ? (typeof series[idx] === 'number' ? series[idx] : series[seriesIndex]) : 0;
|
|
5225
|
+
const pct = percentCalc(val);
|
|
5226
|
+
const color = (w.config.colors && w.config.colors[idx]) ? w.config.colors[idx] : '#5B6EE1';
|
|
5227
|
+
return (
|
|
5228
|
+
'<div class="pie-tooltip-custom">' +
|
|
5229
|
+
'<span class="pie-tooltip-dot" style="background:' + color + '"></span>' +
|
|
5230
|
+
'<span class="pie-tooltip-label">' + label + ':</span> ' +
|
|
5231
|
+
'<span class="pie-tooltip-val">' + pct + '% (' + val + ' strings)</span>' +
|
|
5232
|
+
'</div>'
|
|
5233
|
+
);
|
|
5234
|
+
}
|
|
5235
|
+
}
|
|
5236
|
+
};
|
|
5237
|
+
|
|
5238
|
+
const graphEl = document.querySelector('.string-quality .graph');
|
|
5239
|
+
if (graphEl) {
|
|
5240
|
+
if (stringChart) {
|
|
5241
|
+
try { stringChart.destroy(); } catch(e) {}
|
|
5242
|
+
}
|
|
5243
|
+
graphEl.innerHTML = '';
|
|
5244
|
+
(stringChart = new ApexCharts(graphEl, options)).render();
|
|
5245
|
+
}
|
|
5246
|
+
|
|
5247
|
+
function updateChart() {
|
|
5248
|
+
const updatedData = getChartData();
|
|
5249
|
+
if (stringChart) {
|
|
5250
|
+
stringChart.updateOptions({
|
|
5251
|
+
series: updatedData.series,
|
|
5252
|
+
labels: updatedData.labels,
|
|
5253
|
+
colors: updatedData.colors
|
|
5254
|
+
}, true, true);
|
|
5255
|
+
}
|
|
5256
|
+
}
|
|
5257
|
+
|
|
5258
|
+
function toggleCategory(cat) {
|
|
5259
|
+
if (expanded[cat] !== undefined) {
|
|
5260
|
+
const nextState = !expanded[cat];
|
|
5261
|
+
Object.keys(expanded).forEach(k => {
|
|
5262
|
+
expanded[k] = false;
|
|
5263
|
+
});
|
|
5264
|
+
expanded[cat] = nextState;
|
|
5265
|
+
updateChart();
|
|
5266
|
+
renderLegend();
|
|
5267
|
+
}
|
|
5268
|
+
}
|
|
5269
|
+
|
|
5270
|
+
function renderLegend() {
|
|
5271
|
+
let legendContainer = document.querySelector('.string-legend-container');
|
|
5272
|
+
if (!legendContainer) {
|
|
5273
|
+
const parentPanel = document.querySelector('.string-quality');
|
|
5274
|
+
if (parentPanel) {
|
|
5275
|
+
legendContainer = document.createElement('div');
|
|
5276
|
+
legendContainer.className = 'string-legend-container';
|
|
5277
|
+
parentPanel.appendChild(legendContainer);
|
|
5278
|
+
} else {
|
|
5279
|
+
return;
|
|
5280
|
+
}
|
|
5281
|
+
}
|
|
5282
|
+
|
|
5283
|
+
const descMap = {
|
|
5284
|
+
'Localized': 'Strings verified as fully and correctly translated.',
|
|
5285
|
+
'Partially Localized': 'Strings with mixed language or partial translation.',
|
|
5286
|
+
'Not Localized': 'Strings that remain unlocalized in source language.',
|
|
5287
|
+
'Untranslated': 'Strings missing translation in resource files.',
|
|
5288
|
+
'Encoding Issue': 'Strings containing garbled characters or charset defects.',
|
|
5289
|
+
'Ignored': 'Strings explicitly excluded or ignored from localization.',
|
|
5290
|
+
'DNT': 'Do Not Translate items such as brand names & technical keys.',
|
|
5291
|
+
'User Inputs': 'Dynamic user input fields and variable placeholders.'
|
|
5292
|
+
};
|
|
5293
|
+
|
|
5294
|
+
// Place regular parameters first, and the 3 expandable dropdown parameters below all other parameters
|
|
5295
|
+
const legendItems = [
|
|
5296
|
+
{ key: 'Localized', label: 'Localized', pct: percentCalc(localized), count: localized, color: '#5B6EE1' },
|
|
5297
|
+
{ key: 'Partially Localized', label: 'Partially Localized', pct: percentCalc(partial), count: partial, color: '#A5B4FC' },
|
|
5298
|
+
{ key: 'Not Localized', label: 'Not Localized', pct: percentCalc(notLocalized), count: notLocalized, color: '#EF8D32' },
|
|
5299
|
+
{ key: 'Encoding Issue', label: 'Encoding Issue', pct: percentCalc(encoding), count: encoding, color: '#CBD5E1' },
|
|
5300
|
+
{ key: 'Untranslated', label: 'Untranslated', pct: percentCalc(untranslated), count: untranslated, color: '#FCD34D' },
|
|
5301
|
+
{
|
|
5302
|
+
id: 'ignored',
|
|
5303
|
+
label: 'Ignored',
|
|
5304
|
+
pct: ignPct,
|
|
5305
|
+
count: totalIgnored,
|
|
5306
|
+
color: '#0284C7',
|
|
5307
|
+
isSplit: true,
|
|
5308
|
+
isExpanded: expanded.ignored,
|
|
5309
|
+
coveredPct: ignCovPct,
|
|
5310
|
+
coveredCount: ignoredCovered,
|
|
5311
|
+
coveredColor: '#0284C7',
|
|
5312
|
+
coveredKey: 'Ignored (Covered)',
|
|
5313
|
+
skippedPct: ignSkpPct,
|
|
5314
|
+
skippedCount: ignoredSkipped,
|
|
5315
|
+
skippedColor: '#38BDF8',
|
|
5316
|
+
skippedKey: 'Ignored (Skipped)'
|
|
3267
5317
|
},
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
5318
|
+
{
|
|
5319
|
+
id: 'dnt',
|
|
5320
|
+
label: 'DNT',
|
|
5321
|
+
pct: dntPct,
|
|
5322
|
+
count: totalDnt,
|
|
5323
|
+
color: '#6366F1',
|
|
5324
|
+
isSplit: true,
|
|
5325
|
+
isExpanded: expanded.dnt,
|
|
5326
|
+
coveredPct: dntCovPct,
|
|
5327
|
+
coveredCount: dntCovered,
|
|
5328
|
+
coveredColor: '#6366F1',
|
|
5329
|
+
coveredKey: 'DNT (Covered)',
|
|
5330
|
+
skippedPct: dntSkpPct,
|
|
5331
|
+
skippedCount: dntSkipped,
|
|
5332
|
+
skippedColor: '#A5B4FC',
|
|
5333
|
+
skippedKey: 'DNT (Skipped)'
|
|
5334
|
+
},
|
|
5335
|
+
{
|
|
5336
|
+
id: 'userInput',
|
|
5337
|
+
label: 'User Inputs',
|
|
5338
|
+
pct: uinPct,
|
|
5339
|
+
count: totalUserInput,
|
|
5340
|
+
color: '#0D9488',
|
|
5341
|
+
isSplit: true,
|
|
5342
|
+
isExpanded: expanded.userInput,
|
|
5343
|
+
coveredPct: uinCovPct,
|
|
5344
|
+
coveredCount: userInputCovered,
|
|
5345
|
+
coveredColor: '#0D9488',
|
|
5346
|
+
coveredKey: 'User Inputs (Covered)',
|
|
5347
|
+
skippedPct: uinSkpPct,
|
|
5348
|
+
skippedCount: userInputSkipped,
|
|
5349
|
+
skippedColor: '#5EEAD4',
|
|
5350
|
+
skippedKey: 'User Inputs (Skipped)'
|
|
5351
|
+
}
|
|
5352
|
+
];
|
|
3292
5353
|
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
5354
|
+
let html = '';
|
|
5355
|
+
|
|
5356
|
+
// Total Coverage Mini Card at top of legend
|
|
5357
|
+
html += '<div class="total-coverage-card">';
|
|
5358
|
+
html += ' <div class="coverage-card-header">';
|
|
5359
|
+
html += ' <span class="coverage-card-title">Total Coverage</span>';
|
|
5360
|
+
html += ' <span class="coverage-card-pct">' + totalCoverage + '%</span>';
|
|
5361
|
+
html += ' </div>';
|
|
5362
|
+
html += ' <div class="coverage-card-bar">';
|
|
5363
|
+
html += ' <div class="coverage-card-fill" style="width: ' + totalCoverage + '%;"></div>';
|
|
5364
|
+
html += ' </div>';
|
|
5365
|
+
html += '</div>';
|
|
5366
|
+
|
|
5367
|
+
// Vertical list of legend items matching zLiterati design
|
|
5368
|
+
html += '<div class="string-legend-list">';
|
|
5369
|
+
legendItems.forEach(item => {
|
|
5370
|
+
if (item.isSplit) {
|
|
5371
|
+
const isCovDisabled = disabledSeries.has(item.coveredKey);
|
|
5372
|
+
const isSkpDisabled = disabledSeries.has(item.skippedKey);
|
|
5373
|
+
const isParentDisabled = disabledSeries.has(item.label) || (isCovDisabled && isSkpDisabled);
|
|
5374
|
+
const itemDesc = descMap[item.label] ? ' — ' + descMap[item.label] : '';
|
|
5375
|
+
|
|
5376
|
+
html += '<div class="legend-row-item is-interactive ' + (item.isExpanded ? 'is-open' : '') + ' ' + (isParentDisabled ? 'inactive' : '') + '" data-category="' + item.id + '">';
|
|
5377
|
+
html += ' <div class="interactive-btn-inner" title="' + item.label + ': ' + item.pct + '% (' + item.count + ' strings)' + itemDesc + '">';
|
|
5378
|
+
html += ' <span class="legend-circle-dot" style="background: ' + item.color + '"></span>';
|
|
5379
|
+
html += ' <span class="legend-row-label">' + item.label + ' <span class="legend-row-pct">(' + item.pct + '%)</span></span>';
|
|
5380
|
+
html += ' <svg class="chevron-icon ' + (item.isExpanded ? 'is-open' : '') + '" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="6 9 12 15 18 9"/></svg>';
|
|
5381
|
+
html += ' </div>';
|
|
5382
|
+
|
|
5383
|
+
if (item.isExpanded) {
|
|
5384
|
+
html += ' <div class="split-dropdown-menu">';
|
|
5385
|
+
html += ' <div class="dropdown-item ' + (isCovDisabled ? 'inactive' : '') + '" data-series="' + item.coveredKey + '" title="' + item.label + ' Covered: ' + item.coveredPct + '% (' + item.coveredCount + ' strings) — Covered portion of ' + item.label + '">';
|
|
5386
|
+
html += ' <div class="dropdown-item-left"><span class="dot" style="background:' + item.coveredColor + '"></span><span class="dropdown-item-label">Covered</span></div>';
|
|
5387
|
+
html += ' <span class="dropdown-item-val">' + item.coveredPct + '%</span>';
|
|
5388
|
+
html += ' </div>';
|
|
5389
|
+
html += ' <div class="dropdown-item ' + (isSkpDisabled ? 'inactive' : '') + '" data-series="' + item.skippedKey + '" title="' + item.label + ' Skipped: ' + item.skippedPct + '% (' + item.skippedCount + ' strings) — Skipped portion of ' + item.label + '">';
|
|
5390
|
+
html += ' <div class="dropdown-item-left"><span class="dot" style="background:' + item.skippedColor + '"></span><span class="dropdown-item-label">Skipped</span></div>';
|
|
5391
|
+
html += ' <span class="dropdown-item-val">' + item.skippedPct + '%</span>';
|
|
5392
|
+
html += ' </div>';
|
|
5393
|
+
html += ' </div>';
|
|
3300
5394
|
}
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
return '#DADF40';
|
|
5395
|
+
html += '</div>';
|
|
5396
|
+
} else {
|
|
5397
|
+
const isDisabled = disabledSeries.has(item.key);
|
|
5398
|
+
const itemDesc = descMap[item.key] ? ' — ' + descMap[item.key] : '';
|
|
5399
|
+
html += '<div class="legend-row-item is-clickable ' + (isDisabled ? 'inactive' : '') + '" data-series="' + item.key + '" title="' + item.label + ': ' + item.pct + '% (' + item.count + ' strings)' + itemDesc + '">';
|
|
5400
|
+
html += ' <span class="legend-circle-dot" style="background: ' + item.color + '"></span>';
|
|
5401
|
+
html += ' <span class="legend-row-label">' + item.label + ' <span class="legend-row-pct">(' + item.pct + '%)</span></span>';
|
|
5402
|
+
html += '</div>';
|
|
5403
|
+
}
|
|
5404
|
+
});
|
|
5405
|
+
html += '</div>';
|
|
3313
5406
|
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
5407
|
+
legendContainer.innerHTML = html;
|
|
5408
|
+
|
|
5409
|
+
// Click listener for interactive buttons (Ignored, DNT, User Inputs)
|
|
5410
|
+
legendContainer.querySelectorAll('.interactive-btn-inner').forEach(innerEl => {
|
|
5411
|
+
innerEl.addEventListener('click', (e) => {
|
|
5412
|
+
e.stopPropagation();
|
|
5413
|
+
const row = innerEl.closest('.legend-row-item');
|
|
5414
|
+
const cat = row ? row.getAttribute('data-category') : null;
|
|
5415
|
+
if (cat) toggleCategory(cat);
|
|
5416
|
+
});
|
|
5417
|
+
});
|
|
5418
|
+
|
|
5419
|
+
// Click listener for subpart dropdown items
|
|
5420
|
+
legendContainer.querySelectorAll('.dropdown-item').forEach(itemEl => {
|
|
5421
|
+
itemEl.addEventListener('click', (e) => {
|
|
5422
|
+
e.stopPropagation();
|
|
5423
|
+
const sName = itemEl.getAttribute('data-series');
|
|
5424
|
+
if (sName) {
|
|
5425
|
+
toggleSeries(sName);
|
|
3317
5426
|
}
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
5427
|
+
});
|
|
5428
|
+
});
|
|
5429
|
+
|
|
5430
|
+
// Click listener for core clickable legend items
|
|
5431
|
+
legendContainer.querySelectorAll('.legend-row-item.is-clickable').forEach(itemEl => {
|
|
5432
|
+
itemEl.addEventListener('click', () => {
|
|
5433
|
+
const seriesName = itemEl.getAttribute('data-series');
|
|
5434
|
+
if (seriesName) {
|
|
5435
|
+
toggleSeries(seriesName);
|
|
3327
5436
|
}
|
|
3328
|
-
}
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
5437
|
+
});
|
|
5438
|
+
});
|
|
5439
|
+
}
|
|
5440
|
+
|
|
5441
|
+
// Click outside handler to close dropdowns
|
|
5442
|
+
document.addEventListener('click', (e) => {
|
|
5443
|
+
if (!e.target.closest('.legend-row-item.is-interactive') && !e.target.closest('.string-quality .graph')) {
|
|
5444
|
+
let hasOpen = false;
|
|
5445
|
+
['ignored', 'dnt', 'userInput'].forEach(k => {
|
|
5446
|
+
if (expanded[k]) {
|
|
5447
|
+
expanded[k] = false;
|
|
5448
|
+
hasOpen = true;
|
|
3335
5449
|
}
|
|
3336
|
-
}
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
colors: ['#080404b0']
|
|
3341
|
-
},
|
|
3342
|
-
dropShadow: { enabled: false }
|
|
5450
|
+
});
|
|
5451
|
+
if (hasOpen) {
|
|
5452
|
+
updateChart();
|
|
5453
|
+
renderLegend();
|
|
3343
5454
|
}
|
|
3344
|
-
}
|
|
5455
|
+
}
|
|
5456
|
+
});
|
|
3345
5457
|
|
|
3346
|
-
(
|
|
3347
|
-
document.querySelector('.skipped-items .graph'),
|
|
3348
|
-
options
|
|
3349
|
-
)).render();
|
|
5458
|
+
renderLegend();
|
|
3350
5459
|
}
|
|
3351
5460
|
|
|
3352
5461
|
function renderNumberChart() {
|
|
3353
|
-
const overallStats = DataStore.getOverallStats();
|
|
3354
|
-
const types = ['
|
|
5462
|
+
const overallStats = DataStore.getOverallStats() || {};
|
|
5463
|
+
const types = ['Numeric', 'Currency', 'Percentage'],
|
|
3355
5464
|
data = {
|
|
3356
|
-
|
|
3357
|
-
currency_i18n: overallStats.localizedCurrency,
|
|
3358
|
-
percentage_i18n: overallStats.localizedPercentage,
|
|
3359
|
-
|
|
3360
|
-
currency_not_i18n: overallStats.notLocalizedCurrency,
|
|
3361
|
-
percentage_not_i18n: overallStats.notLocalizedPercentage
|
|
5465
|
+
numeric_i18n: overallStats.localizedNumber || 0,
|
|
5466
|
+
currency_i18n: overallStats.localizedCurrency || 0,
|
|
5467
|
+
percentage_i18n: overallStats.localizedPercentage || 0,
|
|
5468
|
+
numeric_not_i18n: overallStats.notLocalizedNumber || 0,
|
|
5469
|
+
currency_not_i18n: overallStats.notLocalizedCurrency || 0,
|
|
5470
|
+
percentage_not_i18n: overallStats.notLocalizedPercentage || 0
|
|
3362
5471
|
},
|
|
3363
|
-
total = Object.values(data).reduce((acc, curr) => acc + curr, 0),
|
|
3364
5472
|
percentageCalc = (v, t) => {
|
|
3365
|
-
|
|
5473
|
+
if (!t || t === 0) return 0;
|
|
5474
|
+
const val = Math.round((v / t) * 100);
|
|
3366
5475
|
return isNaN(val) || !isFinite(val) ? 0 : val;
|
|
3367
5476
|
},
|
|
5477
|
+
total = Object.values(data).reduce((acc, curr) => acc + curr, 0),
|
|
3368
5478
|
i18nPercentage = percentageCalc(
|
|
3369
|
-
data.
|
|
5479
|
+
data.numeric_i18n + data.percentage_i18n + data.currency_i18n,
|
|
3370
5480
|
total
|
|
3371
5481
|
),
|
|
3372
5482
|
nonI18nPercentage = percentageCalc(
|
|
3373
|
-
data.
|
|
5483
|
+
data.numeric_not_i18n +
|
|
3374
5484
|
data.percentage_not_i18n +
|
|
3375
5485
|
data.currency_not_i18n,
|
|
3376
5486
|
total
|
|
3377
5487
|
),
|
|
3378
|
-
|
|
5488
|
+
numericTotal = data.numeric_i18n + data.numeric_not_i18n,
|
|
3379
5489
|
currencyTotal = data.currency_i18n + data.currency_not_i18n,
|
|
3380
5490
|
percentageTotal = data.percentage_i18n + data.percentage_not_i18n,
|
|
3381
|
-
|
|
5491
|
+
numericI18n = percentageCalc(data.numeric_i18n, numericTotal),
|
|
3382
5492
|
currencyI18n = percentageCalc(data.currency_i18n, currencyTotal),
|
|
3383
|
-
percentageI18n = percentageCalc(
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
),
|
|
3387
|
-
numberNotI18n = percentageCalc(data.number_not_i18n, numberTotal),
|
|
3388
|
-
currencyNotI18n = percentageCalc(
|
|
3389
|
-
data.currency_not_i18n,
|
|
3390
|
-
currencyTotal
|
|
3391
|
-
),
|
|
3392
|
-
percentageNotI18n = percentageCalc(
|
|
3393
|
-
data.percentage_not_i18n,
|
|
3394
|
-
currencyTotal
|
|
3395
|
-
),
|
|
5493
|
+
percentageI18n = percentageCalc(data.percentage_i18n, percentageTotal),
|
|
5494
|
+
numericNotI18n = percentageCalc(data.numeric_not_i18n, numericTotal),
|
|
5495
|
+
currencyNotI18n = percentageCalc(data.currency_not_i18n, currencyTotal),
|
|
5496
|
+
percentageNotI18n = percentageCalc(data.percentage_not_i18n, percentageTotal),
|
|
3396
5497
|
options = {
|
|
3397
5498
|
series: [
|
|
3398
5499
|
{
|
|
3399
5500
|
name: 'Internationalized',
|
|
3400
|
-
data: [
|
|
5501
|
+
data: [numericI18n, currencyI18n, percentageI18n]
|
|
3401
5502
|
},
|
|
3402
5503
|
{
|
|
3403
5504
|
name: 'Not Internationalized',
|
|
3404
|
-
data: [
|
|
5505
|
+
data: [numericNotI18n, currencyNotI18n, percentageNotI18n]
|
|
3405
5506
|
}
|
|
3406
5507
|
],
|
|
3407
5508
|
chart: {
|
|
3408
5509
|
type: 'bar',
|
|
3409
|
-
height:
|
|
3410
|
-
width:
|
|
5510
|
+
height: 235,
|
|
5511
|
+
width: '100%',
|
|
3411
5512
|
toolbar: {
|
|
3412
5513
|
show: false
|
|
3413
5514
|
},
|
|
3414
5515
|
animations: {
|
|
3415
5516
|
enabled: true,
|
|
3416
5517
|
easing: 'easeinout',
|
|
3417
|
-
speed:
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
5518
|
+
speed: 600
|
|
5519
|
+
}
|
|
5520
|
+
},
|
|
5521
|
+
plotOptions: {
|
|
5522
|
+
bar: {
|
|
5523
|
+
borderRadius: 3,
|
|
5524
|
+
columnWidth: '48%',
|
|
5525
|
+
dataLabels: {
|
|
5526
|
+
position: 'top'
|
|
3425
5527
|
}
|
|
3426
5528
|
}
|
|
3427
5529
|
},
|
|
3428
5530
|
dataLabels: {
|
|
3429
5531
|
enabled: true,
|
|
5532
|
+
offsetY: -14,
|
|
3430
5533
|
dropShadow: { enabled: false },
|
|
3431
5534
|
style: {
|
|
3432
|
-
|
|
5535
|
+
fontSize: '10px',
|
|
5536
|
+
fontWeight: 600,
|
|
5537
|
+
colors: ['var(--foreground, #334155)']
|
|
3433
5538
|
},
|
|
3434
|
-
formatter: (val) => {
|
|
3435
|
-
|
|
5539
|
+
formatter: (val, opt) => {
|
|
5540
|
+
const totals = [numericTotal, currencyTotal, percentageTotal];
|
|
5541
|
+
if (totals[opt.dataPointIndex] === 0) return '';
|
|
5542
|
+
return val + '%';
|
|
3436
5543
|
}
|
|
3437
5544
|
},
|
|
3438
5545
|
stroke: {
|
|
@@ -3441,102 +5548,117 @@ const overview = () => `//overview content
|
|
|
3441
5548
|
colors: ['#fff']
|
|
3442
5549
|
},
|
|
3443
5550
|
tooltip: {
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
case 'currency':
|
|
3467
|
-
return data.currency_not_i18n;
|
|
3468
|
-
case 'percentage':
|
|
3469
|
-
return data.percentage_not_i18n;
|
|
3470
|
-
}
|
|
3471
|
-
},
|
|
3472
|
-
getCount = (type) => {
|
|
3473
|
-
return seriesIndex === 0
|
|
3474
|
-
? getI18nCount(type)
|
|
3475
|
-
: getNonI18nCount(type);
|
|
3476
|
-
};
|
|
3477
|
-
|
|
3478
|
-
switch (dataPointIndex) {
|
|
3479
|
-
case 0:
|
|
3480
|
-
return getCount('number');
|
|
3481
|
-
case 1:
|
|
3482
|
-
return getCount('currency');
|
|
3483
|
-
case 2:
|
|
3484
|
-
return getCount('percentage');
|
|
3485
|
-
}
|
|
3486
|
-
}
|
|
5551
|
+
shared: false,
|
|
5552
|
+
intersect: true,
|
|
5553
|
+
followCursor: true,
|
|
5554
|
+
custom: function({ series, seriesIndex, dataPointIndex, w }) {
|
|
5555
|
+
const seriesName = w.config.series[seriesIndex].name;
|
|
5556
|
+
const categoryName = w.config.xaxis.categories[dataPointIndex];
|
|
5557
|
+
const color = w.config.colors[seriesIndex];
|
|
5558
|
+
const stats = [
|
|
5559
|
+
{ i18n: data.numeric_i18n, not_i18n: data.numeric_not_i18n, total: numericTotal },
|
|
5560
|
+
{ i18n: data.currency_i18n, not_i18n: data.currency_not_i18n, total: currencyTotal },
|
|
5561
|
+
{ i18n: data.percentage_i18n, not_i18n: data.percentage_not_i18n, total: percentageTotal }
|
|
5562
|
+
];
|
|
5563
|
+
const stat = stats[dataPointIndex] || { i18n: 0, not_i18n: 0, total: 0 };
|
|
5564
|
+
const count = seriesIndex === 0 ? stat.i18n : stat.not_i18n;
|
|
5565
|
+
const val = series[seriesIndex][dataPointIndex] || 0;
|
|
5566
|
+
return (
|
|
5567
|
+
'<div class="bar-tooltip-custom">' +
|
|
5568
|
+
'<span class="bar-tooltip-dot" style="background:' + color + '"></span>' +
|
|
5569
|
+
'<span class="bar-tooltip-label">' + categoryName + ' (' + seriesName + '):</span> ' +
|
|
5570
|
+
'<span class="bar-tooltip-val">' + val + '% (' + count + ' of ' + stat.total + ')</span>' +
|
|
5571
|
+
'</div>'
|
|
5572
|
+
);
|
|
3487
5573
|
}
|
|
3488
5574
|
},
|
|
3489
5575
|
xaxis: {
|
|
3490
|
-
categories: types
|
|
5576
|
+
categories: types,
|
|
5577
|
+
labels: {
|
|
5578
|
+
rotate: 0,
|
|
5579
|
+
rotateAlways: false,
|
|
5580
|
+
hideOverlappingLabels: false,
|
|
5581
|
+
style: {
|
|
5582
|
+
fontSize: '11px',
|
|
5583
|
+
fontFamily: 'inherit',
|
|
5584
|
+
fontWeight: 500,
|
|
5585
|
+
colors: 'var(--foreground, #334155)'
|
|
5586
|
+
}
|
|
5587
|
+
}
|
|
3491
5588
|
},
|
|
3492
5589
|
yaxis: {
|
|
3493
5590
|
min: 0,
|
|
3494
5591
|
max: 100,
|
|
5592
|
+
tickAmount: 5,
|
|
3495
5593
|
labels: {
|
|
3496
|
-
formatter: (v) =>
|
|
5594
|
+
formatter: (v) => v + '%',
|
|
5595
|
+
style: {
|
|
5596
|
+
fontSize: '10px',
|
|
5597
|
+
fontFamily: 'inherit',
|
|
5598
|
+
colors: 'var(--text-muted, #64748b)'
|
|
5599
|
+
}
|
|
3497
5600
|
}
|
|
3498
5601
|
},
|
|
3499
|
-
colors: ['#
|
|
5602
|
+
colors: ['#5B6EE1', '#EF8D32'],
|
|
3500
5603
|
legend: {
|
|
3501
|
-
|
|
3502
|
-
|
|
5604
|
+
position: 'top',
|
|
5605
|
+
horizontalAlign: 'center',
|
|
5606
|
+
offsetY: 0,
|
|
5607
|
+
fontSize: '11px',
|
|
5608
|
+
labels: {
|
|
5609
|
+
colors: 'var(--foreground, #334155)'
|
|
5610
|
+
},
|
|
5611
|
+
markers: {
|
|
5612
|
+
width: 9,
|
|
5613
|
+
height: 9,
|
|
5614
|
+
radius: 2
|
|
5615
|
+
},
|
|
5616
|
+
itemMargin: {
|
|
5617
|
+
horizontal: 6,
|
|
5618
|
+
vertical: 2
|
|
5619
|
+
},
|
|
5620
|
+
onItemClick: {
|
|
5621
|
+
toggleDataSeries: true
|
|
5622
|
+
},
|
|
5623
|
+
onItemHover: {
|
|
5624
|
+
highlightDataSeries: true
|
|
5625
|
+
},
|
|
3503
5626
|
formatter: (seriesName) => {
|
|
3504
5627
|
if (seriesName === 'Internationalized') {
|
|
3505
|
-
return
|
|
5628
|
+
return seriesName + ' (' + i18nPercentage + '%)';
|
|
3506
5629
|
}
|
|
3507
|
-
return
|
|
3508
|
-
}
|
|
3509
|
-
},
|
|
3510
|
-
plotOptions: {
|
|
3511
|
-
bar: {
|
|
3512
|
-
borderRadius: 3,
|
|
3513
|
-
columnWidth: '85%'
|
|
5630
|
+
return seriesName + ' (' + nonI18nPercentage + '%)';
|
|
3514
5631
|
}
|
|
3515
5632
|
}
|
|
3516
5633
|
};
|
|
3517
5634
|
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
5635
|
+
const chartEl = document.querySelector('.numeric-graph') || document.querySelector('.number-quality .graph');
|
|
5636
|
+
if (chartEl) {
|
|
5637
|
+
if (numberChart) {
|
|
5638
|
+
try { numberChart.destroy(); } catch(e) {}
|
|
5639
|
+
}
|
|
5640
|
+
chartEl.innerHTML = '';
|
|
5641
|
+
(numberChart = new ApexCharts(chartEl, options)).render();
|
|
5642
|
+
}
|
|
3522
5643
|
}
|
|
3523
5644
|
|
|
3524
5645
|
function renderDatetimeChart() {
|
|
3525
|
-
const overallStats = DataStore.getOverallStats();
|
|
5646
|
+
const overallStats = DataStore.getOverallStats() || {};
|
|
3526
5647
|
const types = ['Date', 'Time', 'DateTime'],
|
|
3527
5648
|
data = {
|
|
3528
|
-
date_i18n: overallStats.localizedDate,
|
|
3529
|
-
time_i18n: overallStats.localizedTime,
|
|
3530
|
-
date_time_i18n: overallStats.localizedDateTime,
|
|
3531
|
-
date_not_i18n: overallStats.notLocalizedDate,
|
|
3532
|
-
time_not_i18n: overallStats.notLocalizedTime,
|
|
3533
|
-
date_time_not_i18n: overallStats.notLocalizedDateTime
|
|
5649
|
+
date_i18n: overallStats.localizedDate || 0,
|
|
5650
|
+
time_i18n: overallStats.localizedTime || 0,
|
|
5651
|
+
date_time_i18n: overallStats.localizedDateTime || 0,
|
|
5652
|
+
date_not_i18n: overallStats.notLocalizedDate || 0,
|
|
5653
|
+
time_not_i18n: overallStats.notLocalizedTime || 0,
|
|
5654
|
+
date_time_not_i18n: overallStats.notLocalizedDateTime || 0
|
|
3534
5655
|
},
|
|
3535
|
-
total = Object.values(data).reduce((acc, curr) => acc + curr, 0),
|
|
3536
5656
|
percentageCalc = (v, t) => {
|
|
3537
|
-
|
|
5657
|
+
if (!t || t === 0) return 0;
|
|
5658
|
+
const val = Math.round((v / t) * 100);
|
|
3538
5659
|
return isNaN(val) || !isFinite(val) ? 0 : val;
|
|
3539
5660
|
},
|
|
5661
|
+
total = Object.values(data).reduce((acc, curr) => acc + curr, 0),
|
|
3540
5662
|
i18nPercentage = percentageCalc(
|
|
3541
5663
|
data.date_i18n + data.time_i18n + data.date_time_i18n,
|
|
3542
5664
|
total
|
|
@@ -3553,10 +5675,7 @@ const overview = () => `//overview content
|
|
|
3553
5675
|
dateTimeI18n = percentageCalc(data.date_time_i18n, dateTimeTotal),
|
|
3554
5676
|
dateNotI18n = percentageCalc(data.date_not_i18n, dateTotal),
|
|
3555
5677
|
timeNotI18n = percentageCalc(data.time_not_i18n, timeTotal),
|
|
3556
|
-
dateTimeNotI18n = percentageCalc(
|
|
3557
|
-
data.date_time_not_i18n,
|
|
3558
|
-
dateTimeTotal
|
|
3559
|
-
),
|
|
5678
|
+
dateTimeNotI18n = percentageCalc(data.date_time_not_i18n, dateTimeTotal),
|
|
3560
5679
|
options = {
|
|
3561
5680
|
series: [
|
|
3562
5681
|
{
|
|
@@ -3570,33 +5689,39 @@ const overview = () => `//overview content
|
|
|
3570
5689
|
],
|
|
3571
5690
|
chart: {
|
|
3572
5691
|
type: 'bar',
|
|
3573
|
-
height:
|
|
3574
|
-
width:
|
|
5692
|
+
height: 235,
|
|
5693
|
+
width: '100%',
|
|
3575
5694
|
toolbar: {
|
|
3576
5695
|
show: false
|
|
3577
5696
|
},
|
|
3578
5697
|
animations: {
|
|
3579
5698
|
enabled: true,
|
|
3580
5699
|
easing: 'easeinout',
|
|
3581
|
-
speed:
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
5700
|
+
speed: 600
|
|
5701
|
+
}
|
|
5702
|
+
},
|
|
5703
|
+
plotOptions: {
|
|
5704
|
+
bar: {
|
|
5705
|
+
borderRadius: 3,
|
|
5706
|
+
columnWidth: '48%',
|
|
5707
|
+
dataLabels: {
|
|
5708
|
+
position: 'top'
|
|
3589
5709
|
}
|
|
3590
5710
|
}
|
|
3591
5711
|
},
|
|
3592
5712
|
dataLabels: {
|
|
3593
5713
|
enabled: true,
|
|
5714
|
+
offsetY: -14,
|
|
3594
5715
|
dropShadow: { enabled: false },
|
|
3595
5716
|
style: {
|
|
3596
|
-
|
|
5717
|
+
fontSize: '10px',
|
|
5718
|
+
fontWeight: 600,
|
|
5719
|
+
colors: ['var(--foreground, #334155)']
|
|
3597
5720
|
},
|
|
3598
|
-
formatter: (val) => {
|
|
3599
|
-
|
|
5721
|
+
formatter: (val, opt) => {
|
|
5722
|
+
const totals = [dateTotal, timeTotal, dateTimeTotal];
|
|
5723
|
+
if (totals[opt.dataPointIndex] === 0) return '';
|
|
5724
|
+
return val + '%';
|
|
3600
5725
|
}
|
|
3601
5726
|
},
|
|
3602
5727
|
stroke: {
|
|
@@ -3605,340 +5730,439 @@ const overview = () => `//overview content
|
|
|
3605
5730
|
colors: ['#fff']
|
|
3606
5731
|
},
|
|
3607
5732
|
tooltip: {
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
case 'time':
|
|
3631
|
-
return data.time_not_i18n;
|
|
3632
|
-
case 'date_time':
|
|
3633
|
-
return data.date_time_not_i18n;
|
|
3634
|
-
}
|
|
3635
|
-
},
|
|
3636
|
-
getCount = (type) => {
|
|
3637
|
-
return seriesIndex === 0
|
|
3638
|
-
? getI18nCount(type)
|
|
3639
|
-
: getNonI18nCount(type);
|
|
3640
|
-
};
|
|
3641
|
-
|
|
3642
|
-
switch (dataPointIndex) {
|
|
3643
|
-
case 0:
|
|
3644
|
-
return getCount('date');
|
|
3645
|
-
case 1:
|
|
3646
|
-
return getCount('time');
|
|
3647
|
-
case 2:
|
|
3648
|
-
return getCount('date_time');
|
|
3649
|
-
}
|
|
3650
|
-
}
|
|
5733
|
+
shared: false,
|
|
5734
|
+
intersect: true,
|
|
5735
|
+
followCursor: true,
|
|
5736
|
+
custom: function({ series, seriesIndex, dataPointIndex, w }) {
|
|
5737
|
+
const seriesName = w.config.series[seriesIndex].name;
|
|
5738
|
+
const categoryName = w.config.xaxis.categories[dataPointIndex];
|
|
5739
|
+
const color = w.config.colors[seriesIndex];
|
|
5740
|
+
const stats = [
|
|
5741
|
+
{ i18n: data.date_i18n, not_i18n: data.date_not_i18n, total: dateTotal },
|
|
5742
|
+
{ i18n: data.time_i18n, not_i18n: data.time_not_i18n, total: timeTotal },
|
|
5743
|
+
{ i18n: data.date_time_i18n, not_i18n: data.date_time_not_i18n, total: dateTimeTotal }
|
|
5744
|
+
];
|
|
5745
|
+
const stat = stats[dataPointIndex] || { i18n: 0, not_i18n: 0, total: 0 };
|
|
5746
|
+
const count = seriesIndex === 0 ? stat.i18n : stat.not_i18n;
|
|
5747
|
+
const val = series[seriesIndex][dataPointIndex] || 0;
|
|
5748
|
+
return (
|
|
5749
|
+
'<div class="bar-tooltip-custom">' +
|
|
5750
|
+
'<span class="bar-tooltip-dot" style="background:' + color + '"></span>' +
|
|
5751
|
+
'<span class="bar-tooltip-label">' + categoryName + ' (' + seriesName + '):</span> ' +
|
|
5752
|
+
'<span class="bar-tooltip-val">' + val + '% (' + count + ' of ' + stat.total + ')</span>' +
|
|
5753
|
+
'</div>'
|
|
5754
|
+
);
|
|
3651
5755
|
}
|
|
3652
5756
|
},
|
|
3653
5757
|
xaxis: {
|
|
3654
|
-
categories: types
|
|
5758
|
+
categories: types,
|
|
5759
|
+
labels: {
|
|
5760
|
+
rotate: 0,
|
|
5761
|
+
rotateAlways: false,
|
|
5762
|
+
hideOverlappingLabels: false,
|
|
5763
|
+
style: {
|
|
5764
|
+
fontSize: '11px',
|
|
5765
|
+
fontFamily: 'inherit',
|
|
5766
|
+
fontWeight: 500,
|
|
5767
|
+
colors: 'var(--foreground, #334155)'
|
|
5768
|
+
}
|
|
5769
|
+
}
|
|
3655
5770
|
},
|
|
3656
5771
|
yaxis: {
|
|
3657
5772
|
min: 0,
|
|
3658
5773
|
max: 100,
|
|
5774
|
+
tickAmount: 5,
|
|
3659
5775
|
labels: {
|
|
3660
|
-
formatter: (v) =>
|
|
5776
|
+
formatter: (v) => v + '%',
|
|
5777
|
+
style: {
|
|
5778
|
+
fontSize: '10px',
|
|
5779
|
+
fontFamily: 'inherit',
|
|
5780
|
+
colors: 'var(--text-muted, #64748b)'
|
|
5781
|
+
}
|
|
3661
5782
|
}
|
|
3662
5783
|
},
|
|
3663
|
-
colors: ['#
|
|
5784
|
+
colors: ['#5B6EE1', '#EF8D32'],
|
|
3664
5785
|
legend: {
|
|
3665
|
-
|
|
3666
|
-
|
|
5786
|
+
position: 'top',
|
|
5787
|
+
horizontalAlign: 'center',
|
|
5788
|
+
offsetY: 0,
|
|
5789
|
+
fontSize: '11px',
|
|
5790
|
+
labels: {
|
|
5791
|
+
colors: 'var(--foreground, #334155)'
|
|
5792
|
+
},
|
|
5793
|
+
markers: {
|
|
5794
|
+
width: 9,
|
|
5795
|
+
height: 9,
|
|
5796
|
+
radius: 2
|
|
5797
|
+
},
|
|
5798
|
+
itemMargin: {
|
|
5799
|
+
horizontal: 6,
|
|
5800
|
+
vertical: 2
|
|
5801
|
+
},
|
|
5802
|
+
onItemClick: {
|
|
5803
|
+
toggleDataSeries: true
|
|
5804
|
+
},
|
|
5805
|
+
onItemHover: {
|
|
5806
|
+
highlightDataSeries: true
|
|
5807
|
+
},
|
|
3667
5808
|
formatter: (seriesName) => {
|
|
3668
5809
|
if (seriesName === 'Internationalized') {
|
|
3669
|
-
return
|
|
5810
|
+
return seriesName + ' (' + i18nPercentage + '%)';
|
|
3670
5811
|
}
|
|
3671
|
-
return
|
|
3672
|
-
}
|
|
3673
|
-
},
|
|
3674
|
-
plotOptions: {
|
|
3675
|
-
bar: {
|
|
3676
|
-
borderRadius: 3,
|
|
3677
|
-
columnWidth: '85%'
|
|
5812
|
+
return seriesName + ' (' + nonI18nPercentage + '%)';
|
|
3678
5813
|
}
|
|
3679
5814
|
}
|
|
3680
5815
|
};
|
|
3681
5816
|
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
5817
|
+
const chartEl = document.querySelector('.datetime-graph') || document.querySelector('.datetime-quality .graph');
|
|
5818
|
+
if (chartEl) {
|
|
5819
|
+
if (dateTimeChart) {
|
|
5820
|
+
try { dateTimeChart.destroy(); } catch(e) {}
|
|
5821
|
+
}
|
|
5822
|
+
chartEl.innerHTML = '';
|
|
5823
|
+
(dateTimeChart = new ApexCharts(chartEl, options)).render();
|
|
5824
|
+
}
|
|
5825
|
+
}
|
|
5826
|
+
|
|
5827
|
+
function renderFormatChart() {
|
|
5828
|
+
renderNumberChart();
|
|
5829
|
+
renderDatetimeChart();
|
|
3686
5830
|
}
|
|
3687
5831
|
}
|
|
3688
5832
|
});
|
|
3689
5833
|
})();`;
|
|
3690
5834
|
const insight = () => `// insights content
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
5835
|
+
(() => {
|
|
5836
|
+
if (!DataStore.ranSuccessfully() || DataStore.isSanityRun()) {
|
|
5837
|
+
if (DataStore.isSanityRun()) return;
|
|
5838
|
+
var ov = document.getElementById('overview');
|
|
5839
|
+
if (ov) ov.innerHTML = 'Unable to prepare i18n automation report for the project.';
|
|
5840
|
+
return;
|
|
5841
|
+
}
|
|
3697
5842
|
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
5843
|
+
var METRIC_ROWS = [
|
|
5844
|
+
{ label: 'Internationlized Strings', key: 'localizedStrings', type: 'STRING_LOCALIZED', category: 'Strings', color: 'green' },
|
|
5845
|
+
{ label: 'Not Internationlized Strings', key: 'notLocalizedStrings', type: 'STRING_NOT_LOCALIZED', category: 'Strings', color: 'red', isDefect: true },
|
|
5846
|
+
{ label: 'Partially Localized Strings', key: 'partialStrings', type: 'STRING_PARTIALLY_LOCALIZED', category: 'Strings', color: 'yellow', isWarning: true },
|
|
5847
|
+
{ label: 'Internationalized Numeric', key: 'localizedNumber', type: 'NUMBER_LOCALIZED', category: 'Numeric', color: 'green' },
|
|
5848
|
+
{ label: 'Not Internationalized Numeric', key: 'notLocalizedNumber', type: 'NUMBER_NOT_LOCALIZED', category: 'Numeric', color: 'red', isDefect: true },
|
|
5849
|
+
{ label: 'Internationlized Currency', key: 'localizedCurrency', type: 'CURRENCY_LOCALIZED', category: 'Currency', color: 'green' },
|
|
5850
|
+
{ label: 'Not Internationlized Currency', key: 'notLocalizedCurrency', type: 'CURRENCY_NOT_LOCALIZED', category: 'Currency', color: 'red', isDefect: true },
|
|
5851
|
+
{ label: 'Internationlized Percentage', key: 'localizedPercentage', type: 'PERCENTAGE_LOCALIZED', category: 'Percentage', color: 'green' },
|
|
5852
|
+
{ label: 'Not Internationlized Percentage', key: 'notLocalizedPercentage', type: 'PERCENTAGE_NOT_LOCALIZED', category: 'Percentage', color: 'red', isDefect: true },
|
|
5853
|
+
{ label: 'Internationlized Date', key: 'localizedDate', type: 'DATE_LOCALIZED', category: 'Date', color: 'green' },
|
|
5854
|
+
{ label: 'Not Internationlized Date', key: 'notLocalizedDate', type: 'DATE_NOT_LOCALIZED', category: 'Date', color: 'red', isDefect: true },
|
|
5855
|
+
{ label: 'Internationlized Time', key: 'localizedTime', type: 'TIME_LOCALIZED', category: 'Time', color: 'green' },
|
|
5856
|
+
{ label: 'Not Internationlized Time', key: 'notLocalizedTime', type: 'TIME_NOT_LOCALIZED', category: 'Time', color: 'red', isDefect: true },
|
|
5857
|
+
{ label: 'Internationlized DateTime', key: 'localizedDateTime', type: 'DATE_TIME_LOCALIZED', category: 'DateTime', color: 'green' },
|
|
5858
|
+
{ label: 'Not Internationlized DateTime', key: 'notLocalizedDateTime', type: 'DATE_TIME_NOT_LOCALIZED', category: 'DateTime', color: 'red', isDefect: true },
|
|
5859
|
+
{ label: 'Encoding Issue Strings', key: 'encoding', type: 'ENCODING_ISSUE', category: 'Defects', color: 'cyan', isDefect: true },
|
|
5860
|
+
{ label: 'DNT Strings', key: 'dnt', type: 'DNT', category: 'Skipped', color: 'muted' },
|
|
5861
|
+
{ label: 'Ignored Strings', key: 'ignored', type: 'IGNORE', category: 'Skipped', color: 'muted' },
|
|
5862
|
+
{ label: 'Untranslated Strings', key: 'untranslatedStrings', type: 'UNTRANSLATED', category: 'Defects', color: 'pink', isDefect: true },
|
|
5863
|
+
{ label: 'Auto Ignored Strings', key: 'autoIgnored', type: 'AUTO_IGNORE', category: 'Skipped', color: 'muted' },
|
|
5864
|
+
{ label: 'User Input Strings', key: 'userInput', type: 'USER_INPUT', category: 'Skipped', color: 'muted' },
|
|
5865
|
+
{ label: 'Total Reviewed', key: 'reviewed', type: 'REVIEWED', category: 'Summary', color: 'blue', isTotal: true }
|
|
5866
|
+
];
|
|
5867
|
+
|
|
5868
|
+
window.galleryItems = [];
|
|
5869
|
+
window.galleryIndex = 0;
|
|
5870
|
+
|
|
5871
|
+
function renderGalleryItem(index) {
|
|
5872
|
+
if (!window.galleryItems || !window.galleryItems[index]) return;
|
|
5873
|
+
window.galleryIndex = index;
|
|
5874
|
+
var item = window.galleryItems[index];
|
|
5875
|
+
|
|
5876
|
+
var img = document.getElementById('galleryMainImg');
|
|
5877
|
+
if (img) {
|
|
5878
|
+
var rawPath = (item.imagePath || '').replace(/^[\\/]+/, '');
|
|
5879
|
+
img.src = window.getProductUrl() + '/' + rawPath;
|
|
5880
|
+
}
|
|
3722
5881
|
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
}
|
|
3726
|
-
else {
|
|
3727
|
-
const tableData = {
|
|
3728
|
-
'Internationlized Strings':
|
|
3729
|
-
data.localizedStrings +
|
|
3730
|
-
data.untranslatedStrings +
|
|
3731
|
-
data.partialStrings,
|
|
3732
|
-
'Not Internationlized Strings': data.notLocalizedStrings,
|
|
3733
|
-
'Partially Localized Strings': data.partialStrings,
|
|
3734
|
-
'Internationlized Numbers': data.localizedNumber,
|
|
3735
|
-
'Not Internationlized Numbers': data.notLocalizedNumber,
|
|
3736
|
-
'Internationlized Currency': data.localizedCurrency,
|
|
3737
|
-
'Not Internationlized Currency': data.notLocalizedCurrency,
|
|
3738
|
-
'Internationlized Percentage': data.localizedPercentage,
|
|
3739
|
-
'Not Internationlized Percentage': data.notLocalizedPercentage,
|
|
3740
|
-
'Internationlized Date': data.localizedDate,
|
|
3741
|
-
'Not Internationlized Date': data.notLocalizedDate,
|
|
3742
|
-
'Internationlized Time': data.localizedTime,
|
|
3743
|
-
'Not Internationlized Time': data.notLocalizedTime,
|
|
3744
|
-
'Internationlized DateTime': data.localizedDate,
|
|
3745
|
-
'Not Internationlized DateTime': data.notLocalizedDateTime,
|
|
3746
|
-
'Encoding Issue Strings': data.encoding,
|
|
3747
|
-
'DNT Strings': data.dnt,
|
|
3748
|
-
'Ignored Strings': data.ignored,
|
|
3749
|
-
'Untranslated Strings': data.untranslatedStrings,
|
|
3750
|
-
'Auto Ignored Strings': data.autoIgnored,
|
|
3751
|
-
'User Input Strings': data.userInput,
|
|
3752
|
-
'Total Reviewed': data.reviewed
|
|
3753
|
-
};
|
|
5882
|
+
var counter = document.getElementById('galleryCounter');
|
|
5883
|
+
if (counter) counter.textContent = 'Item ' + (index + 1) + ' of ' + window.galleryItems.length;
|
|
3754
5884
|
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
}
|
|
5885
|
+
var pageBadge = document.getElementById('galleryPageBadge');
|
|
5886
|
+
if (pageBadge) pageBadge.textContent = 'Locale: ' + item.locale + ' | Page: ' + item.page;
|
|
5887
|
+
|
|
5888
|
+
var textVal = document.getElementById('galleryTextVal');
|
|
5889
|
+
if (textVal) textVal.textContent = item.string || '-';
|
|
3761
5890
|
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
5891
|
+
var prevBtn = document.getElementById('galleryPrevBtn');
|
|
5892
|
+
var nextBtn = document.getElementById('galleryNextBtn');
|
|
5893
|
+
if (prevBtn) prevBtn.disabled = index === 0;
|
|
5894
|
+
if (nextBtn) nextBtn.disabled = index === window.galleryItems.length - 1;
|
|
5895
|
+
|
|
5896
|
+
var thumbs = document.querySelectorAll('.gallery-thumb-btn');
|
|
5897
|
+
thumbs.forEach(function(t, i) {
|
|
5898
|
+
if (i === index) {
|
|
5899
|
+
t.classList.add('active');
|
|
5900
|
+
try { t.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }); } catch(e){}
|
|
5901
|
+
} else {
|
|
5902
|
+
t.classList.remove('active');
|
|
5903
|
+
}
|
|
5904
|
+
});
|
|
3766
5905
|
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
5906
|
+
var fullBtn = document.getElementById('galleryFullscreenBtn');
|
|
5907
|
+
if (fullBtn) {
|
|
5908
|
+
fullBtn.onclick = function() {
|
|
5909
|
+
if (item.imagePath && typeof window.openImageViewer === 'function') {
|
|
5910
|
+
window.openImageViewer(item.imagePath);
|
|
3770
5911
|
}
|
|
5912
|
+
};
|
|
5913
|
+
}
|
|
5914
|
+
}
|
|
3771
5915
|
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
5916
|
+
function openScreenshotGallery(locale, rowType, rowLabel) {
|
|
5917
|
+
var localesToSearch = locale === 'ALL' ? DataStore.getLocales() : [locale];
|
|
5918
|
+
var items = [];
|
|
5919
|
+
var seenKeys = {};
|
|
5920
|
+
|
|
5921
|
+
localesToSearch.forEach(function(loc) {
|
|
5922
|
+
var data = DataStore.getDataByLocale(loc) || {};
|
|
5923
|
+
Object.keys(data).forEach(function(str) {
|
|
5924
|
+
var arr = data[str] || [];
|
|
5925
|
+
arr.forEach(function(entry) {
|
|
5926
|
+
var matchesType = (rowType === 'REVIEWED') ||
|
|
5927
|
+
(entry.type === rowType) ||
|
|
5928
|
+
(entry.type && entry.type.toUpperCase() === rowType.toUpperCase()) ||
|
|
5929
|
+
(rowType === 'IGNORE' && (entry.type === 'IGNORED' || entry.type === 'IGNORE')) ||
|
|
5930
|
+
(rowType === 'UNTRANSLATED' && (entry.type === 'UNTRANSLATED_STRINGS' || entry.type === 'UNTRANSLATED'));
|
|
5931
|
+
|
|
5932
|
+
if (matchesType) {
|
|
5933
|
+
var rawPath = entry.imagePath || '';
|
|
5934
|
+
if (rawPath && !rawPath.includes('/screenshots/')) {
|
|
5935
|
+
var sub = (entry.type === 'REVIEWED' || !entry.type) ? 'reviewed' : entry.type.toLowerCase();
|
|
5936
|
+
rawPath = '/' + loc + '/screenshots/' + sub + '/' + rawPath.replace(/^[/]+/, '');
|
|
5937
|
+
}
|
|
3792
5938
|
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
5939
|
+
var itemKey = loc + '|' + str + '|' + rawPath;
|
|
5940
|
+
if (!seenKeys[itemKey]) {
|
|
5941
|
+
seenKeys[itemKey] = true;
|
|
5942
|
+
items.push({
|
|
5943
|
+
string: str,
|
|
5944
|
+
page: entry.description || 'Page',
|
|
5945
|
+
imagePath: rawPath,
|
|
5946
|
+
locale: loc,
|
|
5947
|
+
type: entry.type
|
|
5948
|
+
});
|
|
5949
|
+
}
|
|
5950
|
+
}
|
|
5951
|
+
});
|
|
5952
|
+
});
|
|
5953
|
+
});
|
|
3796
5954
|
|
|
3797
|
-
|
|
3798
|
-
|
|
5955
|
+
if (!items.length) {
|
|
5956
|
+
alert('No screenshots captured for ' + rowLabel + (locale !== 'ALL' ? ' (' + locale + ')' : ''));
|
|
5957
|
+
return;
|
|
5958
|
+
}
|
|
3799
5959
|
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
5960
|
+
window.galleryItems = items;
|
|
5961
|
+
window.galleryIndex = 0;
|
|
5962
|
+
|
|
5963
|
+
var modal = document.getElementById('screenshotGalleryModal');
|
|
5964
|
+
if (modal) modal.style.display = 'block';
|
|
5965
|
+
|
|
5966
|
+
var titleEl = document.getElementById('galleryModalTitle');
|
|
5967
|
+
if (titleEl) titleEl.textContent = rowLabel + (locale !== 'ALL' ? ' - ' + locale : ' - All Locales');
|
|
5968
|
+
|
|
5969
|
+
var badgeEl = document.getElementById('galleryModalBadge');
|
|
5970
|
+
if (badgeEl) badgeEl.textContent = items.length + ' screenshot' + (items.length > 1 ? 's' : '');
|
|
5971
|
+
|
|
5972
|
+
var strip = document.getElementById('galleryThumbnailsStrip');
|
|
5973
|
+
if (strip) {
|
|
5974
|
+
strip.innerHTML = '';
|
|
5975
|
+
items.forEach(function(item, idx) {
|
|
5976
|
+
var thumb = document.createElement('button');
|
|
5977
|
+
thumb.type = 'button';
|
|
5978
|
+
thumb.className = 'gallery-thumb-btn' + (idx === 0 ? ' active' : '');
|
|
5979
|
+
thumb.title = item.string + ' (' + item.page + ')';
|
|
5980
|
+
thumb.innerHTML = '<span class="thumb-idx">' + (idx + 1) + '</span><span class="thumb-lbl">' + (item.page || item.locale) + '</span>';
|
|
5981
|
+
thumb.addEventListener('click', function() {
|
|
5982
|
+
renderGalleryItem(idx);
|
|
5983
|
+
});
|
|
5984
|
+
strip.appendChild(thumb);
|
|
5985
|
+
});
|
|
5986
|
+
}
|
|
3805
5987
|
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
holder.appendChild(barHolder);
|
|
5988
|
+
renderGalleryItem(0);
|
|
5989
|
+
}
|
|
3809
5990
|
|
|
3810
|
-
|
|
3811
|
-
|
|
5991
|
+
window.closeScreenshotGallery = function() {
|
|
5992
|
+
var modal = document.getElementById('screenshotGalleryModal');
|
|
5993
|
+
if (modal) modal.style.display = 'none';
|
|
5994
|
+
var img = document.getElementById('galleryMainImg');
|
|
5995
|
+
if (img) img.src = '';
|
|
5996
|
+
};
|
|
3812
5997
|
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
? 100
|
|
3822
|
-
: data.localizedStrings +
|
|
3823
|
-
data.untranslatedStrings +
|
|
3824
|
-
data.partialStrings,
|
|
3825
|
-
totalLocCount = showFull
|
|
3826
|
-
? 100
|
|
3827
|
-
: totalI18nCount -
|
|
3828
|
-
data.untranslatedStrings -
|
|
3829
|
-
data.notLocalizedStrings,
|
|
3830
|
-
totalNumberCount = showFull
|
|
3831
|
-
? 100
|
|
3832
|
-
: data.localizedNumber +
|
|
3833
|
-
data.localizedCurrency +
|
|
3834
|
-
data.localizedPercentage +
|
|
3835
|
-
data.notLocalizedPercentage +
|
|
3836
|
-
data.notLocalizedCurrency +
|
|
3837
|
-
data.notLocalizedNumber,
|
|
3838
|
-
i18nNumbers = showFull
|
|
3839
|
-
? 100
|
|
3840
|
-
: totalNumberCount -
|
|
3841
|
-
data.notLocalizedPercentage -
|
|
3842
|
-
data.notLocalizedCurrency -
|
|
3843
|
-
data.notLocalizedNumber,
|
|
3844
|
-
totalI18nDateTimeCount = showFull
|
|
3845
|
-
? 100
|
|
3846
|
-
: data.localizedDate +
|
|
3847
|
-
data.localizedDateTime +
|
|
3848
|
-
data.localizedTime +
|
|
3849
|
-
data.notLocalizedDate +
|
|
3850
|
-
data.notLocalizedDateTime +
|
|
3851
|
-
data.notLocalizedTime,
|
|
3852
|
-
i18nDateTime = showFull
|
|
3853
|
-
? 100
|
|
3854
|
-
: totalI18nDateTimeCount -
|
|
3855
|
-
data.notLocalizedDate -
|
|
3856
|
-
data.notLocalizedDateTime -
|
|
3857
|
-
data.notLocalizedTime;
|
|
3858
|
-
|
|
3859
|
-
holder.appendChild(
|
|
3860
|
-
generateBarEl('String I18n level', totalI18nCount, i18nStrings)
|
|
3861
|
-
);
|
|
5998
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
5999
|
+
var closeBtn = document.querySelector('#screenshotGalleryModal .gallery-close-btn');
|
|
6000
|
+
if (closeBtn) {
|
|
6001
|
+
closeBtn.addEventListener('click', function(e) {
|
|
6002
|
+
e.stopPropagation();
|
|
6003
|
+
window.closeScreenshotGallery();
|
|
6004
|
+
});
|
|
6005
|
+
}
|
|
3862
6006
|
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
6007
|
+
var backdrop = document.querySelector('#screenshotGalleryModal .gallery-modal-backdrop');
|
|
6008
|
+
if (backdrop) {
|
|
6009
|
+
backdrop.addEventListener('click', function(e) {
|
|
6010
|
+
e.stopPropagation();
|
|
6011
|
+
window.closeScreenshotGallery();
|
|
6012
|
+
});
|
|
6013
|
+
}
|
|
3866
6014
|
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
6015
|
+
var prevBtn = document.getElementById('galleryPrevBtn');
|
|
6016
|
+
if (prevBtn) {
|
|
6017
|
+
prevBtn.addEventListener('click', function() {
|
|
6018
|
+
if (window.galleryIndex > 0) renderGalleryItem(window.galleryIndex - 1);
|
|
6019
|
+
});
|
|
6020
|
+
}
|
|
3870
6021
|
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3876
|
-
)
|
|
3877
|
-
);
|
|
3878
|
-
return holder;
|
|
6022
|
+
var nextBtn = document.getElementById('galleryNextBtn');
|
|
6023
|
+
if (nextBtn) {
|
|
6024
|
+
nextBtn.addEventListener('click', function() {
|
|
6025
|
+
if (window.galleryItems && window.galleryIndex < window.galleryItems.length - 1) {
|
|
6026
|
+
renderGalleryItem(window.galleryIndex + 1);
|
|
3879
6027
|
}
|
|
6028
|
+
});
|
|
6029
|
+
}
|
|
3880
6030
|
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
|
|
6031
|
+
document.addEventListener('keydown', function(e) {
|
|
6032
|
+
var modal = document.getElementById('screenshotGalleryModal');
|
|
6033
|
+
if (!modal || modal.style.display === 'none') return;
|
|
6034
|
+
if (e.key === 'Escape') {
|
|
6035
|
+
window.closeScreenshotGallery();
|
|
6036
|
+
} else if (e.key === 'ArrowLeft') {
|
|
6037
|
+
if (window.galleryIndex > 0) renderGalleryItem(window.galleryIndex - 1);
|
|
6038
|
+
} else if (e.key === 'ArrowRight') {
|
|
6039
|
+
if (window.galleryItems && window.galleryIndex < window.galleryItems.length - 1) {
|
|
6040
|
+
renderGalleryItem(window.galleryIndex + 1);
|
|
3888
6041
|
}
|
|
6042
|
+
}
|
|
6043
|
+
});
|
|
3889
6044
|
|
|
3890
|
-
|
|
3891
|
-
const card = document.createElement('div');
|
|
3892
|
-
const title = document.createElement('div');
|
|
3893
|
-
card.classList.add('card');
|
|
3894
|
-
card.dataset.locale = locale;
|
|
6045
|
+
renderInsightsTable();
|
|
3895
6046
|
|
|
3896
|
-
|
|
3897
|
-
|
|
6047
|
+
var searchInput = document.getElementById('insightsSearchInput');
|
|
6048
|
+
if (searchInput) {
|
|
6049
|
+
searchInput.addEventListener('input', function(e) {
|
|
6050
|
+
var query = e.target.value.toLowerCase().trim();
|
|
6051
|
+
var rows = document.querySelectorAll('#insightsTableBody tr.insights-metric-row');
|
|
6052
|
+
rows.forEach(function(row) {
|
|
6053
|
+
var text = (row.dataset.search || '').toLowerCase();
|
|
6054
|
+
if (!query || text.indexOf(query) !== -1) {
|
|
6055
|
+
row.style.display = '';
|
|
6056
|
+
} else {
|
|
6057
|
+
row.style.display = 'none';
|
|
3898
6058
|
}
|
|
6059
|
+
});
|
|
6060
|
+
});
|
|
6061
|
+
}
|
|
3899
6062
|
|
|
3900
|
-
|
|
3901
|
-
|
|
6063
|
+
function renderInsightsTable() {
|
|
6064
|
+
var thead = document.getElementById('insightsTableHead');
|
|
6065
|
+
var tbody = document.getElementById('insightsTableBody');
|
|
6066
|
+
if (!thead || !tbody) return;
|
|
3902
6067
|
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
if (previousSelectedSubMenu) {
|
|
3909
|
-
window.previousSelectedLocale =
|
|
3910
|
-
previousSelectedSubMenu.dataset.locale;
|
|
3911
|
-
}
|
|
6068
|
+
var locales = DataStore.getLocales();
|
|
6069
|
+
if (!locales.length) {
|
|
6070
|
+
tbody.innerHTML = '<tr><td colspan="3" style="text-align:center; padding: 24px; color: var(--text-muted);">No locale data available</td></tr>';
|
|
6071
|
+
return;
|
|
6072
|
+
}
|
|
3912
6073
|
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
6074
|
+
// Build header: Verification Item | Locale 1 | Locale 2 ... | Total
|
|
6075
|
+
var headerHtml = '<tr><th class="metric-col-header">Verification Item</th>';
|
|
6076
|
+
locales.forEach(function(locale) {
|
|
6077
|
+
var isDef = DataStore.isDefaultLocale(locale);
|
|
6078
|
+
headerHtml += '<th class="locale-col-header">' +
|
|
6079
|
+
'<div class="col-header-inner">' +
|
|
6080
|
+
'<span class="locale-col-code">' + locale + '</span>' +
|
|
6081
|
+
(isDef ? '<span class="col-default-badge">Default</span>' : '') +
|
|
6082
|
+
'</div>' +
|
|
6083
|
+
'</th>';
|
|
6084
|
+
});
|
|
6085
|
+
headerHtml += '<th class="total-col-header">Total</th></tr>';
|
|
6086
|
+
thead.innerHTML = headerHtml;
|
|
6087
|
+
|
|
6088
|
+
// Build tbody rows for each of the 22 metrics
|
|
6089
|
+
tbody.innerHTML = '';
|
|
6090
|
+
METRIC_ROWS.forEach(function(row) {
|
|
6091
|
+
var tr = document.createElement('tr');
|
|
6092
|
+
tr.className = 'insights-metric-row' + (row.isTotal ? ' row-total' : '') + (row.isDefect ? ' row-defect' : '');
|
|
6093
|
+
tr.dataset.search = (row.label + ' ' + row.category).toLowerCase();
|
|
6094
|
+
tr.dataset.metric = row.type;
|
|
6095
|
+
|
|
6096
|
+
var rowTotal = 0;
|
|
6097
|
+
var cellsHtml = '<td class="metric-name-cell">' +
|
|
6098
|
+
'<div class="metric-name-inner">' +
|
|
6099
|
+
'<span class="metric-cat-pill cat-' + row.category.toLowerCase() + '">' + row.category + '</span>' +
|
|
6100
|
+
'<span class="metric-title-text">' + row.label + '</span>' +
|
|
6101
|
+
'</div>' +
|
|
6102
|
+
'</td>';
|
|
6103
|
+
|
|
6104
|
+
locales.forEach(function(locale) {
|
|
6105
|
+
var stats = DataStore.getStatByLocale(locale) || {};
|
|
6106
|
+
var val = stats[row.key] || 0;
|
|
6107
|
+
rowTotal += val;
|
|
6108
|
+
|
|
6109
|
+
if (val > 0) {
|
|
6110
|
+
cellsHtml += '<td class="metric-value-cell">' +
|
|
6111
|
+
'<button type="button" class="metric-cell-btn cell-active badge-' + row.color + '" ' +
|
|
6112
|
+
'data-locale="' + locale + '" ' +
|
|
6113
|
+
'data-type="' + row.type + '" ' +
|
|
6114
|
+
'data-label="' + row.label + '" ' +
|
|
6115
|
+
'title="Click to view ' + val + ' screenshot(s)">' +
|
|
6116
|
+
'<span class="cell-num">' + val + '</span>' +
|
|
6117
|
+
'<svg class="cell-cam-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>' +
|
|
6118
|
+
'</button>' +
|
|
6119
|
+
'</td>';
|
|
6120
|
+
} else {
|
|
6121
|
+
cellsHtml += '<td class="metric-value-cell"><span class="cell-zero">0</span></td>';
|
|
6122
|
+
}
|
|
6123
|
+
});
|
|
3917
6124
|
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
6125
|
+
// Total cell
|
|
6126
|
+
if (rowTotal > 0) {
|
|
6127
|
+
cellsHtml += '<td class="metric-value-cell total-cell">' +
|
|
6128
|
+
'<button type="button" class="metric-cell-btn cell-active total-badge" ' +
|
|
6129
|
+
'data-locale="ALL" ' +
|
|
6130
|
+
'data-type="' + row.type + '" ' +
|
|
6131
|
+
'data-label="' + row.label + '" ' +
|
|
6132
|
+
'title="Click to view ' + rowTotal + ' screenshot(s) across all locales">' +
|
|
6133
|
+
'<span class="cell-num">' + rowTotal + '</span>' +
|
|
6134
|
+
'<svg class="cell-cam-icon" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>' +
|
|
6135
|
+
'</button>' +
|
|
6136
|
+
'</td>';
|
|
6137
|
+
} else {
|
|
6138
|
+
cellsHtml += '<td class="metric-value-cell total-cell"><span class="cell-zero">0</span></td>';
|
|
3921
6139
|
}
|
|
3922
6140
|
|
|
3923
|
-
|
|
3924
|
-
// read from global variable appData;
|
|
3925
|
-
const localeInfo = DataStore.getLocalesData();
|
|
6141
|
+
tr.innerHTML = cellsHtml;
|
|
3926
6142
|
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
);
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
cardHolder.appendChild(cardEl);
|
|
3937
|
-
}
|
|
3938
|
-
}
|
|
3939
|
-
}
|
|
6143
|
+
// Attach click handlers to active metric buttons
|
|
6144
|
+
tr.querySelectorAll('.metric-cell-btn').forEach(function(btn) {
|
|
6145
|
+
btn.addEventListener('click', function(e) {
|
|
6146
|
+
e.stopPropagation();
|
|
6147
|
+
openScreenshotGallery(btn.dataset.locale, btn.dataset.type, btn.dataset.label);
|
|
6148
|
+
});
|
|
6149
|
+
});
|
|
6150
|
+
|
|
6151
|
+
tbody.appendChild(tr);
|
|
3940
6152
|
});
|
|
3941
|
-
}
|
|
6153
|
+
}
|
|
6154
|
+
|
|
6155
|
+
function drilldownLocale(locale) {
|
|
6156
|
+
var contents = document.querySelectorAll('.content');
|
|
6157
|
+
contents.forEach(function(c) { c.classList.remove('active'); });
|
|
6158
|
+
var locSection = document.getElementById('locale');
|
|
6159
|
+
if (locSection) locSection.classList.add('active');
|
|
6160
|
+
if (window.renderLocaleGrid) {
|
|
6161
|
+
window.renderLocaleGrid(locale);
|
|
6162
|
+
}
|
|
6163
|
+
}
|
|
6164
|
+
});
|
|
6165
|
+
})();`;
|
|
3942
6166
|
const localeGrid = () => `// locale grid
|
|
3943
6167
|
(() => {
|
|
3944
6168
|
if (!DataStore.ranSuccessfully()) {
|
|
@@ -3962,6 +6186,59 @@ const localeGrid = () => `// locale grid
|
|
|
3962
6186
|
).textContent = \`\${locale} \${DataStore.isSanityRun() ? 'Sanity Result' : 'I18n Coverage Details'}\`;
|
|
3963
6187
|
};
|
|
3964
6188
|
|
|
6189
|
+
const getMeta = (type) => {
|
|
6190
|
+
switch (type) {
|
|
6191
|
+
case 'STRING_LOCALIZED':
|
|
6192
|
+
return { category: 'Strings', status: 'Localized', badgeClass: 'status-green', catClass: 'cat-strings' };
|
|
6193
|
+
case 'STRING_NOT_LOCALIZED':
|
|
6194
|
+
return { category: 'Strings', status: 'Not Localized', badgeClass: 'status-red', catClass: 'cat-strings' };
|
|
6195
|
+
case 'STRING_PARTIALLY_LOCALIZED':
|
|
6196
|
+
return { category: 'Strings', status: 'Partially Localized', badgeClass: 'status-yellow', catClass: 'cat-strings' };
|
|
6197
|
+
case 'UNTRANSLATED':
|
|
6198
|
+
return { category: 'Strings', status: 'Untranslated', badgeClass: 'status-pink', catClass: 'cat-strings' };
|
|
6199
|
+
case 'ENCODING_ISSUE':
|
|
6200
|
+
return { category: 'Strings', status: 'Encoding Issue', badgeClass: 'status-cyan', catClass: 'cat-strings' };
|
|
6201
|
+
case 'NUMBER_LOCALIZED':
|
|
6202
|
+
return { category: 'Numbers', status: 'Localized', badgeClass: 'status-green', catClass: 'cat-numbers' };
|
|
6203
|
+
case 'NUMBER_NOT_LOCALIZED':
|
|
6204
|
+
return { category: 'Numbers', status: 'Not Localized', badgeClass: 'status-red', catClass: 'cat-numbers' };
|
|
6205
|
+
case 'CURRENCY_LOCALIZED':
|
|
6206
|
+
return { category: 'Currency', status: 'Localized', badgeClass: 'status-green', catClass: 'cat-currency' };
|
|
6207
|
+
case 'CURRENCY_NOT_LOCALIZED':
|
|
6208
|
+
return { category: 'Currency', status: 'Not Localized', badgeClass: 'status-red', catClass: 'cat-currency' };
|
|
6209
|
+
case 'PERCENTAGE_LOCALIZED':
|
|
6210
|
+
return { category: 'Percentage', status: 'Localized', badgeClass: 'status-green', catClass: 'cat-percentage' };
|
|
6211
|
+
case 'PERCENTAGE_NOT_LOCALIZED':
|
|
6212
|
+
return { category: 'Percentage', status: 'Not Localized', badgeClass: 'status-red', catClass: 'cat-percentage' };
|
|
6213
|
+
case 'DATE_LOCALIZED':
|
|
6214
|
+
return { category: 'Date', status: 'Localized', badgeClass: 'status-green', catClass: 'cat-date' };
|
|
6215
|
+
case 'DATE_NOT_LOCALIZED':
|
|
6216
|
+
return { category: 'Date', status: 'Not Localized', badgeClass: 'status-red', catClass: 'cat-date' };
|
|
6217
|
+
case 'TIME_LOCALIZED':
|
|
6218
|
+
return { category: 'Time', status: 'Localized', badgeClass: 'status-green', catClass: 'cat-time' };
|
|
6219
|
+
case 'TIME_NOT_LOCALIZED':
|
|
6220
|
+
return { category: 'Time', status: 'Not Localized', badgeClass: 'status-red', catClass: 'cat-time' };
|
|
6221
|
+
case 'DATE_TIME_LOCALIZED':
|
|
6222
|
+
return { category: 'DateTime', status: 'Localized', badgeClass: 'status-green', catClass: 'cat-datetime' };
|
|
6223
|
+
case 'DATE_TIME_NOT_LOCALIZED':
|
|
6224
|
+
return { category: 'DateTime', status: 'Not Localized', badgeClass: 'status-red', catClass: 'cat-datetime' };
|
|
6225
|
+
case 'DNT':
|
|
6226
|
+
return { category: 'Skipped', status: 'Do Not Translate (DNT)', badgeClass: 'status-muted', catClass: 'cat-skipped' };
|
|
6227
|
+
case 'IGNORE':
|
|
6228
|
+
return { category: 'Skipped', status: 'Ignored', badgeClass: 'status-muted', catClass: 'cat-skipped' };
|
|
6229
|
+
case 'AUTO_IGNORE':
|
|
6230
|
+
return { category: 'Skipped', status: 'Auto Ignored', badgeClass: 'status-muted', catClass: 'cat-skipped' };
|
|
6231
|
+
case 'USER_INPUT':
|
|
6232
|
+
return { category: 'Skipped', status: 'User Input', badgeClass: 'status-muted', catClass: 'cat-skipped' };
|
|
6233
|
+
case 'TRUNCATION_ISSUE':
|
|
6234
|
+
return { category: 'Layout', status: 'Truncation Issue', badgeClass: 'status-red', catClass: 'cat-layout' };
|
|
6235
|
+
case 'OVERLAPPING_ISSUE':
|
|
6236
|
+
return { category: 'Layout', status: 'Overlapping Issue', badgeClass: 'status-red', catClass: 'cat-layout' };
|
|
6237
|
+
default:
|
|
6238
|
+
return { category: 'General', status: type || '-', badgeClass: 'status-muted', catClass: 'cat-general' };
|
|
6239
|
+
}
|
|
6240
|
+
};
|
|
6241
|
+
|
|
3965
6242
|
const buildGrid = (locale) => {
|
|
3966
6243
|
const data = DataStore.getDataByLocale(locale) || {};
|
|
3967
6244
|
$.fn.dataTable.ext.errMode = 'none';
|
|
@@ -3977,9 +6254,20 @@ const localeGrid = () => `// locale grid
|
|
|
3977
6254
|
else {
|
|
3978
6255
|
Object.entries(data).map((entry) =>
|
|
3979
6256
|
entry[1].forEach(
|
|
3980
|
-
(v) =>
|
|
3981
|
-
(v.type !== 'REVIEWED')
|
|
3982
|
-
|
|
6257
|
+
(v) => {
|
|
6258
|
+
if (v.type !== 'REVIEWED') {
|
|
6259
|
+
const meta = getMeta(v.type);
|
|
6260
|
+
dataSet.push([
|
|
6261
|
+
entry[0],
|
|
6262
|
+
meta.category,
|
|
6263
|
+
meta.status,
|
|
6264
|
+
v.description,
|
|
6265
|
+
v.imagePath,
|
|
6266
|
+
meta.catClass,
|
|
6267
|
+
meta.badgeClass
|
|
6268
|
+
]);
|
|
6269
|
+
}
|
|
6270
|
+
}
|
|
3983
6271
|
)
|
|
3984
6272
|
);
|
|
3985
6273
|
}
|
|
@@ -3996,7 +6284,8 @@ const localeGrid = () => `// locale grid
|
|
|
3996
6284
|
{ title: 'Page' },
|
|
3997
6285
|
{ title: 'Screenshot' },
|
|
3998
6286
|
] : [
|
|
3999
|
-
{ title: 'String' },
|
|
6287
|
+
{ title: 'Used String / Term' },
|
|
6288
|
+
{ title: 'Category' },
|
|
4000
6289
|
{ title: 'Status' },
|
|
4001
6290
|
{ title: 'Page' },
|
|
4002
6291
|
{ title: 'Screenshot' }
|
|
@@ -4015,33 +6304,48 @@ const localeGrid = () => `// locale grid
|
|
|
4015
6304
|
data: null,
|
|
4016
6305
|
render: function (data) {
|
|
4017
6306
|
if (!data || !data[1]) return '<span style="color: var(--text-muted);">-</span>';
|
|
4018
|
-
return \`<a href="javascript:void(0)" class="view-screenshot-btn" data-image="\${data[1]}" onclick="openImageViewer('
|
|
6307
|
+
return \`<a href="javascript:void(0)" class="view-screenshot-btn" data-image="\${data[1]}" onclick="openImageViewer('\\\\\${data[1]}')" title="View screenshot for '\${data[0]}'"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/></svg><span>View</span></a>\`;
|
|
4019
6308
|
},
|
|
4020
6309
|
className: 'dt-head-center dt-body-center'
|
|
4021
6310
|
}
|
|
4022
6311
|
] :
|
|
4023
6312
|
[
|
|
4024
6313
|
{
|
|
4025
|
-
width: '
|
|
4026
|
-
targets: 0
|
|
6314
|
+
width: '35%',
|
|
6315
|
+
targets: 0,
|
|
6316
|
+
render: function(data) {
|
|
6317
|
+
return '<span class="cell-term-text">' + $('<div>').text(data || '').html() + '</span>';
|
|
6318
|
+
}
|
|
6319
|
+
},
|
|
6320
|
+
{
|
|
6321
|
+
width: '15%',
|
|
6322
|
+
targets: 1,
|
|
6323
|
+
render: function(data, type, row) {
|
|
6324
|
+
var catClass = row[5] || 'cat-general';
|
|
6325
|
+
return '<span class="cat-pill ' + catClass + '">' + data + '</span>';
|
|
6326
|
+
}
|
|
4027
6327
|
},
|
|
4028
6328
|
{
|
|
4029
|
-
width: '
|
|
4030
|
-
targets:
|
|
6329
|
+
width: '18%',
|
|
6330
|
+
targets: 2,
|
|
6331
|
+
render: function(data, type, row) {
|
|
6332
|
+
var badgeClass = row[6] || 'status-muted';
|
|
6333
|
+
return '<span class="status-badge ' + badgeClass + '">' + data + '</span>';
|
|
6334
|
+
}
|
|
4031
6335
|
},
|
|
4032
6336
|
{
|
|
4033
|
-
width: '22
|
|
4034
|
-
targets:
|
|
6337
|
+
width: '22%',
|
|
6338
|
+
targets: 3
|
|
4035
6339
|
},
|
|
4036
6340
|
{
|
|
4037
6341
|
width: '10%',
|
|
4038
|
-
targets:
|
|
6342
|
+
targets: 4,
|
|
4039
6343
|
orderable: false,
|
|
4040
6344
|
searchable: false,
|
|
4041
6345
|
data: null,
|
|
4042
6346
|
render: function (data) {
|
|
4043
|
-
if (!data || !data[
|
|
4044
|
-
return \`<a href="javascript:void(0)" class="view-screenshot-btn" data-image="\${data[
|
|
6347
|
+
if (!data || !data[4]) return '<span style="color: var(--text-muted);">-</span>';
|
|
6348
|
+
return \`<a href="javascript:void(0)" class="view-screenshot-btn" data-image="\${data[4]}" onclick="openImageViewer('\\\\\${data[4]}')" title="View screenshot for '\${data[3]}'"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/></svg><span>View</span></a>\`;
|
|
4045
6349
|
},
|
|
4046
6350
|
className: 'dt-head-center dt-body-center'
|
|
4047
6351
|
}
|
|
@@ -4054,7 +6358,7 @@ const localeGrid = () => `// locale grid
|
|
|
4054
6358
|
const column = this;
|
|
4055
6359
|
const columnIdx = column.index();
|
|
4056
6360
|
|
|
4057
|
-
if ((DataStore.isSanityRun() && columnIdx === 1) || columnIdx ===
|
|
6361
|
+
if ((DataStore.isSanityRun() && columnIdx === 1) || columnIdx === 4 || columnIdx === 0) {
|
|
4058
6362
|
return;
|
|
4059
6363
|
}
|
|
4060
6364
|
|
|
@@ -4064,9 +6368,14 @@ const localeGrid = () => `// locale grid
|
|
|
4064
6368
|
select.empty().append('<option value="">Filter By</option>');
|
|
4065
6369
|
|
|
4066
6370
|
const uniqueValues = new Set();
|
|
4067
|
-
tableApi.column(columnIdx, { search: 'applied' }).data().each((d) =>
|
|
6371
|
+
tableApi.column(columnIdx, { search: 'applied' }).data().each((d) => {
|
|
6372
|
+
if (d) {
|
|
6373
|
+
const raw = $('<div>' + d + '</div>').text().trim() || d;
|
|
6374
|
+
uniqueValues.add(raw);
|
|
6375
|
+
}
|
|
6376
|
+
});
|
|
4068
6377
|
|
|
4069
|
-
uniqueValues.forEach((value) => {
|
|
6378
|
+
Array.from(uniqueValues).sort().forEach((value) => {
|
|
4070
6379
|
select.append(\`<option value="\${value}">\${value}</option>\`);
|
|
4071
6380
|
});
|
|
4072
6381
|
|
|
@@ -4080,7 +6389,7 @@ const localeGrid = () => `// locale grid
|
|
|
4080
6389
|
const column = this;
|
|
4081
6390
|
const columnIdx = column.index();
|
|
4082
6391
|
|
|
4083
|
-
if ((DataStore.isSanityRun() && columnIdx === 1) || columnIdx ===
|
|
6392
|
+
if ((DataStore.isSanityRun() && columnIdx === 1) || columnIdx === 4 || columnIdx === 0) {
|
|
4084
6393
|
return;
|
|
4085
6394
|
}
|
|
4086
6395
|
|
|
@@ -4103,7 +6412,14 @@ const localeGrid = () => `// locale grid
|
|
|
4103
6412
|
updateFilters();
|
|
4104
6413
|
});
|
|
4105
6414
|
|
|
4106
|
-
|
|
6415
|
+
const uniqueValues = new Set();
|
|
6416
|
+
column.data().each((d) => {
|
|
6417
|
+
if (d) {
|
|
6418
|
+
const raw = $('<div>' + d + '</div>').text().trim() || d;
|
|
6419
|
+
uniqueValues.add(raw);
|
|
6420
|
+
}
|
|
6421
|
+
});
|
|
6422
|
+
Array.from(uniqueValues).sort().forEach((d) => {
|
|
4107
6423
|
select.append(\`<option value="\${d}">\${d}</option>\`);
|
|
4108
6424
|
});
|
|
4109
6425
|
}
|
|
@@ -4270,7 +6586,8 @@ window.initTheme = function() {
|
|
|
4270
6586
|
function openImageViewer(imageSrc) {
|
|
4271
6587
|
var imageView = document.getElementById("imageView");
|
|
4272
6588
|
if (imageView) {
|
|
4273
|
-
|
|
6589
|
+
var cleanSrc = (imageSrc || "").replace(/^[\\/]+/, "");
|
|
6590
|
+
imageView.src = window.getProductUrl() + "/" + cleanSrc;
|
|
4274
6591
|
}
|
|
4275
6592
|
var viewer = document.getElementById("imageViewer");
|
|
4276
6593
|
if (viewer) {
|
|
@@ -4314,6 +6631,14 @@ document.addEventListener('click', function(e) {
|
|
|
4314
6631
|
window.closeImageViewer();
|
|
4315
6632
|
}
|
|
4316
6633
|
}
|
|
6634
|
+
|
|
6635
|
+
var galleryCloseBtn = e.target.closest('.gallery-close-btn') || (e.target.classList && e.target.classList.contains('gallery-modal-backdrop'));
|
|
6636
|
+
if (galleryCloseBtn) {
|
|
6637
|
+
e.preventDefault();
|
|
6638
|
+
if (typeof window.closeScreenshotGallery === 'function') {
|
|
6639
|
+
window.closeScreenshotGallery();
|
|
6640
|
+
}
|
|
6641
|
+
}
|
|
4317
6642
|
});
|
|
4318
6643
|
|
|
4319
6644
|
document.addEventListener('keydown', function(e) {
|
|
@@ -4321,6 +6646,9 @@ document.addEventListener('keydown', function(e) {
|
|
|
4321
6646
|
if (typeof window.closeImageViewer === 'function') {
|
|
4322
6647
|
window.closeImageViewer();
|
|
4323
6648
|
}
|
|
6649
|
+
if (typeof window.closeScreenshotGallery === 'function') {
|
|
6650
|
+
window.closeScreenshotGallery();
|
|
6651
|
+
}
|
|
4324
6652
|
}
|
|
4325
6653
|
});
|
|
4326
6654
|
|
|
@@ -4342,86 +6670,7 @@ window.getProductUrl = function() {
|
|
|
4342
6670
|
var params = new URLSearchParams(location.href.match(/(\\?.*$)/g)?.[0] || "");
|
|
4343
6671
|
window.isStandaloneReport = params.size ? (params.get("standalone") === "true") : true;
|
|
4344
6672
|
`;
|
|
4345
|
-
const log = () =>
|
|
4346
|
-
document.addEventListener("DOMContentLoaded", function() {
|
|
4347
|
-
var rawLog = window.logData || (DataStore.hasRuntimeError() ? 'We are facing internal issue. Please try again after sometime.' : 'No log data found!');
|
|
4348
|
-
var logPre = document.getElementById("logPre");
|
|
4349
|
-
var copyBtn = document.getElementById("copyLogBtn");
|
|
4350
|
-
var searchInput = document.getElementById("logSearchInput");
|
|
4351
|
-
var currentFilteredText = rawLog;
|
|
4352
|
-
|
|
4353
|
-
var colorizeAndRender = function(filterText) {
|
|
4354
|
-
if (!logPre) return;
|
|
4355
|
-
var lines = rawLog.split("\\n");
|
|
4356
|
-
var filtered = filterText ? lines.filter(function(l) { return l.toLowerCase().indexOf(filterText.toLowerCase()) !== -1; }) : lines;
|
|
4357
|
-
currentFilteredText = filtered.join("\\n");
|
|
4358
|
-
var html = filtered.map(function(line) {
|
|
4359
|
-
var formatted = line.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
4360
|
-
formatted = formatted.replace(/\\[INFO\\]/g, '<span class="log-badge-info">[INFO]</span>');
|
|
4361
|
-
formatted = formatted.replace(/\\[WARN\\]/g, '<span class="log-badge-warn">[WARN]</span>');
|
|
4362
|
-
formatted = formatted.replace(/\\[ERROR\\]/g, '<span class="log-badge-error">[ERROR]</span>');
|
|
4363
|
-
return formatted;
|
|
4364
|
-
}).join("\\n");
|
|
4365
|
-
logPre.innerHTML = html;
|
|
4366
|
-
};
|
|
4367
|
-
|
|
4368
|
-
colorizeAndRender();
|
|
4369
|
-
|
|
4370
|
-
if (searchInput) {
|
|
4371
|
-
searchInput.addEventListener("input", function(e) {
|
|
4372
|
-
colorizeAndRender(e.target.value.trim());
|
|
4373
|
-
});
|
|
4374
|
-
}
|
|
4375
|
-
|
|
4376
|
-
if (copyBtn) {
|
|
4377
|
-
var showCopied = function() {
|
|
4378
|
-
copyBtn.innerHTML = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="#10b981" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg><span style="color: #10b981;">Copied!</span>';
|
|
4379
|
-
setTimeout(function() {
|
|
4380
|
-
copyBtn.innerHTML = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg><span>Copy</span>';
|
|
4381
|
-
}, 2000);
|
|
4382
|
-
};
|
|
4383
|
-
|
|
4384
|
-
var fallbackCopy = function(text) {
|
|
4385
|
-
var textArea = document.createElement("textarea");
|
|
4386
|
-
textArea.value = text;
|
|
4387
|
-
textArea.style.position = "fixed";
|
|
4388
|
-
textArea.style.top = "-9999px";
|
|
4389
|
-
textArea.style.left = "-9999px";
|
|
4390
|
-
textArea.style.opacity = "0";
|
|
4391
|
-
textArea.setAttribute("readonly", "");
|
|
4392
|
-
document.body.appendChild(textArea);
|
|
4393
|
-
textArea.focus();
|
|
4394
|
-
textArea.select();
|
|
4395
|
-
textArea.setSelectionRange(0, textArea.value.length);
|
|
4396
|
-
try {
|
|
4397
|
-
var successful = document.execCommand("copy");
|
|
4398
|
-
document.body.removeChild(textArea);
|
|
4399
|
-
if (successful) {
|
|
4400
|
-
showCopied();
|
|
4401
|
-
} else {
|
|
4402
|
-
console.error("document.execCommand copy was unsuccessful");
|
|
4403
|
-
}
|
|
4404
|
-
} catch (err) {
|
|
4405
|
-
document.body.removeChild(textArea);
|
|
4406
|
-
console.error("Fallback copy error:", err);
|
|
4407
|
-
}
|
|
4408
|
-
};
|
|
4409
|
-
|
|
4410
|
-
copyBtn.addEventListener("click", function() {
|
|
4411
|
-
var textToCopy = currentFilteredText || rawLog;
|
|
4412
|
-
if (navigator.clipboard && typeof navigator.clipboard.writeText === "function") {
|
|
4413
|
-
navigator.clipboard.writeText(textToCopy).then(function() {
|
|
4414
|
-
showCopied();
|
|
4415
|
-
}).catch(function() {
|
|
4416
|
-
fallbackCopy(textToCopy);
|
|
4417
|
-
});
|
|
4418
|
-
} else {
|
|
4419
|
-
fallbackCopy(textToCopy);
|
|
4420
|
-
}
|
|
4421
|
-
});
|
|
4422
|
-
}
|
|
4423
|
-
});
|
|
4424
|
-
})();`;
|
|
6673
|
+
const log = () => '(() => {\n document.addEventListener("DOMContentLoaded", function() {\n var rawLog = window.logData || (DataStore.hasRuntimeError() ? "We are facing internal issue. Please try again after sometime." : "No log data found!");\n var logLinesEl = document.getElementById("logLines");\n var copyBtn = document.getElementById("copyLogBtn");\n var searchInput = document.getElementById("logSearchInput");\n var wrapToggleBtn = document.getElementById("wrapToggleBtn");\n var levelPills = document.querySelectorAll(".log-level-btn");\n\n var statTotal = document.getElementById("logStatTotal");\n var statInfo = document.getElementById("logStatInfo");\n var statWarn = document.getElementById("logStatWarn");\n var statError = document.getElementById("logStatError");\n\n var activeLevel = "ALL";\n var activeSearch = "";\n var isWrapped = false;\n var currentFilteredText = rawLog;\n\n var parsedLines = [];\n var countInfo = 0;\n var countWarn = 0;\n var countError = 0;\n\n var rawLines = rawLog.split("\\n");\n for (var i = 0; i < rawLines.length; i++) {\n var line = rawLines[i];\n var level = "LOG";\n if (line.indexOf("[ERROR]") !== -1) {\n level = "ERROR";\n countError++;\n } else if (line.indexOf("[WARN]") !== -1) {\n level = "WARN";\n countWarn++;\n } else if (line.indexOf("[INFO]") !== -1) {\n level = "INFO";\n countInfo++;\n }\n parsedLines.push({\n num: i + 1,\n level: level,\n text: line\n });\n }\n\n if (statTotal) statTotal.textContent = "Total: " + parsedLines.length;\n if (statInfo) statInfo.textContent = "Info: " + countInfo;\n if (statWarn) statWarn.textContent = "Warn: " + countWarn;\n if (statError) statError.textContent = "Error: " + countError;\n\n function escapeHtml(str) {\n return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);\n }\n\n function renderLogs() {\n if (!logLinesEl) return;\n\n var filtered = parsedLines.filter(function(item) {\n if (activeLevel !== "ALL" && item.level !== activeLevel) {\n return false;\n }\n if (activeSearch && item.text.toLowerCase().indexOf(activeSearch.toLowerCase()) === -1) {\n return false;\n }\n return true;\n });\n\n currentFilteredText = filtered.map(function(item) { return item.text; }).join("\\n");\n\n if (filtered.length === 0) {\n logLinesEl.innerHTML = "<div class=\\"log-empty-state\\">No matching log entries found.</div>";\n return;\n }\n\n var html = "";\n for (var j = 0; j < filtered.length; j++) {\n var item = filtered[j];\n var escaped = escapeHtml(item.text);\n\n if (activeSearch) {\n var safeTerm = activeSearch.split("").map(function(ch) {\n return ".*+?^$()|[]{}".indexOf(ch) !== -1 ? "\\\\" + ch : ch;\n }).join("");\n try {\n var reg = new RegExp("(" + safeTerm + ")", "gi");\n escaped = escaped.replace(reg, "<mark class=\\"log-highlight\\">$1</mark>");\n } catch(e) {}\n }\n\n escaped = escaped.replace(/\\[INFO\\]/g, "<span class=\\"log-badge badge-info\\">INFO</span>");\n escaped = escaped.replace(/\\[WARN\\]/g, "<span class=\\"log-badge badge-warn\\">WARN</span>");\n escaped = escaped.replace(/\\[ERROR\\]/g, "<span class=\\"log-badge badge-error\\">ERROR</span>");\n\n var rowClass = "log-row";\n if (item.level === "ERROR") rowClass += " row-error";\n else if (item.level === "WARN") rowClass += " row-warn";\n\n html += "<div class=\\"" + rowClass + "\\">" +\n "<span class=\\"log-ln\\">" + item.num + "</span>" +\n "<div class=\\"log-msg\\">" + escaped + "</div>" +\n "</div>";\n }\n\n logLinesEl.innerHTML = html;\n }\n\n renderLogs();\n\n levelPills.forEach(function(btn) {\n btn.addEventListener("click", function() {\n levelPills.forEach(function(b) { b.classList.remove("active"); });\n btn.classList.add("active");\n activeLevel = btn.dataset.level || "ALL";\n renderLogs();\n });\n });\n\n if (searchInput) {\n searchInput.addEventListener("input", function(e) {\n activeSearch = e.target.value.trim();\n renderLogs();\n });\n }\n\n if (wrapToggleBtn) {\n wrapToggleBtn.addEventListener("click", function() {\n isWrapped = !isWrapped;\n if (isWrapped) {\n logLinesEl.classList.add("wrapped");\n wrapToggleBtn.classList.add("active");\n } else {\n logLinesEl.classList.remove("wrapped");\n wrapToggleBtn.classList.remove("active");\n }\n });\n }\n\n if (copyBtn) {\n var showCopied = function() {\n copyBtn.innerHTML = "<svg width=\\"13\\" height=\\"13\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"#10b981\\" stroke-width=\\"2.5\\"><polyline points=\\"20 6 9 17 4 12\\"/></svg><span style=\\"color: #10b981;\\">Copied!</span>";\n setTimeout(function() {\n copyBtn.innerHTML = "<svg width=\\"13\\" height=\\"13\\" viewBox=\\"0 0 24 24\\" fill=\\"none\\" stroke=\\"currentColor\\" stroke-width=\\"2\\"><rect width=\\"14\\" height=\\"14\\" x=\\"8\\" y=\\"8\\" rx=\\"2\\" ry=\\"2\\"/><path d=\\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\\"/></svg><span>Copy</span>";\n }, 2000);\n };\n\n var fallbackCopy = function(text) {\n var textArea = document.createElement("textarea");\n textArea.value = text;\n textArea.style.position = "fixed";\n textArea.style.top = "-9999px";\n textArea.style.left = "-9999px";\n textArea.style.opacity = "0";\n textArea.setAttribute("readonly", "");\n document.body.appendChild(textArea);\n textArea.focus();\n textArea.select();\n textArea.setSelectionRange(0, textArea.value.length);\n try {\n var successful = document.execCommand("copy");\n document.body.removeChild(textArea);\n if (successful) showCopied();\n } catch (err) {\n document.body.removeChild(textArea);\n }\n };\n\n copyBtn.addEventListener("click", function() {\n var textToCopy = currentFilteredText || rawLog;\n if (navigator.clipboard && typeof navigator.clipboard.writeText === "function") {\n navigator.clipboard.writeText(textToCopy).then(showCopied).catch(function() {\n fallbackCopy(textToCopy);\n });\n } else {\n fallbackCopy(textToCopy);\n }\n });\n }\n });\n})();';
|
|
4425
6674
|
const getJsData = (metaData) => `${global()}
|
|
4426
6675
|
${data(metaData)}
|
|
4427
6676
|
${menuBar()}
|
|
@@ -4467,6 +6716,7 @@ class HtmlReport extends BaseReport {
|
|
|
4467
6716
|
});
|
|
4468
6717
|
}
|
|
4469
6718
|
write(path2, name, data2) {
|
|
6719
|
+
ensureDirectoryExists(path2);
|
|
4470
6720
|
saveToFile(joinPaths(path2, `${name}.html`), data2, "utf-8");
|
|
4471
6721
|
}
|
|
4472
6722
|
}
|
|
@@ -5237,9 +7487,9 @@ class CacheData {
|
|
|
5237
7487
|
class Reports {
|
|
5238
7488
|
static #baseReportPath;
|
|
5239
7489
|
static #reportTimeStamp;
|
|
5240
|
-
static setup() {
|
|
7490
|
+
static setup(timestamp = null) {
|
|
5241
7491
|
if (!Reports.#reportTimeStamp) {
|
|
5242
|
-
Reports.#reportTimeStamp = Reports.#dateTime();
|
|
7492
|
+
Reports.#reportTimeStamp = timestamp || process.env.REPORT_TIMESTAMP || Reports.#dateTime();
|
|
5243
7493
|
}
|
|
5244
7494
|
const paths = [
|
|
5245
7495
|
Config.getL10nReportsPath(),
|
|
@@ -7298,6 +9548,10 @@ class Config {
|
|
|
7298
9548
|
}
|
|
7299
9549
|
static setOptions(options) {
|
|
7300
9550
|
Config.#options = options;
|
|
9551
|
+
if (options?.mode) Config.#mode = options.mode;
|
|
9552
|
+
if (options?.appName) Config.#appName = options.appName;
|
|
9553
|
+
if (options?.type) Config.#type = options.type;
|
|
9554
|
+
if (options?.qaLocale) Config.#qaLocale = options.qaLocale;
|
|
7301
9555
|
}
|
|
7302
9556
|
static getExecutor() {
|
|
7303
9557
|
if (Config.#executor) {
|