@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capillarytech/cap-ui-dev-tools",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "description": "Development tools for Capillary UI projects including webpack hot-reload plugin and CapVision session recording",
5
5
  "main": "src/index.js",
6
6
  "exports": {
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
- const testHeaderRegex = /(<tr class="test-header">[\s\S]*?<\/tr>)/;
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
- return htmlContent.replace(testHeaderRegex, (match) => {
173
- const recordingPlayersHTML = recordings.map((recording, index) => {
174
- const testName = recording.data.testName || 'Unknown Test';
175
- const recordingNumber = recording.data.recordingNumber || (index + 1);
176
- const displayName = recording.data.testName
177
- ? `${testName} (Recording #${recordingNumber})`
178
- : recording.filename;
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
- return `
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
- }).join('');
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
- return match + recordingPlayersHTML;
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;