@testsmith/api-spector 0.5.9 → 0.6.1

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.
@@ -17,6 +17,14 @@ function orderedChildren(folder) {
17
17
  for (const f of folder.folders) if (!seen.has(`folder:${f.id}`)) out.push({ type: "folder", id: f.id });
18
18
  return out;
19
19
  }
20
+ function findFolder(root, id) {
21
+ if (root.id === id) return root;
22
+ for (const sub of root.folders) {
23
+ const found = findFolder(sub, id);
24
+ if (found) return found;
25
+ }
26
+ return null;
27
+ }
20
28
  function makeHook(req, collectionVars, hookType, scopeId, scopeAncestors, scopePath, mainRequestId) {
21
29
  return { request: req, collectionVars, isHook: true, hookType, scopeId, scopeAncestors, scopePath, mainRequestId };
22
30
  }
@@ -157,7 +165,45 @@ function buildRunPlan(collection, folderId, filterTags) {
157
165
  );
158
166
  }
159
167
  }
168
+ function expandRunPlanWithData(items, ds) {
169
+ if (!ds || ds.rows.length === 0) return items;
170
+ return ds.rows.flatMap((row, ri) => {
171
+ const rowVars = {};
172
+ ds.columns.forEach((col, ci) => {
173
+ if (col) rowVars[col] = row[ci] ?? "";
174
+ });
175
+ return items.map((item) => ({ ...item, dataRow: { ...item.dataRow, ...rowVars }, iterationLabel: `${ri + 1}/${ds.rows.length}` }));
176
+ });
177
+ }
178
+ function nearestFolderDataSet(item, collection) {
179
+ const chain = [item.scopeId, ...item.scopeAncestors ?? []].filter(Boolean);
180
+ for (const id of chain) {
181
+ const f = findFolder(collection.rootFolder, id);
182
+ if (f?.dataSet && f.dataSet.rows.length > 0) return f.dataSet;
183
+ }
184
+ return void 0;
185
+ }
186
+ function expandFolderDataSets(items, collection) {
187
+ const out = [];
188
+ for (const item of items) {
189
+ const ds = item.isHook ? void 0 : nearestFolderDataSet(item, collection);
190
+ if (!ds) {
191
+ out.push(item);
192
+ continue;
193
+ }
194
+ ds.rows.forEach((row, ri) => {
195
+ const rowVars = {};
196
+ ds.columns.forEach((col, ci) => {
197
+ if (col) rowVars[col] = row[ci] ?? "";
198
+ });
199
+ out.push({ ...item, dataRow: { ...item.dataRow, ...rowVars }, iterationLabel: `${ri + 1}/${ds.rows.length}` });
200
+ });
201
+ }
202
+ return out;
203
+ }
160
204
  exports.authIsConfigured = authIsConfigured;
161
205
  exports.buildRunPlan = buildRunPlan;
206
+ exports.expandFolderDataSets = expandFolderDataSets;
207
+ exports.expandRunPlanWithData = expandRunPlanWithData;
162
208
  exports.getAllApplicableHooks = getAllApplicableHooks;
163
209
  exports.resolveInheritedAuthAndHeaders = resolveInheritedAuthAndHeaders;
package/out/main/index.js CHANGED
@@ -33,7 +33,7 @@ const ipcValidate = require("./chunks/ipc-validate-sqUFqRmE.js");
33
33
  const uuid = require("uuid");
34
34
  const jsYaml = require("js-yaml");
35
35
  const undici = require("undici");
36
- const requestCollection = require("./chunks/request-collection-nePoRx_U.js");
36
+ const requestCollection = require("./chunks/request-collection-BQIo1765.js");
37
37
  const mockServer = require("./chunks/mock-server-BxiXhP1m.js");
38
38
  const http = require("http");
39
39
  const WebSocket = require("ws");
@@ -5945,7 +5945,7 @@ function isNewer(a, b) {
5945
5945
  return a2 > b2;
5946
5946
  }
5947
5947
  async function checkForUpdate() {
5948
- const current = "0.5.9";
5948
+ const current = "0.6.1";
5949
5949
  try {
5950
5950
  const res = await fetch(REGISTRY_URL, { signal: AbortSignal.timeout(4e3) });
5951
5951
  if (!res.ok) return null;
@@ -3,7 +3,7 @@
3
3
  const promises = require("fs/promises");
4
4
  const path = require("path");
5
5
  const requestExec = require("./chunks/request-exec-5_3279w1.js");
6
- const requestCollection = require("./chunks/request-collection-nePoRx_U.js");
6
+ const requestCollection = require("./chunks/request-collection-BQIo1765.js");
7
7
  const environments = require("./chunks/environments-iM3SUM-4.js");
8
8
  const cliCommon = require("./chunks/cli-common-BKYgsbGB.js");
9
9
  require("undici");
@@ -403,7 +403,7 @@ async function main() {
403
403
  } else if (!envName && workspace.settings?.defaultEnvironment && !env) {
404
404
  console.warn(cliCommon.color(`Warning: default environment "${workspace.settings.defaultEnvironment}" not found. Running without environment.`, cliCommon.C.yellow));
405
405
  }
406
- const version = `v${"0.5.9"}`;
406
+ const version = `v${"0.6.1"}`;
407
407
  console.log("");
408
408
  console.log(cliCommon.color(" API Test Runner" + (version ? ` ${version}` : ""), cliCommon.C.bold, cliCommon.C.white));
409
409
  console.log(cliCommon.color(` Workspace: ${wsPath}`, cliCommon.C.gray));
@@ -442,7 +442,22 @@ async function main() {
442
442
  let firstColName;
443
443
  for (const col of collections) {
444
444
  if (colName && col.name.toLowerCase() !== colName.toLowerCase()) continue;
445
- const items = requestCollection.buildRunPlan(col, null, filterTags);
445
+ if (col.disabled) {
446
+ console.log(cliCommon.color(` ┌ ${col.name} (disabled)`, cliCommon.C.gray));
447
+ allResults.push({
448
+ requestId: col.id,
449
+ name: col.name,
450
+ method: "",
451
+ resolvedUrl: "",
452
+ status: "skipped",
453
+ error: "Collection disabled",
454
+ scopePath: []
455
+ });
456
+ summary.total++;
457
+ summary.skipped++;
458
+ continue;
459
+ }
460
+ let items = requestCollection.buildRunPlan(col, null, filterTags);
446
461
  if (items.length === 0) continue;
447
462
  if (!firstColName) firstColName = col.name;
448
463
  let runEnvVars = await requestExec.buildEnvVars(env);
@@ -463,6 +478,8 @@ async function main() {
463
478
  req.headers = [...inheritedHeaders, ...req.headers];
464
479
  }
465
480
  }
481
+ items = requestCollection.expandFolderDataSets(items, col);
482
+ items = requestCollection.expandRunPlanWithData(items, col.dataSet);
466
483
  let bailed = false;
467
484
  let lastPrintedScope = null;
468
485
  const skipTracker = new requestExec.HookSkipTracker();
@@ -486,7 +503,8 @@ async function main() {
486
503
  isHook,
487
504
  hookType,
488
505
  scopeId,
489
- scopePath: item.scopePath
506
+ scopePath: item.scopePath,
507
+ iterationLabel: item.iterationLabel
490
508
  };
491
509
  } else {
492
510
  const out = await requestExec.executeRunnerRequest({
@@ -494,7 +512,7 @@ async function main() {
494
512
  collectionVars: { ...item.collectionVars, ...runCollectionVars },
495
513
  envVars: runEnvVars,
496
514
  globals: runGlobals,
497
- localVars: { ...runLocalVars },
515
+ localVars: { ...runLocalVars, ...item.dataRow ?? {} },
498
516
  dispatcher,
499
517
  piiMaskPatterns: piiPatterns,
500
518
  tls: effectiveTls,
@@ -509,6 +527,7 @@ async function main() {
509
527
  result.hookType = hookType;
510
528
  result.scopeId = scopeId;
511
529
  result.scopePath = item.scopePath;
530
+ result.iterationLabel = item.iterationLabel;
512
531
  skipTracker.recordResult(item, result.status);
513
532
  }
514
533
  const scopeKey = (item.scopePath ?? []).join(" / ");
@@ -1,4 +1,4 @@
1
- import { l as linter, E as EditorView, L as LanguageSupport, a as LRLanguage, s as styleTags, i as indentNodeProp, d as delimitedIndent, f as foldNodeProp, b as foldInside, S as StateField, c as LRParser, e as StateEffect, t as tags, u as useT, r as reactExports, g as useStore, h as useActiveEnvironment, j as jsxRuntimeExports, R as ReactCodeMirror, o as oneDark, k as json } from "./index-CQBAG6N4.js";
1
+ import { l as linter, E as EditorView, L as LanguageSupport, a as LRLanguage, s as styleTags, i as indentNodeProp, d as delimitedIndent, f as foldNodeProp, b as foldInside, S as StateField, c as LRParser, e as StateEffect, t as tags, u as useT, r as reactExports, g as useStore, h as useActiveEnvironment, j as jsxRuntimeExports, R as ReactCodeMirror, o as oneDark, k as json } from "./index-CdxTj7i6.js";
2
2
  function devAssert(condition, message) {
3
3
  const booleanCondition = Boolean(condition);
4
4
  if (!booleanCondition) {
@@ -12047,7 +12047,7 @@ function FieldNode({
12047
12047
  "button",
12048
12048
  {
12049
12049
  onClick: () => setExpanded((v) => !v),
12050
- className: "text-surface-600 hover:text-surface-300 w-3 text-[10px] leading-none flex-shrink-0",
12050
+ className: "text-surface-600 hover:text-surface-300 w-3 text-[22px] leading-none flex-shrink-0",
12051
12051
  children: expanded ? "▾" : "▸"
12052
12052
  }
12053
12053
  ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-3 flex-shrink-0" }),
@@ -12107,7 +12107,7 @@ function RootTypeSection({
12107
12107
  onClick: () => setExpanded((v) => !v),
12108
12108
  className: "w-full flex items-center gap-1.5 px-2 py-1 text-[10px] font-semibold uppercase tracking-wider text-surface-500 hover:text-surface-300 transition-colors",
12109
12109
  children: [
12110
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px]", children: expanded ? "▾" : "▸" }),
12110
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: expanded ? "▾" : "▸" }),
12111
12111
  label,
12112
12112
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-400 normal-case tracking-normal font-normal ml-auto", children: t2(":count field|:count fields", { count: fields.length }) })
12113
12113
  ]
@@ -12361,7 +12361,7 @@ function GraphQLEditor({ request, onChange }) {
12361
12361
  onClick: () => setShowVars((v) => !v),
12362
12362
  className: "text-[10px] text-surface-600 hover:text-surface-300 uppercase tracking-wider font-medium flex items-center gap-1",
12363
12363
  children: [
12364
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: showVars ? "▾" : "▸" }),
12364
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: showVars ? "▾" : "▸" }),
12365
12365
  " ",
12366
12366
  t2("Variables"),
12367
12367
  gql.variables?.trim() && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-400 ml-1", children: "●" })
@@ -1,4 +1,4 @@
1
- import { u as useT, r as reactExports, j as jsxRuntimeExports, R as ReactCodeMirror, m as commentKeymap, o as oneDark, x as xml } from "./index-CQBAG6N4.js";
1
+ import { u as useT, r as reactExports, j as jsxRuntimeExports, R as ReactCodeMirror, m as commentKeymap, o as oneDark, x as xml } from "./index-CdxTj7i6.js";
2
2
  const SOAP_11_CONTENT_TYPE = "text/xml; charset=utf-8";
3
3
  const SOAP_12_CONTENT_TYPE = "application/soap+xml; charset=utf-8";
4
4
  function contentTypeForSoap(version) {
@@ -13779,6 +13779,12 @@ const createCollectionsSlice = (set2, get2) => ({
13779
13779
  s.workspace.collections = s.workspace.collections.map((p) => p === oldRelPath ? newRelPath : p);
13780
13780
  }
13781
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
+ }),
13782
13788
  duplicateCollection: (id2) => set2((s) => {
13783
13789
  const entry = s.collections[id2];
13784
13790
  if (!entry) return;
@@ -35470,6 +35476,7 @@ const Aggressive$6 = "Aggressive";
35470
35476
  const Next$6 = "Next";
35471
35477
  const More$6 = "More";
35472
35478
  const or$6 = "or";
35479
+ const Disabled$6 = "Disabled";
35473
35480
  const en = {
35474
35481
  "Close tab": "Close tab",
35475
35482
  Collections: Collections$6,
@@ -36521,7 +36528,8 @@ const en = {
36521
36528
  "Post-script:": "Post-script:",
36522
36529
  "No data row": "No data row",
36523
36530
  "Row :n": "Row :n",
36524
- "Run this request with the variables from one data table row": "Run this request with the variables from one data table row"
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
36525
36533
  };
36526
36534
  const Collections$5 = "Sammlungen";
36527
36535
  const History$5 = "Verlauf";
@@ -36723,6 +36731,7 @@ const Aggressive$5 = "Aggressiv";
36723
36731
  const Next$5 = "Weiter";
36724
36732
  const More$5 = "Mehr";
36725
36733
  const or$5 = "oder";
36734
+ const Disabled$5 = "Deaktiviert";
36726
36735
  const de = {
36727
36736
  "Close tab": "Tab schließen",
36728
36737
  Collections: Collections$5,
@@ -37774,7 +37783,8 @@ const de = {
37774
37783
  "Post-script:": "Post-Script:",
37775
37784
  "No data row": "Keine Datenzeile",
37776
37785
  "Row :n": "Zeile :n",
37777
- "Run this request with the variables from one data table row": "Diesen Request mit den Variablen einer Datentabellenzeile ausführen"
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
37778
37788
  };
37779
37789
  const Collections$4 = "Collections";
37780
37790
  const History$4 = "Historique";
@@ -37976,6 +37986,7 @@ const Aggressive$4 = "Agressif";
37976
37986
  const Next$4 = "Suivant";
37977
37987
  const More$4 = "Plus";
37978
37988
  const or$4 = "ou";
37989
+ const Disabled$4 = "Désactivé";
37979
37990
  const fr = {
37980
37991
  "Close tab": "Fermer l'onglet",
37981
37992
  Collections: Collections$4,
@@ -39027,7 +39038,8 @@ const fr = {
39027
39038
  "Post-script:": "Post-script :",
39028
39039
  "No data row": "Aucune ligne de données",
39029
39040
  "Row :n": "Ligne :n",
39030
- "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"
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
39031
39043
  };
39032
39044
  const Collections$3 = "Colecciones";
39033
39045
  const History$3 = "Historial";
@@ -39229,6 +39241,7 @@ const Aggressive$3 = "Agresivo";
39229
39241
  const Next$3 = "Siguiente";
39230
39242
  const More$3 = "Más";
39231
39243
  const or$3 = "o";
39244
+ const Disabled$3 = "Desactivada";
39232
39245
  const es = {
39233
39246
  "Close tab": "Cerrar pestaña",
39234
39247
  Collections: Collections$3,
@@ -40280,7 +40293,8 @@ const es = {
40280
40293
  "Post-script:": "Post-script:",
40281
40294
  "No data row": "Sin fila de datos",
40282
40295
  "Row :n": "Fila :n",
40283
- "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"
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
40284
40298
  };
40285
40299
  const Collections$2 = "Raccolte";
40286
40300
  const History$2 = "Cronologia";
@@ -40482,6 +40496,7 @@ const Aggressive$2 = "Aggressivo";
40482
40496
  const Next$2 = "Avanti";
40483
40497
  const More$2 = "Altro";
40484
40498
  const or$2 = "o";
40499
+ const Disabled$2 = "Disattivata";
40485
40500
  const it = {
40486
40501
  "Close tab": "Chiudi scheda",
40487
40502
  Collections: Collections$2,
@@ -41533,7 +41548,8 @@ const it = {
41533
41548
  "Post-script:": "Post-script:",
41534
41549
  "No data row": "Nessuna riga di dati",
41535
41550
  "Row :n": "Riga :n",
41536
- "Run this request with the variables from one data table row": "Esegui questo request con le variabili di una riga della tabella dati"
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
41537
41553
  };
41538
41554
  const Collections$1 = "Collecties";
41539
41555
  const History$1 = "Geschiedenis";
@@ -41735,6 +41751,7 @@ const Aggressive$1 = "Agressief";
41735
41751
  const Next$1 = "Volgende";
41736
41752
  const More$1 = "Meer";
41737
41753
  const or$1 = "of";
41754
+ const Disabled$1 = "Uitgeschakeld";
41738
41755
  const nl = {
41739
41756
  "Close tab": "Tabblad sluiten",
41740
41757
  Collections: Collections$1,
@@ -42786,7 +42803,8 @@ const nl = {
42786
42803
  "Post-script:": "Post-script:",
42787
42804
  "No data row": "Geen datarij",
42788
42805
  "Row :n": "Rij :n",
42789
- "Run this request with the variables from one data table row": "Voer dit request uit met de variabelen van één datatabelrij"
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
42790
42808
  };
42791
42809
  const Collections = "Coleções";
42792
42810
  const History = "Histórico";
@@ -42988,6 +43006,7 @@ const Aggressive = "Agressivo";
42988
43006
  const Next = "Seguinte";
42989
43007
  const More = "Mais";
42990
43008
  const or = "ou";
43009
+ const Disabled = "Desativada";
42991
43010
  const pt = {
42992
43011
  "Close tab": "Fechar separador",
42993
43012
  Collections,
@@ -44039,7 +44058,8 @@ const pt = {
44039
44058
  "Post-script:": "Pós-script:",
44040
44059
  "No data row": "Sem linha de dados",
44041
44060
  "Row :n": "Linha :n",
44042
- "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"
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
44043
44063
  };
44044
44064
  const CATALOGS = { en, de, fr, es, it, nl, pt };
44045
44065
  const LOCALES = {
@@ -44927,7 +44947,7 @@ function BasicCredentialsFields({
44927
44947
  onClick: () => setKeychainOpen((o) => !o),
44928
44948
  className: "text-[10px] text-surface-500 hover:text-surface-300 text-left transition-colors w-fit",
44929
44949
  children: [
44930
- keychainOpen ? "▾" : "▸",
44950
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: keychainOpen ? "▾" : "▸" }),
44931
44951
  " ",
44932
44952
  t2("Store password in OS keychain instead")
44933
44953
  ]
@@ -45005,7 +45025,7 @@ function BearerPanel({
45005
45025
  onClick: () => setKeychainOpen((o) => !o),
45006
45026
  className: "text-[10px] text-surface-500 hover:text-surface-300 text-left transition-colors w-fit",
45007
45027
  children: [
45008
- keychainOpen ? "▾" : "▸",
45028
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: keychainOpen ? "▾" : "▸" }),
45009
45029
  " ",
45010
45030
  t2("Store in OS keychain instead")
45011
45031
  ]
@@ -46330,6 +46350,12 @@ function PencilIcon() {
46330
46350
  function TrashIcon() {
46331
46351
  return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6M9 7h6m2 0a1 1 0 00-1-1h-4a1 1 0 00-1 1m6 0H7" }) });
46332
46352
  }
46353
+ function BanIcon() {
46354
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", children: [
46355
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "9" }),
46356
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { strokeLinecap: "round", d: "M5.64 5.64l12.72 12.72" })
46357
+ ] });
46358
+ }
46333
46359
  function TableIcon() {
46334
46360
  return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M3 10h18M3 14h18M10 3v18M3 6a1 1 0 011-1h16a1 1 0 011 1v12a1 1 0 01-1 1H4a1 1 0 01-1-1V6z" }) });
46335
46361
  }
@@ -46563,7 +46589,7 @@ function RequestRow({
46563
46589
  e.stopPropagation();
46564
46590
  setExamplesOpen((o) => !o);
46565
46591
  },
46566
- className: "shrink-0 w-3 text-surface-500 hover:text-white leading-none",
46592
+ 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]",
46567
46593
  title: examplesOpen ? t2("Hide examples") : t2("Show :count example(s)", { count: examples.length }),
46568
46594
  children: examplesOpen ? "▾" : "▸"
46569
46595
  }
@@ -46882,6 +46908,7 @@ function CollectionTree() {
46882
46908
  const deleteRequest = useStore((s) => s.deleteRequest);
46883
46909
  const duplicateRequest = useStore((s) => s.duplicateRequest);
46884
46910
  const duplicateCollection = useStore((s) => s.duplicateCollection);
46911
+ const toggleCollectionDisabled = useStore((s) => s.toggleCollectionDisabled);
46885
46912
  const duplicateFolder = useStore((s) => s.duplicateFolder);
46886
46913
  const updateFolderTags = useStore((s) => s.updateFolderTags);
46887
46914
  const updateRequestTags = useStore((s) => s.updateRequestTags);
@@ -47012,6 +47039,7 @@ function CollectionTree() {
47012
47039
  onRenameCollection: (name2) => renameCollection(col.id, name2),
47013
47040
  onDeleteCollection: () => confirmThen(t2('Delete collection ":name"?', { name: col.name }), () => deleteCollection(col.id)),
47014
47041
  onDuplicateCollection: () => duplicateCollection(col.id),
47042
+ onToggleCollectionDisabled: () => toggleCollectionDisabled(col.id),
47015
47043
  onRenameFolder: (folderId, name2) => renameFolder(col.id, folderId, name2),
47016
47044
  onDeleteFolder: (folderId) => confirmThen(t2("Delete this folder and all its requests?"), () => deleteFolder(col.id, folderId)),
47017
47045
  onDuplicateFolder: (folderId) => duplicateFolder(col.id, folderId),
@@ -47106,6 +47134,7 @@ function CollectionNode({
47106
47134
  onRenameCollection,
47107
47135
  onDeleteCollection,
47108
47136
  onDuplicateCollection,
47137
+ onToggleCollectionDisabled,
47109
47138
  onRenameFolder,
47110
47139
  onDeleteFolder,
47111
47140
  onDuplicateFolder,
@@ -47138,7 +47167,7 @@ function CollectionNode({
47138
47167
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
47139
47168
  "div",
47140
47169
  {
47141
- 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" : ""}`,
47170
+ 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" : ""}`,
47142
47171
  onClick: () => {
47143
47172
  onSelectCollection();
47144
47173
  setExpanded((e) => !e);
@@ -47155,7 +47184,7 @@ function CollectionNode({
47155
47184
  else dragCtx.onDropRequest(col.id, col.rootFolder.id);
47156
47185
  },
47157
47186
  children: [
47158
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] w-3 text-center shrink-0 mt-0.5", children: expanded ? "▾" : "▸" }),
47187
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none w-4 h-4 shrink-0 flex items-center justify-center", children: expanded ? "▾" : "▸" }),
47159
47188
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0", children: renaming ? /* @__PURE__ */ jsxRuntimeExports.jsx(
47160
47189
  InlineEdit,
47161
47190
  {
@@ -47168,7 +47197,10 @@ function CollectionNode({
47168
47197
  className: "w-full text-xs",
47169
47198
  validate: (v) => existingCollectionNames.filter((n) => n !== col.name).includes(v) ? t2('":name" already exists', { name: v }) : null
47170
47199
  }
47171
- ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold truncate block", children: col.name }) }),
47200
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-semibold truncate block", children: [
47201
+ col.name,
47202
+ 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") })
47203
+ ] }) }),
47172
47204
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(DotsBtn, { items: [
47173
47205
  { type: "item", label: t2("Run collection"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(PlayIcon, {}), onClick: onRunCollection },
47174
47206
  { type: "separator" },
@@ -47182,6 +47214,7 @@ function CollectionNode({
47182
47214
  { type: "item", label: t2("Settings"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(GearIcon, {}), onClick: () => setShowSettings(true) },
47183
47215
  { type: "item", label: t2("Sync schemas"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowSchemaSync(true) },
47184
47216
  ...cloudEnabled() ? [{ type: "item", label: t2("Push contract to cloud"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowPushContract(true) }] : [],
47217
+ { type: "item", label: col.disabled ? t2("Enable") : t2("Disable"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(BanIcon, {}), onClick: onToggleCollectionDisabled },
47185
47218
  { type: "item", label: t2("Rename"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(PencilIcon, {}), onClick: () => setRenaming(true) },
47186
47219
  { type: "item", label: t2("Duplicate"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyIcon, {}), onClick: onDuplicateCollection },
47187
47220
  { type: "separator" },
@@ -47277,7 +47310,7 @@ function FolderRow({
47277
47310
  "div",
47278
47311
  {
47279
47312
  draggable: true,
47280
- className: `group flex items-start gap-1 py-1 hover:bg-surface-800 transition-colors cursor-pointer text-surface-400 ${dropInside ? "outline outline-1 outline-blue-500 rounded" : ""}`,
47313
+ 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" : ""}`,
47281
47314
  style: { paddingLeft: indent },
47282
47315
  onClick: () => setExpanded((e) => !e),
47283
47316
  onDragStart: (e) => {
@@ -47293,8 +47326,8 @@ function FolderRow({
47293
47326
  onDragLeave: () => setDropInside(false),
47294
47327
  onDrop: handleFolderDrop,
47295
47328
  children: [
47296
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] w-3 text-center shrink-0 mt-0.5", children: expanded ? "▾" : "▸" }),
47297
- /* @__PURE__ */ jsxRuntimeExports.jsx(FolderIcon, { className: `shrink-0 mt-0.5 ${hasInheritedConfig ? "text-blue-500" : "text-amber-600"}` }),
47329
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none w-4 h-4 shrink-0 flex items-center justify-center", children: expanded ? "▾" : "▸" }),
47330
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FolderIcon, { className: `shrink-0 ${hasInheritedConfig ? "text-blue-500" : "text-amber-600"}` }),
47298
47331
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
47299
47332
  renaming ? /* @__PURE__ */ jsxRuntimeExports.jsx(
47300
47333
  InlineEdit,
@@ -53248,8 +53281,8 @@ function jsonWithComments() {
53248
53281
  function xmlWithComments() {
53249
53282
  return [xml(), commentKeymap];
53250
53283
  }
53251
- const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-D8v3dLPR.js"), true ? [] : void 0, import.meta.url).then((m) => ({ default: m.GraphQLEditor })));
53252
- const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-vPPiu9kt.js"), true ? [] : void 0, import.meta.url).then((m) => ({ default: m.SoapEditor })));
53284
+ const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-8wU1UeBL.js"), true ? [] : void 0, import.meta.url).then((m) => ({ default: m.GraphQLEditor })));
53285
+ const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-DQwLLqCX.js"), true ? [] : void 0, import.meta.url).then((m) => ({ default: m.SoapEditor })));
53253
53286
  function BodyTab({ request: request2, onChange }) {
53254
53287
  const t2 = useT();
53255
53288
  const editorFallback = /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 text-xs text-surface-500", children: t2("Loading editor…") });
@@ -54396,7 +54429,7 @@ function ScriptsTab({ request: request2, onChange }) {
54396
54429
  onClick: () => setSnippetsOpen(false),
54397
54430
  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",
54398
54431
  children: [
54399
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "▾" }),
54432
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: "▾" }),
54400
54433
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Quick inserts") })
54401
54434
  ]
54402
54435
  }
@@ -54417,7 +54450,7 @@ function ScriptsTab({ request: request2, onChange }) {
54417
54450
  className: "w-full text-left text-xs font-medium text-surface-400 hover:text-white flex items-center justify-between py-0.5",
54418
54451
  children: [
54419
54452
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2(group.group) }),
54420
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px]", children: expandedGroup === group.group ? "▾" : "▸" })
54453
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: expandedGroup === group.group ? "▾" : "▸" })
54421
54454
  ]
54422
54455
  }
54423
54456
  ),
@@ -61383,7 +61416,7 @@ function TraceRow({ trace, onCopy }) {
61383
61416
  onClick: () => setOpen((v) => !v),
61384
61417
  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]",
61385
61418
  children: [
61386
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-surface-600 w-3", children: open2 ? "▾" : "▸" }),
61419
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-surface-600 w-3 text-[22px] leading-none", children: open2 ? "▾" : "▸" }),
61387
61420
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `shrink-0 font-bold w-9 ${statusTone(trace.status, trace.finding)}`, children: trace.status || t2("ERR") }),
61388
61421
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 text-surface-300", children: trace.mutation.target }),
61389
61422
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500 truncate", children: trace.mutation.kind }),
@@ -62184,7 +62217,7 @@ function JsonNode({ nodeKey, value: value2, path, depth, onLeaf }) {
62184
62217
  onClick: () => setExpanded((v) => !v),
62185
62218
  className: "flex items-center gap-1.5 py-0.5 pl-1 rounded hover:bg-surface-800/40 w-full text-left",
62186
62219
  children: [
62187
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[10px] w-3 shrink-0 text-center", children: expanded ? "▾" : "▸" }),
62220
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[22px] leading-none w-3 shrink-0 text-center", children: expanded ? "▾" : "▸" }),
62188
62221
  keySpan,
62189
62222
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-xs", children: summary })
62190
62223
  ]
@@ -62249,7 +62282,7 @@ function XmlNode({ element, depth, onLeaf }) {
62249
62282
  onClick: () => setExpanded((v) => !v),
62250
62283
  className: "flex items-center gap-1.5 py-0.5 pl-1 rounded hover:bg-surface-800/40 w-full text-left",
62251
62284
  children: [
62252
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[10px] w-3 shrink-0 text-center", children: expanded ? "▾" : "▸" }),
62285
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[22px] leading-none w-3 shrink-0 text-center", children: expanded ? "▾" : "▸" }),
62253
62286
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-300 font-mono text-xs", children: [
62254
62287
  "<",
62255
62288
  tag,
@@ -62466,7 +62499,7 @@ function AssertMenu({ state, onClose, onConfirm }) {
62466
62499
  onClick: () => setJpOpen((o) => !o),
62467
62500
  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",
62468
62501
  children: [
62469
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: jpOpen ? "▾" : "▸" }),
62502
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: jpOpen ? "▾" : "▸" }),
62470
62503
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("JSONPath assert (with filter)") })
62471
62504
  ]
62472
62505
  }
@@ -63035,7 +63068,7 @@ function HookResultsPanel({ results }) {
63035
63068
  onClick: () => setOpen((o) => !o),
63036
63069
  className: "w-full flex items-center gap-2 px-4 py-1.5 text-xs hover:bg-surface-800/30 transition-colors",
63037
63070
  children: [
63038
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-400", children: open2 ? "▾" : "▸" }),
63071
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-400 text-[22px] leading-none", children: open2 ? "▾" : "▸" }),
63039
63072
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-medium text-surface-400", children: t2("Hooks") }),
63040
63073
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500", children: t2(":count ran", { count: results.length }) }),
63041
63074
  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 }) })
@@ -63061,7 +63094,7 @@ function HookResultsPanel({ results }) {
63061
63094
  r.durationMs,
63062
63095
  "ms"
63063
63096
  ] }),
63064
- hasDetail2 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500 shrink-0", children: isExpanded ? "▾" : "▸" })
63097
+ hasDetail2 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500 shrink-0 text-[22px] leading-none", children: isExpanded ? "▾" : "▸" })
63065
63098
  ]
63066
63099
  }
63067
63100
  ),
@@ -63707,7 +63740,7 @@ function HistoryTabRow({ entry, onLoad, onResend }) {
63707
63740
  const reqBody = requestBodyText(entry.request.body);
63708
63741
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-surface-800", children: [
63709
63742
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-4 py-2 hover:bg-surface-800/40", children: [
63710
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setOpen((o) => !o), className: "text-surface-600 text-xs w-3 shrink-0", children: open2 ? "▾" : "▸" }),
63743
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setOpen((o) => !o), className: "text-surface-600 text-[22px] leading-none w-3 shrink-0", children: open2 ? "▾" : "▸" }),
63711
63744
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] font-bold font-mono shrink-0 w-10 ${getMethodColor(entry.request.method)}`, children: entry.request.method }),
63712
63745
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-xs font-bold font-mono shrink-0 w-8 ${getStatusColor(entry.response.status)}`, children: entry.response.status || "ERR" }),
63713
63746
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs text-surface-400 shrink-0", children: [
@@ -63984,7 +64017,7 @@ function ResponseViewer() {
63984
64017
  button: /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
63985
64018
  t2("More"),
63986
64019
  " ",
63987
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: "▾" })
64020
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", className: "text-[22px] leading-none", children: "▾" })
63988
64021
  ] }),
63989
64022
  ariaLabel: t2("More response sections"),
63990
64023
  align: "left",
@@ -64805,7 +64838,7 @@ function WelcomeScreen() {
64805
64838
  )
64806
64839
  ] }),
64807
64840
  /* @__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.") }),
64808
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t2("version :version", { version: "0.5.9" }) })
64841
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t2("version :version", { version: "0.6.1" }) })
64809
64842
  ] }),
64810
64843
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 w-64", children: [
64811
64844
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -68361,7 +68394,7 @@ function RunnerModal() {
68361
68394
  className: `border-b border-surface-800/50 hover:bg-surface-800/30 ${r.isHook ? "opacity-80" : ""} ${hasDetail(r) ? "cursor-pointer" : ""}`,
68362
68395
  children: [
68363
68396
  /* @__PURE__ */ jsxRuntimeExports.jsx("td", { className: "px-4 py-2 w-6", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1", children: [
68364
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 text-surface-600 text-[9px]", children: hasDetail(r) ? expandedRows.has(idx) ? "▾" : "▸" : "" }),
68397
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-3 text-surface-600 text-[22px] leading-none", children: hasDetail(r) ? expandedRows.has(idx) ? "▾" : "▸" : "" }),
68365
68398
  /* @__PURE__ */ jsxRuntimeExports.jsx(StatusDot, { status: r.status })
68366
68399
  ] }) }),
68367
68400
  /* @__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 }) }),
@@ -69951,7 +69984,7 @@ function RouteRow({
69951
69984
  onClick: () => setScriptOpen((o) => !o),
69952
69985
  className: "flex items-center gap-1.5 text-[11px] text-surface-400 uppercase tracking-wider hover:text-white transition-colors",
69953
69986
  children: [
69954
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: scriptOpen ? "▾" : "▸" }),
69987
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none", children: scriptOpen ? "▾" : "▸" }),
69955
69988
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Pre-response script") }),
69956
69989
  draft.script?.trim() && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-purple-400 normal-case font-normal tracking-normal ml-1", children: [
69957
69990
  "⚡ ",
@@ -70056,7 +70089,7 @@ function HitRow({ hit, matched }) {
70056
70089
  onClick: () => setOpen((o) => !o),
70057
70090
  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`,
70058
70091
  children: [
70059
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[10px] w-3 shrink-0", children: open2 ? "▾" : "▸" }),
70092
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[22px] leading-none w-3 shrink-0", children: open2 ? "▾" : "▸" }),
70060
70093
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-bold w-16 shrink-0 text-xs ${getMethodColor(hit.method)}`, children: hit.method }),
70061
70094
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-surface-200", title: hit.path, children: hit.path }),
70062
70095
  /* @__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 || "-" }),
@@ -73248,7 +73281,7 @@ function App() {
73248
73281
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
73249
73282
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-50", children: [
73250
73283
  "v",
73251
- "0.5.9"
73284
+ "0.6.1"
73252
73285
  ] }),
73253
73286
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", children: "·" }),
73254
73287
  /* @__PURE__ */ jsxRuntimeExports.jsx(