@testsmith/api-spector 0.5.8 → 0.6.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.
@@ -13317,6 +13317,23 @@ function v4(options, buf, offset) {
13317
13317
  rnds[8] = rnds[8] & 63 | 128;
13318
13318
  return unsafeStringify(rnds);
13319
13319
  }
13320
+ function orderedChildren(folder2) {
13321
+ const reqSet = new Set(folder2.requestIds);
13322
+ const folderSet = new Set(folder2.folders.map((f) => f.id));
13323
+ const seen2 = /* @__PURE__ */ new Set();
13324
+ const out = [];
13325
+ for (const ref2 of folder2.childOrder ?? []) {
13326
+ const key = `${ref2.type}:${ref2.id}`;
13327
+ if (seen2.has(key)) continue;
13328
+ if (ref2.type === "request" && reqSet.has(ref2.id) || ref2.type === "folder" && folderSet.has(ref2.id)) {
13329
+ out.push({ type: ref2.type, id: ref2.id });
13330
+ seen2.add(key);
13331
+ }
13332
+ }
13333
+ for (const id2 of folder2.requestIds) if (!seen2.has(`request:${id2}`)) out.push({ type: "request", id: id2 });
13334
+ for (const f of folder2.folders) if (!seen2.has(`folder:${f.id}`)) out.push({ type: "folder", id: f.id });
13335
+ return out;
13336
+ }
13320
13337
  function findFolder$1(root2, id2) {
13321
13338
  if (root2.id === id2) return root2;
13322
13339
  for (const sub of root2.folders) {
@@ -13762,6 +13779,12 @@ const createCollectionsSlice = (set2, get2) => ({
13762
13779
  s.workspace.collections = s.workspace.collections.map((p) => p === oldRelPath ? newRelPath : p);
13763
13780
  }
13764
13781
  }),
13782
+ toggleCollectionDisabled: (id2) => set2((s) => {
13783
+ const entry = s.collections[id2];
13784
+ if (!entry) return;
13785
+ entry.data.disabled = !entry.data.disabled;
13786
+ entry.dirty = true;
13787
+ }),
13765
13788
  duplicateCollection: (id2) => set2((s) => {
13766
13789
  const entry = s.collections[id2];
13767
13790
  if (!entry) return;
@@ -14121,6 +14144,30 @@ const createCollectionsSlice = (set2, get2) => ({
14121
14144
  }
14122
14145
  s.collections[collectionId].dirty = true;
14123
14146
  }),
14147
+ reorderChild: (collectionId, ref2, destParentFolderId, destIndex) => set2((s) => {
14148
+ const col = s.collections[collectionId]?.data;
14149
+ if (!col) return;
14150
+ const destParent = findFolder$1(col.rootFolder, destParentFolderId);
14151
+ if (!destParent) return;
14152
+ if (ref2.type === "request") {
14153
+ if (!col.requests[ref2.id]) return;
14154
+ removeFromFolder(col.rootFolder, ref2.id);
14155
+ if (!destParent.requestIds.includes(ref2.id)) destParent.requestIds.push(ref2.id);
14156
+ } else {
14157
+ const moving = findFolder$1(col.rootFolder, ref2.id);
14158
+ if (!moving) return;
14159
+ if (ref2.id === destParentFolderId || findFolder$1(moving, destParentFolderId)) return;
14160
+ const srcParent = findFolderParent(col.rootFolder, ref2.id) ?? col.rootFolder;
14161
+ const srcIdx = srcParent.folders.findIndex((f) => f.id === ref2.id);
14162
+ if (srcIdx >= 0) srcParent.folders.splice(srcIdx, 1);
14163
+ if (!destParent.folders.some((f) => f.id === ref2.id)) destParent.folders.push(moving);
14164
+ }
14165
+ const others = orderedChildren(destParent).filter((c) => !(c.type === ref2.type && c.id === ref2.id));
14166
+ const idx = Math.max(0, Math.min(destIndex, others.length));
14167
+ others.splice(idx, 0, { type: ref2.type, id: ref2.id });
14168
+ destParent.childOrder = others;
14169
+ s.collections[collectionId].dirty = true;
14170
+ }),
14124
14171
  // ── Tags ────────────────────────────────────────────────────────────────────
14125
14172
  updateFolderTags: (collectionId, folderId, tags2) => set2((s) => {
14126
14173
  const col = s.collections[collectionId]?.data;
@@ -35180,6 +35227,16 @@ function useVarNames() {
35180
35227
  const col = collections[activeCollectionId]?.data;
35181
35228
  if (col) {
35182
35229
  Object.keys(col.collectionVariables ?? {}).forEach((k) => names2.add(k));
35230
+ (col.dataSet?.columns ?? []).forEach((c) => {
35231
+ if (c) names2.add(c);
35232
+ });
35233
+ const addFolderCols = (f) => {
35234
+ (f.dataSet?.columns ?? []).forEach((c) => {
35235
+ if (c) names2.add(c);
35236
+ });
35237
+ f.folders.forEach(addFolderCols);
35238
+ };
35239
+ addFolderCols(col.rootFolder);
35183
35240
  for (const req of Object.values(col.requests)) {
35184
35241
  extractScriptVarNames(req.preRequestScript).forEach((k) => names2.add(k));
35185
35242
  extractScriptVarNames(req.postRequestScript).forEach((k) => names2.add(k));
@@ -35417,6 +35474,9 @@ const Basic$6 = "Basic";
35417
35474
  const Standard$6 = "Standard";
35418
35475
  const Aggressive$6 = "Aggressive";
35419
35476
  const Next$6 = "Next";
35477
+ const More$6 = "More";
35478
+ const or$6 = "or";
35479
+ const Disabled$6 = "Disabled";
35420
35480
  const en = {
35421
35481
  "Close tab": "Close tab",
35422
35482
  Collections: Collections$6,
@@ -36455,7 +36515,21 @@ const en = {
36455
36515
  "Replay the guided walkthrough of collections, environments and requests.": "Replay the guided walkthrough of collections, environments and requests.",
36456
36516
  "Schema: a local scratch check.": "Schema: a local scratch check.",
36457
36517
  "Validate this request's last response against a JSON Schema, right here. It is **not saved to the contract and not published**. A dev-time sanity check only. To define what the provider *must* return (which drives contract testing), use the **Contract** tab.": "Validate this request's last response against a JSON Schema, right here. It is **not saved to the contract and not published**. A dev-time sanity check only. To define what the provider *must* return (which drives contract testing), use the **Contract** tab.",
36458
- "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab."
36518
+ "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.",
36519
+ More: More$6,
36520
+ "Response sections": "Response sections",
36521
+ "More response sections": "More response sections",
36522
+ "More actions": "More actions",
36523
+ "Body view mode": "Body view mode",
36524
+ "Cell values can also use variables and faker, e.g.": "Cell values can also use variables and faker, e.g.",
36525
+ or: or$6,
36526
+ "Script errors": "Script errors",
36527
+ "Pre-script:": "Pre-script:",
36528
+ "Post-script:": "Post-script:",
36529
+ "No data row": "No data row",
36530
+ "Row :n": "Row :n",
36531
+ "Run this request with the variables from one data table row": "Run this request with the variables from one data table row",
36532
+ Disabled: Disabled$6
36459
36533
  };
36460
36534
  const Collections$5 = "Sammlungen";
36461
36535
  const History$5 = "Verlauf";
@@ -36655,6 +36729,9 @@ const Basic$5 = "Einfach";
36655
36729
  const Standard$5 = "Standard";
36656
36730
  const Aggressive$5 = "Aggressiv";
36657
36731
  const Next$5 = "Weiter";
36732
+ const More$5 = "Mehr";
36733
+ const or$5 = "oder";
36734
+ const Disabled$5 = "Deaktiviert";
36658
36735
  const de = {
36659
36736
  "Close tab": "Tab schließen",
36660
36737
  Collections: Collections$5,
@@ -37693,7 +37770,21 @@ const de = {
37693
37770
  "Replay the guided walkthrough of collections, environments and requests.": "Wiederhole die geführte Tour durch Sammlungen, Umgebungen und Requests.",
37694
37771
  "Schema: a local scratch check.": "Schema: eine lokale Schnellprüfung.",
37695
37772
  "Validate this request's last response against a JSON Schema, right here. It is **not saved to the contract and not published**. A dev-time sanity check only. To define what the provider *must* return (which drives contract testing), use the **Contract** tab.": "Validiere die letzte Antwort dieses Requests hier direkt gegen ein JSON Schema. Sie wird **nicht im Contract gespeichert und nicht veröffentlicht**. Nur eine Sanity-Prüfung zur Entwicklungszeit. Um zu definieren, was der Provider zurückgeben *muss* (was Contract-Tests steuert), verwende den **Contract**-Tab.",
37696
- "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "Was dieses Request vom Provider *erwartet*: Status, Header und Body-Form (ein JSON Schema). Es wird im **Contract**-Panel gegen die Antwort geprüft und ist die Consumer-Seite von Contract-Tests (Consumer- und bidirektionale Verifikation), die den `deploy-check`-Gate speist. Für eine schnelle Body-Prüfung bei jeder Sendung verwende den **Schema**-Tab."
37773
+ "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "Was dieses Request vom Provider *erwartet*: Status, Header und Body-Form (ein JSON Schema). Es wird im **Contract**-Panel gegen die Antwort geprüft und ist die Consumer-Seite von Contract-Tests (Consumer- und bidirektionale Verifikation), die den `deploy-check`-Gate speist. Für eine schnelle Body-Prüfung bei jeder Sendung verwende den **Schema**-Tab.",
37774
+ More: More$5,
37775
+ "Response sections": "Antwortbereiche",
37776
+ "More response sections": "Weitere Antwortbereiche",
37777
+ "More actions": "Weitere Aktionen",
37778
+ "Body view mode": "Body-Ansichtsmodus",
37779
+ "Cell values can also use variables and faker, e.g.": "Zellwerte können auch Variablen und faker verwenden, z. B.",
37780
+ or: or$5,
37781
+ "Script errors": "Skriptfehler",
37782
+ "Pre-script:": "Pre-Script:",
37783
+ "Post-script:": "Post-Script:",
37784
+ "No data row": "Keine Datenzeile",
37785
+ "Row :n": "Zeile :n",
37786
+ "Run this request with the variables from one data table row": "Diesen Request mit den Variablen einer Datentabellenzeile ausführen",
37787
+ Disabled: Disabled$5
37697
37788
  };
37698
37789
  const Collections$4 = "Collections";
37699
37790
  const History$4 = "Historique";
@@ -37893,6 +37984,9 @@ const Basic$4 = "Basique";
37893
37984
  const Standard$4 = "Standard";
37894
37985
  const Aggressive$4 = "Agressif";
37895
37986
  const Next$4 = "Suivant";
37987
+ const More$4 = "Plus";
37988
+ const or$4 = "ou";
37989
+ const Disabled$4 = "Désactivé";
37896
37990
  const fr = {
37897
37991
  "Close tab": "Fermer l'onglet",
37898
37992
  Collections: Collections$4,
@@ -38931,7 +39025,21 @@ const fr = {
38931
39025
  "Replay the guided walkthrough of collections, environments and requests.": "Rejouez la visite guidée des collections, environnements et requests.",
38932
39026
  "Schema: a local scratch check.": "Schema : une vérification locale de travail.",
38933
39027
  "Validate this request's last response against a JSON Schema, right here. It is **not saved to the contract and not published**. A dev-time sanity check only. To define what the provider *must* return (which drives contract testing), use the **Contract** tab.": "Validez la dernière réponse de ce request directement ici par rapport à un JSON Schema. Elle n'est **pas enregistrée dans le contract ni publiée**. Juste une vérification de bon sens en développement. Pour définir ce que le provider *doit* renvoyer (ce qui pilote les tests de contract), utilisez l'onglet **Contract**.",
38934
- "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "Ce que ce request *attend* du provider : statut, en-têtes et forme du body (un JSON Schema). C'est vérifié par rapport à la réponse dans le panneau **Contract** et c'est le côté consommateur des tests de contract (vérification consommateur et bidirectionnelle), qui alimente la gate `deploy-check`. Pour une vérification rapide du body à chaque envoi, utilisez l'onglet **Schema**."
39028
+ "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "Ce que ce request *attend* du provider : statut, en-têtes et forme du body (un JSON Schema). C'est vérifié par rapport à la réponse dans le panneau **Contract** et c'est le côté consommateur des tests de contract (vérification consommateur et bidirectionnelle), qui alimente la gate `deploy-check`. Pour une vérification rapide du body à chaque envoi, utilisez l'onglet **Schema**.",
39029
+ More: More$4,
39030
+ "Response sections": "Sections de réponse",
39031
+ "More response sections": "Autres sections de réponse",
39032
+ "More actions": "Autres actions",
39033
+ "Body view mode": "Mode d’affichage du body",
39034
+ "Cell values can also use variables and faker, e.g.": "Les valeurs de cellule peuvent aussi utiliser des variables et faker, p. ex.",
39035
+ or: or$4,
39036
+ "Script errors": "Erreurs de script",
39037
+ "Pre-script:": "Pré-script :",
39038
+ "Post-script:": "Post-script :",
39039
+ "No data row": "Aucune ligne de données",
39040
+ "Row :n": "Ligne :n",
39041
+ "Run this request with the variables from one data table row": "Exécuter ce request avec les variables d'une ligne de la table de données",
39042
+ Disabled: Disabled$4
38935
39043
  };
38936
39044
  const Collections$3 = "Colecciones";
38937
39045
  const History$3 = "Historial";
@@ -39131,6 +39239,9 @@ const Basic$3 = "Básico";
39131
39239
  const Standard$3 = "Estándar";
39132
39240
  const Aggressive$3 = "Agresivo";
39133
39241
  const Next$3 = "Siguiente";
39242
+ const More$3 = "Más";
39243
+ const or$3 = "o";
39244
+ const Disabled$3 = "Desactivada";
39134
39245
  const es = {
39135
39246
  "Close tab": "Cerrar pestaña",
39136
39247
  Collections: Collections$3,
@@ -40169,7 +40280,21 @@ const es = {
40169
40280
  "Replay the guided walkthrough of collections, environments and requests.": "Vuelve a ver el recorrido guiado por colecciones, entornos y requests.",
40170
40281
  "Schema: a local scratch check.": "Schema: una comprobación local rápida.",
40171
40282
  "Validate this request's last response against a JSON Schema, right here. It is **not saved to the contract and not published**. A dev-time sanity check only. To define what the provider *must* return (which drives contract testing), use the **Contract** tab.": "Valida la última respuesta de este request aquí mismo contra un JSON Schema. **No se guarda en el contract ni se publica**. Solo una comprobación de validez en desarrollo. Para definir lo que el provider *debe* devolver (lo que impulsa las pruebas de contract), usa la pestaña **Contract**.",
40172
- "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "Lo que este request *espera* del provider: estado, headers y forma del body (un JSON Schema). Se comprueba contra la respuesta en el panel **Contract** y es el lado consumidor de las pruebas de contract (verificación de consumidor y bidireccional), que alimenta la gate `deploy-check`. Para una comprobación rápida del body en cada envío, usa la pestaña **Schema**."
40283
+ "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "Lo que este request *espera* del provider: estado, headers y forma del body (un JSON Schema). Se comprueba contra la respuesta en el panel **Contract** y es el lado consumidor de las pruebas de contract (verificación de consumidor y bidireccional), que alimenta la gate `deploy-check`. Para una comprobación rápida del body en cada envío, usa la pestaña **Schema**.",
40284
+ More: More$3,
40285
+ "Response sections": "Secciones de respuesta",
40286
+ "More response sections": "Más secciones de respuesta",
40287
+ "More actions": "Más acciones",
40288
+ "Body view mode": "Modo de vista del body",
40289
+ "Cell values can also use variables and faker, e.g.": "Los valores de celda también pueden usar variables y faker, p. ej.",
40290
+ or: or$3,
40291
+ "Script errors": "Errores de script",
40292
+ "Pre-script:": "Pre-script:",
40293
+ "Post-script:": "Post-script:",
40294
+ "No data row": "Sin fila de datos",
40295
+ "Row :n": "Fila :n",
40296
+ "Run this request with the variables from one data table row": "Ejecuta este request con las variables de una fila de la tabla de datos",
40297
+ Disabled: Disabled$3
40173
40298
  };
40174
40299
  const Collections$2 = "Raccolte";
40175
40300
  const History$2 = "Cronologia";
@@ -40369,6 +40494,9 @@ const Basic$2 = "Base";
40369
40494
  const Standard$2 = "Standard";
40370
40495
  const Aggressive$2 = "Aggressivo";
40371
40496
  const Next$2 = "Avanti";
40497
+ const More$2 = "Altro";
40498
+ const or$2 = "o";
40499
+ const Disabled$2 = "Disattivata";
40372
40500
  const it = {
40373
40501
  "Close tab": "Chiudi scheda",
40374
40502
  Collections: Collections$2,
@@ -41407,7 +41535,21 @@ const it = {
41407
41535
  "Replay the guided walkthrough of collections, environments and requests.": "Riproduci la panoramica guidata di raccolte, ambienti e requests.",
41408
41536
  "Schema: a local scratch check.": "Schema: un controllo locale rapido.",
41409
41537
  "Validate this request's last response against a JSON Schema, right here. It is **not saved to the contract and not published**. A dev-time sanity check only. To define what the provider *must* return (which drives contract testing), use the **Contract** tab.": "Valida l'ultima risposta di questo request qui stesso rispetto a un JSON Schema. **Non viene salvata nel contract né pubblicata**. Solo un controllo di validità in fase di sviluppo. Per definire ciò che il provider *deve* restituire (ciò che guida i test di contract), usa la scheda **Contract**.",
41410
- "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "Ciò che questo request *si aspetta* dal provider: stato, header e forma del body (un JSON Schema). Viene verificato rispetto alla risposta nel pannello **Contract** ed è il lato consumer dei test di contract (verifica consumer e bidirezionale), che alimenta la gate `deploy-check`. Per un controllo rapido del body a ogni invio, usa la scheda **Schema**."
41538
+ "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "Ciò che questo request *si aspetta* dal provider: stato, header e forma del body (un JSON Schema). Viene verificato rispetto alla risposta nel pannello **Contract** ed è il lato consumer dei test di contract (verifica consumer e bidirezionale), che alimenta la gate `deploy-check`. Per un controllo rapido del body a ogni invio, usa la scheda **Schema**.",
41539
+ More: More$2,
41540
+ "Response sections": "Sezioni della risposta",
41541
+ "More response sections": "Altre sezioni della risposta",
41542
+ "More actions": "Altre azioni",
41543
+ "Body view mode": "Modalità di visualizzazione del body",
41544
+ "Cell values can also use variables and faker, e.g.": "I valori delle celle possono usare anche variabili e faker, ad es.",
41545
+ or: or$2,
41546
+ "Script errors": "Errori di script",
41547
+ "Pre-script:": "Pre-script:",
41548
+ "Post-script:": "Post-script:",
41549
+ "No data row": "Nessuna riga di dati",
41550
+ "Row :n": "Riga :n",
41551
+ "Run this request with the variables from one data table row": "Esegui questo request con le variabili di una riga della tabella dati",
41552
+ Disabled: Disabled$2
41411
41553
  };
41412
41554
  const Collections$1 = "Collecties";
41413
41555
  const History$1 = "Geschiedenis";
@@ -41607,6 +41749,9 @@ const Basic$1 = "Basis";
41607
41749
  const Standard$1 = "Standaard";
41608
41750
  const Aggressive$1 = "Agressief";
41609
41751
  const Next$1 = "Volgende";
41752
+ const More$1 = "Meer";
41753
+ const or$1 = "of";
41754
+ const Disabled$1 = "Uitgeschakeld";
41610
41755
  const nl = {
41611
41756
  "Close tab": "Tabblad sluiten",
41612
41757
  Collections: Collections$1,
@@ -42645,7 +42790,21 @@ const nl = {
42645
42790
  "Replay the guided walkthrough of collections, environments and requests.": "Speel de rondleiding door collecties, omgevingen en requests opnieuw af.",
42646
42791
  "Schema: a local scratch check.": "Schema: een lokale kladcontrole.",
42647
42792
  "Validate this request's last response against a JSON Schema, right here. It is **not saved to the contract and not published**. A dev-time sanity check only. To define what the provider *must* return (which drives contract testing), use the **Contract** tab.": "Valideer de laatste respons van dit request hier direct tegen een JSON Schema. Het wordt **niet opgeslagen in het contract en niet gepubliceerd**. Alleen een sanity check tijdens ontwikkeling. Om te definiëren wat de provider *moet* retourneren (wat contracttesten aanstuurt), gebruik je het **Contract** tabblad.",
42648
- "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "Wat dit request *verwacht* van de provider: status, headers en body-vorm (een JSON Schema). Het wordt gecontroleerd tegen de respons in het **Contract** paneel en is de consumerzijde van contracttesten (consumer- en bidirectionele verificatie), wat de `deploy-check` gate voedt. Gebruik voor een snelle body-controle bij elke verzending het **Schema** tabblad."
42793
+ "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "Wat dit request *verwacht* van de provider: status, headers en body-vorm (een JSON Schema). Het wordt gecontroleerd tegen de respons in het **Contract** paneel en is de consumerzijde van contracttesten (consumer- en bidirectionele verificatie), wat de `deploy-check` gate voedt. Gebruik voor een snelle body-controle bij elke verzending het **Schema** tabblad.",
42794
+ More: More$1,
42795
+ "Response sections": "Responssecties",
42796
+ "More response sections": "Meer responssecties",
42797
+ "More actions": "Meer acties",
42798
+ "Body view mode": "Body-weergavemodus",
42799
+ "Cell values can also use variables and faker, e.g.": "Celwaarden kunnen ook variabelen en faker gebruiken, bijv.",
42800
+ or: or$1,
42801
+ "Script errors": "Scriptfouten",
42802
+ "Pre-script:": "Pre-script:",
42803
+ "Post-script:": "Post-script:",
42804
+ "No data row": "Geen datarij",
42805
+ "Row :n": "Rij :n",
42806
+ "Run this request with the variables from one data table row": "Voer dit request uit met de variabelen van één datatabelrij",
42807
+ Disabled: Disabled$1
42649
42808
  };
42650
42809
  const Collections = "Coleções";
42651
42810
  const History = "Histórico";
@@ -42845,6 +43004,9 @@ const Basic = "Básico";
42845
43004
  const Standard = "Padrão";
42846
43005
  const Aggressive = "Agressivo";
42847
43006
  const Next = "Seguinte";
43007
+ const More = "Mais";
43008
+ const or = "ou";
43009
+ const Disabled = "Desativada";
42848
43010
  const pt = {
42849
43011
  "Close tab": "Fechar separador",
42850
43012
  Collections,
@@ -43883,7 +44045,21 @@ const pt = {
43883
44045
  "Replay the guided walkthrough of collections, environments and requests.": "Reproduz o guia de coleções, ambientes e requests.",
43884
44046
  "Schema: a local scratch check.": "Schema: uma verificação local rápida.",
43885
44047
  "Validate this request's last response against a JSON Schema, right here. It is **not saved to the contract and not published**. A dev-time sanity check only. To define what the provider *must* return (which drives contract testing), use the **Contract** tab.": "Valida a última resposta deste request aqui mesmo contra um JSON Schema. **Não é guardada no contract nem publicada**. Apenas uma verificação de sanidade em desenvolvimento. Para definir o que o provider *deve* devolver (o que orienta os testes de contract), usa o separador **Contract**.",
43886
- "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "O que este request *espera* do provider: estado, headers e forma do body (um JSON Schema). É verificado contra a resposta no painel **Contract** e é o lado consumidor dos testes de contract (verificação de consumidor e bidirecional), que alimenta a gate `deploy-check`. Para uma verificação rápida do body a cada envio, usa o separador **Schema**."
44048
+ "What this request *expects* from the provider: status, headers, and body shape (a JSON Schema). It is checked against the response in the **Contract** panel and is the consumer side of contract testing (consumer and bi-directional verify), feeding the `deploy-check` gate. For a quick body check that runs on every send, use the **Schema** tab.": "O que este request *espera* do provider: estado, headers e forma do body (um JSON Schema). É verificado contra a resposta no painel **Contract** e é o lado consumidor dos testes de contract (verificação de consumidor e bidirecional), que alimenta a gate `deploy-check`. Para uma verificação rápida do body a cada envio, usa o separador **Schema**.",
44049
+ More,
44050
+ "Response sections": "Secções da resposta",
44051
+ "More response sections": "Mais secções da resposta",
44052
+ "More actions": "Mais ações",
44053
+ "Body view mode": "Modo de visualização do body",
44054
+ "Cell values can also use variables and faker, e.g.": "Os valores das células também podem usar variáveis e faker, por ex.",
44055
+ or,
44056
+ "Script errors": "Erros de script",
44057
+ "Pre-script:": "Pré-script:",
44058
+ "Post-script:": "Pós-script:",
44059
+ "No data row": "Sem linha de dados",
44060
+ "Row :n": "Linha :n",
44061
+ "Run this request with the variables from one data table row": "Executa este request com as variáveis de uma linha da tabela de dados",
44062
+ Disabled
43887
44063
  };
43888
44064
  const CATALOGS = { en, de, fr, es, it, nl, pt };
43889
44065
  const LOCALES = {
@@ -43902,8 +44078,7 @@ function detectLocale() {
43902
44078
  if (saved && saved in CATALOGS) return saved;
43903
44079
  } catch {
43904
44080
  }
43905
- const nav2 = (typeof navigator !== "undefined" ? navigator.language : "en").slice(0, 2);
43906
- return nav2 in CATALOGS ? nav2 : "en";
44081
+ return "en";
43907
44082
  }
43908
44083
  function interpolate(str, vars) {
43909
44084
  if (!vars) return str;
@@ -43951,6 +44126,18 @@ function useLocale() {
43951
44126
  const { locale, setLocale } = reactExports.useContext(I18nContext);
43952
44127
  return [locale, setLocale];
43953
44128
  }
44129
+ const DAYJS_OPTIONS = [
44130
+ { label: "dayjs().format('YYYY-MM-DD')", insert: "dayjs().format('YYYY-MM-DD')" },
44131
+ { label: "dayjs().toISOString()", insert: "dayjs().toISOString()" },
44132
+ { label: "dayjs().valueOf()", insert: "dayjs().valueOf()" },
44133
+ { label: "dayjs().subtract(1,'day').format(…)", insert: "dayjs().subtract(1,'day').format('YYYY-MM-DD')" },
44134
+ { label: "dayjs().add(1,'day').format(…)", insert: "dayjs().add(1,'day').format('YYYY-MM-DD')" }
44135
+ ];
44136
+ const ICON = {
44137
+ variable: { glyph: "𝑥", cls: "text-emerald-400" },
44138
+ function: { glyph: "ƒ", cls: "text-violet-400" },
44139
+ property: { glyph: "◆", cls: "text-blue-400" }
44140
+ };
43954
44141
  function parseVarTokens(str) {
43955
44142
  const found = [];
43956
44143
  const re = /\{\{([^}]+)\}\}/g;
@@ -43972,23 +44159,23 @@ function PortalDropdown({
43972
44159
  /* @__PURE__ */ jsxRuntimeExports.jsx(
43973
44160
  "ul",
43974
44161
  {
43975
- style: { position: "fixed", top: pos.top, left: pos.left, minWidth: pos.minWidth, zIndex: 9999 },
43976
- className: "max-h-52 overflow-y-auto bg-surface-800 border border-surface-600 rounded shadow-xl text-xs",
43977
- children: items2.map((s, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
44162
+ style: { position: "fixed", top: pos.top, left: pos.left, minWidth: Math.max(pos.minWidth, 220), zIndex: 9999 },
44163
+ className: "max-h-56 overflow-y-auto bg-surface-800 border border-surface-600 rounded shadow-xl text-xs py-0.5",
44164
+ children: items2.map((s, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("li", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
43978
44165
  "button",
43979
44166
  {
43980
44167
  onMouseDown: (e) => {
43981
44168
  e.preventDefault();
43982
44169
  onPick(s);
43983
44170
  },
43984
- className: `w-full text-left px-3 py-1.5 font-mono transition-colors ${i === activeIndex ? "bg-blue-600 text-white" : "hover:bg-surface-700"}`,
43985
- children: mode === "var" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
43986
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500", children: "{{" }),
43987
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: s }),
43988
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500", children: "}}" })
43989
- ] }) : s
44171
+ className: `w-full text-left px-2 py-1 font-mono transition-colors flex items-center gap-1.5 ${i === activeIndex ? "bg-blue-600 text-white" : "hover:bg-surface-700"}`,
44172
+ children: [
44173
+ mode === "var" ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-3 shrink-0 text-center ${i === activeIndex ? "text-white/80" : ICON[s.type].cls}`, children: ICON[s.type].glyph }) : null,
44174
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: s.label }),
44175
+ s.detail && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `ml-auto pl-2 shrink-0 italic ${i === activeIndex ? "text-white/70" : "text-surface-500"}`, children: s.detail })
44176
+ ]
43990
44177
  }
43991
- ) }, s))
44178
+ ) }, s.label + i))
43992
44179
  }
43993
44180
  ),
43994
44181
  document.body
@@ -44004,6 +44191,7 @@ function VarInput({ value: value2, onChange, className, wrapperClassName, static
44004
44191
  const [activeIndex, setActiveIndex] = reactExports.useState(-1);
44005
44192
  const [dropPos, setDropPos] = reactExports.useState(null);
44006
44193
  const [showPreview, setShowPreview] = reactExports.useState(false);
44194
+ const partialLen = reactExports.useRef(0);
44007
44195
  reactExports.useEffect(() => {
44008
44196
  if (suggestions.length === 0) {
44009
44197
  setDropPos(null);
@@ -44014,28 +44202,60 @@ function VarInput({ value: value2, onChange, className, wrapperClassName, static
44014
44202
  const r = el.getBoundingClientRect();
44015
44203
  setDropPos({ top: r.bottom + 2, left: r.left, minWidth: r.width });
44016
44204
  }, [suggestions.length]);
44205
+ function show(items2, from) {
44206
+ partialLen.current = from;
44207
+ setSuggestions(items2);
44208
+ setSuggestionMode("var");
44209
+ setActiveIndex(-1);
44210
+ }
44017
44211
  function detectQuery(val, cursor2) {
44018
44212
  const before = val.slice(0, cursor2);
44019
- const varMatch = /\{\{(\w*)$/.exec(before);
44020
- if (varMatch) {
44021
- const q = varMatch[1].toLowerCase();
44022
- const filtered = varNames.filter((n) => n.toLowerCase().includes(q));
44023
- setSuggestions(filtered);
44024
- setSuggestionMode("var");
44025
- setActiveIndex(-1);
44026
- } else if (staticSuggestions) {
44213
+ const sortByMatch = (items2, q) => items2.map((it2, i) => ({ it: it2, i })).sort((a, b) => {
44214
+ const ap = a.it.label.toLowerCase().startsWith(q) ? 0 : 1;
44215
+ const bp = b.it.label.toLowerCase().startsWith(q) ? 0 : 1;
44216
+ return ap - bp || (b.it.boost ?? 0) - (a.it.boost ?? 0) || a.i - b.i;
44217
+ }).map((x) => x.it);
44218
+ let m = /\{\{faker\.(\w+)\.(\w*)$/.exec(before);
44219
+ if (m) {
44220
+ const q = m[2].toLowerCase();
44221
+ const subs = (FAKER_SUB[m[1]] ?? []).filter((c) => c.label.toLowerCase().includes(q));
44222
+ show(sortByMatch(subs.map((c) => ({ label: c.label, type: "function", detail: c.detail ?? "()", insert: `${c.label}()`, close: true })), q), m[2].length);
44223
+ return;
44224
+ }
44225
+ m = /\{\{faker\.(\w*)$/.exec(before);
44226
+ if (m) {
44227
+ const q = m[1].toLowerCase();
44228
+ const items2 = FAKER_NAMESPACES.filter((c) => c.label.toLowerCase().includes(q)).map((c) => ({ label: c.label, type: "property", insert: `${c.label}.` }));
44229
+ show(sortByMatch(items2, q), m[1].length);
44230
+ return;
44231
+ }
44232
+ m = /\{\{(dayjs\b[^}]*)$/.exec(before);
44233
+ if (m) {
44234
+ const q = m[1].toLowerCase();
44235
+ show(DAYJS_OPTIONS.filter((o) => o.label.toLowerCase().includes(q)).map((o) => ({ label: o.label, type: "function", insert: o.insert, close: true })), m[1].length);
44236
+ return;
44237
+ }
44238
+ m = /\{\{(\$?\w*)$/.exec(before);
44239
+ if (m) {
44240
+ const q = m[1].toLowerCase();
44241
+ const vars = varNames.filter((n) => n.toLowerCase().includes(q)).map((n) => ({ label: n, insert: n, type: "variable", close: true, boost: n.startsWith("$") ? 1 : 0 }));
44242
+ const starters = [
44243
+ { label: "faker", insert: "faker.", type: "property" },
44244
+ { label: "dayjs", insert: "dayjs().", type: "function" }
44245
+ ].filter((s) => s.label.includes(q));
44246
+ show([...sortByMatch(vars, q), ...starters], m[1].length);
44247
+ return;
44248
+ }
44249
+ if (staticSuggestions) {
44027
44250
  const q = val.toLowerCase();
44028
- const filtered = q ? staticSuggestions.filter((s) => s.toLowerCase().includes(q)).sort((a, b) => {
44029
- const aP = a.toLowerCase().startsWith(q) ? 0 : 1;
44030
- const bP = b.toLowerCase().startsWith(q) ? 0 : 1;
44031
- return aP - bP;
44032
- }).slice(0, 20) : staticSuggestions.slice(0, 20);
44033
- setSuggestions(filtered);
44251
+ const filtered = q ? staticSuggestions.filter((s) => s.toLowerCase().includes(q)).sort((a, b) => (a.toLowerCase().startsWith(q) ? 0 : 1) - (b.toLowerCase().startsWith(q) ? 0 : 1)).slice(0, 20) : staticSuggestions.slice(0, 20);
44252
+ partialLen.current = 0;
44253
+ setSuggestions(filtered.map((s) => ({ label: s, insert: s, type: "variable" })));
44034
44254
  setSuggestionMode("static");
44035
44255
  setActiveIndex(-1);
44036
- } else {
44037
- setSuggestions([]);
44256
+ return;
44038
44257
  }
44258
+ setSuggestions([]);
44039
44259
  }
44040
44260
  function handleChange(e) {
44041
44261
  const newVal = e.target.value;
@@ -44062,9 +44282,9 @@ function VarInput({ value: value2, onChange, className, wrapperClassName, static
44062
44282
  setSuggestions([]);
44063
44283
  }
44064
44284
  }
44065
- const apply = reactExports.useCallback((suggestion) => {
44285
+ function apply(item) {
44066
44286
  if (suggestionMode === "static") {
44067
- onChange(suggestion);
44287
+ onChange(item.insert);
44068
44288
  setSuggestions([]);
44069
44289
  return;
44070
44290
  }
@@ -44072,14 +44292,22 @@ function VarInput({ value: value2, onChange, className, wrapperClassName, static
44072
44292
  const cursor2 = el?.selectionStart ?? value2.length;
44073
44293
  const before = value2.slice(0, cursor2);
44074
44294
  const after = value2.slice(cursor2);
44075
- const match = /\{\{(\w*)$/.exec(before);
44076
- if (!match) return;
44077
- const newVal = before.slice(0, match.index) + `{{${suggestion}}}` + after;
44078
- const newCursor = match.index + suggestion.length + 4;
44295
+ const start = cursor2 - partialLen.current;
44296
+ const insert2 = item.insert + (item.close ? "}}" : "");
44297
+ const newVal = before.slice(0, start) + insert2 + after;
44298
+ const newCursor = start + insert2.length;
44079
44299
  onChange(newVal);
44080
- setSuggestions([]);
44081
- requestAnimationFrame(() => el?.setSelectionRange(newCursor, newCursor));
44082
- }, [suggestionMode, value2, onChange]);
44300
+ if (item.close) {
44301
+ setSuggestions([]);
44302
+ requestAnimationFrame(() => el?.setSelectionRange(newCursor, newCursor));
44303
+ } else {
44304
+ requestAnimationFrame(() => {
44305
+ el?.focus();
44306
+ el?.setSelectionRange(newCursor, newCursor);
44307
+ detectQuery(newVal, newCursor);
44308
+ });
44309
+ }
44310
+ }
44083
44311
  function handleBlur(e) {
44084
44312
  setTimeout(() => setSuggestions([]), 150);
44085
44313
  setShowPreview(false);
@@ -44719,7 +44947,7 @@ function BasicCredentialsFields({
44719
44947
  onClick: () => setKeychainOpen((o) => !o),
44720
44948
  className: "text-[10px] text-surface-500 hover:text-surface-300 text-left transition-colors w-fit",
44721
44949
  children: [
44722
- keychainOpen ? "▾" : "▸",
44950
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: keychainOpen ? "▾" : "▸" }),
44723
44951
  " ",
44724
44952
  t2("Store password in OS keychain instead")
44725
44953
  ]
@@ -44797,7 +45025,7 @@ function BearerPanel({
44797
45025
  onClick: () => setKeychainOpen((o) => !o),
44798
45026
  className: "text-[10px] text-surface-500 hover:text-surface-300 text-left transition-colors w-fit",
44799
45027
  children: [
44800
- keychainOpen ? "▾" : "▸",
45028
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: keychainOpen ? "▾" : "▸" }),
44801
45029
  " ",
44802
45030
  t2("Store in OS keychain instead")
44803
45031
  ]
@@ -44919,6 +45147,19 @@ function DataSetEditor({ ds, onChange, exportName, scopeLabel = "collection" })
44919
45147
  " ",
44920
45148
  t2("placeholders.")
44921
45149
  ] }),
45150
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-surface-600 text-[11px]", children: [
45151
+ t2("Cell values can also use variables and faker, e.g."),
45152
+ " ",
45153
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-surface-500", children: "{{baseUrl}}" }),
45154
+ ",",
45155
+ " ",
45156
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-surface-500", children: "{{$randomEmail}}" }),
45157
+ " ",
45158
+ t2("or"),
45159
+ " ",
45160
+ /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-surface-500", children: "{{faker.person.firstName()}}" }),
45161
+ "."
45162
+ ] }),
44922
45163
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
44923
45164
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: addColumn, className: "px-2.5 py-1 bg-surface-700 hover:bg-surface-600 rounded transition-colors", children: t2("+ Column") }),
44924
45165
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: addRow, disabled: !hasColumns, className: "px-2.5 py-1 bg-surface-700 hover:bg-surface-600 disabled:opacity-40 rounded transition-colors", children: t2("+ Row") }),
@@ -44957,11 +45198,12 @@ function DataSetEditor({ ds, onChange, exportName, scopeLabel = "collection" })
44957
45198
  ds.rows.map((row, ri) => /* @__PURE__ */ jsxRuntimeExports.jsxs("tr", { className: "group border-b border-surface-800/60 hover:bg-surface-800/30", children: [
44958
45199
  /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-2 py-1 text-surface-600", children: ri + 1 }),
44959
45200
  ds.columns.map((_, ci) => /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-1 py-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
44960
- "input",
45201
+ VarInput,
44961
45202
  {
44962
45203
  value: row[ci] ?? "",
44963
- onChange: (e) => setCell(ri, ci, e.target.value),
44964
- className: "w-full bg-surface-800 border border-transparent rounded px-1.5 py-0.5 font-mono focus:outline-none focus:border-blue-500 hover:border-surface-600"
45204
+ onChange: (v) => setCell(ri, ci, v),
45205
+ wrapperClassName: "w-full",
45206
+ className: "bg-surface-800 border border-transparent rounded px-1.5 py-0.5 font-mono focus:outline-none focus:border-blue-500 hover:border-surface-600"
44965
45207
  }
44966
45208
  ) }, ci)),
44967
45209
  /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-1 py-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => removeRow(ri), className: "text-surface-400 hover:text-red-400 opacity-0 group-hover:opacity-100 transition-all", children: "×" }) })
@@ -45574,36 +45816,43 @@ function buildFolderPlan(folder2, requests, collectionVars, filterTags, scopeId,
45574
45816
  for (const req of beforeAllHooks) {
45575
45817
  result.push(makeHook(req, collectionVars, "beforeAll", scopeId, ancestorIds, scopePath));
45576
45818
  }
45577
- for (const req of regularReqs) {
45578
- const tags2 = req.meta?.tags ?? [];
45579
- if (filterTags.length > 0 && !filterTags.some((t2) => tags2.includes(t2))) continue;
45580
- for (const w of allWrappers) {
45581
- for (const hookReq of w.before) {
45582
- result.push(makeHook(hookReq, collectionVars, "before", w.scopeId, w.ancestors, w.scopePath, req.id));
45819
+ const regularById = new Map(regularReqs.map((r) => [r.id, r]));
45820
+ const subById = new Map(folder2.folders.map((f) => [f.id, f]));
45821
+ for (const child of orderedChildren(folder2)) {
45822
+ if (child.type === "request") {
45823
+ const req = regularById.get(child.id);
45824
+ if (!req) continue;
45825
+ const tags2 = req.meta?.tags ?? [];
45826
+ if (filterTags.length > 0 && !filterTags.some((t2) => tags2.includes(t2))) continue;
45827
+ for (const w of allWrappers) {
45828
+ for (const hookReq of w.before) {
45829
+ result.push(makeHook(hookReq, collectionVars, "before", w.scopeId, w.ancestors, w.scopePath, req.id));
45830
+ }
45583
45831
  }
45584
- }
45585
- result.push({ request: req, collectionVars, scopeId, scopeAncestors: ancestorIds, scopePath });
45586
- for (const w of [...allWrappers].reverse()) {
45587
- for (const hookReq of w.after) {
45588
- result.push(makeHook(hookReq, collectionVars, "after", w.scopeId, w.ancestors, w.scopePath, req.id));
45832
+ result.push({ request: req, collectionVars, scopeId, scopeAncestors: ancestorIds, scopePath });
45833
+ for (const w of [...allWrappers].reverse()) {
45834
+ for (const hookReq of w.after) {
45835
+ result.push(makeHook(hookReq, collectionVars, "after", w.scopeId, w.ancestors, w.scopePath, req.id));
45836
+ }
45589
45837
  }
45838
+ } else {
45839
+ const sub = subById.get(child.id);
45840
+ if (!sub) continue;
45841
+ const folderTags = sub.tags ?? [];
45842
+ const effectiveFilter = filterTags.length === 0 ? filterTags : folderTags.some((t2) => filterTags.includes(t2)) ? [] : filterTags;
45843
+ result.push(...buildFolderPlan(
45844
+ sub,
45845
+ requests,
45846
+ collectionVars,
45847
+ effectiveFilter,
45848
+ sub.id,
45849
+ [...ancestorIds, scopeId],
45850
+ scopePath,
45851
+ allWrappers,
45852
+ false
45853
+ ));
45590
45854
  }
45591
45855
  }
45592
- for (const sub of folder2.folders) {
45593
- const folderTags = sub.tags ?? [];
45594
- const effectiveFilter = filterTags.length === 0 ? filterTags : folderTags.some((t2) => filterTags.includes(t2)) ? [] : filterTags;
45595
- result.push(...buildFolderPlan(
45596
- sub,
45597
- requests,
45598
- collectionVars,
45599
- effectiveFilter,
45600
- sub.id,
45601
- [...ancestorIds, scopeId],
45602
- scopePath,
45603
- allWrappers,
45604
- false
45605
- ));
45606
- }
45607
45856
  for (const req of afterAllHooks) {
45608
45857
  result.push(makeHook(req, collectionVars, "afterAll", scopeId, ancestorIds, scopePath));
45609
45858
  }
@@ -45754,6 +46003,42 @@ function buildRunPlan(collection2, folderId, filterTags) {
45754
46003
  }
45755
46004
  return result;
45756
46005
  }
46006
+ function expandRunPlanWithData(items2, ds) {
46007
+ if (!ds || ds.rows.length === 0) return items2;
46008
+ return ds.rows.flatMap((row, ri) => {
46009
+ const rowVars = {};
46010
+ ds.columns.forEach((col, ci) => {
46011
+ if (col) rowVars[col] = row[ci] ?? "";
46012
+ });
46013
+ return items2.map((item) => ({ ...item, dataRow: { ...item.dataRow, ...rowVars }, iterationLabel: `${ri + 1}/${ds.rows.length}` }));
46014
+ });
46015
+ }
46016
+ function nearestFolderDataSet(item, collection2) {
46017
+ const chain = [item.scopeId, ...item.scopeAncestors ?? []].filter(Boolean);
46018
+ for (const id2 of chain) {
46019
+ const f = findFolder$1(collection2.rootFolder, id2);
46020
+ if (f?.dataSet && f.dataSet.rows.length > 0) return f.dataSet;
46021
+ }
46022
+ return void 0;
46023
+ }
46024
+ function expandFolderDataSets(items2, collection2) {
46025
+ const out = [];
46026
+ for (const item of items2) {
46027
+ const ds = item.isHook ? void 0 : nearestFolderDataSet(item, collection2);
46028
+ if (!ds) {
46029
+ out.push(item);
46030
+ continue;
46031
+ }
46032
+ ds.rows.forEach((row, ri) => {
46033
+ const rowVars = {};
46034
+ ds.columns.forEach((col, ci) => {
46035
+ if (col) rowVars[col] = row[ci] ?? "";
46036
+ });
46037
+ out.push({ ...item, dataRow: { ...item.dataRow, ...rowVars }, iterationLabel: `${ri + 1}/${ds.rows.length}` });
46038
+ });
46039
+ }
46040
+ return out;
46041
+ }
45757
46042
  function hasContract(r) {
45758
46043
  const c = r.contract;
45759
46044
  return !!c && (c.statusCode != null || !!c.bodySchema || !!c.bodyMatcher || (c.headers?.length ?? 0) > 0 || (c.providerStates?.length ?? 0) > 0);
@@ -46204,8 +46489,6 @@ const AUTH_BADGE_LABELS = {
46204
46489
  function RequestRow({
46205
46490
  reqId,
46206
46491
  collectionId,
46207
- folderId,
46208
- reqIndex,
46209
46492
  name: name2,
46210
46493
  url,
46211
46494
  method,
@@ -46237,7 +46520,6 @@ function RequestRow({
46237
46520
  const [examplesOpen, setExamplesOpen] = reactExports.useState(true);
46238
46521
  const [addingTag, setAddingTag] = reactExports.useState(false);
46239
46522
  const [showSchemaSync, setShowSchemaSync] = reactExports.useState(false);
46240
- const [dropPos, setDropPos] = reactExports.useState(null);
46241
46523
  const dragCtx = reactExports.useContext(DragCtx);
46242
46524
  const sel = reactExports.useContext(SelectionCtx);
46243
46525
  const selected = sel.isSelected(collectionId, reqId);
@@ -46266,21 +46548,7 @@ function RequestRow({
46266
46548
  label: (hookType === ht ? "✓ " : " ") + t2(HOOK_LABELS[ht]),
46267
46549
  onClick: () => onSetHookType(hookType === ht ? void 0 : ht)
46268
46550
  }));
46269
- function handleDragOver(e) {
46270
- if (!dragCtx.dragging || dragCtx.dragging.type !== "request" || dragCtx.dragging.requestId === reqId) return;
46271
- e.preventDefault();
46272
- const rect = e.currentTarget.getBoundingClientRect();
46273
- setDropPos(e.clientY < rect.top + rect.height / 2 ? "before" : "after");
46274
- }
46275
- function handleDrop(e) {
46276
- e.preventDefault();
46277
- e.stopPropagation();
46278
- const insertIndex = dropPos === "before" ? reqIndex : reqIndex + 1;
46279
- dragCtx.onDropRequest(collectionId, folderId, insertIndex);
46280
- setDropPos(null);
46281
- }
46282
46551
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
46283
- dropPos === "before" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-0 inset-x-0 h-0.5 bg-blue-500 z-10 pointer-events-none" }),
46284
46552
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
46285
46553
  "div",
46286
46554
  {
@@ -46295,11 +46563,7 @@ function RequestRow({
46295
46563
  },
46296
46564
  onDragEnd: () => {
46297
46565
  dragCtx.setDragging(null);
46298
- setDropPos(null);
46299
46566
  },
46300
- onDragOver: handleDragOver,
46301
- onDragLeave: () => setDropPos(null),
46302
- onDrop: handleDrop,
46303
46567
  children: [
46304
46568
  /* @__PURE__ */ jsxRuntimeExports.jsx(
46305
46569
  "input",
@@ -46319,7 +46583,7 @@ function RequestRow({
46319
46583
  e.stopPropagation();
46320
46584
  setExamplesOpen((o) => !o);
46321
46585
  },
46322
- className: "shrink-0 w-3 text-surface-500 hover:text-white leading-none",
46586
+ className: "shrink-0 w-4 h-4 mt-0.5 inline-flex items-center justify-center text-surface-500 hover:text-white leading-none text-[22px]",
46323
46587
  title: examplesOpen ? t2("Hide examples") : t2("Show :count example(s)", { count: examples.length }),
46324
46588
  children: examplesOpen ? "▾" : "▸"
46325
46589
  }
@@ -46395,8 +46659,7 @@ function RequestRow({
46395
46659
  { type: "separator" },
46396
46660
  { type: "item", label: t2("Delete"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(TrashIcon, {}), danger: true, onClick: onDelete }
46397
46661
  ] }) }),
46398
- toast && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed bottom-4 right-4 z-[100] w-96", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Toast, { toast }) }),
46399
- dropPos === "after" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute bottom-0 inset-x-0 h-0.5 bg-blue-500 z-10 pointer-events-none" })
46662
+ toast && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed bottom-4 right-4 z-[100] w-96", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Toast, { toast }) })
46400
46663
  ]
46401
46664
  }
46402
46665
  ),
@@ -46493,7 +46756,33 @@ function ConfirmDialog({ message, onConfirm, onCancel }) {
46493
46756
  const DragCtx = reactExports.createContext({ dragging: null, setDragging: () => {
46494
46757
  }, onDropRequest: () => {
46495
46758
  }, onDropFolder: () => {
46759
+ }, onReorderChild: () => {
46496
46760
  } });
46761
+ function DropLine({ collectionId, parentFolderId, index: index2, indent }) {
46762
+ const dragCtx = reactExports.useContext(DragCtx);
46763
+ const [over, setOver] = reactExports.useState(false);
46764
+ if (!dragCtx.dragging) return null;
46765
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
46766
+ "div",
46767
+ {
46768
+ style: { paddingLeft: indent },
46769
+ className: "relative h-2 -my-1 z-20",
46770
+ onDragOver: (e) => {
46771
+ e.preventDefault();
46772
+ e.stopPropagation();
46773
+ setOver(true);
46774
+ },
46775
+ onDragLeave: () => setOver(false),
46776
+ onDrop: (e) => {
46777
+ e.preventDefault();
46778
+ e.stopPropagation();
46779
+ setOver(false);
46780
+ dragCtx.onReorderChild(collectionId, parentFolderId, index2);
46781
+ },
46782
+ children: over && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute inset-x-2 top-1/2 -translate-y-1/2 h-0.5 bg-blue-500 rounded pointer-events-none" })
46783
+ }
46784
+ );
46785
+ }
46497
46786
  const SelectionCtx = reactExports.createContext({ active: false, isSelected: () => false, toggle: () => {
46498
46787
  }, clear: () => {
46499
46788
  } });
@@ -46613,6 +46902,7 @@ function CollectionTree() {
46613
46902
  const deleteRequest = useStore((s) => s.deleteRequest);
46614
46903
  const duplicateRequest = useStore((s) => s.duplicateRequest);
46615
46904
  const duplicateCollection = useStore((s) => s.duplicateCollection);
46905
+ const toggleCollectionDisabled = useStore((s) => s.toggleCollectionDisabled);
46616
46906
  const duplicateFolder = useStore((s) => s.duplicateFolder);
46617
46907
  const updateFolderTags = useStore((s) => s.updateFolderTags);
46618
46908
  const updateRequestTags = useStore((s) => s.updateRequestTags);
@@ -46620,6 +46910,7 @@ function CollectionTree() {
46620
46910
  const openRunner = useStore((s) => s.openRunner);
46621
46911
  const moveRequest = useStore((s) => s.moveRequest);
46622
46912
  const moveFolder = useStore((s) => s.moveFolder);
46913
+ const reorderChild = useStore((s) => s.reorderChild);
46623
46914
  const colList = Object.values(collections);
46624
46915
  const [query, setQuery] = reactExports.useState("");
46625
46916
  const q = query.trim().toLowerCase();
@@ -46664,7 +46955,17 @@ function CollectionTree() {
46664
46955
  moveFolder(dragging.collectionId, dragging.folderId, destParentFolderId, destIndex);
46665
46956
  setDragging(null);
46666
46957
  }
46667
- return /* @__PURE__ */ jsxRuntimeExports.jsx(DragCtx.Provider, { value: { dragging, setDragging, onDropRequest, onDropFolder }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectionCtx.Provider, { value: selectionCtx, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0 select-none", children: [
46958
+ function onReorderChild(destCollectionId, destParentFolderId, destIndex) {
46959
+ if (!dragging) return;
46960
+ if (dragging.collectionId === destCollectionId) {
46961
+ const ref2 = dragging.type === "folder" ? { type: "folder", id: dragging.folderId } : { type: "request", id: dragging.requestId };
46962
+ reorderChild(destCollectionId, ref2, destParentFolderId, destIndex);
46963
+ } else if (dragging.type === "request") {
46964
+ moveRequest(dragging.collectionId, dragging.requestId, destCollectionId, destParentFolderId);
46965
+ }
46966
+ setDragging(null);
46967
+ }
46968
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(DragCtx.Provider, { value: { dragging, setDragging, onDropRequest, onDropFolder, onReorderChild }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(SelectionCtx.Provider, { value: selectionCtx, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0 select-none", children: [
46668
46969
  pendingConfirm && /* @__PURE__ */ jsxRuntimeExports.jsx(
46669
46970
  ConfirmDialog,
46670
46971
  {
@@ -46732,6 +47033,7 @@ function CollectionTree() {
46732
47033
  onRenameCollection: (name2) => renameCollection(col.id, name2),
46733
47034
  onDeleteCollection: () => confirmThen(t2('Delete collection ":name"?', { name: col.name }), () => deleteCollection(col.id)),
46734
47035
  onDuplicateCollection: () => duplicateCollection(col.id),
47036
+ onToggleCollectionDisabled: () => toggleCollectionDisabled(col.id),
46735
47037
  onRenameFolder: (folderId, name2) => renameFolder(col.id, folderId, name2),
46736
47038
  onDeleteFolder: (folderId) => confirmThen(t2("Delete this folder and all its requests?"), () => deleteFolder(col.id, folderId)),
46737
47039
  onDuplicateFolder: (folderId) => duplicateFolder(col.id, folderId),
@@ -46826,6 +47128,7 @@ function CollectionNode({
46826
47128
  onRenameCollection,
46827
47129
  onDeleteCollection,
46828
47130
  onDuplicateCollection,
47131
+ onToggleCollectionDisabled,
46829
47132
  onRenameFolder,
46830
47133
  onDeleteFolder,
46831
47134
  onDuplicateFolder,
@@ -46858,7 +47161,7 @@ function CollectionNode({
46858
47161
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
46859
47162
  "div",
46860
47163
  {
46861
- className: `group flex items-start gap-1 px-2 py-1.5 cursor-pointer hover:bg-surface-800 transition-colors ${isActive ? "text-[var(--text-primary)]" : "text-surface-400"} ${dropOver ? "outline outline-1 outline-blue-500 rounded" : ""}`,
47164
+ className: `group flex items-center gap-1 px-2 py-1.5 cursor-pointer hover:bg-surface-800 transition-colors ${isActive ? "text-[var(--text-primary)]" : "text-surface-400"} ${col.disabled ? "opacity-50" : ""} ${dropOver ? "outline outline-1 outline-blue-500 rounded" : ""}`,
46862
47165
  onClick: () => {
46863
47166
  onSelectCollection();
46864
47167
  setExpanded((e) => !e);
@@ -46875,7 +47178,7 @@ function CollectionNode({
46875
47178
  else dragCtx.onDropRequest(col.id, col.rootFolder.id);
46876
47179
  },
46877
47180
  children: [
46878
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] w-3 text-center shrink-0 mt-0.5", children: expanded ? "▾" : "▸" }),
47181
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none w-4 h-4 shrink-0 flex items-center justify-center", children: expanded ? "▾" : "▸" }),
46879
47182
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0", children: renaming ? /* @__PURE__ */ jsxRuntimeExports.jsx(
46880
47183
  InlineEdit,
46881
47184
  {
@@ -46888,7 +47191,10 @@ function CollectionNode({
46888
47191
  className: "w-full text-xs",
46889
47192
  validate: (v) => existingCollectionNames.filter((n) => n !== col.name).includes(v) ? t2('":name" already exists', { name: v }) : null
46890
47193
  }
46891
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold truncate block", children: col.name }) }),
47194
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-semibold truncate block", children: [
47195
+ col.name,
47196
+ col.disabled && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-1.5 text-[9px] uppercase tracking-wider text-surface-500 border border-surface-700 rounded px-1 py-px", children: t2("Disabled") })
47197
+ ] }) }),
46892
47198
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(DotsBtn, { items: [
46893
47199
  { type: "item", label: t2("Run collection"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(PlayIcon, {}), onClick: onRunCollection },
46894
47200
  { type: "separator" },
@@ -46902,6 +47208,7 @@ function CollectionNode({
46902
47208
  { type: "item", label: t2("Settings"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(GearIcon, {}), onClick: () => setShowSettings(true) },
46903
47209
  { type: "item", label: t2("Sync schemas"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowSchemaSync(true) },
46904
47210
  ...cloudEnabled() ? [{ type: "item", label: t2("Push contract to cloud"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowPushContract(true) }] : [],
47211
+ { type: "item", label: col.disabled ? t2("Enable") : t2("Disable"), onClick: onToggleCollectionDisabled },
46905
47212
  { type: "item", label: t2("Rename"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(PencilIcon, {}), onClick: () => setRenaming(true) },
46906
47213
  { type: "item", label: t2("Duplicate"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyIcon, {}), onClick: onDuplicateCollection },
46907
47214
  { type: "separator" },
@@ -46951,8 +47258,6 @@ function CollectionNode({
46951
47258
  function FolderRow({
46952
47259
  folder: folder2,
46953
47260
  collectionId,
46954
- parentFolderId,
46955
- folderIndex,
46956
47261
  depth,
46957
47262
  expandCtrl,
46958
47263
  onAddRequest,
@@ -46975,7 +47280,7 @@ function FolderRow({
46975
47280
  const [showPushContract, setShowPushContract] = reactExports.useState(false);
46976
47281
  const [addingTag, setAddingTag] = reactExports.useState(false);
46977
47282
  const folderCollection = useStore((s) => s.collections[collectionId]?.data);
46978
- const [dropPos, setDropPos] = reactExports.useState(null);
47283
+ const [dropInside, setDropInside] = reactExports.useState(false);
46979
47284
  const dragCtx = reactExports.useContext(DragCtx);
46980
47285
  const tags2 = folder2.tags ?? [];
46981
47286
  const indent = depth * 12 + 8;
@@ -46984,40 +47289,22 @@ function FolderRow({
46984
47289
  if (!dragCtx.dragging) return;
46985
47290
  if (dragCtx.dragging.type === "folder" && dragCtx.dragging.folderId === folder2.id) return;
46986
47291
  e.preventDefault();
46987
- const rect = e.currentTarget.getBoundingClientRect();
46988
- const y = e.clientY - rect.top;
46989
- const zone = y / rect.height;
46990
- if (dragCtx.dragging.type === "folder") {
46991
- if (zone < 0.25) setDropPos("before");
46992
- else if (zone > 0.75) setDropPos("after");
46993
- else setDropPos("inside");
46994
- } else {
46995
- setDropPos("inside");
46996
- }
47292
+ setDropInside(true);
46997
47293
  }
46998
47294
  function handleFolderDrop(e) {
46999
47295
  e.preventDefault();
47000
47296
  e.stopPropagation();
47297
+ setDropInside(false);
47001
47298
  if (!dragCtx.dragging) return;
47002
- if (dragCtx.dragging.type === "folder") {
47003
- if (dropPos === "inside") {
47004
- dragCtx.onDropFolder(collectionId, folder2.id);
47005
- } else {
47006
- const insertIndex = dropPos === "before" ? folderIndex : folderIndex + 1;
47007
- dragCtx.onDropFolder(collectionId, parentFolderId, insertIndex);
47008
- }
47009
- } else {
47010
- dragCtx.onDropRequest(collectionId, folder2.id);
47011
- }
47012
- setDropPos(null);
47299
+ if (dragCtx.dragging.type === "folder") dragCtx.onDropFolder(collectionId, folder2.id);
47300
+ else dragCtx.onDropRequest(collectionId, folder2.id);
47013
47301
  }
47014
47302
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [
47015
- dropPos === "before" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute top-0 inset-x-0 h-0.5 bg-blue-500 z-10 pointer-events-none" }),
47016
47303
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
47017
47304
  "div",
47018
47305
  {
47019
47306
  draggable: true,
47020
- className: `group flex items-start gap-1 py-1 hover:bg-surface-800 transition-colors cursor-pointer text-surface-400 ${dropPos === "inside" ? "outline outline-1 outline-blue-500 rounded" : ""}`,
47307
+ className: `group flex items-center gap-1 py-1 hover:bg-surface-800 transition-colors cursor-pointer text-surface-400 ${dropInside ? "outline outline-1 outline-blue-500 rounded" : ""}`,
47021
47308
  style: { paddingLeft: indent },
47022
47309
  onClick: () => setExpanded((e) => !e),
47023
47310
  onDragStart: (e) => {
@@ -47027,15 +47314,14 @@ function FolderRow({
47027
47314
  },
47028
47315
  onDragEnd: () => {
47029
47316
  dragCtx.setDragging(null);
47030
- setDropPos(null);
47317
+ setDropInside(false);
47031
47318
  },
47032
47319
  onDragOver: handleFolderDragOver,
47033
- onDragLeave: () => setDropPos(null),
47320
+ onDragLeave: () => setDropInside(false),
47034
47321
  onDrop: handleFolderDrop,
47035
47322
  children: [
47036
- dropPos === "after" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "absolute bottom-0 inset-x-0 h-0.5 bg-blue-500 z-10 pointer-events-none" }),
47037
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] w-3 text-center shrink-0 mt-0.5", children: expanded ? "▾" : "▸" }),
47038
- /* @__PURE__ */ jsxRuntimeExports.jsx(FolderIcon, { className: `shrink-0 mt-0.5 ${hasInheritedConfig ? "text-blue-500" : "text-amber-600"}` }),
47323
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none w-4 h-4 shrink-0 flex items-center justify-center", children: expanded ? "▾" : "▸" }),
47324
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FolderIcon, { className: `shrink-0 ${hasInheritedConfig ? "text-blue-500" : "text-amber-600"}` }),
47039
47325
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
47040
47326
  renaming ? /* @__PURE__ */ jsxRuntimeExports.jsx(
47041
47327
  InlineEdit,
@@ -47137,94 +47423,101 @@ function FolderContents({
47137
47423
  const renameExample = useStore((s) => s.renameExample);
47138
47424
  const deleteExample = useStore((s) => s.deleteExample);
47139
47425
  const duplicateExample = useStore((s) => s.duplicateExample);
47140
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
47141
- folder2.folders.map((sub, subIndex) => /* @__PURE__ */ jsxRuntimeExports.jsx(
47142
- FolderRow,
47143
- {
47144
- folder: sub,
47145
- collectionId,
47146
- parentFolderId: folder2.id,
47147
- folderIndex: subIndex,
47148
- depth: depth + 1,
47149
- expandCtrl,
47150
- onAddRequest: () => onAddRequest(sub.id),
47151
- onAddFolder: () => onAddFolder(sub.id, "New Folder"),
47152
- onRename: (name2) => onRenameFolder(sub.id, name2),
47153
- onDelete: () => onDeleteFolder(sub.id),
47154
- onDuplicate: () => onDuplicateFolder(sub.id),
47155
- onUpdateTags: (tags2) => onUpdateFolderTags(sub.id, tags2),
47156
- onRun: () => onRunFolder(sub.id),
47157
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
47158
- FolderContents,
47159
- {
47160
- folder: sub,
47161
- collectionId,
47162
- requests,
47163
- activeRequestId,
47164
- depth: depth + 1,
47165
- expandCtrl,
47166
- newRequestId,
47167
- onSelectRequest,
47168
- onAddRequest,
47169
- onAddFolder,
47170
- onRenameFolder,
47171
- onDeleteFolder,
47172
- onDuplicateFolder,
47173
- onRenameRequest,
47174
- onDeleteRequest,
47175
- onDuplicateRequest,
47176
- onUpdateFolderTags,
47177
- onUpdateRequestTags,
47178
- onSetRequestHookType,
47179
- onToggleRequestDisabled,
47180
- onRunFolder
47181
- }
47182
- )
47183
- },
47184
- sub.id
47185
- )),
47186
- folder2.requestIds.map((reqId, reqIndex) => {
47187
- const req = requests[reqId];
47188
- if (!req) return null;
47426
+ const dropIndent = (depth + 1) * 12 + 8;
47427
+ const renderChild = (child) => {
47428
+ if (child.type === "folder") {
47429
+ const sub = folder2.folders.find((f) => f.id === child.id);
47430
+ if (!sub) return null;
47189
47431
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
47190
- RequestRow,
47432
+ FolderRow,
47191
47433
  {
47192
- reqId: req.id,
47434
+ folder: sub,
47193
47435
  collectionId,
47194
- folderId: folder2.id,
47195
- reqIndex,
47196
- name: req.name,
47197
- url: req.url,
47198
- method: req.method,
47199
- protocol: req.protocol,
47200
- authType: req.auth.type,
47201
- hookType: req.hookType,
47202
- disabled: req.disabled,
47203
- tags: req.meta?.tags ?? [],
47204
- isActive: req.id === activeRequestId,
47205
- autoRename: req.id === newRequestId,
47206
- indent: (depth + 1) * 12 + 8,
47207
- examples: req.examples?.map((e) => ({ id: e.id, name: e.name })),
47208
- activeExampleId: req.id === activeRequestId ? activeExampleId : null,
47209
- onSelect: () => onSelectRequest(req.id),
47210
- onRename: (name2) => onRenameRequest(req.id, name2),
47211
- onDelete: () => onDeleteRequest(req.id),
47212
- onDuplicate: () => onDuplicateRequest(req.id),
47213
- onUpdateTags: (tags2) => onUpdateRequestTags(req.id, tags2),
47214
- onSetHookType: (ht) => onSetRequestHookType(req.id, ht),
47215
- onToggleDisabled: () => onToggleRequestDisabled(req.id),
47216
- onAddExample: () => {
47217
- const exId = addExampleFromRequest(req.id);
47218
- if (exId) openExample(req.id, collectionId, exId);
47219
- },
47220
- onOpenExample: (exId) => openExample(req.id, collectionId, exId),
47221
- onRenameExample: (exId, name2) => renameExample(req.id, exId, name2),
47222
- onDeleteExample: (exId) => deleteExample(req.id, exId),
47223
- onDuplicateExample: (exId) => duplicateExample(req.id, exId)
47224
- },
47225
- req.id
47436
+ parentFolderId: folder2.id,
47437
+ depth: depth + 1,
47438
+ expandCtrl,
47439
+ onAddRequest: () => onAddRequest(sub.id),
47440
+ onAddFolder: () => onAddFolder(sub.id, "New Folder"),
47441
+ onRename: (name2) => onRenameFolder(sub.id, name2),
47442
+ onDelete: () => onDeleteFolder(sub.id),
47443
+ onDuplicate: () => onDuplicateFolder(sub.id),
47444
+ onUpdateTags: (tags2) => onUpdateFolderTags(sub.id, tags2),
47445
+ onRun: () => onRunFolder(sub.id),
47446
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
47447
+ FolderContents,
47448
+ {
47449
+ folder: sub,
47450
+ collectionId,
47451
+ requests,
47452
+ activeRequestId,
47453
+ depth: depth + 1,
47454
+ expandCtrl,
47455
+ newRequestId,
47456
+ onSelectRequest,
47457
+ onAddRequest,
47458
+ onAddFolder,
47459
+ onRenameFolder,
47460
+ onDeleteFolder,
47461
+ onDuplicateFolder,
47462
+ onRenameRequest,
47463
+ onDeleteRequest,
47464
+ onDuplicateRequest,
47465
+ onUpdateFolderTags,
47466
+ onUpdateRequestTags,
47467
+ onSetRequestHookType,
47468
+ onToggleRequestDisabled,
47469
+ onRunFolder
47470
+ }
47471
+ )
47472
+ }
47226
47473
  );
47227
- })
47474
+ }
47475
+ const req = requests[child.id];
47476
+ if (!req) return null;
47477
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
47478
+ RequestRow,
47479
+ {
47480
+ reqId: req.id,
47481
+ collectionId,
47482
+ folderId: folder2.id,
47483
+ name: req.name,
47484
+ url: req.url,
47485
+ method: req.method,
47486
+ protocol: req.protocol,
47487
+ authType: req.auth.type,
47488
+ hookType: req.hookType,
47489
+ disabled: req.disabled,
47490
+ tags: req.meta?.tags ?? [],
47491
+ isActive: req.id === activeRequestId,
47492
+ autoRename: req.id === newRequestId,
47493
+ indent: (depth + 1) * 12 + 8,
47494
+ examples: req.examples?.map((e) => ({ id: e.id, name: e.name })),
47495
+ activeExampleId: req.id === activeRequestId ? activeExampleId : null,
47496
+ onSelect: () => onSelectRequest(req.id),
47497
+ onRename: (name2) => onRenameRequest(req.id, name2),
47498
+ onDelete: () => onDeleteRequest(req.id),
47499
+ onDuplicate: () => onDuplicateRequest(req.id),
47500
+ onUpdateTags: (tags2) => onUpdateRequestTags(req.id, tags2),
47501
+ onSetHookType: (ht) => onSetRequestHookType(req.id, ht),
47502
+ onToggleDisabled: () => onToggleRequestDisabled(req.id),
47503
+ onAddExample: () => {
47504
+ const exId = addExampleFromRequest(req.id);
47505
+ if (exId) openExample(req.id, collectionId, exId);
47506
+ },
47507
+ onOpenExample: (exId) => openExample(req.id, collectionId, exId),
47508
+ onRenameExample: (exId, name2) => renameExample(req.id, exId, name2),
47509
+ onDeleteExample: (exId) => deleteExample(req.id, exId),
47510
+ onDuplicateExample: (exId) => duplicateExample(req.id, exId)
47511
+ }
47512
+ );
47513
+ };
47514
+ const children = orderedChildren(folder2);
47515
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
47516
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DropLine, { collectionId, parentFolderId: folder2.id, index: 0, indent: dropIndent }),
47517
+ children.map((child, k) => /* @__PURE__ */ jsxRuntimeExports.jsxs(React$2.Fragment, { children: [
47518
+ renderChild(child),
47519
+ /* @__PURE__ */ jsxRuntimeExports.jsx(DropLine, { collectionId, parentFolderId: folder2.id, index: k + 1, indent: dropIndent })
47520
+ ] }, child.type + ":" + child.id))
47228
47521
  ] });
47229
47522
  }
47230
47523
  function safeDecode(s) {
@@ -52982,8 +53275,8 @@ function jsonWithComments() {
52982
53275
  function xmlWithComments() {
52983
53276
  return [xml(), commentKeymap];
52984
53277
  }
52985
- const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-CkrzU3x2.js"), true ? [] : void 0, import.meta.url).then((m) => ({ default: m.GraphQLEditor })));
52986
- const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-KEOZCmWl.js"), true ? [] : void 0, import.meta.url).then((m) => ({ default: m.SoapEditor })));
53278
+ const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-DITvPhtG.js"), true ? [] : void 0, import.meta.url).then((m) => ({ default: m.GraphQLEditor })));
53279
+ const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-Bf-oE-rS.js"), true ? [] : void 0, import.meta.url).then((m) => ({ default: m.SoapEditor })));
52987
53280
  function BodyTab({ request: request2, onChange }) {
52988
53281
  const t2 = useT();
52989
53282
  const editorFallback = /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 text-xs text-surface-500", children: t2("Loading editor…") });
@@ -54130,7 +54423,7 @@ function ScriptsTab({ request: request2, onChange }) {
54130
54423
  onClick: () => setSnippetsOpen(false),
54131
54424
  className: "flex items-center gap-1 text-[10px] font-semibold text-surface-400 uppercase tracking-wider mb-2 hover:text-white transition-colors w-full",
54132
54425
  children: [
54133
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "▾" }),
54426
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: "▾" }),
54134
54427
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Quick inserts") })
54135
54428
  ]
54136
54429
  }
@@ -54151,7 +54444,7 @@ function ScriptsTab({ request: request2, onChange }) {
54151
54444
  className: "w-full text-left text-xs font-medium text-surface-400 hover:text-white flex items-center justify-between py-0.5",
54152
54445
  children: [
54153
54446
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2(group.group) }),
54154
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px]", children: expandedGroup === group.group ? "▾" : "▸" })
54447
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: expandedGroup === group.group ? "▾" : "▸" })
54155
54448
  ]
54156
54449
  }
54157
54450
  ),
@@ -55169,10 +55462,10 @@ var scope = {};
55169
55462
  }
55170
55463
  exports$1.and = and;
55171
55464
  const orCode = mappend(exports$1.operators.OR);
55172
- function or(...args) {
55465
+ function or2(...args) {
55173
55466
  return args.reduce(orCode);
55174
55467
  }
55175
- exports$1.or = or;
55468
+ exports$1.or = or2;
55176
55469
  function mappend(op) {
55177
55470
  return (x, y) => x === code_12.nil ? y : y === code_12.nil ? x : (0, code_12._)`${par(x)} ${op} ${par(y)}`;
55178
55471
  }
@@ -61117,7 +61410,7 @@ function TraceRow({ trace, onCopy }) {
61117
61410
  onClick: () => setOpen((v) => !v),
61118
61411
  className: "w-full flex items-center gap-3 px-3 py-1.5 text-left hover:bg-surface-800/60 transition-colors font-mono text-[11px]",
61119
61412
  children: [
61120
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-surface-600 w-3", children: open2 ? "▾" : "▸" }),
61413
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-surface-600 w-3 text-[22px] leading-none", children: open2 ? "▾" : "▸" }),
61121
61414
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `shrink-0 font-bold w-9 ${statusTone(trace.status, trace.finding)}`, children: trace.status || t2("ERR") }),
61122
61415
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-surface-300", children: trace.mutation.target }),
61123
61416
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500 truncate", children: trace.mutation.kind }),
@@ -61431,6 +61724,25 @@ function RequestBuilder({ request: request2 }) {
61431
61724
  return next;
61432
61725
  });
61433
61726
  }
61727
+ const applicableDataSet = reactExports.useMemo(() => {
61728
+ const col = activeCollectionId ? collections[activeCollectionId]?.data : null;
61729
+ if (!col) return null;
61730
+ const folder2 = findFolderContaining(col.rootFolder, request2.id);
61731
+ if (folder2?.dataSet && folder2.dataSet.rows.length > 0) return folder2.dataSet;
61732
+ if (col.dataSet && col.dataSet.rows.length > 0) return col.dataSet;
61733
+ return null;
61734
+ }, [activeCollectionId, collections, request2.id]);
61735
+ const [dataRowIdx, setDataRowIdx] = reactExports.useState(-1);
61736
+ function selectedDataRow() {
61737
+ if (!applicableDataSet || dataRowIdx < 0) return void 0;
61738
+ const row = applicableDataSet.rows[dataRowIdx];
61739
+ if (!row) return void 0;
61740
+ const dr = {};
61741
+ applicableDataSet.columns.forEach((c, ci) => {
61742
+ if (c) dr[c] = row[ci] ?? "";
61743
+ });
61744
+ return dr;
61745
+ }
61434
61746
  function update(patch) {
61435
61747
  if (activeAppTab?.exampleId) updateExampleRequest(request2.id, activeAppTab.exampleId, patch);
61436
61748
  else updateRequest(request2.id, patch);
@@ -61550,7 +61862,8 @@ function RequestBuilder({ request: request2 }) {
61550
61862
  request: mergedRequest,
61551
61863
  collectionVars: { ...collectionVars, ...freshSessionVars },
61552
61864
  globals: liveGlobals,
61553
- streamId
61865
+ streamId,
61866
+ ...selectedDataRow() ? { dataRow: selectedDataRow() } : {}
61554
61867
  });
61555
61868
  } finally {
61556
61869
  finishLiveStream(streamId);
@@ -61669,135 +61982,156 @@ function RequestBuilder({ request: request2 }) {
61669
61982
  request2.examples?.find((e) => e.id === activeAppTab.exampleId)?.name ?? ""
61670
61983
  ] })
61671
61984
  ] }) }),
61672
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-4 py-2 flex-shrink-0", children: [
61673
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-surface-800 border border-surface-700 rounded overflow-hidden text-xs font-bold flex-shrink-0", children: [
61674
- /* @__PURE__ */ jsxRuntimeExports.jsx(
61675
- "button",
61985
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 px-4 py-2 flex-shrink-0", children: [
61986
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
61987
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-surface-800 border border-surface-700 rounded overflow-hidden text-xs font-bold flex-shrink-0", children: [
61988
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
61989
+ "button",
61990
+ {
61991
+ onClick: () => update({ protocol: "http" }),
61992
+ className: `px-2 py-1.5 transition-colors ${!isWs && !isSoap && !isGrpc ? "bg-blue-600 text-white" : "text-surface-500 hover:text-white"}`,
61993
+ title: t2("HTTP request"),
61994
+ children: "HTTP"
61995
+ }
61996
+ ),
61997
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
61998
+ "button",
61999
+ {
62000
+ onClick: () => update({ protocol: "websocket" }),
62001
+ className: `px-2 py-1.5 transition-colors ${isWs ? "bg-cyan-700 text-cyan-200" : "text-surface-500 hover:text-white"}`,
62002
+ title: t2("WebSocket"),
62003
+ children: "WS"
62004
+ }
62005
+ ),
62006
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
62007
+ "button",
62008
+ {
62009
+ onClick: () => {
62010
+ update({
62011
+ protocol: "soap",
62012
+ method: "POST",
62013
+ body: request2.body.mode === "soap" ? request2.body : { ...request2.body, mode: "soap", soap: request2.body.soap ?? { wsdlUrl: "", envelope: "" } }
62014
+ });
62015
+ if (activeTabId) setTabRequestTab(activeTabId, "body");
62016
+ },
62017
+ className: `px-2 py-1.5 transition-colors ${isSoap ? "bg-amber-700 text-amber-100" : "text-surface-500 hover:text-white"}`,
62018
+ title: t2("SOAP - endpoint and method are derived from the WSDL"),
62019
+ children: "SOAP"
62020
+ }
62021
+ ),
62022
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
62023
+ "button",
62024
+ {
62025
+ onClick: () => update({
62026
+ protocol: "grpc",
62027
+ body: request2.body.mode === "grpc" ? request2.body : { ...request2.body, mode: "grpc", grpc: request2.body.grpc ?? { message: "{}", metadata: [], plaintext: false } }
62028
+ }),
62029
+ className: `px-2 py-1.5 transition-colors ${isGrpc ? "bg-violet-700 text-violet-100" : "text-surface-500 hover:text-white"}`,
62030
+ title: t2("gRPC - proto-defined services over HTTP/2"),
62031
+ children: "gRPC"
62032
+ }
62033
+ )
62034
+ ] }),
62035
+ !isWs && !isSoap && !isGrpc && (customVerb ? /* @__PURE__ */ jsxRuntimeExports.jsx(
62036
+ "input",
61676
62037
  {
61677
- onClick: () => update({ protocol: "http" }),
61678
- className: `px-2 py-1.5 transition-colors ${!isWs && !isSoap && !isGrpc ? "bg-blue-600 text-white" : "text-surface-500 hover:text-white"}`,
61679
- title: t2("HTTP request"),
61680
- children: "HTTP"
62038
+ autoFocus: true,
62039
+ value: request2.method,
62040
+ onChange: (e) => update({ method: e.target.value.toUpperCase() }),
62041
+ onBlur: () => setCustomVerb(false),
62042
+ onKeyDown: (e) => {
62043
+ if (e.key === "Enter") {
62044
+ e.preventDefault();
62045
+ setCustomVerb(false);
62046
+ }
62047
+ },
62048
+ placeholder: t2("VERB"),
62049
+ title: t2("Type any HTTP method"),
62050
+ className: "w-24 bg-surface-800 border border-blue-500 rounded px-2 py-1.5 text-xs font-bold uppercase focus:outline-none text-fuchsia-400 placeholder-surface-600"
61681
62051
  }
61682
- ),
61683
- /* @__PURE__ */ jsxRuntimeExports.jsx(
61684
- "button",
62052
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
62053
+ "select",
61685
62054
  {
61686
- onClick: () => update({ protocol: "websocket" }),
61687
- className: `px-2 py-1.5 transition-colors ${isWs ? "bg-cyan-700 text-cyan-200" : "text-surface-500 hover:text-white"}`,
61688
- title: t2("WebSocket"),
61689
- children: "WS"
62055
+ value: METHODS.includes(request2.method) ? request2.method : "__current__",
62056
+ onChange: (e) => {
62057
+ if (e.target.value === "__custom__") setCustomVerb(true);
62058
+ else if (e.target.value !== "__current__") update({ method: e.target.value });
62059
+ },
62060
+ className: `bg-surface-800 border border-surface-700 rounded px-2 py-1.5 text-xs font-bold focus:outline-none focus:border-blue-500 ${METHOD_COLORS[request2.method] ?? "text-fuchsia-400"}`,
62061
+ children: [
62062
+ METHODS.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: m, className: "text-white", children: m }, m)),
62063
+ !METHODS.includes(request2.method) && /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "__current__", className: "text-white", children: request2.method }),
62064
+ /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "__custom__", className: "text-white", children: t2("Custom…") })
62065
+ ]
61690
62066
  }
61691
- ),
61692
- /* @__PURE__ */ jsxRuntimeExports.jsx(
61693
- "button",
62067
+ )),
62068
+ isSoap && /* @__PURE__ */ jsxRuntimeExports.jsx(
62069
+ "span",
61694
62070
  {
61695
- onClick: () => {
61696
- update({
61697
- protocol: "soap",
61698
- method: "POST",
61699
- body: request2.body.mode === "soap" ? request2.body : { ...request2.body, mode: "soap", soap: request2.body.soap ?? { wsdlUrl: "", envelope: "" } }
61700
- });
61701
- if (activeTabId) setTabRequestTab(activeTabId, "body");
61702
- },
61703
- className: `px-2 py-1.5 transition-colors ${isSoap ? "bg-amber-700 text-amber-100" : "text-surface-500 hover:text-white"}`,
61704
- title: t2("SOAP - endpoint and method are derived from the WSDL"),
61705
- children: "SOAP"
62071
+ className: "bg-surface-900 border border-surface-700 rounded px-2 py-1.5 text-xs font-bold text-amber-400 select-none",
62072
+ title: t2("SOAP requests are always POST"),
62073
+ children: "POST"
61706
62074
  }
61707
62075
  ),
61708
- /* @__PURE__ */ jsxRuntimeExports.jsx(
61709
- "button",
62076
+ isGrpc && /* @__PURE__ */ jsxRuntimeExports.jsx(
62077
+ "span",
61710
62078
  {
61711
- onClick: () => update({
61712
- protocol: "grpc",
61713
- body: request2.body.mode === "grpc" ? request2.body : { ...request2.body, mode: "grpc", grpc: request2.body.grpc ?? { message: "{}", metadata: [], plaintext: false } }
61714
- }),
61715
- className: `px-2 py-1.5 transition-colors ${isGrpc ? "bg-violet-700 text-violet-100" : "text-surface-500 hover:text-white"}`,
61716
- title: t2("gRPC - proto-defined services over HTTP/2"),
62079
+ className: "bg-surface-900 border border-surface-700 rounded px-2 py-1.5 text-xs font-bold text-violet-400 select-none",
62080
+ title: t2("gRPC target is host:port"),
61717
62081
  children: "gRPC"
61718
62082
  }
61719
62083
  )
61720
62084
  ] }),
61721
- !isWs && !isSoap && !isGrpc && (customVerb ? /* @__PURE__ */ jsxRuntimeExports.jsx(
61722
- "input",
61723
- {
61724
- autoFocus: true,
61725
- value: request2.method,
61726
- onChange: (e) => update({ method: e.target.value.toUpperCase() }),
61727
- onBlur: () => setCustomVerb(false),
61728
- onKeyDown: (e) => {
61729
- if (e.key === "Enter") {
61730
- e.preventDefault();
61731
- setCustomVerb(false);
61732
- }
61733
- },
61734
- placeholder: t2("VERB"),
61735
- title: t2("Type any HTTP method"),
61736
- className: "w-24 bg-surface-800 border border-blue-500 rounded px-2 py-1.5 text-xs font-bold uppercase focus:outline-none text-fuchsia-400 placeholder-surface-600"
61737
- }
61738
- ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
61739
- "select",
61740
- {
61741
- value: METHODS.includes(request2.method) ? request2.method : "__current__",
61742
- onChange: (e) => {
61743
- if (e.target.value === "__custom__") setCustomVerb(true);
61744
- else if (e.target.value !== "__current__") update({ method: e.target.value });
61745
- },
61746
- className: `bg-surface-800 border border-surface-700 rounded px-2 py-1.5 text-xs font-bold focus:outline-none focus:border-blue-500 ${METHOD_COLORS[request2.method] ?? "text-fuchsia-400"}`,
61747
- children: [
61748
- METHODS.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: m, className: "text-white", children: m }, m)),
61749
- !METHODS.includes(request2.method) && /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "__current__", className: "text-white", children: request2.method }),
61750
- /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "__custom__", className: "text-white", children: t2("Custom…") })
61751
- ]
61752
- }
61753
- )),
61754
- isSoap && /* @__PURE__ */ jsxRuntimeExports.jsx(
61755
- "span",
61756
- {
61757
- className: "bg-surface-900 border border-surface-700 rounded px-2 py-1.5 text-xs font-bold text-amber-400 select-none",
61758
- title: t2("SOAP requests are always POST"),
61759
- children: "POST"
61760
- }
61761
- ),
61762
- isGrpc && /* @__PURE__ */ jsxRuntimeExports.jsx(
61763
- "span",
61764
- {
61765
- className: "bg-surface-900 border border-surface-700 rounded px-2 py-1.5 text-xs font-bold text-violet-400 select-none",
61766
- title: t2("gRPC target is host:port"),
61767
- children: "gRPC"
61768
- }
61769
- ),
61770
- /* @__PURE__ */ jsxRuntimeExports.jsx(
61771
- VarInput,
61772
- {
61773
- value: request2.url,
61774
- onChange: (url) => update({ url }),
61775
- onPaste: handleUrlPaste,
61776
- placeholder: isWs ? "ws://example.com/socket" : isSoap ? t2("Endpoint (auto-filled from WSDL <soap:address>)") : isGrpc ? "localhost:50051" : "https://api.example.com/endpoint",
61777
- wrapperClassName: "flex-1",
61778
- className: `border rounded px-3 py-1.5 text-sm focus:outline-none focus:border-blue-500 font-mono placeholder-surface-700 ${isSoap ? "bg-surface-900 border-amber-900/50 text-surface-300" : "bg-surface-800 border-surface-700"}`
61779
- }
61780
- ),
61781
- !isWs && !isGrpc && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
62085
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
61782
62086
  /* @__PURE__ */ jsxRuntimeExports.jsx(
61783
- "button",
62087
+ VarInput,
61784
62088
  {
61785
- onClick: toggleRunHooks,
61786
- title: runHooks ? t2("Hooks enabled - click to disable") : t2("Hooks disabled - click to enable"),
61787
- className: `px-2 py-1.5 rounded text-xs font-medium transition-colors border ${runHooks ? "border-violet-500 text-violet-400 hover:bg-violet-500/10" : "border-surface-700 text-surface-500 hover:text-surface-300"}`,
61788
- children: t2("hooks")
62089
+ value: request2.url,
62090
+ onChange: (url) => update({ url }),
62091
+ onPaste: handleUrlPaste,
62092
+ placeholder: isWs ? "ws://example.com/socket" : isSoap ? t2("Endpoint (auto-filled from WSDL <soap:address>)") : isGrpc ? "localhost:50051" : "https://api.example.com/endpoint",
62093
+ wrapperClassName: "flex-1",
62094
+ className: `border rounded px-3 py-1.5 text-sm focus:outline-none focus:border-blue-500 font-mono placeholder-surface-700 ${isSoap ? "bg-surface-900 border-amber-900/50 text-surface-300" : "bg-surface-800 border-surface-700"}`
61789
62095
  }
61790
62096
  ),
61791
- /* @__PURE__ */ jsxRuntimeExports.jsx(
61792
- "button",
62097
+ !isWs && !isGrpc && applicableDataSet && /* @__PURE__ */ jsxRuntimeExports.jsxs(
62098
+ "select",
61793
62099
  {
61794
- onClick: sendRequest,
61795
- disabled: isSending || !request2.url,
61796
- title: t2("Send (Cmd/Ctrl+Enter)"),
61797
- className: "px-4 py-1.5 bg-blue-600 hover:bg-blue-500 disabled:bg-surface-800 disabled:text-surface-400 rounded text-sm font-medium transition-colors min-w-[72px]",
61798
- children: isSending ? "..." : t2("Send")
62100
+ value: dataRowIdx,
62101
+ onChange: (e) => setDataRowIdx(Number(e.target.value)),
62102
+ title: t2("Run this request with the variables from one data table row"),
62103
+ className: "bg-surface-800 border border-surface-700 rounded px-2 py-1.5 text-xs focus:outline-none focus:border-blue-500 max-w-[150px]",
62104
+ style: { color: "var(--text-primary)" },
62105
+ children: [
62106
+ /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: -1, children: t2("No data row") }),
62107
+ applicableDataSet.rows.map((row, ri) => /* @__PURE__ */ jsxRuntimeExports.jsxs("option", { value: ri, children: [
62108
+ t2("Row :n", { n: ri + 1 }),
62109
+ row[0] ? ` · ${row[0]}` : ""
62110
+ ] }, ri))
62111
+ ]
61799
62112
  }
61800
- )
62113
+ ),
62114
+ !isWs && !isGrpc && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
62115
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
62116
+ "button",
62117
+ {
62118
+ onClick: toggleRunHooks,
62119
+ title: runHooks ? t2("Hooks enabled - click to disable") : t2("Hooks disabled - click to enable"),
62120
+ className: `px-2 py-1.5 rounded text-xs font-medium transition-colors border ${runHooks ? "border-violet-500 text-violet-400 hover:bg-violet-500/10" : "border-surface-700 text-surface-500 hover:text-surface-300"}`,
62121
+ children: t2("hooks")
62122
+ }
62123
+ ),
62124
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
62125
+ "button",
62126
+ {
62127
+ onClick: sendRequest,
62128
+ disabled: isSending || !request2.url,
62129
+ title: t2("Send (Cmd/Ctrl+Enter)"),
62130
+ className: "px-4 py-1.5 bg-blue-600 hover:bg-blue-500 disabled:bg-surface-800 disabled:text-surface-400 rounded text-sm font-medium transition-colors min-w-[72px]",
62131
+ children: isSending ? "..." : t2("Send")
62132
+ }
62133
+ )
62134
+ ] })
61801
62135
  ] })
61802
62136
  ] }),
61803
62137
  showFuzz && /* @__PURE__ */ jsxRuntimeExports.jsx(FuzzModal, { request: request2, onClose: () => setShowFuzz(false) }),
@@ -61877,7 +62211,7 @@ function JsonNode({ nodeKey, value: value2, path, depth, onLeaf }) {
61877
62211
  onClick: () => setExpanded((v) => !v),
61878
62212
  className: "flex items-center gap-1.5 py-0.5 pl-1 rounded hover:bg-surface-800/40 w-full text-left",
61879
62213
  children: [
61880
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[10px] w-3 shrink-0 text-center", children: expanded ? "▾" : "▸" }),
62214
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[22px] leading-none w-3 shrink-0 text-center", children: expanded ? "▾" : "▸" }),
61881
62215
  keySpan,
61882
62216
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-xs", children: summary })
61883
62217
  ]
@@ -61942,7 +62276,7 @@ function XmlNode({ element, depth, onLeaf }) {
61942
62276
  onClick: () => setExpanded((v) => !v),
61943
62277
  className: "flex items-center gap-1.5 py-0.5 pl-1 rounded hover:bg-surface-800/40 w-full text-left",
61944
62278
  children: [
61945
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[10px] w-3 shrink-0 text-center", children: expanded ? "▾" : "▸" }),
62279
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[22px] leading-none w-3 shrink-0 text-center", children: expanded ? "▾" : "▸" }),
61946
62280
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-300 font-mono text-xs", children: [
61947
62281
  "<",
61948
62282
  tag,
@@ -62159,7 +62493,7 @@ function AssertMenu({ state, onClose, onConfirm }) {
62159
62493
  onClick: () => setJpOpen((o) => !o),
62160
62494
  className: "w-full text-left text-xs text-blue-400 hover:text-blue-300 hover:bg-surface-800 rounded px-2 py-1.5 transition-colors flex items-center gap-1",
62161
62495
  children: [
62162
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: jpOpen ? "▾" : "▸" }),
62496
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: jpOpen ? "▾" : "▸" }),
62163
62497
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("JSONPath assert (with filter)") })
62164
62498
  ]
62165
62499
  }
@@ -62728,7 +63062,7 @@ function HookResultsPanel({ results }) {
62728
63062
  onClick: () => setOpen((o) => !o),
62729
63063
  className: "w-full flex items-center gap-2 px-4 py-1.5 text-xs hover:bg-surface-800/30 transition-colors",
62730
63064
  children: [
62731
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-400", children: open2 ? "▾" : "▸" }),
63065
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-400 text-[22px] leading-none", children: open2 ? "▾" : "▸" }),
62732
63066
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium text-surface-400", children: t2("Hooks") }),
62733
63067
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500", children: t2(":count ran", { count: results.length }) }),
62734
63068
  failed > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-1 px-1.5 py-0.5 rounded text-[10px] bg-red-800/60 text-red-300", children: t2(":count failed", { count: failed }) })
@@ -62737,14 +63071,14 @@ function HookResultsPanel({ results }) {
62737
63071
  ),
62738
63072
  open2 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-4 pb-2 flex flex-col gap-0.5", children: results.map((r, i) => {
62739
63073
  const badge = HOOK_BADGE$1[r.hookType ?? ""];
62740
- const hasDetail = (r.consoleOutput?.length ?? 0) > 0 || (r.testResults?.length ?? 0) > 0 || r.error || r.preScriptError || r.postScriptError;
63074
+ const hasDetail2 = (r.consoleOutput?.length ?? 0) > 0 || (r.testResults?.length ?? 0) > 0 || r.error || r.preScriptError || r.postScriptError;
62741
63075
  const isExpanded = expanded.has(r.requestId + i);
62742
63076
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs", children: [
62743
63077
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
62744
63078
  "div",
62745
63079
  {
62746
- className: `flex items-center gap-2 py-0.5 ${hasDetail ? "cursor-pointer hover:bg-surface-800/20 rounded px-1 -mx-1" : ""}`,
62747
- onClick: () => hasDetail && toggle(r.requestId + i),
63080
+ className: `flex items-center gap-2 py-0.5 ${hasDetail2 ? "cursor-pointer hover:bg-surface-800/20 rounded px-1 -mx-1" : ""}`,
63081
+ onClick: () => hasDetail2 && toggle(r.requestId + i),
62748
63082
  children: [
62749
63083
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-1.5 h-1.5 rounded-full shrink-0 ${r.status === "passed" ? "bg-emerald-500" : r.status === "failed" ? "bg-red-500" : "bg-orange-500"}` }),
62750
63084
  badge && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[9px] font-bold px-1 py-0.5 rounded uppercase tracking-wide shrink-0 ${badge.cls}`, children: t2(badge.label) }),
@@ -62754,7 +63088,7 @@ function HookResultsPanel({ results }) {
62754
63088
  r.durationMs,
62755
63089
  "ms"
62756
63090
  ] }),
62757
- hasDetail && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500 shrink-0", children: isExpanded ? "▾" : "▸" })
63091
+ hasDetail2 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500 shrink-0 text-[22px] leading-none", children: isExpanded ? "▾" : "▸" })
62758
63092
  ]
62759
63093
  }
62760
63094
  ),
@@ -63177,6 +63511,88 @@ function ConsolePanel({ scriptResult }) {
63177
63511
  )) })
63178
63512
  ] });
63179
63513
  }
63514
+ function OverflowMenu({ button, ariaLabel, title: title2, wrapperClassName = "", buttonClassName = "", align = "right", children }) {
63515
+ const [open2, setOpen] = reactExports.useState(false);
63516
+ const wrapRef = reactExports.useRef(null);
63517
+ const menuRef = reactExports.useRef(null);
63518
+ const btnRef = reactExports.useRef(null);
63519
+ const menuId = reactExports.useId();
63520
+ function items2() {
63521
+ if (!menuRef.current) return [];
63522
+ return Array.from(menuRef.current.querySelectorAll('[role="menuitem"]')).filter((el) => el.offsetParent !== null && !el.hasAttribute("disabled"));
63523
+ }
63524
+ reactExports.useEffect(() => {
63525
+ if (!open2) return;
63526
+ function onDown(e) {
63527
+ if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
63528
+ }
63529
+ document.addEventListener("mousedown", onDown, true);
63530
+ return () => document.removeEventListener("mousedown", onDown, true);
63531
+ }, [open2]);
63532
+ reactExports.useEffect(() => {
63533
+ if (open2) items2()[0]?.focus();
63534
+ }, [open2]);
63535
+ function onMenuKeyDown(e) {
63536
+ const list = items2();
63537
+ const idx = list.indexOf(document.activeElement);
63538
+ if (e.key === "ArrowDown") {
63539
+ e.preventDefault();
63540
+ list[(idx + 1) % list.length]?.focus();
63541
+ } else if (e.key === "ArrowUp") {
63542
+ e.preventDefault();
63543
+ list[(idx - 1 + list.length) % list.length]?.focus();
63544
+ } else if (e.key === "Home") {
63545
+ e.preventDefault();
63546
+ list[0]?.focus();
63547
+ } else if (e.key === "End") {
63548
+ e.preventDefault();
63549
+ list[list.length - 1]?.focus();
63550
+ } else if (e.key === "Escape") {
63551
+ e.preventDefault();
63552
+ setOpen(false);
63553
+ btnRef.current?.focus();
63554
+ } else if (e.key === "Tab") {
63555
+ setOpen(false);
63556
+ }
63557
+ }
63558
+ function onTriggerKeyDown(e) {
63559
+ if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
63560
+ e.preventDefault();
63561
+ setOpen(true);
63562
+ }
63563
+ }
63564
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { ref: wrapRef, className: `relative ${wrapperClassName}`, children: [
63565
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
63566
+ "button",
63567
+ {
63568
+ ref: btnRef,
63569
+ type: "button",
63570
+ "aria-haspopup": "menu",
63571
+ "aria-expanded": open2,
63572
+ "aria-controls": open2 ? menuId : void 0,
63573
+ "aria-label": ariaLabel,
63574
+ title: title2 ?? ariaLabel,
63575
+ onClick: () => setOpen((o) => !o),
63576
+ onKeyDown: onTriggerKeyDown,
63577
+ className: buttonClassName,
63578
+ children: button
63579
+ }
63580
+ ),
63581
+ open2 && /* @__PURE__ */ jsxRuntimeExports.jsx(
63582
+ "div",
63583
+ {
63584
+ ref: menuRef,
63585
+ id: menuId,
63586
+ role: "menu",
63587
+ "aria-label": ariaLabel,
63588
+ onKeyDown: onMenuKeyDown,
63589
+ onClick: () => setOpen(false),
63590
+ className: `absolute top-full mt-1 z-50 min-w-[150px] bg-surface-900 border border-surface-700 rounded-lg shadow-2xl py-1 flex flex-col ${align === "right" ? "right-0" : "left-0"}`,
63591
+ children
63592
+ }
63593
+ )
63594
+ ] });
63595
+ }
63180
63596
  function header(headers, name2) {
63181
63597
  const lower = name2.toLowerCase();
63182
63598
  for (const [k, v] of Object.entries(headers)) {
@@ -63318,7 +63734,7 @@ function HistoryTabRow({ entry, onLoad, onResend }) {
63318
63734
  const reqBody = requestBodyText(entry.request.body);
63319
63735
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-surface-800", children: [
63320
63736
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-4 py-2 hover:bg-surface-800/40", children: [
63321
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setOpen((o) => !o), className: "text-surface-600 text-xs w-3 shrink-0", children: open2 ? "▾" : "▸" }),
63737
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setOpen((o) => !o), className: "text-surface-600 text-[22px] leading-none w-3 shrink-0", children: open2 ? "▾" : "▸" }),
63322
63738
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] font-bold font-mono shrink-0 w-10 ${getMethodColor(entry.request.method)}`, children: entry.request.method }),
63323
63739
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-xs font-bold font-mono shrink-0 w-8 ${getStatusColor(entry.response.status)}`, children: entry.response.status || "ERR" }),
63324
63740
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-surface-400 shrink-0", children: [
@@ -63358,6 +63774,26 @@ function HistoryTabRow({ entry, onLoad, onResend }) {
63358
63774
  ] })
63359
63775
  ] });
63360
63776
  }
63777
+ const TAB_INLINE_VIS = {
63778
+ error: "flex",
63779
+ request: "flex",
63780
+ body: "flex",
63781
+ headers: "flex",
63782
+ tests: "hidden @min-[520px]:flex",
63783
+ console: "hidden @min-[520px]:flex",
63784
+ history: "hidden @min-[720px]:flex",
63785
+ http: "hidden @min-[720px]:flex"
63786
+ };
63787
+ const TAB_MENU_VIS = {
63788
+ error: "hidden",
63789
+ request: "hidden",
63790
+ body: "hidden",
63791
+ headers: "hidden",
63792
+ tests: "flex @min-[520px]:hidden",
63793
+ console: "flex @min-[520px]:hidden",
63794
+ history: "flex @min-[720px]:hidden",
63795
+ http: "flex @min-[720px]:hidden"
63796
+ };
63361
63797
  function ResponseViewer() {
63362
63798
  const t2 = useT();
63363
63799
  const activeTab = useStore((s) => s.tabs.find((t22) => t22.id === s.activeTabId));
@@ -63500,112 +63936,223 @@ function ResponseViewer() {
63500
63936
  },
63501
63937
  entry.id
63502
63938
  )) });
63503
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col", children: [
63504
- hookResults && hookResults.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(HookResultsPanel, { results: hookResults }),
63505
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4 px-4 py-1.5 border-b border-surface-800 flex-shrink-0 overflow-x-auto", children: [
63506
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `text-sm font-bold shrink-0 ${getStatusColor(response.status)}`, children: [
63507
- response.status,
63508
- " ",
63509
- response.statusText
63510
- ] }),
63511
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-surface-400 shrink-0", children: [
63512
- response.durationMs,
63513
- "ms"
63514
- ] }),
63515
- /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-surface-400 shrink-0", children: [
63516
- (response.bodySize / 1024).toFixed(1),
63517
- " KB"
63518
- ] }),
63519
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex gap-0 ml-2 shrink-0", children: tabList.map((t22) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
63939
+ function renderTabButton(def2, variant) {
63940
+ const active2 = tab === def2.id;
63941
+ const badge = def2.badge !== void 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] px-1 rounded ${def2.error ? "bg-red-800 text-red-200" : def2.id === "tests" && passedCount < totalCount ? "bg-red-800 text-red-200" : "bg-surface-700 text-white"}`, children: def2.badge }) : null;
63942
+ if (variant === "menu") {
63943
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
63520
63944
  "button",
63521
63945
  {
63522
- onClick: () => setTab(t22.id),
63523
- className: `px-3 py-1 text-xs rounded transition-colors flex items-center gap-1 ${tab === t22.id ? "bg-surface-800 text-white" : "text-surface-400 hover:text-white"}`,
63946
+ role: "menuitem",
63947
+ tabIndex: -1,
63948
+ onClick: () => setTab(def2.id),
63949
+ className: `${active2 ? "hidden" : TAB_MENU_VIS[def2.id]} w-full items-center justify-between gap-3 px-3 py-1.5 text-xs ${active2 ? "" : "text-surface-300 hover:bg-surface-800 hover:text-white"}`,
63524
63950
  children: [
63525
- t22.label,
63526
- t22.badge !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] px-1 rounded ${t22.error ? "bg-red-800 text-red-200" : t22.id === "tests" && passedCount < totalCount ? "bg-red-800 text-red-200" : "bg-surface-700 text-white"}`, children: t22.badge })
63951
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: def2.label }),
63952
+ badge
63527
63953
  ]
63528
63954
  },
63529
- t22.id
63530
- )) }),
63531
- !response.error && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ml-auto flex items-center gap-1 shrink-0", children: [
63532
- assertToast.toast && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-emerald-400 font-medium px-1", children: assertToast.toast.msg }),
63533
- contractToast.toast && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-blue-400 font-medium px-1", children: contractToast.toast.msg }),
63534
- tab === "body" && supportsTree && !response.streamed && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex rounded overflow-hidden border border-surface-800 mr-1", children: [
63955
+ def2.id
63956
+ );
63957
+ }
63958
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
63959
+ "button",
63960
+ {
63961
+ role: "tab",
63962
+ "aria-selected": active2,
63963
+ onClick: () => setTab(def2.id),
63964
+ className: `${active2 ? "flex" : TAB_INLINE_VIS[def2.id]} px-3 py-1 text-xs rounded transition-colors items-center gap-1 ${active2 ? "bg-surface-800 text-white" : "text-surface-400 hover:text-white"}`,
63965
+ children: [
63966
+ def2.label,
63967
+ badge
63968
+ ]
63969
+ },
63970
+ def2.id
63971
+ );
63972
+ }
63973
+ function onTablistKey(e) {
63974
+ if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(e.key)) return;
63975
+ const btns = Array.from(e.currentTarget.querySelectorAll('[role="tab"]')).filter((el) => el.offsetParent !== null);
63976
+ const idx = btns.indexOf(document.activeElement);
63977
+ e.preventDefault();
63978
+ if (e.key === "ArrowRight") btns[(idx + 1) % btns.length]?.focus();
63979
+ else if (e.key === "ArrowLeft") btns[(idx - 1 + btns.length) % btns.length]?.focus();
63980
+ else if (e.key === "Home") btns[0]?.focus();
63981
+ else btns[btns.length - 1]?.focus();
63982
+ }
63983
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col", children: [
63984
+ hookResults && hookResults.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(HookResultsPanel, { results: hookResults }),
63985
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "@container flex-shrink-0 border-b border-surface-800", children: [
63986
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-4 py-1.5 min-w-0", children: [
63987
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 shrink-0", children: [
63988
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `text-sm font-bold ${getStatusColor(response.status)}`, children: [
63989
+ response.status,
63990
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "hidden @min-[440px]:inline", children: [
63991
+ " ",
63992
+ response.statusText
63993
+ ] })
63994
+ ] }),
63995
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-surface-400", children: [
63996
+ response.durationMs,
63997
+ "ms"
63998
+ ] }),
63999
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-surface-400", children: [
64000
+ (response.bodySize / 1024).toFixed(1),
64001
+ " KB"
64002
+ ] })
64003
+ ] }),
64004
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { role: "tablist", "aria-label": t2("Response sections"), onKeyDown: onTablistKey, className: "flex items-center gap-0 min-w-0 ml-1", children: [
64005
+ tabList.map((def2) => renderTabButton(def2, "inline")),
64006
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
64007
+ OverflowMenu,
64008
+ {
64009
+ wrapperClassName: "flex @min-[720px]:hidden",
64010
+ buttonClassName: "px-2 py-1 text-xs rounded text-surface-400 hover:text-white hover:bg-surface-800 flex items-center gap-1",
64011
+ button: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
64012
+ t2("More"),
64013
+ " ",
64014
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", className: "text-[22px] leading-none", children: "▾" })
64015
+ ] }),
64016
+ ariaLabel: t2("More response sections"),
64017
+ align: "left",
64018
+ children: tabList.map((def2) => renderTabButton(def2, "menu"))
64019
+ }
64020
+ )
64021
+ ] })
64022
+ ] }),
64023
+ !response.error && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-4 py-1 border-t border-surface-800/60 min-w-0", children: [
64024
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] uppercase tracking-wider text-surface-500 font-medium truncate", children: tabList.find((x) => x.id === tab)?.label ?? t2("Body") }),
64025
+ assertToast.toast && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-emerald-400 font-medium px-1 shrink-0", children: assertToast.toast.msg }),
64026
+ contractToast.toast && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-blue-400 font-medium px-1 shrink-0", children: contractToast.toast.msg }),
64027
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ml-auto flex items-center gap-1 shrink-0", children: [
64028
+ tab === "body" && supportsTree && !response.streamed && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { role: "group", "aria-label": t2("Body view mode"), className: "flex rounded overflow-hidden border border-surface-800 mr-1", children: [
64029
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
64030
+ "button",
64031
+ {
64032
+ onClick: () => setBodyView("tree"),
64033
+ "aria-pressed": bodyView === "tree",
64034
+ className: `px-2 py-0.5 text-[10px] transition-colors ${bodyView === "tree" ? "bg-surface-700 text-white" : "text-surface-600 hover:text-white"}`,
64035
+ title: t2("Interactive tree view - click values to add assertions"),
64036
+ children: t2("Tree")
64037
+ }
64038
+ ),
64039
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
64040
+ "button",
64041
+ {
64042
+ onClick: () => setBodyView("raw"),
64043
+ "aria-pressed": bodyView === "raw",
64044
+ className: `px-2 py-0.5 text-[10px] transition-colors ${bodyView === "raw" ? "bg-surface-700 text-white" : "text-surface-600 hover:text-white"}`,
64045
+ title: t2("Raw body view"),
64046
+ children: t2("Raw")
64047
+ }
64048
+ ),
64049
+ showTable && /* @__PURE__ */ jsxRuntimeExports.jsx(
64050
+ "button",
64051
+ {
64052
+ onClick: () => setBodyView("table"),
64053
+ "aria-pressed": bodyView === "table",
64054
+ className: `px-2 py-0.5 text-[10px] transition-colors ${bodyView === "table" ? "bg-surface-700 text-white" : "text-surface-600 hover:text-white"}`,
64055
+ title: t2("Show an array in the response as a sortable table"),
64056
+ children: t2("Table")
64057
+ }
64058
+ )
64059
+ ] }),
63535
64060
  /* @__PURE__ */ jsxRuntimeExports.jsx(
63536
64061
  "button",
63537
64062
  {
63538
- onClick: () => setBodyView("tree"),
63539
- className: `px-2 py-0.5 text-[10px] transition-colors ${bodyView === "tree" ? "bg-surface-700 text-white" : "text-surface-600 hover:text-white"}`,
63540
- title: t2("Interactive tree view - click values to add assertions"),
63541
- children: t2("Tree")
64063
+ onClick: () => setPinned(response),
64064
+ "aria-pressed": pinnedResponse === response,
64065
+ title: t2("Pin this response to compare against later responses"),
64066
+ className: `px-2 py-0.5 text-[10px] rounded transition-colors shrink-0 ${pinnedResponse === response ? "bg-blue-700 text-white" : "bg-surface-800 hover:bg-surface-700"}`,
64067
+ children: t2("Pin")
63542
64068
  }
63543
64069
  ),
63544
- /* @__PURE__ */ jsxRuntimeExports.jsx(
64070
+ pinnedResponse && /* @__PURE__ */ jsxRuntimeExports.jsx(
63545
64071
  "button",
63546
64072
  {
63547
- onClick: () => setBodyView("raw"),
63548
- className: `px-2 py-0.5 text-[10px] transition-colors ${bodyView === "raw" ? "bg-surface-700 text-white" : "text-surface-600 hover:text-white"}`,
63549
- title: t2("Raw body view"),
63550
- children: t2("Raw")
64073
+ onClick: () => setDiffMode((d) => !d),
64074
+ "aria-pressed": diffMode,
64075
+ title: t2("Toggle diff view against pinned response"),
64076
+ className: `hidden @min-[350px]:flex px-2 py-0.5 text-[10px] rounded transition-colors ${diffMode ? "bg-amber-700 text-white" : "bg-surface-800 hover:bg-surface-700"}`,
64077
+ children: t2("Diff")
64078
+ }
64079
+ ),
64080
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
64081
+ "button",
64082
+ {
64083
+ onClick: saveAsContract,
64084
+ className: "hidden @min-[350px]:flex px-2 py-0.5 text-[10px] bg-surface-800 hover:bg-surface-700 rounded transition-colors",
64085
+ title: t2("Capture this response as a contract expectation"),
64086
+ children: [
64087
+ "↓ ",
64088
+ t2("Contract")
64089
+ ]
63551
64090
  }
63552
64091
  ),
63553
- showTable && /* @__PURE__ */ jsxRuntimeExports.jsx(
64092
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
63554
64093
  "button",
63555
64094
  {
63556
- onClick: () => setBodyView("table"),
63557
- className: `px-2 py-0.5 text-[10px] transition-colors ${bodyView === "table" ? "bg-surface-700 text-white" : "text-surface-600 hover:text-white"}`,
63558
- title: t2("Show an array in the response as a sortable table"),
63559
- children: t2("Table")
64095
+ onClick: () => setShowMockModal(true),
64096
+ className: "hidden @min-[350px]:flex px-2 py-0.5 text-[10px] bg-surface-800 hover:bg-surface-700 rounded transition-colors",
64097
+ title: t2("Save this response as a mock route"),
64098
+ children: [
64099
+ "↓ ",
64100
+ t2("Mock")
64101
+ ]
64102
+ }
64103
+ ),
64104
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
64105
+ OverflowMenu,
64106
+ {
64107
+ wrapperClassName: "flex @min-[350px]:hidden",
64108
+ buttonClassName: "px-1.5 py-1 text-[10px] rounded bg-surface-800 hover:bg-surface-700 text-surface-300 flex items-center",
64109
+ button: /* @__PURE__ */ jsxRuntimeExports.jsx(DotsHorizontalIcon, {}),
64110
+ ariaLabel: t2("More actions"),
64111
+ children: [
64112
+ pinnedResponse && /* @__PURE__ */ jsxRuntimeExports.jsx(
64113
+ "button",
64114
+ {
64115
+ role: "menuitem",
64116
+ tabIndex: -1,
64117
+ onClick: () => setDiffMode((d) => !d),
64118
+ className: "flex @min-[350px]:hidden w-full items-center gap-2 px-3 py-1.5 text-xs text-surface-300 hover:bg-surface-800 hover:text-white",
64119
+ children: t2("Diff")
64120
+ }
64121
+ ),
64122
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
64123
+ "button",
64124
+ {
64125
+ role: "menuitem",
64126
+ tabIndex: -1,
64127
+ onClick: saveAsContract,
64128
+ className: "flex @min-[350px]:hidden w-full items-center gap-2 px-3 py-1.5 text-xs text-surface-300 hover:bg-surface-800 hover:text-white",
64129
+ children: [
64130
+ "↓ ",
64131
+ t2("Contract")
64132
+ ]
64133
+ }
64134
+ ),
64135
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
64136
+ "button",
64137
+ {
64138
+ role: "menuitem",
64139
+ tabIndex: -1,
64140
+ onClick: () => setShowMockModal(true),
64141
+ className: "flex @min-[350px]:hidden w-full items-center gap-2 px-3 py-1.5 text-xs text-surface-300 hover:bg-surface-800 hover:text-white",
64142
+ children: [
64143
+ "↓ ",
64144
+ t2("Mock")
64145
+ ]
64146
+ }
64147
+ )
64148
+ ]
63560
64149
  }
63561
64150
  )
63562
- ] }),
63563
- /* @__PURE__ */ jsxRuntimeExports.jsx(
63564
- "button",
63565
- {
63566
- onClick: () => setPinned(response),
63567
- title: t2("Pin this response to compare against later responses"),
63568
- className: `px-2 py-0.5 text-[10px] rounded transition-colors ${pinnedResponse === response ? "bg-blue-700 text-white" : "bg-surface-800 hover:bg-surface-700"}`,
63569
- children: t2("Pin")
63570
- }
63571
- ),
63572
- pinnedResponse && /* @__PURE__ */ jsxRuntimeExports.jsx(
63573
- "button",
63574
- {
63575
- onClick: () => setDiffMode((d) => !d),
63576
- title: t2("Toggle diff view against pinned response"),
63577
- className: `px-2 py-0.5 text-[10px] rounded transition-colors ${diffMode ? "bg-amber-700 text-white" : "bg-surface-800 hover:bg-surface-700"}`,
63578
- children: t2("Diff")
63579
- }
63580
- ),
63581
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
63582
- "button",
63583
- {
63584
- onClick: saveAsContract,
63585
- className: "px-2 py-0.5 text-[10px] bg-surface-800 hover:bg-surface-700 rounded transition-colors",
63586
- title: t2("Capture this response as a contract expectation"),
63587
- children: [
63588
- "↓ ",
63589
- t2("Contract")
63590
- ]
63591
- }
63592
- ),
63593
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
63594
- "button",
63595
- {
63596
- onClick: () => setShowMockModal(true),
63597
- className: "px-2 py-0.5 text-[10px] bg-surface-800 hover:bg-surface-700 rounded transition-colors",
63598
- title: t2("Save this response as a mock route"),
63599
- children: [
63600
- "↓ ",
63601
- t2("Mock")
63602
- ]
63603
- }
63604
- )
64151
+ ] })
63605
64152
  ] })
63606
64153
  ] }),
63607
64154
  showMockModal && /* @__PURE__ */ jsxRuntimeExports.jsx(SaveAsMockModal, { onClose: () => setShowMockModal(false) }),
63608
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 flex flex-col overflow-y-auto", children: response.error ? tab === "request" ? /* @__PURE__ */ jsxRuntimeExports.jsx(RequestPanel, { sentRequest }) : tab === "history" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: historyContent }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col p-4 gap-2", children: [
64155
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { role: "tabpanel", "aria-label": tabList.find((x) => x.id === tab)?.label, className: "flex-1 min-h-0 flex flex-col overflow-y-auto", children: response.error ? tab === "request" ? /* @__PURE__ */ jsxRuntimeExports.jsx(RequestPanel, { sentRequest }) : tab === "history" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: historyContent }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col p-4 gap-2", children: [
63609
64156
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-red-400 text-sm font-medium", children: t2("Request failed") }),
63610
64157
  /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs text-red-300 whitespace-pre-wrap", children: response.error })
63611
64158
  ] }) : diffMode && pinnedResponse ? /* @__PURE__ */ jsxRuntimeExports.jsx(DiffView, { pinned: pinnedResponse, current: response }) : tab === "body" && response.streamed ? /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -64285,7 +64832,7 @@ function WelcomeScreen() {
64285
64832
  )
64286
64833
  ] }),
64287
64834
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-400 text-sm max-w-sm", children: t2("Local-first API testing with Robot Framework & Playwright code generation. Secrets stay on your machine.") }),
64288
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t2("version :version", { version: "0.5.8" }) })
64835
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t2("version :version", { version: "0.6.0" }) })
64289
64836
  ] }),
64290
64837
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 w-64", children: [
64291
64838
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -67538,6 +68085,68 @@ function StatusDot({ status }) {
67538
68085
  };
67539
68086
  return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `inline-block w-2 h-2 rounded-full shrink-0 ${colors[status] ?? "bg-surface-700"}` });
67540
68087
  }
68088
+ function hasDetail(r) {
68089
+ return !!(r.testResults?.length || r.consoleOutput?.length || r.preScriptError || r.postScriptError || r.sentRequest || r.receivedResponse || r.error && !r.error.startsWith("Skipped"));
68090
+ }
68091
+ function DetailSection({ label, children }) {
68092
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
68093
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] uppercase tracking-wider text-surface-600 font-semibold", children: label }),
68094
+ children
68095
+ ] });
68096
+ }
68097
+ function KVRows$1({ rows }) {
68098
+ if (rows.length === 0) return null;
68099
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-0.5", children: rows.map(([k, v]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 font-mono text-[10px]", children: [
68100
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-500 shrink-0", children: [
68101
+ k,
68102
+ ":"
68103
+ ] }),
68104
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-300 break-all", children: v })
68105
+ ] }, k)) });
68106
+ }
68107
+ const PRE_CLS = "text-[10px] font-mono text-surface-300 bg-surface-900 border border-surface-800 rounded px-2 py-1.5 overflow-x-auto whitespace-pre-wrap break-words max-h-56 overflow-y-auto";
68108
+ function ResultDetail({ r }) {
68109
+ const t2 = useT();
68110
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 text-xs", children: [
68111
+ r.testResults && r.testResults.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(DetailSection, { label: t2("Tests"), children: r.testResults.map((tr, i) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-baseline gap-2", children: [
68112
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: tr.passed ? "text-emerald-400" : "text-red-400", children: tr.passed ? "✓" : "✗" }),
68113
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-300", children: tr.name }),
68114
+ tr.error && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-400 font-mono text-[10px] break-all", children: tr.error })
68115
+ ] }, i)) }),
68116
+ (r.preScriptError || r.postScriptError) && /* @__PURE__ */ jsxRuntimeExports.jsxs(DetailSection, { label: t2("Script errors"), children: [
68117
+ r.preScriptError && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] text-red-300 font-mono break-all", children: [
68118
+ t2("Pre-script:"),
68119
+ " ",
68120
+ r.preScriptError
68121
+ ] }),
68122
+ r.postScriptError && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] text-red-300 font-mono break-all", children: [
68123
+ t2("Post-script:"),
68124
+ " ",
68125
+ r.postScriptError
68126
+ ] })
68127
+ ] }),
68128
+ r.error && !r.error.startsWith("Skipped") && /* @__PURE__ */ jsxRuntimeExports.jsx(DetailSection, { label: t2("Error"), children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-red-300 font-mono break-all", children: r.error }) }),
68129
+ r.consoleOutput && r.consoleOutput.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(DetailSection, { label: t2("Console"), children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: PRE_CLS, children: r.consoleOutput.join("\n") }) }),
68130
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(DetailSection, { label: t2("Request"), children: [
68131
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "font-mono text-[10px] text-surface-300 break-all", children: [
68132
+ r.method,
68133
+ " ",
68134
+ r.resolvedUrl
68135
+ ] }),
68136
+ r.sentRequest && /* @__PURE__ */ jsxRuntimeExports.jsx(KVRows$1, { rows: Object.entries(r.sentRequest.headers ?? {}) }),
68137
+ r.sentRequest?.body && /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: PRE_CLS, children: r.sentRequest.body })
68138
+ ] }),
68139
+ r.receivedResponse && /* @__PURE__ */ jsxRuntimeExports.jsxs(DetailSection, { label: t2("Response"), children: [
68140
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-mono text-[10px]", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: r.receivedResponse.status < 400 ? "text-emerald-400" : "text-red-400", children: [
68141
+ r.receivedResponse.status,
68142
+ " ",
68143
+ r.receivedResponse.statusText
68144
+ ] }) }),
68145
+ /* @__PURE__ */ jsxRuntimeExports.jsx(KVRows$1, { rows: Object.entries(r.receivedResponse.headers ?? {}) }),
68146
+ r.receivedResponse.body && /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: PRE_CLS, children: r.receivedResponse.body })
68147
+ ] })
68148
+ ] });
68149
+ }
67541
68150
  function RunnerModal() {
67542
68151
  const t2 = useT();
67543
68152
  const runnerModal = useStore((s) => s.runnerModal);
@@ -67558,6 +68167,13 @@ function RunnerModal() {
67558
68167
  const [copiedKey, setCopiedKey] = reactExports.useState(null);
67559
68168
  const [exportFormat, setExportFormat] = reactExports.useState("json");
67560
68169
  const [requestDelay, setRequestDelay] = reactExports.useState(0);
68170
+ const [expandedRows, setExpandedRows] = reactExports.useState(/* @__PURE__ */ new Set());
68171
+ const toggleRow = (idx) => setExpandedRows((prev) => {
68172
+ const next = new Set(prev);
68173
+ if (next.has(idx)) next.delete(idx);
68174
+ else next.add(idx);
68175
+ return next;
68176
+ });
67561
68177
  const { collectionId, folderId } = runnerModal;
67562
68178
  const colEntry = collectionId ? collections[collectionId] : null;
67563
68179
  const colName = colEntry?.data.name ?? t2("Collection");
@@ -67574,6 +68190,7 @@ function RunnerModal() {
67574
68190
  setFilterTags(initFilterTagsRef.current);
67575
68191
  setSelectedEnvId(initEnvIdRef.current ?? "");
67576
68192
  setSummary(null);
68193
+ setExpandedRows(/* @__PURE__ */ new Set());
67577
68194
  progressIdxRef.current = 0;
67578
68195
  }, [runnerModal.open]);
67579
68196
  const toggleTag = (tag) => setFilterTags((prev) => prev.includes(tag) ? prev.filter((tg) => tg !== tag) : [...prev, tag]);
@@ -67581,22 +68198,9 @@ function RunnerModal() {
67581
68198
  const ds = (folderId && colEntry ? findFolder$1(colEntry.data.rootFolder, folderId)?.dataSet : null) ?? colEntry?.data.dataSet ?? { columns: [], rows: [] };
67582
68199
  const baseItems = collectionId ? collectRequests(collectionId, folderId, filterTags) : [];
67583
68200
  if (baseItems.length === 0) return;
67584
- let items2;
67585
- if (ds.rows.length > 0) {
67586
- items2 = ds.rows.flatMap((row, ri) => {
67587
- const dataRow = {};
67588
- ds.columns.forEach((col2, ci) => {
67589
- dataRow[col2] = row[ci] ?? "";
67590
- });
67591
- return baseItems.map((item) => ({
67592
- ...item,
67593
- dataRow,
67594
- iterationLabel: `${ri + 1}/${ds.rows.length}`
67595
- }));
67596
- });
67597
- } else {
67598
- items2 = baseItems;
67599
- }
68201
+ let items2 = baseItems;
68202
+ if (!folderId && colEntry) items2 = expandFolderDataSets(items2, colEntry.data);
68203
+ items2 = expandRunPlanWithData(items2, ds);
67600
68204
  const col = colEntry?.data;
67601
68205
  if (col) {
67602
68206
  items2 = items2.map((item) => {
@@ -67613,6 +68217,7 @@ function RunnerModal() {
67613
68217
  });
67614
68218
  }
67615
68219
  const env2 = resolveEnvironmentById(environments, selectedEnvId || null);
68220
+ setExpandedRows(/* @__PURE__ */ new Set());
67616
68221
  setRunnerResults(items2.map((item) => ({
67617
68222
  requestId: item.request.id,
67618
68223
  name: item.request.name,
@@ -67779,9 +68384,13 @@ function RunnerModal() {
67779
68384
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
67780
68385
  "tr",
67781
68386
  {
67782
- className: `border-b border-surface-800/50 hover:bg-surface-800/30 ${r.isHook ? "opacity-80" : ""}`,
68387
+ onClick: () => hasDetail(r) && toggleRow(idx),
68388
+ className: `border-b border-surface-800/50 hover:bg-surface-800/30 ${r.isHook ? "opacity-80" : ""} ${hasDetail(r) ? "cursor-pointer" : ""}`,
67783
68389
  children: [
67784
- /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-4 py-2 w-6", children: /* @__PURE__ */ jsxRuntimeExports.jsx(StatusDot, { status: r.status }) }),
68390
+ /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-4 py-2 w-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
68391
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-3 text-surface-600 text-[22px] leading-none", children: hasDetail(r) ? expandedRows.has(idx) ? "▾" : "▸" : "" }),
68392
+ /* @__PURE__ */ jsxRuntimeExports.jsx(StatusDot, { status: r.status })
68393
+ ] }) }),
67785
68394
  /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "py-2 pr-2 w-20", children: r.isHook && r.hookType ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[9px] font-bold px-1.5 py-0.5 rounded uppercase tracking-wide whitespace-nowrap ${HOOK_BADGE[r.hookType]?.cls ?? ""}`, children: t2(HOOK_BADGE[r.hookType]?.label ?? "") }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] font-bold ${getMethodColor(r.method)}`, children: r.method }) }),
67786
68395
  /* @__PURE__ */ jsxRuntimeExports.jsxs("td", { className: "py-2 pr-2", children: [
67787
68396
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `truncate max-w-[260px] ${r.isHook ? "text-surface-400 italic" : "text-[var(--text-primary)]"}`, children: [
@@ -67805,7 +68414,8 @@ function RunnerModal() {
67805
68414
  ] })
67806
68415
  ]
67807
68416
  }
67808
- )
68417
+ ),
68418
+ expandedRows.has(idx) && hasDetail(r) && /* @__PURE__ */ jsxRuntimeExports.jsx("tr", { className: "border-b border-surface-800/50 bg-surface-950/40", children: /* @__PURE__ */ jsxRuntimeExports.jsx("td", { colSpan: 6, className: "px-6 py-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ResultDetail, { r }) }) })
67809
68419
  ] }, idx);
67810
68420
  }) }) }) }),
67811
68421
  summary && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-4 py-2 border-t border-surface-800 bg-surface-800/30 flex-shrink-0 text-xs", children: [
@@ -69368,7 +69978,7 @@ function RouteRow({
69368
69978
  onClick: () => setScriptOpen((o) => !o),
69369
69979
  className: "flex items-center gap-1.5 text-[11px] text-surface-400 uppercase tracking-wider hover:text-white transition-colors",
69370
69980
  children: [
69371
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: scriptOpen ? "▾" : "▸" }),
69981
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: scriptOpen ? "▾" : "▸" }),
69372
69982
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Pre-response script") }),
69373
69983
  draft.script?.trim() && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-purple-400 normal-case font-normal tracking-normal ml-1", children: [
69374
69984
  "⚡ ",
@@ -69473,7 +70083,7 @@ function HitRow({ hit, matched }) {
69473
70083
  onClick: () => setOpen((o) => !o),
69474
70084
  className: `w-full flex items-center gap-3 px-4 py-2 text-sm font-mono text-left ${unmatched ? "" : "hover:bg-surface-800/20"} transition-colors`,
69475
70085
  children: [
69476
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[10px] w-3 shrink-0", children: open2 ? "▾" : "▸" }),
70086
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[22px] leading-none w-3 shrink-0", children: open2 ? "▾" : "▸" }),
69477
70087
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-bold w-16 shrink-0 text-xs ${getMethodColor(hit.method)}`, children: hit.method }),
69478
70088
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-surface-200", title: hit.path, children: hit.path }),
69479
70089
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-32 shrink-0 truncate text-surface-600 text-xs font-sans", title: matched?.description ?? matched?.path ?? "", children: unmatched ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-400", children: t2("no match") }) : matched?.description || matched?.path || "-" }),
@@ -72665,7 +73275,7 @@ function App() {
72665
73275
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
72666
73276
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-50", children: [
72667
73277
  "v",
72668
- "0.5.8"
73278
+ "0.6.0"
72669
73279
  ] }),
72670
73280
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", children: "·" }),
72671
73281
  /* @__PURE__ */ jsxRuntimeExports.jsx(