lib-e2e-cypress-for-dummys-ts 0.1.0 → 0.3.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/dist/index.cjs CHANGED
@@ -578,7 +578,9 @@ var I18N_ES = {
578
578
  NO_TAGS: "Sin etiquetas",
579
579
  SAVE_BTN: "\u{1F4BE} Guardar",
580
580
  SAVE_AND_EDIT: "\u{1F4DD} Guardar y editar",
581
- REMOVE_TAG_TITLE: "Quitar"
581
+ REMOVE_TAG_TITLE: "Quitar",
582
+ NOTES_LABEL: "Descripci\xF3n / Notas (opcional):",
583
+ NOTES_PLACEHOLDER: "Qu\xE9 valida este test, condiciones previas, etc."
582
584
  },
583
585
  TEST_EDITOR: {
584
586
  NO_TAGS: "Sin etiquetas",
@@ -627,7 +629,10 @@ var I18N_ES = {
627
629
  JSON_BAD_FORMAT: "El archivo no tiene el formato esperado.",
628
630
  SMART_SELECTOR_SECTION: "\u{1F50D} Selector inteligente",
629
631
  SMART_SELECTOR_TITLE: "Selector inteligente",
630
- SMART_SELECTOR_SUB: "Muestra un picker al hacer click en elementos sin selector v\xE1lido."
632
+ SMART_SELECTOR_SUB: "Muestra un picker al hacer click en elementos sin selector v\xE1lido.",
633
+ START_HIDDEN_SECTION: "\u{1F441} Visibilidad del widget",
634
+ START_HIDDEN_TITLE: "Iniciar oculto",
635
+ START_HIDDEN_SUB: "El widget arranca invisible. Usa Ctrl+Shift+E para mostrarlo u ocultarlo."
631
636
  },
632
637
  SELECTOR_PICKER: {
633
638
  TITLE: "Selecciona un elemento del DOM",
@@ -666,7 +671,12 @@ var I18N_ES = {
666
671
  COPY_ICP_BTN: "\u{1F4CB} Copiar interceptores",
667
672
  INSERT_BTN: "\u{1F4BE} Insertar en archivo",
668
673
  EDIT_MANUAL_BTN: "\u270F\uFE0F Editar manualmente",
669
- CLOSE_BTN: "\u2715 Cerrar"
674
+ CLOSE_BTN: "\u2715 Cerrar",
675
+ NEW_FILE_BTN: "+ Nuevo archivo",
676
+ REFRESH_BTN: "\u21BB Actualizar",
677
+ NEW_FILE_PLACEHOLDER: "nombre-del-test",
678
+ NEW_FILE_CONFIRM: "Crear",
679
+ NEW_FILE_CANCEL: "Cancelar"
670
680
  },
671
681
  FILE_PREVIEW: {
672
682
  NO_FILE: "Sin archivo",
@@ -735,7 +745,9 @@ var I18N_EN = {
735
745
  NO_TAGS: "No tags",
736
746
  SAVE_BTN: "\u{1F4BE} Save",
737
747
  SAVE_AND_EDIT: "\u{1F4DD} Save and edit",
738
- REMOVE_TAG_TITLE: "Remove"
748
+ REMOVE_TAG_TITLE: "Remove",
749
+ NOTES_LABEL: "Description / Notes (optional):",
750
+ NOTES_PLACEHOLDER: "What this test validates, preconditions, etc."
739
751
  },
740
752
  TEST_EDITOR: {
741
753
  NO_TAGS: "No tags",
@@ -784,7 +796,10 @@ var I18N_EN = {
784
796
  JSON_BAD_FORMAT: "The file does not have the expected format.",
785
797
  SMART_SELECTOR_SECTION: "\u{1F50D} Smart selector",
786
798
  SMART_SELECTOR_TITLE: "Smart selector",
787
- SMART_SELECTOR_SUB: "Shows a picker when clicking elements with no valid selector."
799
+ SMART_SELECTOR_SUB: "Shows a picker when clicking elements with no valid selector.",
800
+ START_HIDDEN_SECTION: "\u{1F441} Widget visibility",
801
+ START_HIDDEN_TITLE: "Start hidden",
802
+ START_HIDDEN_SUB: "The widget starts invisible. Use Ctrl+Shift+E to show or hide it."
788
803
  },
789
804
  SELECTOR_PICKER: {
790
805
  TITLE: "Select a DOM element",
@@ -823,7 +838,12 @@ var I18N_EN = {
823
838
  COPY_ICP_BTN: "\u{1F4CB} Copy interceptors",
824
839
  INSERT_BTN: "\u{1F4BE} Insert into file",
825
840
  EDIT_MANUAL_BTN: "\u270F\uFE0F Edit manually",
826
- CLOSE_BTN: "\u2715 Close"
841
+ CLOSE_BTN: "\u2715 Close",
842
+ NEW_FILE_BTN: "+ New file",
843
+ REFRESH_BTN: "\u21BB Refresh",
844
+ NEW_FILE_PLACEHOLDER: "test-name",
845
+ NEW_FILE_CONFIRM: "Create",
846
+ NEW_FILE_CANCEL: "Cancel"
827
847
  },
828
848
  FILE_PREVIEW: {
829
849
  NO_FILE: "No file",
@@ -892,7 +912,9 @@ var I18N_FR = {
892
912
  NO_TAGS: "Sans \xE9tiquettes",
893
913
  SAVE_BTN: "\u{1F4BE} Enregistrer",
894
914
  SAVE_AND_EDIT: "\u{1F4DD} Enregistrer et \xE9diter",
895
- REMOVE_TAG_TITLE: "Retirer"
915
+ REMOVE_TAG_TITLE: "Retirer",
916
+ NOTES_LABEL: "Description / Notes (optionnel) :",
917
+ NOTES_PLACEHOLDER: "Ce que ce test valide, conditions pr\xE9alables, etc."
896
918
  },
897
919
  TEST_EDITOR: {
898
920
  NO_TAGS: "Sans \xE9tiquettes",
@@ -941,7 +963,10 @@ var I18N_FR = {
941
963
  JSON_BAD_FORMAT: "Le fichier n'a pas le format attendu.",
942
964
  SMART_SELECTOR_SECTION: "\u{1F50D} S\xE9lecteur intelligent",
943
965
  SMART_SELECTOR_TITLE: "S\xE9lecteur intelligent",
944
- SMART_SELECTOR_SUB: "Affiche un s\xE9lecteur lors du clic sur des \xE9l\xE9ments sans s\xE9lecteur valide."
966
+ SMART_SELECTOR_SUB: "Affiche un s\xE9lecteur lors du clic sur des \xE9l\xE9ments sans s\xE9lecteur valide.",
967
+ START_HIDDEN_SECTION: "\u{1F441} Visibilit\xE9 du widget",
968
+ START_HIDDEN_TITLE: "D\xE9marrer masqu\xE9",
969
+ START_HIDDEN_SUB: "Le widget d\xE9marre invisible. Utilisez Ctrl+Shift+E pour l'afficher ou le masquer."
945
970
  },
946
971
  SELECTOR_PICKER: {
947
972
  TITLE: "S\xE9lectionnez un \xE9l\xE9ment du DOM",
@@ -980,7 +1005,12 @@ var I18N_FR = {
980
1005
  COPY_ICP_BTN: "\u{1F4CB} Copier les intercepteurs",
981
1006
  INSERT_BTN: "\u{1F4BE} Ins\xE9rer dans le fichier",
982
1007
  EDIT_MANUAL_BTN: "\u270F\uFE0F \xC9diter manuellement",
983
- CLOSE_BTN: "\u2715 Fermer"
1008
+ CLOSE_BTN: "\u2715 Fermer",
1009
+ NEW_FILE_BTN: "+ Nouveau fichier",
1010
+ REFRESH_BTN: "\u21BB Actualiser",
1011
+ NEW_FILE_PLACEHOLDER: "nom-du-test",
1012
+ NEW_FILE_CONFIRM: "Cr\xE9er",
1013
+ NEW_FILE_CANCEL: "Annuler"
984
1014
  },
985
1015
  FILE_PREVIEW: {
986
1016
  NO_FILE: "Sans fichier",
@@ -1049,7 +1079,9 @@ var I18N_IT = {
1049
1079
  NO_TAGS: "Nessuna etichetta",
1050
1080
  SAVE_BTN: "\u{1F4BE} Salva",
1051
1081
  SAVE_AND_EDIT: "\u{1F4DD} Salva e modifica",
1052
- REMOVE_TAG_TITLE: "Rimuovi"
1082
+ REMOVE_TAG_TITLE: "Rimuovi",
1083
+ NOTES_LABEL: "Descrizione / Note (opzionale):",
1084
+ NOTES_PLACEHOLDER: "Cosa valida questo test, condizioni preliminari, ecc."
1053
1085
  },
1054
1086
  TEST_EDITOR: {
1055
1087
  NO_TAGS: "Nessuna etichetta",
@@ -1098,7 +1130,10 @@ var I18N_IT = {
1098
1130
  JSON_BAD_FORMAT: "Il file non ha il formato previsto.",
1099
1131
  SMART_SELECTOR_SECTION: "\u{1F50D} Selettore intelligente",
1100
1132
  SMART_SELECTOR_TITLE: "Selettore intelligente",
1101
- SMART_SELECTOR_SUB: "Mostra un selettore quando si fa clic su elementi senza selettore valido."
1133
+ SMART_SELECTOR_SUB: "Mostra un selettore quando si fa clic su elementi senza selettore valido.",
1134
+ START_HIDDEN_SECTION: "\u{1F441} Visibilit\xE0 del widget",
1135
+ START_HIDDEN_TITLE: "Avvia nascosto",
1136
+ START_HIDDEN_SUB: "Il widget si avvia invisibile. Usa Ctrl+Shift+E per mostrarlo o nasconderlo."
1102
1137
  },
1103
1138
  SELECTOR_PICKER: {
1104
1139
  TITLE: "Seleziona un elemento DOM",
@@ -1137,7 +1172,12 @@ var I18N_IT = {
1137
1172
  COPY_ICP_BTN: "\u{1F4CB} Copia interceptor",
1138
1173
  INSERT_BTN: "\u{1F4BE} Inserisci nel file",
1139
1174
  EDIT_MANUAL_BTN: "\u270F\uFE0F Modifica manualmente",
1140
- CLOSE_BTN: "\u2715 Chiudi"
1175
+ CLOSE_BTN: "\u2715 Chiudi",
1176
+ NEW_FILE_BTN: "+ Nuovo file",
1177
+ REFRESH_BTN: "\u21BB Aggiorna",
1178
+ NEW_FILE_PLACEHOLDER: "nome-del-test",
1179
+ NEW_FILE_CONFIRM: "Crea",
1180
+ NEW_FILE_CANCEL: "Annulla"
1141
1181
  },
1142
1182
  FILE_PREVIEW: {
1143
1183
  NO_FILE: "Nessun file",
@@ -1206,7 +1246,9 @@ var I18N_DE = {
1206
1246
  NO_TAGS: "Keine Tags",
1207
1247
  SAVE_BTN: "\u{1F4BE} Speichern",
1208
1248
  SAVE_AND_EDIT: "\u{1F4DD} Speichern und bearbeiten",
1209
- REMOVE_TAG_TITLE: "Entfernen"
1249
+ REMOVE_TAG_TITLE: "Entfernen",
1250
+ NOTES_LABEL: "Beschreibung / Notizen (optional):",
1251
+ NOTES_PLACEHOLDER: "Was dieser Test validiert, Voraussetzungen usw."
1210
1252
  },
1211
1253
  TEST_EDITOR: {
1212
1254
  NO_TAGS: "Keine Tags",
@@ -1255,7 +1297,10 @@ var I18N_DE = {
1255
1297
  JSON_BAD_FORMAT: "Die Datei hat nicht das erwartete Format.",
1256
1298
  SMART_SELECTOR_SECTION: "\u{1F50D} Intelligenter Selektor",
1257
1299
  SMART_SELECTOR_TITLE: "Intelligenter Selektor",
1258
- SMART_SELECTOR_SUB: "Zeigt ein Auswahlfeld, wenn auf Elemente ohne g\xFCltigen Selektor geklickt wird."
1300
+ SMART_SELECTOR_SUB: "Zeigt ein Auswahlfeld, wenn auf Elemente ohne g\xFCltigen Selektor geklickt wird.",
1301
+ START_HIDDEN_SECTION: "\u{1F441} Widget-Sichtbarkeit",
1302
+ START_HIDDEN_TITLE: "Versteckt starten",
1303
+ START_HIDDEN_SUB: "Das Widget startet unsichtbar. Verwenden Sie Ctrl+Shift+E zum Ein-/Ausblenden."
1259
1304
  },
1260
1305
  SELECTOR_PICKER: {
1261
1306
  TITLE: "DOM-Element ausw\xE4hlen",
@@ -1294,7 +1339,12 @@ var I18N_DE = {
1294
1339
  COPY_ICP_BTN: "\u{1F4CB} Interceptors kopieren",
1295
1340
  INSERT_BTN: "\u{1F4BE} In Datei einf\xFCgen",
1296
1341
  EDIT_MANUAL_BTN: "\u270F\uFE0F Manuell bearbeiten",
1297
- CLOSE_BTN: "\u2715 Schlie\xDFen"
1342
+ CLOSE_BTN: "\u2715 Schlie\xDFen",
1343
+ NEW_FILE_BTN: "+ Neue Datei",
1344
+ REFRESH_BTN: "\u21BB Aktualisieren",
1345
+ NEW_FILE_PLACEHOLDER: "test-name",
1346
+ NEW_FILE_CONFIRM: "Erstellen",
1347
+ NEW_FILE_CANCEL: "Abbrechen"
1298
1348
  },
1299
1349
  FILE_PREVIEW: {
1300
1350
  NO_FILE: "Keine Datei",
@@ -1376,13 +1426,37 @@ var TranslationService = class {
1376
1426
  };
1377
1427
  var translationService = new TranslationService();
1378
1428
 
1429
+ // src/utils/code-format.utils.ts
1430
+ function gcd(a, b) {
1431
+ while (b) {
1432
+ const t = b;
1433
+ b = a % b;
1434
+ a = t;
1435
+ }
1436
+ return a;
1437
+ }
1438
+ function normalizeBlock(code, baseIndent) {
1439
+ const lines = code.split("\n").map((l) => l.trimEnd());
1440
+ const nonEmpty = lines.filter((l) => l.trim().length > 0);
1441
+ if (!nonEmpty.length) return "";
1442
+ const indents = nonEmpty.map((l) => l.length - l.trimStart().length);
1443
+ const minIndent = Math.min(...indents);
1444
+ const relIndents = [...new Set(indents.map((n) => n - minIndent).filter((n) => n > 0))];
1445
+ const step = relIndents.length > 0 ? relIndents.reduce(gcd) : 2;
1446
+ return lines.map((l) => {
1447
+ if (!l.trim()) return "";
1448
+ const level = Math.round((l.length - l.trimStart().length - minIndent) / step);
1449
+ return baseIndent + " ".repeat(level) + l.trimStart();
1450
+ }).join("\n");
1451
+ }
1452
+
1379
1453
  // src/services/transformation.service.ts
1380
1454
  var TransformationService = class {
1381
1455
  toLang(lang) {
1382
1456
  return isLang(lang) ? lang : "en";
1383
1457
  }
1384
1458
  generateItDescription(description, commands) {
1385
- const commandsBlock = commands.map((cmd) => ` ${cmd}`).join("\n");
1459
+ const commandsBlock = commands.map((cmd) => normalizeBlock(cmd, " ")).join("\n");
1386
1460
  return `it('${description}', () => {
1387
1461
  ${commandsBlock}
1388
1462
  });`;
@@ -1413,6 +1487,13 @@ ${interceptors} })
1413
1487
  }
1414
1488
  return content.slice(0, idx) + "\n" + itBlock + "\n" + content.slice(idx);
1415
1489
  }
1490
+ buildBlockComment(notes) {
1491
+ if (!notes.trim()) return "";
1492
+ const lines = notes.split("\n").map((l) => ` * ${l}`).join("\n");
1493
+ return `/**
1494
+ ${lines}
1495
+ */`;
1496
+ }
1416
1497
  isFile(file) {
1417
1498
  return !!file && file.kind === "file";
1418
1499
  }
@@ -1824,9 +1905,9 @@ var PersistenceService = class {
1824
1905
  return this._db;
1825
1906
  }
1826
1907
  // ── Tests ─────────────────────────────────────────────────────────────────
1827
- async insertTest(name, commands = [], interceptors = [], tags = []) {
1908
+ async insertTest(name, commands = [], interceptors = [], tags = [], notes) {
1828
1909
  const db = await this.getDB();
1829
- const record = { name, createdAt: Date.now(), ...tags.length ? { tags } : {} };
1910
+ const record = { name, createdAt: Date.now(), ...tags.length ? { tags } : {}, ...notes ? { notes } : {} };
1830
1911
  const id = await db.add("tests", record);
1831
1912
  if (commands.length) await this.insertCommands(commands, id);
1832
1913
  if (interceptors.length) await this.insertInterceptors(interceptors, id);
@@ -1850,9 +1931,9 @@ var PersistenceService = class {
1850
1931
  const commands = await this.getCommandStrings(testId);
1851
1932
  const interceptors = await this.getInterceptorStrings(testId);
1852
1933
  const itBlock = `it('${record.name}', () => {
1853
- ${commands.join("\n ")}
1934
+ ${commands.map((c) => normalizeBlock(c, " ")).join("\n")}
1854
1935
  });`;
1855
- const interceptorsBlock = interceptors.length ? " // Auto-generated Cypress interceptors\n" + interceptors.map((i) => " " + i).join("\n") + "\n" : "";
1936
+ const interceptorsBlock = interceptors.length ? " // Auto-generated Cypress interceptors\n" + interceptors.map((i) => normalizeBlock(i, " ")).join("\n") + "\n" : "";
1856
1937
  return { ...record, commands, interceptors, cypressCommands: commands, itBlock, interceptorsBlock };
1857
1938
  }
1858
1939
  async deleteTest(id) {
@@ -2592,7 +2673,8 @@ if (!customElements.get("test-previsualizer")) {
2592
2673
  var SAVE_TEST_STYLES = `
2593
2674
  :host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }
2594
2675
  * { box-sizing: border-box; }
2595
- .container { padding: 24px 28px; text-align: center; }
2676
+ .container { padding: 24px 28px; text-align: left; }
2677
+ .btn-row, p { text-align: center; }
2596
2678
  p { margin: 0 0 20px; font-size: 14px; color: #8b949e; line-height: 1.5; }
2597
2679
  .btn-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }
2598
2680
  button {
@@ -2614,6 +2696,15 @@ var SAVE_TEST_STYLES = `
2614
2696
  }
2615
2697
  input[type="text"]:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.15); }
2616
2698
  input[type="text"]::placeholder { color: #484f58; }
2699
+ textarea {
2700
+ width: 100%; padding: 10px 14px; border: 1px solid #30363d;
2701
+ border-radius: 8px; background: #0d1117; color: #e6edf3;
2702
+ font-size: 14px; outline: none; margin-bottom: 4px;
2703
+ font-family: inherit; resize: vertical; line-height: 1.5;
2704
+ transition: border-color 0.15s, box-shadow 0.15s;
2705
+ }
2706
+ textarea:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.15); }
2707
+ textarea::placeholder { color: #484f58; }
2617
2708
  .tag-label {
2618
2709
  font-size: 11px; color: #484f58; text-align: left; margin-bottom: 5px; display: block;
2619
2710
  }
@@ -2653,7 +2744,7 @@ function renderSaveTestAsk(t) {
2653
2744
  </div>
2654
2745
  </div>`;
2655
2746
  }
2656
- function renderSaveTestDesc(description, tags, t) {
2747
+ function renderSaveTestDesc(description, notes, tags, t) {
2657
2748
  const chipsHtml = tags.map(
2658
2749
  (tag) => `<span class="chip">${escHtml(tag)}<button class="chip-del" data-tag="${escAttr(tag)}" title="${t("SAVE_TEST.REMOVE_TAG_TITLE")}">\u2715</button></span>`
2659
2750
  ).join("");
@@ -2662,6 +2753,8 @@ function renderSaveTestDesc(description, tags, t) {
2662
2753
  <p>${t("SAVE_TEST.DESC_LABEL")} (<code>it()</code>):</p>
2663
2754
  <input id="desc-input" type="text" placeholder="${t("SAVE_TEST.DESC_PLACEHOLDER")}"
2664
2755
  value="${escAttr(description)}" autocomplete="off" />
2756
+ <span class="tag-label">${t("SAVE_TEST.NOTES_LABEL")}</span>
2757
+ <textarea id="notes-input" rows="3" placeholder="${escAttr(t("SAVE_TEST.NOTES_PLACEHOLDER"))}">${escHtml(notes)}</textarea>
2665
2758
  <span class="tag-label">${t("SAVE_TEST.TAGS_LABEL")}</span>
2666
2759
  <div class="tag-input-row">
2667
2760
  <input id="tag-input" type="text" placeholder="${t("SAVE_TEST.TAGS_PLACEHOLDER")}" autocomplete="off" />
@@ -2681,6 +2774,7 @@ var SaveTestElement = class extends HTMLElement {
2681
2774
  shadow;
2682
2775
  _step = "ask";
2683
2776
  description = "";
2777
+ notes = "";
2684
2778
  tags = [];
2685
2779
  translation = translationService;
2686
2780
  constructor() {
@@ -2698,17 +2792,18 @@ var SaveTestElement = class extends HTMLElement {
2698
2792
  this.render();
2699
2793
  }
2700
2794
  confirmSave() {
2701
- this.dispatch("savetest", { description: this.description.trim(), tags: [...this.tags] });
2795
+ this.dispatch("savetest", { description: this.description.trim(), notes: this.notes, tags: [...this.tags] });
2702
2796
  }
2703
2797
  confirmSaveAndExport() {
2704
- this.dispatch("saveandexport", { description: this.description.trim(), tags: [...this.tags] });
2798
+ this.dispatch("saveandexport", { description: this.description.trim(), notes: this.notes, tags: [...this.tags] });
2705
2799
  }
2706
2800
  cancel() {
2707
- this.dispatch("savetest", { description: null, tags: [] });
2801
+ this.dispatch("savetest", { description: null, notes: "", tags: [] });
2708
2802
  }
2709
2803
  restartComponent() {
2710
2804
  this._step = "ask";
2711
2805
  this.description = "";
2806
+ this.notes = "";
2712
2807
  this.tags = [];
2713
2808
  this.render();
2714
2809
  }
@@ -2735,12 +2830,16 @@ var SaveTestElement = class extends HTMLElement {
2735
2830
  this.shadow.getElementById("btn-yes")?.addEventListener("click", () => this.askSave());
2736
2831
  this.shadow.getElementById("btn-no")?.addEventListener("click", () => this.cancel());
2737
2832
  } else {
2738
- this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestDesc(this.description, this.tags, this.t.bind(this))}`;
2833
+ this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestDesc(this.description, this.notes, this.tags, this.t.bind(this))}`;
2739
2834
  const descInput = this.shadow.getElementById("desc-input");
2835
+ const notesInput = this.shadow.getElementById("notes-input");
2740
2836
  const tagInput = this.shadow.getElementById("tag-input");
2741
2837
  descInput.addEventListener("input", () => {
2742
2838
  this.description = descInput.value;
2743
2839
  });
2840
+ notesInput.addEventListener("input", () => {
2841
+ this.notes = notesInput.value;
2842
+ });
2744
2843
  const tryAddTag = () => {
2745
2844
  this.addTag(tagInput.value);
2746
2845
  tagInput.value = "";
@@ -2846,17 +2945,129 @@ var TEST_EDITOR_STYLES = `
2846
2945
  background: #0d1117; padding: 10px 14px;
2847
2946
  border-top: 1px solid #21262d;
2848
2947
  }
2849
- .section-title { font-size: 10px; color: #484f58; text-transform: uppercase;
2850
- letter-spacing: 0.8px; margin-bottom: 6px; font-weight: 600; }
2851
- .cmd-list { font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
2852
- font-size: 11px; color: #c9d1d9; line-height: 1.8; }
2853
- .icp-list { font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
2854
- font-size: 11px; color: #3fb950; line-height: 1.8; margin-top: 10px; }
2855
- .copy-row { display: flex; gap: 6px; margin-top: 10px; }
2948
+ .test-notes {
2949
+ margin: 0 0 10px; padding: 8px 12px;
2950
+ background: rgba(47,129,247,0.06); border-left: 3px solid rgba(47,129,247,0.4);
2951
+ border-radius: 0 6px 6px 0; font-size: 12px; color: #8b949e;
2952
+ line-height: 1.6; white-space: pre-wrap; word-break: break-word;
2953
+ }
2954
+ .code-preview {
2955
+ margin: 0; padding: 10px 12px; background: #161b22;
2956
+ border-radius: 6px; border: 1px solid #21262d;
2957
+ font-size: 11px; color: #c9d1d9; line-height: 1.7;
2958
+ font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
2959
+ overflow-x: auto; white-space: pre;
2960
+ scrollbar-width: thin; scrollbar-color: #30363d transparent;
2961
+ }
2962
+ .code-preview::-webkit-scrollbar { height: 4px; }
2963
+ .code-preview::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }
2964
+ .code-preview-icp { margin-top: 8px; }
2965
+ .sh-kw { color: #ff7b72; }
2966
+ .sh-bi { color: #d2a8ff; }
2967
+ .sh-str { color: #a5d6ff; }
2968
+ .sh-cmt { color: #8b949e; font-style: italic; }
2969
+ .sh-num { color: #79c0ff; }
2856
2970
  `;
2857
2971
 
2858
2972
  // src/components/test-editor/test-editor.template.ts
2859
2973
  init_html_utils();
2974
+
2975
+ // src/utils/syntax-highlight.utils.ts
2976
+ init_html_utils();
2977
+ var KEYWORDS = /* @__PURE__ */ new Set([
2978
+ "describe",
2979
+ "it",
2980
+ "xit",
2981
+ "fit",
2982
+ "xdescribe",
2983
+ "fdescribe",
2984
+ "beforeEach",
2985
+ "afterEach",
2986
+ "before",
2987
+ "after",
2988
+ "context",
2989
+ "const",
2990
+ "let",
2991
+ "var",
2992
+ "function",
2993
+ "return",
2994
+ "if",
2995
+ "else",
2996
+ "import",
2997
+ "export",
2998
+ "from",
2999
+ "new",
3000
+ "this",
3001
+ "null",
3002
+ "undefined",
3003
+ "true",
3004
+ "false",
3005
+ "async",
3006
+ "await",
3007
+ "of",
3008
+ "in",
3009
+ "typeof",
3010
+ "void"
3011
+ ]);
3012
+ var BUILTINS = /* @__PURE__ */ new Set(["cy", "expect", "assert", "Cypress", "chai"]);
3013
+ function syntaxHighlight(code) {
3014
+ return code.split("\n").map(highlightLine).join("\n");
3015
+ }
3016
+ function highlightLine(line) {
3017
+ let result = "";
3018
+ let i = 0;
3019
+ const len = line.length;
3020
+ while (i < len) {
3021
+ if (line[i] === "/" && i + 1 < len && line[i + 1] === "/") {
3022
+ result += `<span class="sh-cmt">${escHtml(line.slice(i))}</span>`;
3023
+ return result;
3024
+ }
3025
+ const q = line[i];
3026
+ if (q === "'" || q === '"' || q === "`") {
3027
+ let j = i + 1;
3028
+ while (j < len) {
3029
+ if (line[j] === "\\") {
3030
+ j += 2;
3031
+ continue;
3032
+ }
3033
+ if (line[j] === q) {
3034
+ j++;
3035
+ break;
3036
+ }
3037
+ j++;
3038
+ }
3039
+ result += `<span class="sh-str">${escHtml(line.slice(i, j))}</span>`;
3040
+ i = j;
3041
+ continue;
3042
+ }
3043
+ if (/[0-9]/.test(line[i]) && (i === 0 || !/[a-zA-Z_$]/.test(line[i - 1]))) {
3044
+ let j = i;
3045
+ while (j < len && /[0-9.]/.test(line[j])) j++;
3046
+ result += `<span class="sh-num">${escHtml(line.slice(i, j))}</span>`;
3047
+ i = j;
3048
+ continue;
3049
+ }
3050
+ if (/[a-zA-Z_$]/.test(line[i])) {
3051
+ let j = i;
3052
+ while (j < len && /[a-zA-Z0-9_$]/.test(line[j])) j++;
3053
+ const word = line.slice(i, j);
3054
+ if (KEYWORDS.has(word)) {
3055
+ result += `<span class="sh-kw">${escHtml(word)}</span>`;
3056
+ } else if (BUILTINS.has(word)) {
3057
+ result += `<span class="sh-bi">${escHtml(word)}</span>`;
3058
+ } else {
3059
+ result += escHtml(word);
3060
+ }
3061
+ i = j;
3062
+ continue;
3063
+ }
3064
+ result += escHtml(line[i]);
3065
+ i++;
3066
+ }
3067
+ return result;
3068
+ }
3069
+
3070
+ // src/components/test-editor/test-editor.template.ts
2860
3071
  function renderTestEditor(state, t) {
2861
3072
  const { tags, visible, selectedVisible, activeTag, selectMode, selectedIds, describeName, expandedIndex, interceptorsByTest } = state;
2862
3073
  const tagFilterHtml = tags.length ? `<div class="tag-filter">
@@ -2873,18 +3084,20 @@ function renderTestEditor(state, t) {
2873
3084
  const icps = interceptorsByTest[test.id] ?? test.interceptors ?? [];
2874
3085
  const tagsHtml = (test.tags ?? []).length ? `<span class="test-tags">${(test.tags ?? []).map((tag) => `<span class="test-tag">${escHtml(tag)}</span>`).join("")}</span>` : "";
2875
3086
  const checkbox = selectMode ? `<input type="checkbox" ${selectedIds.has(test.id) ? "checked" : ""} data-select="${test.id}" />` : "";
3087
+ const hasIcps = (test.interceptors ?? []).length > 0;
3088
+ const itBlockCode = `it('${test.name}', () => {
3089
+ ${(test.commands ?? []).map((c) => normalizeBlock(c, " ")).join("\n")}
3090
+ });`;
3091
+ const icpBlockCode = icps.length ? `beforeEach(() => {
3092
+ // Auto-generated Cypress interceptors
3093
+ ${icps.map((c) => normalizeBlock(c, " ")).join("\n")}
3094
+ });` : "";
3095
+ const notesHtml = expanded && test.notes ? `<p class="test-notes">${escHtml(test.notes)}</p>` : "";
2876
3096
  const body = expanded ? `
2877
3097
  <div class="row-body">
2878
- <div class="section-title">${t("TEST_EDITOR.SECTION_COMMANDS")} (${(test.commands ?? []).length})</div>
2879
- <div class="cmd-list">${(test.commands ?? []).map(escHtml).join("<br>")}</div>
2880
- ${icps.length ? `<div class="icp-list">
2881
- <div class="section-title" style="margin-top:8px">${t("TEST_EDITOR.SECTION_INTERCEPTORS")}</div>
2882
- ${icps.map(escHtml).join("<br>")}
2883
- </div>` : ""}
2884
- <div class="copy-row">
2885
- <button class="btn-icon" data-action="copy-cmds" data-idx="${i}">${t("TEST_EDITOR.COPY_CMDS_BTN")}</button>
2886
- ${icps.length ? `<button class="btn-icon" data-action="copy-icps" data-idx="${i}">${t("TEST_EDITOR.COPY_ICPS_BTN")}</button>` : ""}
2887
- </div>
3098
+ ${notesHtml}
3099
+ <pre class="code-preview">${syntaxHighlight(itBlockCode)}</pre>
3100
+ ${icpBlockCode ? `<pre class="code-preview code-preview-icp">${syntaxHighlight(icpBlockCode)}</pre>` : ""}
2888
3101
  </div>` : "";
2889
3102
  return `
2890
3103
  <div class="row${selectedIds.has(test.id) ? " selected-row" : ""}">
@@ -2893,6 +3106,8 @@ function renderTestEditor(state, t) {
2893
3106
  <span class="test-name">${escHtml(test.name)}</span>
2894
3107
  ${tagsHtml}
2895
3108
  <span class="test-date">${date}</span>
3109
+ <button class="btn-icon" data-action="copy-cmds" data-idx="${i}" title="${t("TEST_EDITOR.COPY_CMDS_BTN")}">${t("TEST_EDITOR.COPY_CMDS_BTN")}</button>
3110
+ ${hasIcps ? `<button class="btn-icon" data-action="copy-icps" data-idx="${i}" title="${t("TEST_EDITOR.COPY_ICPS_BTN")}">${t("TEST_EDITOR.COPY_ICPS_BTN")}</button>` : ""}
2896
3111
  <button class="btn-icon btn-del" data-action="delete" data-id="${test.id}" title="${t("TEST_EDITOR.DELETE_TITLE")}">\u{1F5D1}</button>
2897
3112
  </div>
2898
3113
  ${body}
@@ -3071,7 +3286,7 @@ ${beforeEach}${itBlocks}
3071
3286
  ev.stopPropagation();
3072
3287
  const idx = Number(el.dataset["idx"]);
3073
3288
  const t = visible[idx];
3074
- this.copyToClipboard((this.interceptorsByTest[t?.id] ?? []).join("\n"));
3289
+ this.copyToClipboard((this.interceptorsByTest[t?.id] ?? t?.interceptors ?? []).join("\n"));
3075
3290
  });
3076
3291
  });
3077
3292
  }
@@ -3184,7 +3399,7 @@ var LANGS = [
3184
3399
  { value: "de", label: "Deutsch" }
3185
3400
  ];
3186
3401
  function renderConfiguration(state, t) {
3187
- const { selectedLanguage, advancedHttpConfig, selectorStrategy, filesystemGranted, cypressFolderName, smartSelectorEnabled } = state;
3402
+ const { selectedLanguage, advancedHttpConfig, selectorStrategy, filesystemGranted, cypressFolderName, smartSelectorEnabled, startHidden } = state;
3188
3403
  const langOptions = LANGS.map(
3189
3404
  (l) => `<option value="${l.value}" ${selectedLanguage === l.value ? "selected" : ""}>${l.label}</option>`
3190
3405
  ).join("");
@@ -3224,6 +3439,18 @@ function renderConfiguration(state, t) {
3224
3439
  </label>
3225
3440
  </div>
3226
3441
 
3442
+ <!-- Start Hidden -->
3443
+ <div class="card">
3444
+ <div class="card-hd">${t("CONFIG.START_HIDDEN_SECTION")}</div>
3445
+ <label class="check-row">
3446
+ <input type="checkbox" id="start-hidden-toggle" ${startHidden ? "checked" : ""} />
3447
+ <div>
3448
+ <div class="check-title">${t("CONFIG.START_HIDDEN_TITLE")}</div>
3449
+ <div class="check-sub">${t("CONFIG.START_HIDDEN_SUB")}</div>
3450
+ </div>
3451
+ </label>
3452
+ </div>
3453
+
3227
3454
  <!-- Selector Strategy -->
3228
3455
  <div class="card card-wide">
3229
3456
  <div class="card-hd">${t("CONFIG.SELECTOR_SECTION")}</div>
@@ -3286,6 +3513,7 @@ var ConfigurationElement = class extends HTMLElement {
3286
3513
  advancedHttpConfig = false;
3287
3514
  selectorStrategy = "data-cy";
3288
3515
  smartSelectorEnabled = true;
3516
+ startHidden = false;
3289
3517
  filesystemGranted = false;
3290
3518
  cypressFolderName = null;
3291
3519
  constructor() {
@@ -3311,6 +3539,7 @@ var ConfigurationElement = class extends HTMLElement {
3311
3539
  this.advancedHttpConfig = localStorage.getItem("extendedHttpCommands") === "true";
3312
3540
  this.selectorStrategy = config?.["selectorStrategy"] ?? "data-cy";
3313
3541
  this.smartSelectorEnabled = config?.["smartSelectorEnabled"] !== "false";
3542
+ this.startHidden = config?.["startHidden"] === "true";
3314
3543
  this.filesystemGranted = config?.["allowReadWriteFiles"] === "true";
3315
3544
  const handle = config?.["cypressDirectoryHandle"];
3316
3545
  this.cypressFolderName = handle?.name ?? null;
@@ -3328,6 +3557,12 @@ var ConfigurationElement = class extends HTMLElement {
3328
3557
  this.persistence.setConfig({ extendedHttpCommands: checked ? "true" : "false" });
3329
3558
  this.render();
3330
3559
  }
3560
+ async onStartHiddenChange(checked) {
3561
+ this.startHidden = checked;
3562
+ await this.persistence.setConfig({ startHidden: checked ? "true" : "false" });
3563
+ this.dispatchEvent(new CustomEvent("starthiddenchange", { detail: checked, bubbles: true, composed: true }));
3564
+ this.render();
3565
+ }
3331
3566
  async onSmartSelectorChange(enabled) {
3332
3567
  this.smartSelectorEnabled = enabled;
3333
3568
  await this.persistence.setConfig({ smartSelectorEnabled: enabled ? "true" : "false" });
@@ -3388,7 +3623,8 @@ var ConfigurationElement = class extends HTMLElement {
3388
3623
  selectorStrategy: this.selectorStrategy,
3389
3624
  filesystemGranted: this.filesystemGranted,
3390
3625
  cypressFolderName: this.cypressFolderName,
3391
- smartSelectorEnabled: this.smartSelectorEnabled
3626
+ smartSelectorEnabled: this.smartSelectorEnabled,
3627
+ startHidden: this.startHidden
3392
3628
  }, this.t.bind(this))}`;
3393
3629
  ;
3394
3630
  this.shadow.getElementById("lang-select").addEventListener(
@@ -3403,6 +3639,10 @@ var ConfigurationElement = class extends HTMLElement {
3403
3639
  "change",
3404
3640
  (e) => this.onSmartSelectorChange(e.target.checked)
3405
3641
  );
3642
+ this.shadow.getElementById("start-hidden-toggle").addEventListener(
3643
+ "change",
3644
+ (e) => this.onStartHiddenChange(e.target.checked)
3645
+ );
3406
3646
  this.shadow.getElementById("selector-strategy").addEventListener(
3407
3647
  "change",
3408
3648
  (e) => this.onSelectorStrategyChange(e.target.value)
@@ -3434,26 +3674,38 @@ var ADVANCED_TEST_EDITOR_STYLES = `
3434
3674
  * { box-sizing: border-box; }
3435
3675
  .layout { display: flex; flex: 1; min-height: 0; }
3436
3676
  .sidebar {
3437
- width: 220px; border-right: 1px solid #21262d; overflow-y: auto;
3438
- padding: 8px; background: #0d1117; flex-shrink: 0;
3677
+ border-right: none; display: flex; flex-direction: column;
3678
+ background: #0d1117; flex-shrink: 0; min-width: 140px; max-width: 500px;
3679
+ }
3680
+ .tree-scroll {
3681
+ flex: 1; overflow-y: auto; padding: 6px 4px;
3439
3682
  scrollbar-width: thin; scrollbar-color: #30363d transparent;
3440
3683
  }
3441
- .sidebar::-webkit-scrollbar { width: 4px; }
3442
- .sidebar::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }
3443
- .main { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: #161b22; }
3684
+ .tree-scroll::-webkit-scrollbar { width: 4px; }
3685
+ .tree-scroll::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }
3686
+ .resize-handle {
3687
+ width: 4px; background: #21262d; cursor: col-resize; flex-shrink: 0;
3688
+ transition: background 0.15s;
3689
+ }
3690
+ .resize-handle:hover, .resize-handle.dragging { background: #2f81f7; }
3691
+ .main { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: #161b22; min-width: 0; }
3444
3692
  .no-perm {
3445
3693
  padding: 28px; color: #484f58; font-size: 13px; text-align: center;
3446
3694
  display: flex; flex-direction: column; align-items: center; gap: 12px; line-height: 1.6;
3447
3695
  }
3448
3696
  .tree-item {
3449
- padding: 5px 8px; border-radius: 5px; cursor: pointer;
3697
+ padding: 4px 6px; border-radius: 4px; cursor: pointer;
3450
3698
  font-size: 12px; color: #8b949e; white-space: nowrap;
3451
3699
  overflow: hidden; text-overflow: ellipsis;
3452
3700
  transition: background 0.12s, color 0.12s;
3701
+ display: flex; align-items: center; gap: 4px; user-select: none;
3453
3702
  }
3454
3703
  .tree-item:hover { background: #161b22; color: #c9d1d9; }
3455
3704
  .tree-item.selected { background: rgba(47,129,247,0.12); color: #2f81f7; }
3456
3705
  .tree-item.dir { color: #e3b341; font-weight: 600; }
3706
+ .tree-item.dir:hover { background: rgba(227,179,65,0.08); color: #f0c040; }
3707
+ .dir-arrow { font-size: 8px; color: #484f58; width: 10px; flex-shrink: 0; line-height: 1; }
3708
+ .tree-connector { display: block; width: 1px; background: #21262d; margin-left: 13px; height: 100%; }
3457
3709
  .content-area {
3458
3710
  flex: 1; padding: 12px 14px; overflow-y: auto;
3459
3711
  scrollbar-width: thin; scrollbar-color: #30363d transparent;
@@ -3463,12 +3715,21 @@ var ADVANCED_TEST_EDITOR_STYLES = `
3463
3715
  .file-name { font-size: 11px; color: #484f58; margin-bottom: 8px; font-family: monospace; }
3464
3716
  pre {
3465
3717
  background: #0d1117; padding: 12px; border-radius: 8px;
3466
- font-size: 11px; color: #c9d1d9; overflow-x: auto;
3467
- white-space: pre-wrap; word-break: break-all; margin: 0;
3718
+ font-size: 11px; color: #c9d1d9; margin: 0;
3468
3719
  font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;
3469
- line-height: 1.7; overflow-y: auto;
3470
- border: 1px solid #21262d;
3720
+ line-height: 1.7; border: 1px solid #21262d;
3721
+ white-space: pre; overflow-x: auto; overflow-y: auto;
3722
+ scrollbar-width: thin; scrollbar-color: #30363d transparent;
3471
3723
  }
3724
+ pre::-webkit-scrollbar { width: 4px; height: 4px; }
3725
+ pre::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }
3726
+ .pre-block { font-size: 10.5px; }
3727
+ .pre-icp .sh-str { color: #85e89d; }
3728
+ .sh-kw { color: #ff7b72; }
3729
+ .sh-bi { color: #d2a8ff; }
3730
+ .sh-str { color: #a5d6ff; }
3731
+ .sh-cmt { color: #8b949e; font-style: italic; }
3732
+ .sh-num { color: #79c0ff; }
3472
3733
  .footer {
3473
3734
  padding: 10px 14px; border-top: 1px solid #21262d;
3474
3735
  display: flex; gap: 8px; justify-content: flex-end; background: #161b22;
@@ -3484,6 +3745,12 @@ var ADVANCED_TEST_EDITOR_STYLES = `
3484
3745
  .btn-save:hover { background: #1f6feb; border-color: #1f6feb; color: #fff; }
3485
3746
  .btn-save:disabled { background: #21262d; border-color: #30363d; color: #8b949e; }
3486
3747
  .placeholder { color: #484f58; font-size: 13px; padding: 28px; text-align: center; }
3748
+ .test-notes {
3749
+ margin: 0 0 10px; padding: 8px 12px;
3750
+ background: rgba(47,129,247,0.06); border-left: 3px solid rgba(47,129,247,0.4);
3751
+ border-radius: 0 6px 6px 0; font-size: 12px; color: #8b949e;
3752
+ line-height: 1.6; white-space: pre-wrap; word-break: break-word;
3753
+ }
3487
3754
  .block-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
3488
3755
  .btn-copy {
3489
3756
  padding: 3px 10px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer;
@@ -3491,6 +3758,34 @@ var ADVANCED_TEST_EDITOR_STYLES = `
3491
3758
  transition: background 0.12s, color 0.12s; white-space: nowrap; flex-shrink: 0;
3492
3759
  }
3493
3760
  .btn-copy:hover { background: #30363d; color: #e6edf3; }
3761
+ .sidebar-toolbar {
3762
+ display: flex; gap: 4px; padding: 6px 6px 4px;
3763
+ border-bottom: 1px solid #21262d; flex-shrink: 0; background: #0d1117;
3764
+ }
3765
+ .btn-toolbar {
3766
+ flex: 1; padding: 4px 6px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer;
3767
+ font-size: 10px; font-weight: 500; background: #161b22; color: #8b949e;
3768
+ transition: background 0.12s, color 0.12s; white-space: nowrap; overflow: hidden;
3769
+ text-overflow: ellipsis;
3770
+ }
3771
+ .btn-toolbar:hover { background: #30363d; color: #e6edf3; }
3772
+ .btn-toolbar.btn-new { color: #3fb950; border-color: #238636; }
3773
+ .btn-toolbar.btn-new:hover { background: #238636; color: #fff; }
3774
+ .new-file-form {
3775
+ padding: 6px; border-bottom: 1px solid #21262d; display: flex; flex-direction: column; gap: 4px;
3776
+ }
3777
+ .new-file-form input {
3778
+ width: 100%; padding: 4px 7px; background: #0d1117; border: 1px solid #30363d;
3779
+ border-radius: 5px; color: #e6edf3; font-size: 11px; font-family: monospace;
3780
+ outline: none;
3781
+ }
3782
+ .new-file-form input:focus { border-color: #2f81f7; }
3783
+ .new-file-form .ext { font-size: 9px; color: #484f58; padding: 0 2px; }
3784
+ .new-file-actions { display: flex; gap: 4px; }
3785
+ .btn-confirm { flex: 1; padding: 3px 6px; border: 1px solid #238636; border-radius: 5px; cursor: pointer; font-size: 10px; font-weight: 500; background: #238636; color: #fff; transition: background 0.12s; }
3786
+ .btn-confirm:hover { background: #2ea043; }
3787
+ .btn-cancel-form { flex: 1; padding: 3px 6px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer; font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e; transition: background 0.12s; }
3788
+ .btn-cancel-form:hover { background: #30363d; color: #e6edf3; }
3494
3789
  `;
3495
3790
 
3496
3791
  // src/components/advanced-test-editor/advanced-test-editor.template.ts
@@ -3509,29 +3804,48 @@ function renderNoPermission(needsReauth, t) {
3509
3804
  </div>`;
3510
3805
  }
3511
3806
  function renderAdvancedEditor(state, t) {
3512
- const { e2eTree, selectedFile, selectedFileContent, testItBlock, interceptorsBlock, saveButtonEnabled } = state;
3513
- const treeHtml = e2eTree.length ? renderTree(e2eTree, selectedFile) : `<div class="tree-item" style="color:#6c7a99">${t("ADVANCED_EDITOR.NO_FILES")}</div>`;
3807
+ const { e2eTree, selectedFile, selectedFileContent, testItBlock, interceptorsBlock, testNotes, saveButtonEnabled, isCreatingFile, collapsedDirs, sidebarWidth } = state;
3808
+ const treeHtml = e2eTree.length ? renderTree(e2eTree, selectedFile, collapsedDirs) : `<div class="tree-item" style="color:#6c7a99">${t("ADVANCED_EDITOR.NO_FILES")}</div>`;
3514
3809
  const contentHtml = selectedFileContent ? `<div class="file-name">\u{1F4C4} ${escHtml(selectedFile?.name ?? "")}</div>
3515
- <pre>${escHtml(selectedFileContent.slice(0, 4e3))}${selectedFileContent.length > 4e3 ? "\n..." : ""}</pre>` : `<div class="placeholder">${t("ADVANCED_EDITOR.SELECT_FILE")}</div>`;
3810
+ <pre class="pre-file">${syntaxHighlight(selectedFileContent.slice(0, 6e3))}${selectedFileContent.length > 6e3 ? "\n..." : ""}</pre>` : `<div class="placeholder">${t("ADVANCED_EDITOR.SELECT_FILE")}</div>`;
3811
+ const notesHtml = testItBlock && testNotes ? `<p class="test-notes">${escHtml(testNotes)}</p>` : "";
3516
3812
  const itHtml = testItBlock ? `<div style="margin-top:10px">
3517
3813
  <div class="file-name block-header">
3518
3814
  <span>${t("ADVANCED_EDITOR.IT_LABEL")}</span>
3519
3815
  <button id="btn-copy-it" class="btn-copy">${t("ADVANCED_EDITOR.COPY_IT_BTN")}</button>
3520
3816
  </div>
3521
- <pre style="max-height:120px;font-size:10.5px">${escHtml(testItBlock.slice(0, 500))}</pre>
3817
+ <pre class="pre-block">${syntaxHighlight(testItBlock.slice(0, 3e3))}</pre>
3522
3818
  </div>` : "";
3523
3819
  const interceptorsHtml = interceptorsBlock ? `<div style="margin-top:10px">
3524
3820
  <div class="file-name block-header">
3525
3821
  <span>${t("ADVANCED_EDITOR.BEFORE_EACH_LABEL")}</span>
3526
3822
  <button id="btn-copy-interceptors" class="btn-copy">${t("ADVANCED_EDITOR.COPY_ICP_BTN")}</button>
3527
3823
  </div>
3528
- <pre style="max-height:120px;font-size:10.5px;color:#3fb950">${escHtml(interceptorsBlock.slice(0, 500))}</pre>
3824
+ <pre class="pre-block pre-icp">${syntaxHighlight(interceptorsBlock.slice(0, 3e3))}</pre>
3529
3825
  </div>` : "";
3826
+ const newFileForm = isCreatingFile ? `<div class="new-file-form">
3827
+ <input id="input-new-file" type="text" placeholder="${escHtml(t("ADVANCED_EDITOR.NEW_FILE_PLACEHOLDER"))}" autocomplete="off" />
3828
+ <span class="ext">.cy.ts</span>
3829
+ <div class="new-file-actions">
3830
+ <button id="btn-new-file-confirm" class="btn-confirm">${t("ADVANCED_EDITOR.NEW_FILE_CONFIRM")}</button>
3831
+ <button id="btn-new-file-cancel" class="btn-cancel-form">${t("ADVANCED_EDITOR.NEW_FILE_CANCEL")}</button>
3832
+ </div>
3833
+ </div>` : "";
3834
+ const toolbar = `
3835
+ <div class="sidebar-toolbar">
3836
+ <button id="btn-new-file" class="btn-toolbar btn-new">${t("ADVANCED_EDITOR.NEW_FILE_BTN")}</button>
3837
+ <button id="btn-refresh" class="btn-toolbar">${t("ADVANCED_EDITOR.REFRESH_BTN")}</button>
3838
+ </div>`;
3530
3839
  return `
3531
3840
  <div class="layout">
3532
- <div class="sidebar">${treeHtml}</div>
3841
+ <div class="sidebar" style="width:${sidebarWidth}px">
3842
+ ${toolbar}
3843
+ ${newFileForm}
3844
+ <div class="tree-scroll">${treeHtml}</div>
3845
+ </div>
3846
+ <div id="resize-handle" class="resize-handle"></div>
3533
3847
  <div class="main">
3534
- <div class="content-area">${contentHtml}${itHtml}${interceptorsHtml}</div>
3848
+ <div class="content-area">${contentHtml}${notesHtml}${itHtml}${interceptorsHtml}</div>
3535
3849
  <div class="footer">
3536
3850
  <button id="btn-save" class="btn-save"
3537
3851
  ${!saveButtonEnabled || !testItBlock ? "disabled" : ""}>
@@ -3545,16 +3859,24 @@ function renderAdvancedEditor(state, t) {
3545
3859
  </div>
3546
3860
  </div>`;
3547
3861
  }
3548
- function renderTree(nodes, selected, indent = 0) {
3862
+ function renderTree(nodes, selected, collapsedDirs, indent = 0, parentPath = "") {
3549
3863
  return nodes.map((n) => {
3864
+ const currentPath = parentPath ? `${parentPath}/${n.name}` : n.name;
3550
3865
  const isFile = n.kind === "file";
3551
- const isSel = selected === n || selected?.name === n.name;
3552
- const cls = `tree-item${isFile ? "" : " dir"}${isSel ? " selected" : ""}`;
3553
- const pad = `padding-left:${8 + indent * 14}px`;
3554
- if (!isFile && n.children?.length) {
3555
- return `<div class="${cls}" style="${pad}">\u{1F4C1} ${escHtml(n.name)}</div>
3556
- ${renderTree(n.children, selected, indent + 1)}`;
3866
+ const pad = `padding-left:${6 + indent * 14}px`;
3867
+ if (!isFile) {
3868
+ const dir = n;
3869
+ const hasChildren = (dir.children?.length ?? 0) > 0;
3870
+ const isCollapsed = collapsedDirs.has(currentPath);
3871
+ const arrow = hasChildren ? isCollapsed ? "\u25B6" : "\u25BC" : "\xB7";
3872
+ const dirHtml = `<div class="tree-item dir" style="${pad}" data-dir-path="${escAttr(currentPath)}">
3873
+ <span class="dir-arrow">${arrow}</span>\u{1F4C1} ${escHtml(n.name)}
3874
+ </div>`;
3875
+ if (!hasChildren || isCollapsed) return dirHtml;
3876
+ return dirHtml + renderTree(dir.children, selected, collapsedDirs, indent + 1, currentPath);
3557
3877
  }
3878
+ const isSel = selected?.name === n.name;
3879
+ const cls = `tree-item${isSel ? " selected" : ""}`;
3558
3880
  const data = JSON.stringify({ kind: n.kind, name: n.name }).replace(/"/g, "&quot;");
3559
3881
  return `<div class="${cls}" style="${pad}" data-file="${data}">\u{1F4C4} ${escHtml(n.name)}</div>`;
3560
3882
  }).join("");
@@ -3584,12 +3906,17 @@ var AdvancedTestEditorElement = class extends HTMLElement {
3584
3906
  selectedFileContent = null;
3585
3907
  testItBlock = "";
3586
3908
  interceptorsBlock = "";
3909
+ testNotes = "";
3587
3910
  isPreviewMode = false;
3588
3911
  previewFileName = null;
3589
3912
  previewFileContent = null;
3913
+ isCreatingFile = false;
3914
+ collapsedDirs = /* @__PURE__ */ new Set();
3915
+ sidebarWidth = 220;
3590
3916
  hasPermission = false;
3591
3917
  needsReauth = false;
3592
3918
  _dirHandle = null;
3919
+ _e2eHandle = null;
3593
3920
  constructor() {
3594
3921
  super();
3595
3922
  this.shadow = this.attachShadow({ mode: "open" });
@@ -3631,7 +3958,8 @@ var AdvancedTestEditorElement = class extends HTMLElement {
3631
3958
  try {
3632
3959
  for await (const entry of this._dirHandle.values()) {
3633
3960
  if (entry.kind === "directory" && entry.name === "e2e") {
3634
- const tree = await this.transformationService.scanDirectory(entry);
3961
+ this._e2eHandle = entry;
3962
+ const tree = await this.transformationService.scanDirectory(this._e2eHandle);
3635
3963
  this.e2eTree = tree.children ?? [];
3636
3964
  this.render();
3637
3965
  return;
@@ -3640,13 +3968,40 @@ var AdvancedTestEditorElement = class extends HTMLElement {
3640
3968
  } catch {
3641
3969
  }
3642
3970
  }
3971
+ async createNewFile(rawName) {
3972
+ if (!this._e2eHandle) return;
3973
+ const name = rawName.trim().replace(/\.cy\.ts$/, "");
3974
+ if (!name) return;
3975
+ const fileName = `${name}.cy.ts`;
3976
+ const template = `describe('${name}', () => {
3977
+
3978
+ it('should ', () => {
3979
+
3980
+ });
3981
+
3982
+ });
3983
+ `;
3984
+ try {
3985
+ const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });
3986
+ const writable = await fileHandle.createWritable();
3987
+ await writable.write(template);
3988
+ await writable.close();
3989
+ } catch {
3990
+ }
3991
+ this.isCreatingFile = false;
3992
+ await this.getFoldersData();
3993
+ }
3994
+ async refreshTree() {
3995
+ await this.getFoldersData();
3996
+ }
3643
3997
  async saveCommandsToFile() {
3644
3998
  if (!this.selectedFileHandle || !this.selectedFileContent || !this.testItBlock) return;
3645
3999
  let content = this.selectedFileContent;
3646
4000
  if (this.interceptorsBlock) {
3647
4001
  content = this.transformationService.insertBeforeEach(content, this.interceptorsBlock);
3648
4002
  }
3649
- content = this.transformationService.insertItBlock(content, this.testItBlock);
4003
+ const comment = this.testNotes ? this.transformationService.buildBlockComment(this.testNotes) + "\n" : "";
4004
+ content = this.transformationService.insertItBlock(content, comment + this.testItBlock);
3650
4005
  if (!content) return;
3651
4006
  const writable = await this.selectedFileHandle.createWritable();
3652
4007
  await writable.write(content);
@@ -3673,9 +4028,11 @@ var AdvancedTestEditorElement = class extends HTMLElement {
3673
4028
  if (test) {
3674
4029
  this.testItBlock = test.itBlock ?? "";
3675
4030
  this.interceptorsBlock = test.interceptorsBlock ?? "";
4031
+ this.testNotes = test.notes ?? "";
3676
4032
  } else {
3677
4033
  this.testItBlock = "";
3678
4034
  this.interceptorsBlock = "";
4035
+ this.testNotes = "";
3679
4036
  }
3680
4037
  this.render();
3681
4038
  }
@@ -3697,6 +4054,44 @@ var AdvancedTestEditorElement = class extends HTMLElement {
3697
4054
  composed: true
3698
4055
  }));
3699
4056
  }
4057
+ toggleDir(path) {
4058
+ if (this.collapsedDirs.has(path)) {
4059
+ this.collapsedDirs.delete(path);
4060
+ } else {
4061
+ this.collapsedDirs.add(path);
4062
+ }
4063
+ this.render();
4064
+ }
4065
+ setupResizeHandle() {
4066
+ const handle = this.shadow.getElementById("resize-handle");
4067
+ const sidebar = this.shadow.querySelector(".sidebar");
4068
+ if (!handle || !sidebar) return;
4069
+ let startX = 0;
4070
+ let startWidth = 0;
4071
+ const onMouseMove = (e) => {
4072
+ const delta = e.clientX - startX;
4073
+ const newWidth = Math.max(140, Math.min(500, startWidth + delta));
4074
+ this.sidebarWidth = newWidth;
4075
+ sidebar.style.width = `${newWidth}px`;
4076
+ };
4077
+ const onMouseUp = () => {
4078
+ document.removeEventListener("mousemove", onMouseMove);
4079
+ document.removeEventListener("mouseup", onMouseUp);
4080
+ document.body.style.cursor = "";
4081
+ document.body.style.userSelect = "";
4082
+ handle.classList.remove("dragging");
4083
+ };
4084
+ handle.addEventListener("mousedown", (e) => {
4085
+ startX = e.clientX;
4086
+ startWidth = sidebar.offsetWidth;
4087
+ document.addEventListener("mousemove", onMouseMove);
4088
+ document.addEventListener("mouseup", onMouseUp);
4089
+ document.body.style.cursor = "col-resize";
4090
+ document.body.style.userSelect = "none";
4091
+ handle.classList.add("dragging");
4092
+ e.preventDefault();
4093
+ });
4094
+ }
3700
4095
  closePreview() {
3701
4096
  this.isPreviewMode = false;
3702
4097
  this.previewFileName = null;
@@ -3727,7 +4122,11 @@ var AdvancedTestEditorElement = class extends HTMLElement {
3727
4122
  selectedFileContent: this.selectedFileContent,
3728
4123
  testItBlock: this.testItBlock,
3729
4124
  interceptorsBlock: this.interceptorsBlock,
3730
- saveButtonEnabled: this.saveButtonEnabled
4125
+ testNotes: this.testNotes,
4126
+ saveButtonEnabled: this.saveButtonEnabled,
4127
+ isCreatingFile: this.isCreatingFile,
4128
+ collapsedDirs: this.collapsedDirs,
4129
+ sidebarWidth: this.sidebarWidth
3731
4130
  }, this.t.bind(this))}`;
3732
4131
  this.shadow.querySelectorAll("[data-file]").forEach((el) => {
3733
4132
  el.addEventListener("click", () => {
@@ -3735,11 +4134,41 @@ var AdvancedTestEditorElement = class extends HTMLElement {
3735
4134
  if (data) this.onFileClick(JSON.parse(data));
3736
4135
  });
3737
4136
  });
4137
+ this.shadow.querySelectorAll("[data-dir-path]").forEach((el) => {
4138
+ el.addEventListener("click", () => {
4139
+ const path = el.dataset["dirPath"];
4140
+ if (path) this.toggleDir(path);
4141
+ });
4142
+ });
4143
+ this.setupResizeHandle();
3738
4144
  this.shadow.getElementById("btn-save")?.addEventListener("click", () => this.saveCommandsToFile());
3739
4145
  this.shadow.getElementById("btn-edit")?.addEventListener("click", () => this.openEditManually());
3740
4146
  this.shadow.getElementById("btn-copy-it")?.addEventListener("click", () => this.copyToClipboard(this.testItBlock));
3741
4147
  this.shadow.getElementById("btn-copy-interceptors")?.addEventListener("click", () => this.copyToClipboard(this.interceptorsBlock));
3742
4148
  this.shadow.getElementById("btn-close")?.addEventListener("click", () => this.closePreview());
4149
+ this.shadow.getElementById("btn-new-file")?.addEventListener("click", () => {
4150
+ this.isCreatingFile = !this.isCreatingFile;
4151
+ this.render();
4152
+ if (this.isCreatingFile) this.shadow.getElementById("input-new-file")?.focus();
4153
+ });
4154
+ this.shadow.getElementById("btn-refresh")?.addEventListener("click", () => this.refreshTree());
4155
+ this.shadow.getElementById("btn-new-file-confirm")?.addEventListener("click", () => {
4156
+ const input2 = this.shadow.getElementById("input-new-file");
4157
+ this.createNewFile(input2?.value ?? "");
4158
+ });
4159
+ this.shadow.getElementById("btn-new-file-cancel")?.addEventListener("click", () => {
4160
+ this.isCreatingFile = false;
4161
+ this.render();
4162
+ });
4163
+ const input = this.shadow.getElementById("input-new-file");
4164
+ input?.addEventListener("keydown", (e) => {
4165
+ if (e.key === "Enter") {
4166
+ this.createNewFile(input.value);
4167
+ } else if (e.key === "Escape") {
4168
+ this.isCreatingFile = false;
4169
+ this.render();
4170
+ }
4171
+ });
3743
4172
  }
3744
4173
  };
3745
4174
  if (!customElements.get("advanced-test-editor")) {
@@ -4247,6 +4676,7 @@ function renderRecorderWidget(rec, paused, t) {
4247
4676
  // src/components/lib-e2e-recorder/lib-e2e-recorder.ts
4248
4677
  var LibE2eRecorderElement = class extends HTMLElement {
4249
4678
  shadow;
4679
+ _isDisabled = false;
4250
4680
  keydownHandler;
4251
4681
  recordingUnsub;
4252
4682
  commandsUnsub;
@@ -4260,6 +4690,7 @@ var LibE2eRecorderElement = class extends HTMLElement {
4260
4690
  recording;
4261
4691
  persistence;
4262
4692
  translation;
4693
+ isVisible = false;
4263
4694
  isRecording = false;
4264
4695
  isPaused = false;
4265
4696
  cypressCommands = [];
@@ -4274,6 +4705,10 @@ var LibE2eRecorderElement = class extends HTMLElement {
4274
4705
  this.shadow = this.attachShadow({ mode: "open" });
4275
4706
  }
4276
4707
  connectedCallback() {
4708
+ if ("Cypress" in window) {
4709
+ this._isDisabled = true;
4710
+ return;
4711
+ }
4277
4712
  if (!this.getAttribute("data-cy")) {
4278
4713
  this.setAttribute("data-cy", "lib-e2e-cypress-for-dummys");
4279
4714
  }
@@ -4290,10 +4725,12 @@ var LibE2eRecorderElement = class extends HTMLElement {
4290
4725
  this.initSelectorStrategy();
4291
4726
  this.initSubscriptions();
4292
4727
  this.render();
4728
+ this.initVisibility();
4293
4729
  this.keydownHandler = (e) => this.handleKeyboardEvent(e);
4294
4730
  window.addEventListener("keydown", this.keydownHandler);
4295
4731
  }
4296
4732
  disconnectedCallback() {
4733
+ if (this._isDisabled) return;
4297
4734
  window.removeEventListener("keydown", this.keydownHandler);
4298
4735
  this.recordingUnsub?.();
4299
4736
  this.commandsUnsub?.();
@@ -4354,6 +4791,16 @@ var LibE2eRecorderElement = class extends HTMLElement {
4354
4791
  document.body.appendChild(picker);
4355
4792
  });
4356
4793
  }
4794
+ async initVisibility() {
4795
+ if (this.hasAttribute("start-hidden")) {
4796
+ this.isVisible = this.getAttribute("start-hidden") === "false";
4797
+ this.style.display = this.isVisible ? "" : "none";
4798
+ return;
4799
+ }
4800
+ const config = await this.persistence.getGeneralConfig();
4801
+ this.isVisible = config?.["startHidden"] !== "true";
4802
+ this.style.display = this.isVisible ? "" : "none";
4803
+ }
4357
4804
  async initSelectorStrategy() {
4358
4805
  const config = await this.persistence.getGeneralConfig();
4359
4806
  const strategy = config?.["selectorStrategy"];
@@ -4373,6 +4820,12 @@ var LibE2eRecorderElement = class extends HTMLElement {
4373
4820
  handleKeyboardEvent(event) {
4374
4821
  if (!event.ctrlKey) return;
4375
4822
  const key = event.key.toLowerCase();
4823
+ if (key === "e" && event.shiftKey) {
4824
+ event.preventDefault();
4825
+ this.toggleVisibility();
4826
+ return;
4827
+ }
4828
+ if (!this.isVisible) return;
4376
4829
  if (key === "r") {
4377
4830
  event.preventDefault();
4378
4831
  this.toggle();
@@ -4390,6 +4843,10 @@ var LibE2eRecorderElement = class extends HTMLElement {
4390
4843
  this.showSettingsDialog();
4391
4844
  }
4392
4845
  }
4846
+ toggleVisibility() {
4847
+ this.isVisible = !this.isVisible;
4848
+ this.style.display = this.isVisible ? "" : "none";
4849
+ }
4393
4850
  // ── recording history (task 5) ────────────────────────────────────────────
4394
4851
  saveRecordingHistory() {
4395
4852
  if (!this.cypressCommands.length) return;
@@ -4625,13 +5082,13 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
4625
5082
  child.translation = this.translation;
4626
5083
  container.appendChild(child);
4627
5084
  child.addEventListener("savetest", (e) => {
4628
- const { description, tags } = e.detail ?? {};
4629
- this.onSaveTest(description ?? null, tags ?? []);
5085
+ const { description, notes, tags } = e.detail ?? {};
5086
+ this.onSaveTest(description ?? null, tags ?? [], notes ?? "");
4630
5087
  import_sweetalert2.default.close();
4631
5088
  });
4632
5089
  child.addEventListener("saveandexport", (e) => {
4633
- const { description, tags } = e.detail ?? {};
4634
- this.onSaveAndExportTest(description ?? null, tags ?? []);
5090
+ const { description, notes, tags } = e.detail ?? {};
5091
+ this.onSaveAndExportTest(description ?? null, tags ?? [], notes ?? "");
4635
5092
  import_sweetalert2.default.close();
4636
5093
  });
4637
5094
  },
@@ -4662,6 +5119,10 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
4662
5119
  child.addEventListener("smartselectorchange", (e) => {
4663
5120
  this.smartSelectorEnabled = e.detail;
4664
5121
  });
5122
+ child.addEventListener("starthiddenchange", (e) => {
5123
+ this.isVisible = !e.detail;
5124
+ this.style.display = this.isVisible ? "" : "none";
5125
+ });
4665
5126
  },
4666
5127
  willClose: () => {
4667
5128
  this.isSettingsDialogOpen = false;
@@ -4674,7 +5135,7 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
4674
5135
  this.toggleModal("isAdvancedEditorDialogOpen", () => {
4675
5136
  import_sweetalert2.default.fire({
4676
5137
  title: this.translation.translate("MAIN_FRAME.SHOW_ADVANCED_EDITOR"),
4677
- html: '<div id="advanced-editor-modal-content" style="min-height:300px;padding:0"></div>',
5138
+ html: '<div id="advanced-editor-modal-content" style="flex:1;min-height:0;display:flex;flex-direction:column;padding:0"></div>',
4678
5139
  showCloseButton: true,
4679
5140
  showConfirmButton: false,
4680
5141
  allowOutsideClick: false,
@@ -4683,6 +5144,20 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
4683
5144
  didOpen: () => {
4684
5145
  makeSwalDraggable();
4685
5146
  setSwal2DataCyAttribute();
5147
+ const popup = import_sweetalert2.default.getPopup();
5148
+ if (popup) {
5149
+ popup.style.height = "600px";
5150
+ const htmlContainer = popup.querySelector(".swal2-html-container");
5151
+ if (htmlContainer) {
5152
+ htmlContainer.style.flex = "1";
5153
+ htmlContainer.style.minHeight = "0";
5154
+ htmlContainer.style.overflow = "hidden";
5155
+ htmlContainer.style.padding = "0";
5156
+ htmlContainer.style.margin = "0";
5157
+ htmlContainer.style.display = "flex";
5158
+ htmlContainer.style.flexDirection = "column";
5159
+ }
5160
+ }
4686
5161
  const container = document.getElementById("advanced-editor-modal-content");
4687
5162
  if (!container) return;
4688
5163
  const child = document.createElement("advanced-test-editor");
@@ -4710,7 +5185,10 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
4710
5185
  this.isAdvancedEditorDialogOpen = false;
4711
5186
  }
4712
5187
  });
4713
- this.resizePopup();
5188
+ setTimeout(() => {
5189
+ const popup = import_sweetalert2.default.getPopup();
5190
+ if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 0 });
5191
+ }, 0);
4714
5192
  });
4715
5193
  }
4716
5194
  showFileEditorDialog(handle, content, fileName, testId, itBlock = "", interceptorsBlock = "") {
@@ -4756,18 +5234,18 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
4756
5234
  this.resizePopup();
4757
5235
  }
4758
5236
  // ── save handlers ─────────────────────────────────────────────────────────
4759
- async onSaveTest(description, tags = []) {
5237
+ async onSaveTest(description, tags = [], notes = "") {
4760
5238
  if (description) {
4761
- await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags);
5239
+ await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes);
4762
5240
  this.recording.clearCommands();
4763
5241
  this.clearRecordingHistory();
4764
5242
  this.cypressCommands = [];
4765
5243
  this.interceptors = [];
4766
5244
  }
4767
5245
  }
4768
- async onSaveAndExportTest(description, tags = []) {
5246
+ async onSaveAndExportTest(description, tags = [], notes = "") {
4769
5247
  if (description) {
4770
- const id = await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags);
5248
+ const id = await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes);
4771
5249
  this.recording.clearCommands();
4772
5250
  this.clearRecordingHistory();
4773
5251
  this.cypressCommands = [];
@@ -4794,6 +5272,7 @@ cypress/ <span style="color:#484f58">${this.translation.translate("RECOR
4794
5272
  render() {
4795
5273
  const rec = this.isRecording;
4796
5274
  const paused = this.isPaused;
5275
+ this.style.display = this.isVisible ? "" : "none";
4797
5276
  this.shadow.innerHTML = `<style>${getRecorderStyles(rec, paused)}</style>${renderRecorderWidget(rec, paused, this.translation.translate.bind(this.translation))}`;
4798
5277
  this.shadow.querySelector('[data-action="toggle"]')?.addEventListener("click", () => this.toggle());
4799
5278
  this.shadow.querySelector('[data-action="pause"]')?.addEventListener("click", () => this.togglePause());