@capillarytech/cap-ui-dev-tools 1.2.0 → 1.4.0
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/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
@@ -155,6 +155,109 @@ class ReportEnhancer {
|
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Generate logo HTML header with toggle button
|
|
160
|
+
* @private
|
|
161
|
+
* @returns {string} Logo HTML
|
|
162
|
+
*/
|
|
163
|
+
generateLogoHTML() {
|
|
164
|
+
// Load PNG logo from assets folder and convert to base64
|
|
165
|
+
let logoImage = '';
|
|
166
|
+
try {
|
|
167
|
+
const logoPath = path.join(__dirname, '../assets/CapVisionIcon.png');
|
|
168
|
+
if (fs.existsSync(logoPath)) {
|
|
169
|
+
const imageBuffer = fs.readFileSync(logoPath);
|
|
170
|
+
const base64Image = imageBuffer.toString('base64');
|
|
171
|
+
logoImage = `<img src="data:image/png;base64,${base64Image}" alt="CapVision Logo" style="display: inline-block; vertical-align: middle; height: 80px; width: auto;" />`;
|
|
172
|
+
} else {
|
|
173
|
+
console.warn('⚠️ CapVisionIcon.png not found, using fallback');
|
|
174
|
+
logoImage = '<span style="color: #007bff; font-weight: bold;">CapVision</span>';
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.warn('⚠️ Failed to load CapVisionIcon.png:', error.message);
|
|
178
|
+
logoImage = '<span style="color: #007bff; font-weight: bold;">CapVision</span>';
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return `
|
|
182
|
+
<tr class="recording-logo-header">
|
|
183
|
+
<td colspan="2">
|
|
184
|
+
<div style="padding: 20px 15px; display: flex; justify-content: space-between; align-items: center;">
|
|
185
|
+
<span id="capvision-toggle-wrapper"
|
|
186
|
+
onclick="toggleCapVisionRecordings()"
|
|
187
|
+
style="cursor: pointer; padding: 10px; user-select: none; background-color: none; border-radius: 3px; display: inline-block; flex: 1; max-width: calc(100% - 150px); margin-right: 20px;">
|
|
188
|
+
<span id="capvision-toggle-icon" class="collapsed" style="font-size: 20px; display: inline-block;"></span>
|
|
189
|
+
</span>
|
|
190
|
+
<div style="text-align: right;">
|
|
191
|
+
${logoImage}
|
|
192
|
+
</div>
|
|
193
|
+
</div>
|
|
194
|
+
</td>
|
|
195
|
+
</tr>`;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Generate wrapper HTML for recordings (table structure)
|
|
200
|
+
* @private
|
|
201
|
+
* @param {string} logoHTML - Logo HTML
|
|
202
|
+
* @param {string} recordingPlayersHTML - Recording players HTML
|
|
203
|
+
* @returns {string} Wrapped HTML
|
|
204
|
+
*/
|
|
205
|
+
generateRecordingsWrapper(logoHTML, recordingPlayersHTML) {
|
|
206
|
+
return `
|
|
207
|
+
<table class="table table-bordered" style="margin-top: 20px;">
|
|
208
|
+
<thead style="background: rgb(0, 70, 255, 0.2);">
|
|
209
|
+
${logoHTML}
|
|
210
|
+
</thead>
|
|
211
|
+
<tbody id="capvision-recordings-container" class="collapsed" style="display: table-row-group;">
|
|
212
|
+
${recordingPlayersHTML}
|
|
213
|
+
</tbody>
|
|
214
|
+
</table>
|
|
215
|
+
<style>
|
|
216
|
+
#capvision-recordings-container {
|
|
217
|
+
transition: opacity 0.3s ease-in-out;
|
|
218
|
+
}
|
|
219
|
+
#capvision-recordings-container.collapsed {
|
|
220
|
+
display: none !important;
|
|
221
|
+
}
|
|
222
|
+
#capvision-toggle-wrapper {
|
|
223
|
+
transition: background-color 0.2s ease;
|
|
224
|
+
}
|
|
225
|
+
#capvision-toggle-wrapper:hover {
|
|
226
|
+
background-color: none;
|
|
227
|
+
}
|
|
228
|
+
#capvision-toggle-wrapper:hover #capvision-toggle-icon {
|
|
229
|
+
color: #333;
|
|
230
|
+
}
|
|
231
|
+
#capvision-toggle-icon {
|
|
232
|
+
display: inline-block;
|
|
233
|
+
}
|
|
234
|
+
#capvision-toggle-icon::before {
|
|
235
|
+
font-family: "Glyphicons Halflings", "Font Awesome", Arial, sans-serif;
|
|
236
|
+
color: #333;
|
|
237
|
+
}
|
|
238
|
+
#capvision-toggle-icon.collapsed::before {
|
|
239
|
+
content: "\\e113";
|
|
240
|
+
}
|
|
241
|
+
#capvision-toggle-icon:not(.collapsed)::before {
|
|
242
|
+
content: "\\e114";
|
|
243
|
+
}
|
|
244
|
+
</style>
|
|
245
|
+
<script>
|
|
246
|
+
function toggleCapVisionRecordings() {
|
|
247
|
+
const container = document.getElementById('capvision-recordings-container');
|
|
248
|
+
const toggleIcon = document.getElementById('capvision-toggle-icon');
|
|
249
|
+
|
|
250
|
+
if (container.classList.contains('collapsed')) {
|
|
251
|
+
container.classList.remove('collapsed');
|
|
252
|
+
toggleIcon.classList.remove('collapsed');
|
|
253
|
+
} else {
|
|
254
|
+
container.classList.add('collapsed');
|
|
255
|
+
toggleIcon.classList.add('collapsed');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
</script>`;
|
|
259
|
+
}
|
|
260
|
+
|
|
158
261
|
/**
|
|
159
262
|
* Add inline recording players to HTML content
|
|
160
263
|
* @private
|
|
@@ -167,17 +270,60 @@ class ReportEnhancer {
|
|
|
167
270
|
return htmlContent;
|
|
168
271
|
}
|
|
169
272
|
|
|
170
|
-
|
|
273
|
+
// Find table with class "table table-bordered table-suite"
|
|
274
|
+
const tableSuiteRegex = /<table[^>]*class=["'][^"']*table[^"']*table-bordered[^"']*table-suite[^"']*["'][^>]*>/i;
|
|
275
|
+
const match = htmlContent.match(tableSuiteRegex);
|
|
276
|
+
|
|
277
|
+
if (!match) {
|
|
278
|
+
// Table not found, return original content
|
|
279
|
+
return htmlContent;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const tableStartIndex = match.index;
|
|
283
|
+
const tableStartTag = match[0];
|
|
284
|
+
|
|
285
|
+
// Find the matching closing </table> tag for this table
|
|
286
|
+
// We need to account for nested tables
|
|
287
|
+
let depth = 1;
|
|
288
|
+
let searchIndex = tableStartIndex + tableStartTag.length;
|
|
289
|
+
let closingTableIndex = -1;
|
|
290
|
+
|
|
291
|
+
while (searchIndex < htmlContent.length && depth > 0) {
|
|
292
|
+
const nextOpen = htmlContent.indexOf('<table', searchIndex);
|
|
293
|
+
const nextClose = htmlContent.indexOf('</table>', searchIndex);
|
|
294
|
+
|
|
295
|
+
if (nextClose === -1) {
|
|
296
|
+
break; // No closing tag found
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (nextOpen !== -1 && nextOpen < nextClose) {
|
|
300
|
+
depth++;
|
|
301
|
+
searchIndex = nextOpen + 6;
|
|
302
|
+
} else {
|
|
303
|
+
depth--;
|
|
304
|
+
if (depth === 0) {
|
|
305
|
+
closingTableIndex = nextClose;
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
searchIndex = nextClose + 8;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (closingTableIndex === -1) {
|
|
313
|
+
// If we can't find matching closing tag, return original content
|
|
314
|
+
return htmlContent;
|
|
315
|
+
}
|
|
171
316
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
317
|
+
// Generate logo and players HTML
|
|
318
|
+
const logoHTML = this.generateLogoHTML();
|
|
319
|
+
const recordingPlayersHTML = recordings.map((recording, index) => {
|
|
320
|
+
const testName = recording.data.testName || 'Unknown Test';
|
|
321
|
+
const recordingNumber = recording.data.recordingNumber || (index + 1);
|
|
322
|
+
const displayName = recording.data.testName
|
|
323
|
+
? `${testName} (Recording #${recordingNumber})`
|
|
324
|
+
: recording.filename;
|
|
179
325
|
|
|
180
|
-
|
|
326
|
+
return `
|
|
181
327
|
<tr class="test-row recording">
|
|
182
328
|
<td colspan="2">
|
|
183
329
|
<div class="recordingWrapper" style="padding: 15px; background: #f8f9fa; margin: 10px 0;">
|
|
@@ -195,10 +341,15 @@ class ReportEnhancer {
|
|
|
195
341
|
</div>
|
|
196
342
|
</td>
|
|
197
343
|
</tr>`;
|
|
198
|
-
|
|
344
|
+
}).join('');
|
|
345
|
+
|
|
346
|
+
// Wrap logo and players in a new table and inject after the closing </table> tag
|
|
347
|
+
const recordingsWrapper = this.generateRecordingsWrapper(logoHTML, recordingPlayersHTML);
|
|
348
|
+
const insertPosition = closingTableIndex + 8; // 8 = length of '</table>'
|
|
199
349
|
|
|
200
|
-
|
|
201
|
-
|
|
350
|
+
return htmlContent.substring(0, insertPosition) +
|
|
351
|
+
recordingsWrapper +
|
|
352
|
+
htmlContent.substring(insertPosition);
|
|
202
353
|
}
|
|
203
354
|
|
|
204
355
|
/**
|
|
@@ -441,7 +592,7 @@ class ReportEnhancer {
|
|
|
441
592
|
// Add player scripts and CSS
|
|
442
593
|
const capVisionPlayerHTML = this.generateCapVisionPlayerHTML(recordings);
|
|
443
594
|
const bodyEndIndex = htmlContent.lastIndexOf('</body>');
|
|
444
|
-
|
|
595
|
+
|
|
445
596
|
if (bodyEndIndex === -1) {
|
|
446
597
|
console.log('🟡 Could not find </body> tag, appending to end');
|
|
447
598
|
htmlContent += capVisionPlayerHTML;
|