@testsmith/api-spector 0.8.6 → 0.8.8

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.
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./GraphQLEditor-BwaRI4Ba.js","./codemirror-BKmwMUlV.js","./ajv-CJPwFjiP.js","./SoapEditor-DafZPr0j.js"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./GraphQLEditor-TklsnkDw.js","./codemirror-BKmwMUlV.js","./ajv-CJPwFjiP.js","./SoapEditor-CllZqWyv.js"])))=>i.map(i=>d[i]);
2
2
  import { r as requireReact, g as getDefaultExportFromCjs, R as React, a as reactExports, b as autocompletion, h as hoverTooltip, j as jsxRuntimeExports, k as keymap, t as toggleComment, D as Decoration, E as EditorView, V as ViewPlugin, c as RangeSetBuilder, x as xml, d as json, e as ReactCodeMirror, o as oneDark, f as javascript } from "./codemirror-BKmwMUlV.js";
3
3
  import { r as requireAjv } from "./ajv-CJPwFjiP.js";
4
4
  var client = { exports: {} };
@@ -11977,6 +11977,131 @@ function requireClient() {
11977
11977
  }
11978
11978
  var clientExports = requireClient();
11979
11979
  const ReactDOM$1 = /* @__PURE__ */ getDefaultExportFromCjs(clientExports);
11980
+ const byteToHex = [];
11981
+ for (let i = 0; i < 256; ++i) {
11982
+ byteToHex.push((i + 256).toString(16).slice(1));
11983
+ }
11984
+ function unsafeStringify(arr, offset = 0) {
11985
+ return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
11986
+ }
11987
+ let getRandomValues;
11988
+ const rnds8 = new Uint8Array(16);
11989
+ function rng() {
11990
+ if (!getRandomValues) {
11991
+ if (typeof crypto === "undefined" || !crypto.getRandomValues) {
11992
+ throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
11993
+ }
11994
+ getRandomValues = crypto.getRandomValues.bind(crypto);
11995
+ }
11996
+ return getRandomValues(rnds8);
11997
+ }
11998
+ const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
11999
+ const native = { randomUUID };
12000
+ function v4(options, buf, offset) {
12001
+ if (native.randomUUID && true && !options) {
12002
+ return native.randomUUID();
12003
+ }
12004
+ options = options || {};
12005
+ const rnds = options.random ?? options.rng?.() ?? rng();
12006
+ if (rnds.length < 16) {
12007
+ throw new Error("Random bytes length must be >= 16");
12008
+ }
12009
+ rnds[6] = rnds[6] & 15 | 64;
12010
+ rnds[8] = rnds[8] & 63 | 128;
12011
+ return unsafeStringify(rnds);
12012
+ }
12013
+ function orderedChildren(folder2) {
12014
+ const reqSet = new Set(folder2.requestIds);
12015
+ const folderSet = new Set(folder2.folders.map((f) => f.id));
12016
+ const seen2 = /* @__PURE__ */ new Set();
12017
+ const out = [];
12018
+ for (const ref of folder2.childOrder ?? []) {
12019
+ const key = `${ref.type}:${ref.id}`;
12020
+ if (seen2.has(key)) continue;
12021
+ if (ref.type === "request" && reqSet.has(ref.id) || ref.type === "folder" && folderSet.has(ref.id)) {
12022
+ out.push({ type: ref.type, id: ref.id });
12023
+ seen2.add(key);
12024
+ }
12025
+ }
12026
+ for (const id2 of folder2.requestIds) if (!seen2.has(`request:${id2}`)) out.push({ type: "request", id: id2 });
12027
+ for (const f of folder2.folders) if (!seen2.has(`folder:${f.id}`)) out.push({ type: "folder", id: f.id });
12028
+ return out;
12029
+ }
12030
+ function sortChildOrder(folder2, requestName) {
12031
+ const nameOf = (ref) => ref.type === "folder" ? folder2.folders.find((f) => f.id === ref.id)?.name ?? "" : requestName(ref.id);
12032
+ return [...orderedChildren(folder2)].sort((a, b) => nameOf(a).localeCompare(nameOf(b), void 0, { sensitivity: "base", numeric: true }));
12033
+ }
12034
+ function findFolder$1(root2, id2) {
12035
+ if (root2.id === id2) return root2;
12036
+ for (const sub of root2.folders) {
12037
+ const found = findFolder$1(sub, id2);
12038
+ if (found) return found;
12039
+ }
12040
+ return null;
12041
+ }
12042
+ function findFolderContaining(root2, reqId) {
12043
+ if (root2.requestIds.includes(reqId)) return root2;
12044
+ for (const sub of root2.folders) {
12045
+ const found = findFolderContaining(sub, reqId);
12046
+ if (found) return found;
12047
+ }
12048
+ return null;
12049
+ }
12050
+ function removeFromFolder(root2, reqId) {
12051
+ root2.requestIds = root2.requestIds.filter((id2) => id2 !== reqId);
12052
+ root2.folders.forEach((sub) => removeFromFolder(sub, reqId));
12053
+ }
12054
+ function removeFolderById(parent, folderId) {
12055
+ const idx = parent.folders.findIndex((f) => f.id === folderId);
12056
+ if (idx !== -1) {
12057
+ parent.folders.splice(idx, 1);
12058
+ return true;
12059
+ }
12060
+ for (const sub of parent.folders) {
12061
+ if (removeFolderById(sub, folderId)) return true;
12062
+ }
12063
+ return false;
12064
+ }
12065
+ function findFolderParent(root2, folderId) {
12066
+ for (const sub of root2.folders) {
12067
+ if (sub.id === folderId) return root2;
12068
+ const found = findFolderParent(sub, folderId);
12069
+ if (found) return found;
12070
+ }
12071
+ return null;
12072
+ }
12073
+ function findFolderPath(root2, requestId) {
12074
+ if (root2.requestIds.includes(requestId)) return [root2];
12075
+ for (const sub of root2.folders) {
12076
+ const path = findFolderPath(sub, requestId);
12077
+ if (path.length > 0) return [root2, ...path];
12078
+ }
12079
+ return [];
12080
+ }
12081
+ function collectRequestIds$1(f) {
12082
+ return [...f.requestIds, ...f.folders.flatMap(collectRequestIds$1)];
12083
+ }
12084
+ function reIdFolderTree(root2, mapRequestId) {
12085
+ root2.id = v4();
12086
+ root2.requestIds = root2.requestIds.map(mapRequestId);
12087
+ root2.folders.forEach((sub) => reIdFolderTree(sub, mapRequestId));
12088
+ }
12089
+ function cloneAndReId(folder2, mapRequestId) {
12090
+ const cloned = structuredClone(folder2);
12091
+ reIdFolderTree(cloned, mapRequestId);
12092
+ return cloned;
12093
+ }
12094
+ function collectFolderVars(root2, reqId) {
12095
+ const walk2 = (folder2) => {
12096
+ if ((folder2.requestIds ?? []).includes(reqId)) return { ...folder2.variables ?? {} };
12097
+ for (const sub of folder2.folders ?? []) {
12098
+ const inner = walk2(sub);
12099
+ if (inner) return { ...folder2.variables ?? {}, ...inner };
12100
+ }
12101
+ return null;
12102
+ };
12103
+ return walk2(root2) ?? {};
12104
+ }
11980
12105
  const createStoreImpl$1 = (createState) => {
11981
12106
  let state;
11982
12107
  const listeners = /* @__PURE__ */ new Set();
@@ -13069,59 +13194,56 @@ const createContractSlice = (set2) => ({
13069
13194
  s.contractDesignerSeed = null;
13070
13195
  })
13071
13196
  });
13072
- const byteToHex = [];
13073
- for (let i = 0; i < 256; ++i) {
13074
- byteToHex.push((i + 256).toString(16).slice(1));
13075
- }
13076
- function unsafeStringify(arr, offset = 0) {
13077
- return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
13078
- }
13079
- let getRandomValues;
13080
- const rnds8 = new Uint8Array(16);
13081
- function rng() {
13082
- if (!getRandomValues) {
13083
- if (typeof crypto === "undefined" || !crypto.getRandomValues) {
13084
- throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
13085
- }
13086
- getRandomValues = crypto.getRandomValues.bind(crypto);
13087
- }
13088
- return getRandomValues(rnds8);
13089
- }
13090
- const randomUUID = typeof crypto !== "undefined" && crypto.randomUUID && crypto.randomUUID.bind(crypto);
13091
- const native = { randomUUID };
13092
- function v4(options, buf, offset) {
13093
- if (native.randomUUID && true && !options) {
13094
- return native.randomUUID();
13095
- }
13096
- options = options || {};
13097
- const rnds = options.random ?? options.rng?.() ?? rng();
13098
- if (rnds.length < 16) {
13099
- throw new Error("Random bytes length must be >= 16");
13100
- }
13101
- rnds[6] = rnds[6] & 15 | 64;
13102
- rnds[8] = rnds[8] & 63 | 128;
13103
- return unsafeStringify(rnds);
13104
- }
13105
- function makeTab(requestId, collectionId, opts = {}) {
13197
+ function baseTab(collectionId) {
13106
13198
  return {
13107
13199
  id: v4(),
13108
- requestId,
13109
- exampleId: opts.exampleId ?? null,
13110
13200
  collectionId,
13111
13201
  lastResponse: null,
13112
13202
  lastScriptResult: null,
13113
13203
  lastSentRequest: null,
13114
13204
  lastHookResults: null,
13115
13205
  isSending: false,
13206
+ scriptTab: "post"
13207
+ };
13208
+ }
13209
+ function makeTab(requestId, collectionId, opts = {}) {
13210
+ return {
13211
+ ...baseTab(collectionId),
13212
+ kind: "request",
13213
+ requestId,
13214
+ folderId: null,
13215
+ exampleId: opts.exampleId ?? null,
13116
13216
  // Examples have no Docs tab and fall back to Body (see RequestBuilder).
13117
13217
  // Otherwise open on the workspace's configured default sub-tab (Docs unless
13118
13218
  // the workspace overrides it).
13119
- requestTab: opts.exampleId ? "body" : opts.defaultTab ?? "docs",
13120
- // Default to the post-response tab — that's where the typical workflow
13121
- // (assertions, extracting tokens, saving variables) lives.
13122
- scriptTab: "post"
13219
+ requestTab: opts.exampleId ? "body" : opts.defaultTab ?? "docs"
13123
13220
  };
13124
13221
  }
13222
+ function makeFolderTab(collectionId, folderId) {
13223
+ return { ...baseTab(collectionId), kind: "folder", requestId: null, folderId, exampleId: null, requestTab: "docs" };
13224
+ }
13225
+ function makeCollectionTab(collectionId) {
13226
+ return { ...baseTab(collectionId), kind: "collection", requestId: null, folderId: null, exampleId: null, requestTab: "docs" };
13227
+ }
13228
+ function syncPanelsToActiveTab(s) {
13229
+ const tab = s.tabs.find((t) => t.id === s.activeTabId);
13230
+ if (!tab) {
13231
+ s.collectionPanelOpen = false;
13232
+ s.folderPanel = null;
13233
+ return;
13234
+ }
13235
+ if (tab.collectionId) s.activeCollectionId = tab.collectionId;
13236
+ if (tab.kind === "folder" && tab.collectionId && tab.folderId) {
13237
+ s.folderPanel = { collectionId: tab.collectionId, folderId: tab.folderId };
13238
+ s.collectionPanelOpen = false;
13239
+ } else if (tab.kind === "collection") {
13240
+ s.collectionPanelOpen = true;
13241
+ s.folderPanel = null;
13242
+ } else {
13243
+ s.folderPanel = null;
13244
+ s.collectionPanelOpen = false;
13245
+ }
13246
+ }
13125
13247
  function protocolFor(state, requestId) {
13126
13248
  for (const c of Object.values(state.collections)) {
13127
13249
  const r = c.data.requests[requestId];
@@ -13134,18 +13256,36 @@ const createTabsSlice = (set2, get2) => ({
13134
13256
  activeTabId: null,
13135
13257
  activeCollectionId: null,
13136
13258
  openInTab: (requestId, collectionId) => set2((s) => {
13137
- s.collectionPanelOpen = false;
13138
- s.folderPanel = null;
13139
- const existing = s.tabs.find((t) => t.requestId === requestId && !t.exampleId);
13259
+ const existing = s.tabs.find((t) => t.kind === "request" && t.requestId === requestId && !t.exampleId);
13140
13260
  if (existing) {
13141
13261
  s.activeTabId = existing.id;
13142
- s.activeCollectionId = collectionId;
13143
13262
  } else {
13144
13263
  const tab = makeTab(requestId, collectionId, { protocol: protocolFor(s, requestId), defaultTab: s.workspace?.settings?.defaultRequestTab });
13145
13264
  s.tabs.push(tab);
13146
13265
  s.activeTabId = tab.id;
13147
- s.activeCollectionId = collectionId;
13148
13266
  }
13267
+ s.activeCollectionId = collectionId;
13268
+ syncPanelsToActiveTab(s);
13269
+ }),
13270
+ openFolderTab: (collectionId, folderId) => set2((s) => {
13271
+ const existing = s.tabs.find((t) => t.kind === "folder" && t.folderId === folderId && t.collectionId === collectionId);
13272
+ if (existing) s.activeTabId = existing.id;
13273
+ else {
13274
+ const tab = makeFolderTab(collectionId, folderId);
13275
+ s.tabs.push(tab);
13276
+ s.activeTabId = tab.id;
13277
+ }
13278
+ syncPanelsToActiveTab(s);
13279
+ }),
13280
+ openCollectionTab: (collectionId) => set2((s) => {
13281
+ const existing = s.tabs.find((t) => t.kind === "collection" && t.collectionId === collectionId);
13282
+ if (existing) s.activeTabId = existing.id;
13283
+ else {
13284
+ const tab = makeCollectionTab(collectionId);
13285
+ s.tabs.push(tab);
13286
+ s.activeTabId = tab.id;
13287
+ }
13288
+ syncPanelsToActiveTab(s);
13149
13289
  }),
13150
13290
  closeTab: (tabId) => set2((s) => {
13151
13291
  const idx = s.tabs.findIndex((t) => t.id === tabId);
@@ -13154,25 +13294,24 @@ const createTabsSlice = (set2, get2) => ({
13154
13294
  if (s.activeTabId === tabId) {
13155
13295
  const next = s.tabs[idx] ?? s.tabs[idx - 1] ?? null;
13156
13296
  s.activeTabId = next?.id ?? null;
13157
- s.activeCollectionId = next?.collectionId ?? null;
13297
+ syncPanelsToActiveTab(s);
13158
13298
  }
13159
13299
  }),
13160
13300
  closeAllTabs: () => set2((s) => {
13161
13301
  s.tabs = [];
13162
13302
  s.activeTabId = null;
13303
+ s.collectionPanelOpen = false;
13304
+ s.folderPanel = null;
13163
13305
  }),
13164
13306
  closeOtherTabs: (keepTabId) => set2((s) => {
13165
13307
  const kept = s.tabs.find((t) => t.id === keepTabId);
13166
13308
  s.tabs = kept ? [kept] : [];
13167
13309
  s.activeTabId = kept?.id ?? null;
13168
- if (kept) s.activeCollectionId = kept.collectionId;
13310
+ syncPanelsToActiveTab(s);
13169
13311
  }),
13170
13312
  setActiveTabId: (id2) => set2((s) => {
13171
13313
  s.activeTabId = id2;
13172
- s.collectionPanelOpen = false;
13173
- s.folderPanel = null;
13174
- const tab = s.tabs.find((t) => t.id === id2);
13175
- if (tab) s.activeCollectionId = tab.collectionId;
13314
+ syncPanelsToActiveTab(s);
13176
13315
  }),
13177
13316
  setTabResponse: (tabId, response, scriptResult, sentRequest) => set2((s) => {
13178
13317
  const tab = s.tabs.find((t) => t.id === tabId);
@@ -13254,98 +13393,6 @@ function flowRelPath(name, id2) {
13254
13393
  function safeName(name) {
13255
13394
  return name.trim().toLowerCase().replaceAll(/\s+/g, "-").replaceAll(/[^a-z0-9-_]/g, "").replaceAll(/-+/g, "-").replaceAll(/^-|-$/g, "");
13256
13395
  }
13257
- function orderedChildren(folder2) {
13258
- const reqSet = new Set(folder2.requestIds);
13259
- const folderSet = new Set(folder2.folders.map((f) => f.id));
13260
- const seen2 = /* @__PURE__ */ new Set();
13261
- const out = [];
13262
- for (const ref of folder2.childOrder ?? []) {
13263
- const key = `${ref.type}:${ref.id}`;
13264
- if (seen2.has(key)) continue;
13265
- if (ref.type === "request" && reqSet.has(ref.id) || ref.type === "folder" && folderSet.has(ref.id)) {
13266
- out.push({ type: ref.type, id: ref.id });
13267
- seen2.add(key);
13268
- }
13269
- }
13270
- for (const id2 of folder2.requestIds) if (!seen2.has(`request:${id2}`)) out.push({ type: "request", id: id2 });
13271
- for (const f of folder2.folders) if (!seen2.has(`folder:${f.id}`)) out.push({ type: "folder", id: f.id });
13272
- return out;
13273
- }
13274
- function sortChildOrder(folder2, requestName) {
13275
- const nameOf = (ref) => ref.type === "folder" ? folder2.folders.find((f) => f.id === ref.id)?.name ?? "" : requestName(ref.id);
13276
- return [...orderedChildren(folder2)].sort((a, b) => nameOf(a).localeCompare(nameOf(b), void 0, { sensitivity: "base", numeric: true }));
13277
- }
13278
- function findFolder$1(root2, id2) {
13279
- if (root2.id === id2) return root2;
13280
- for (const sub of root2.folders) {
13281
- const found = findFolder$1(sub, id2);
13282
- if (found) return found;
13283
- }
13284
- return null;
13285
- }
13286
- function findFolderContaining(root2, reqId) {
13287
- if (root2.requestIds.includes(reqId)) return root2;
13288
- for (const sub of root2.folders) {
13289
- const found = findFolderContaining(sub, reqId);
13290
- if (found) return found;
13291
- }
13292
- return null;
13293
- }
13294
- function removeFromFolder(root2, reqId) {
13295
- root2.requestIds = root2.requestIds.filter((id2) => id2 !== reqId);
13296
- root2.folders.forEach((sub) => removeFromFolder(sub, reqId));
13297
- }
13298
- function removeFolderById(parent, folderId) {
13299
- const idx = parent.folders.findIndex((f) => f.id === folderId);
13300
- if (idx !== -1) {
13301
- parent.folders.splice(idx, 1);
13302
- return true;
13303
- }
13304
- for (const sub of parent.folders) {
13305
- if (removeFolderById(sub, folderId)) return true;
13306
- }
13307
- return false;
13308
- }
13309
- function findFolderParent(root2, folderId) {
13310
- for (const sub of root2.folders) {
13311
- if (sub.id === folderId) return root2;
13312
- const found = findFolderParent(sub, folderId);
13313
- if (found) return found;
13314
- }
13315
- return null;
13316
- }
13317
- function findFolderPath(root2, requestId) {
13318
- if (root2.requestIds.includes(requestId)) return [root2];
13319
- for (const sub of root2.folders) {
13320
- const path = findFolderPath(sub, requestId);
13321
- if (path.length > 0) return [root2, ...path];
13322
- }
13323
- return [];
13324
- }
13325
- function collectRequestIds$1(f) {
13326
- return [...f.requestIds, ...f.folders.flatMap(collectRequestIds$1)];
13327
- }
13328
- function reIdFolderTree(root2, mapRequestId) {
13329
- root2.id = v4();
13330
- root2.requestIds = root2.requestIds.map(mapRequestId);
13331
- root2.folders.forEach((sub) => reIdFolderTree(sub, mapRequestId));
13332
- }
13333
- function cloneAndReId(folder2, mapRequestId) {
13334
- const cloned = structuredClone(folder2);
13335
- reIdFolderTree(cloned, mapRequestId);
13336
- return cloned;
13337
- }
13338
- function collectFolderVars(root2, reqId) {
13339
- const walk2 = (folder2) => {
13340
- if ((folder2.requestIds ?? []).includes(reqId)) return { ...folder2.variables ?? {} };
13341
- for (const sub of folder2.folders ?? []) {
13342
- const inner = walk2(sub);
13343
- if (inner) return { ...folder2.variables ?? {}, ...inner };
13344
- }
13345
- return null;
13346
- };
13347
- return walk2(root2) ?? {};
13348
- }
13349
13396
  const WRITE_METHODS$1 = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH"]);
13350
13397
  function newId$1() {
13351
13398
  try {
@@ -13432,6 +13479,14 @@ function makeRequest(override = {}) {
13432
13479
  ...override
13433
13480
  };
13434
13481
  }
13482
+ function uniqueFolderName(parent, desired, exclude) {
13483
+ const taken = new Set(parent.folders.filter((f) => f.id !== exclude).map((f) => f.name));
13484
+ if (!taken.has(desired)) return desired;
13485
+ for (let i = 2; ; i++) {
13486
+ const candidate = `${desired} ${i}`;
13487
+ if (!taken.has(candidate)) return candidate;
13488
+ }
13489
+ }
13435
13490
  function makeCollection(name) {
13436
13491
  return {
13437
13492
  version: "1.0",
@@ -13590,6 +13645,7 @@ const createCollectionsSlice = (set2, get2) => ({
13590
13645
  const hasActiveTab = s.tabs.some((t) => t.id === s.activeTabId);
13591
13646
  if (!hasActiveTab) s.activeTabId = s.tabs[0]?.id ?? null;
13592
13647
  }
13648
+ syncPanelsToActiveTab(s);
13593
13649
  });
13594
13650
  },
13595
13651
  updateCollectionDataSet: (id2, ds) => set2((s) => {
@@ -13607,9 +13663,10 @@ const createCollectionsSlice = (set2, get2) => ({
13607
13663
  s.collections[id2].data.description = description;
13608
13664
  s.collections[id2].dirty = true;
13609
13665
  }),
13610
- updateCollectionVariables: (id2, variables) => set2((s) => {
13666
+ updateCollectionVariables: (id2, variables, disabled) => set2((s) => {
13611
13667
  if (!s.collections[id2]) return;
13612
13668
  s.collections[id2].data.collectionVariables = variables;
13669
+ s.collections[id2].data.collectionVariablesDisabled = disabled;
13613
13670
  s.collections[id2].dirty = true;
13614
13671
  }),
13615
13672
  updateCollectionAuthAndHeaders: (id2, auth, headers) => set2((s) => {
@@ -13624,17 +13681,18 @@ const createCollectionsSlice = (set2, get2) => ({
13624
13681
  if (!col) return;
13625
13682
  const parent = findFolder$1(col.rootFolder, parentFolderId);
13626
13683
  if (!parent) return;
13627
- parent.folders.push({ id: v4(), name, description: "", folders: [], requestIds: [] });
13684
+ parent.folders.push({ id: v4(), name: uniqueFolderName(parent, name), description: "", folders: [], requestIds: [] });
13628
13685
  s.collections[collectionId].dirty = true;
13629
13686
  }),
13630
13687
  renameFolder: (collectionId, folderId, name) => set2((s) => {
13631
13688
  const col = s.collections[collectionId]?.data;
13632
13689
  if (!col) return;
13633
13690
  const folder2 = findFolder$1(col.rootFolder, folderId);
13634
- if (folder2) {
13635
- folder2.name = name;
13636
- s.collections[collectionId].dirty = true;
13637
- }
13691
+ if (!folder2) return;
13692
+ const parent = findFolderParent(col.rootFolder, folderId) ?? col.rootFolder;
13693
+ if (parent.folders.some((f) => f.id !== folderId && f.name === name)) return;
13694
+ folder2.name = name;
13695
+ s.collections[collectionId].dirty = true;
13638
13696
  }),
13639
13697
  duplicateFolder: (collectionId, folderId) => set2((s) => {
13640
13698
  const col = s.collections[collectionId]?.data;
@@ -13646,8 +13704,8 @@ const createCollectionsSlice = (set2, get2) => ({
13646
13704
  col.requests[newId2] = { ...JSON.parse(JSON.stringify(col.requests[oldId])), id: newId2 };
13647
13705
  return newId2;
13648
13706
  });
13649
- copy2.name = orig.name + " (copy)";
13650
13707
  const parent = findFolderParent(col.rootFolder, folderId) ?? col.rootFolder;
13708
+ copy2.name = uniqueFolderName(parent, orig.name + " (copy)");
13651
13709
  const idx = parent.folders.findIndex((f) => f.id === folderId);
13652
13710
  parent.folders.splice(idx + 1, 0, copy2);
13653
13711
  s.collections[collectionId].dirty = true;
@@ -13656,11 +13714,26 @@ const createCollectionsSlice = (set2, get2) => ({
13656
13714
  const col = s.collections[collectionId]?.data;
13657
13715
  if (!col) return;
13658
13716
  const folder2 = findFolder$1(col.rootFolder, folderId);
13717
+ const removedRequests = /* @__PURE__ */ new Set();
13718
+ const removedFolders = /* @__PURE__ */ new Set();
13659
13719
  if (folder2) {
13660
- collectRequestIds$1(folder2).forEach((rid) => delete col.requests[rid]);
13720
+ collectRequestIds$1(folder2).forEach((rid) => {
13721
+ removedRequests.add(rid);
13722
+ delete col.requests[rid];
13723
+ });
13724
+ const collect = (f) => {
13725
+ removedFolders.add(f.id);
13726
+ f.folders.forEach(collect);
13727
+ };
13728
+ collect(folder2);
13661
13729
  }
13662
13730
  removeFolderById(col.rootFolder, folderId);
13663
13731
  s.collections[collectionId].dirty = true;
13732
+ s.tabs = s.tabs.filter((t) => !(t.requestId && removedRequests.has(t.requestId) || t.kind === "folder" && t.folderId && removedFolders.has(t.folderId)));
13733
+ if (!s.tabs.some((t) => t.id === s.activeTabId)) {
13734
+ s.activeTabId = s.tabs[s.tabs.length - 1]?.id ?? null;
13735
+ }
13736
+ syncPanelsToActiveTab(s);
13664
13737
  }),
13665
13738
  // ── Request CRUD ────────────────────────────────────────────────────────────
13666
13739
  addRequest: (collectionId, folderId) => {
@@ -13676,6 +13749,7 @@ const createCollectionsSlice = (set2, get2) => ({
13676
13749
  const tab = makeTab(req.id, collectionId, { defaultTab: s.workspace?.settings?.defaultRequestTab });
13677
13750
  s.tabs.push(tab);
13678
13751
  s.activeTabId = tab.id;
13752
+ syncPanelsToActiveTab(s);
13679
13753
  });
13680
13754
  return req.id;
13681
13755
  },
@@ -13807,12 +13881,11 @@ const createCollectionsSlice = (set2, get2) => ({
13807
13881
  entry.dirty = true;
13808
13882
  }),
13809
13883
  openExample: (requestId, collectionId, exampleId) => set2((s) => {
13810
- s.collectionPanelOpen = false;
13811
- s.folderPanel = null;
13812
13884
  const existing = s.tabs.find((t) => t.requestId === requestId && t.exampleId === exampleId);
13813
13885
  if (existing) {
13814
13886
  s.activeTabId = existing.id;
13815
13887
  s.activeCollectionId = collectionId;
13888
+ syncPanelsToActiveTab(s);
13816
13889
  return;
13817
13890
  }
13818
13891
  const ex = Object.values(s.collections).find((c) => c.data.requests[requestId])?.data.requests[requestId].examples?.find((e) => e.id === exampleId);
@@ -13821,6 +13894,7 @@ const createCollectionsSlice = (set2, get2) => ({
13821
13894
  s.tabs.push(tab);
13822
13895
  s.activeTabId = tab.id;
13823
13896
  s.activeCollectionId = collectionId;
13897
+ syncPanelsToActiveTab(s);
13824
13898
  }),
13825
13899
  renameRequest: (id2, name) => set2((s) => {
13826
13900
  const entry = Object.values(s.collections).find((c) => c.data.requests[id2]);
@@ -13840,7 +13914,7 @@ const createCollectionsSlice = (set2, get2) => ({
13840
13914
  if (wasActive) {
13841
13915
  const next = s.tabs[tabIdx] ?? s.tabs[tabIdx - 1] ?? null;
13842
13916
  s.activeTabId = next?.id ?? null;
13843
- s.activeCollectionId = next?.collectionId ?? null;
13917
+ syncPanelsToActiveTab(s);
13844
13918
  }
13845
13919
  }
13846
13920
  s.collections[collectionId].dirty = true;
@@ -13860,6 +13934,7 @@ const createCollectionsSlice = (set2, get2) => ({
13860
13934
  const tab = makeTab(copy2.id, collectionId, { protocol: copy2.protocol, defaultTab: s.workspace?.settings?.defaultRequestTab });
13861
13935
  s.tabs.push(tab);
13862
13936
  s.activeTabId = tab.id;
13937
+ syncPanelsToActiveTab(s);
13863
13938
  }),
13864
13939
  addSecurityTests: (collectionId, requestId) => {
13865
13940
  const col = get2().collections[collectionId]?.data;
@@ -13922,6 +13997,7 @@ const createCollectionsSlice = (set2, get2) => ({
13922
13997
  srcParent.folders.splice(srcIdx, 1);
13923
13998
  const destParent = findFolder$1(col.rootFolder, destParentFolderId);
13924
13999
  if (!destParent) return;
14000
+ if (destParent.id !== srcParent.id) folder2.name = uniqueFolderName(destParent, folder2.name, folder2.id);
13925
14001
  if (destIndex !== void 0) {
13926
14002
  let adjusted = destIndex;
13927
14003
  if (srcParent.id === destParent.id && srcIdx < destIndex) adjusted--;
@@ -13948,6 +14024,7 @@ const createCollectionsSlice = (set2, get2) => ({
13948
14024
  const srcParent = findFolderParent(col.rootFolder, ref.id) ?? col.rootFolder;
13949
14025
  const srcIdx = srcParent.folders.findIndex((f) => f.id === ref.id);
13950
14026
  if (srcIdx >= 0) srcParent.folders.splice(srcIdx, 1);
14027
+ if (destParent.id !== srcParent.id) moving.name = uniqueFolderName(destParent, moving.name, moving.id);
13951
14028
  if (!destParent.folders.some((f) => f.id === ref.id)) destParent.folders.push(moving);
13952
14029
  }
13953
14030
  const others = orderedChildren(destParent).filter((c) => !(c.type === ref.type && c.id === ref.id));
@@ -14494,7 +14571,7 @@ const createFlowsSlice = (set2, get2) => ({
14494
14571
  entry.dirty = true;
14495
14572
  })
14496
14573
  });
14497
- const createUiSlice = (set2) => ({
14574
+ const createUiSlice = (set2, get2) => ({
14498
14575
  showGeneratorPanel: false,
14499
14576
  theme: localStorage.getItem(STORAGE_KEYS.theme) ?? "dark",
14500
14577
  zoom: Number(localStorage.getItem(STORAGE_KEYS.zoom) ?? "1.1"),
@@ -14578,14 +14655,23 @@ const createUiSlice = (set2) => ({
14578
14655
  cycleSubTab: (dir) => set2((s) => {
14579
14656
  s.subTabCycle = { nonce: s.subTabCycle.nonce + 1, pane: s.focusedPane, dir };
14580
14657
  }),
14581
- setCollectionPanelOpen: (open2) => set2((s) => {
14582
- s.collectionPanelOpen = open2;
14583
- if (open2) s.folderPanel = null;
14584
- }),
14585
- openFolderPanel: (collectionId, folderId) => set2((s) => {
14586
- s.folderPanel = { collectionId, folderId };
14587
- s.collectionPanelOpen = false;
14588
- }),
14658
+ // A collection / folder now opens as a tab. These keep their old names (and
14659
+ // callers) but delegate to the tab openers; the active tab drives the panels.
14660
+ setCollectionPanelOpen: (open2) => {
14661
+ if (!open2) {
14662
+ set2((s) => {
14663
+ s.collectionPanelOpen = false;
14664
+ });
14665
+ return;
14666
+ }
14667
+ const collectionId = get2().activeCollectionId;
14668
+ if (collectionId) get2().openCollectionTab(collectionId);
14669
+ else set2((s) => {
14670
+ s.collectionPanelOpen = true;
14671
+ s.folderPanel = null;
14672
+ });
14673
+ },
14674
+ openFolderPanel: (collectionId, folderId) => get2().openFolderTab(collectionId, folderId),
14589
14675
  setCoverageOpen: (open2) => set2((s) => {
14590
14676
  s.coverageOpen = open2;
14591
14677
  }),
@@ -14619,12 +14705,12 @@ const useStore$1 = create$1()(
14619
14705
  ...createEnvironmentsSlice(set2, get2),
14620
14706
  ...createMocksSlice(set2, get2),
14621
14707
  ...createFlowsSlice(set2, get2),
14622
- ...createUiSlice(set2),
14708
+ ...createUiSlice(set2, get2),
14623
14709
  // ── Workspace-level state ─────────────────────────────────────────────────
14624
14710
  workspace: null,
14625
14711
  workspacePath: null,
14626
14712
  globals: {},
14627
- sessionVars: {},
14713
+ sessionScriptVars: { env: {}, collection: {}, folder: {}, globals: {} },
14628
14714
  // ── Workspace ─────────────────────────────────────────────────────────────
14629
14715
  setWorkspace: (ws, path) => set2((s) => {
14630
14716
  s.workspace = ws;
@@ -14642,7 +14728,7 @@ const useStore$1 = create$1()(
14642
14728
  s.activeTabId = null;
14643
14729
  s.activeCollectionId = null;
14644
14730
  s.globals = {};
14645
- s.sessionVars = {};
14731
+ s.sessionScriptVars = { env: {}, collection: {}, folder: {}, globals: {} };
14646
14732
  s.runnerResults = [];
14647
14733
  s.runnerRunning = false;
14648
14734
  s.runnerModal = { open: false, collectionId: null, folderId: null, filterTags: [] };
@@ -14667,44 +14753,21 @@ const useStore$1 = create$1()(
14667
14753
  patchGlobals: (patch) => set2((s) => {
14668
14754
  s.globals = { ...s.globals, ...patch };
14669
14755
  }),
14670
- // ── Apply script results back to store ────────────────────────────────────
14671
- applyScriptUpdates: (result) => set2((s) => {
14672
- const isMaskSentinel = (v) => v === "[REDACTED]" || v === "[*****]";
14673
- const safeFilter = (m) => {
14674
- const out = {};
14675
- for (const [k, v] of Object.entries(m)) {
14676
- if (!isMaskSentinel(v)) out[k] = v;
14677
- else console.warn(`applyScriptUpdates: refusing to persist mask sentinel into "${k}"`);
14678
- }
14679
- return out;
14680
- };
14681
- const safeColVars = safeFilter(result.updatedCollectionVars);
14682
- const safeEnvVars = safeFilter(result.updatedEnvVars);
14683
- const safeGlobals = safeFilter(result.updatedGlobals);
14684
- const safeLocalVars = safeFilter(result.updatedLocalVars);
14685
- const activeColId = s.activeCollectionId;
14686
- if (activeColId && s.collections[activeColId]) {
14687
- const col = s.collections[activeColId].data;
14688
- col.collectionVariables = {
14689
- ...col.collectionVariables,
14690
- ...safeColVars
14691
- };
14692
- s.collections[activeColId].dirty = true;
14693
- }
14694
- const activeEnvId = s.activeEnvironmentId;
14695
- if (activeEnvId && s.environments[activeEnvId]) {
14696
- const env2 = s.environments[activeEnvId].data;
14697
- for (const [key, value2] of Object.entries(safeEnvVars)) {
14698
- const existing = env2.variables.find((v) => v.key === key);
14699
- if (existing && !existing.secret) {
14700
- existing.value = value2;
14701
- } else if (!existing) {
14702
- env2.variables.push({ key, value: value2, enabled: true });
14703
- }
14704
- }
14705
- }
14706
- s.globals = { ...s.globals, ...safeGlobals };
14707
- s.sessionVars = { ...s.sessionVars, ...safeLocalVars };
14756
+ // ── Script session ──────────────────────────────────────────────────────
14757
+ // Session semantics for script `.set()` on the named scopes: a value a
14758
+ // script sets (e.g. `sp.environment.set('authToken', …)`) is kept in memory
14759
+ // so the NEXT manually-sent request can read it, but is never written to the
14760
+ // `.env.json` / `.spector` / `globals.json` files or shown as a change in the
14761
+ // Variables screens, and it clears on workspace close / app restart. Within a
14762
+ // single send the value is threaded locally (see RequestBuilder); this sink
14763
+ // is what carries it across separate manual sends. `sp.variables.set` (local)
14764
+ // is request-scoped and intentionally not recorded here.
14765
+ recordScriptSession: (delta) => set2((s) => {
14766
+ const nonEmpty = (m) => m && Object.keys(m).length > 0;
14767
+ if (nonEmpty(delta.env)) s.sessionScriptVars.env = { ...s.sessionScriptVars.env, ...delta.env };
14768
+ if (nonEmpty(delta.collection)) s.sessionScriptVars.collection = { ...s.sessionScriptVars.collection, ...delta.collection };
14769
+ if (nonEmpty(delta.folder)) s.sessionScriptVars.folder = { ...s.sessionScriptVars.folder, ...delta.folder };
14770
+ if (nonEmpty(delta.globals)) s.sessionScriptVars.globals = { ...s.sessionScriptVars.globals, ...delta.globals };
14708
14771
  })
14709
14772
  }))
14710
14773
  );
@@ -14881,6 +14944,26 @@ function resolveEnvironmentChain(env2, all2) {
14881
14944
  }
14882
14945
  return { ...env2, variables: [...merged.values()] };
14883
14946
  }
14947
+ function withEnvOverrides(env2, overrides) {
14948
+ if (Object.keys(overrides).length === 0) return env2;
14949
+ if (!env2) {
14950
+ return {
14951
+ version: "1.0",
14952
+ id: "__session__",
14953
+ name: "",
14954
+ variables: Object.entries(overrides).map(([key, value2]) => ({ key, value: value2, enabled: true }))
14955
+ };
14956
+ }
14957
+ const variables = env2.variables.map(
14958
+ (v) => v.key in overrides && !v.secret ? { ...v, value: overrides[v.key] } : v
14959
+ );
14960
+ for (const [key, value2] of Object.entries(overrides)) {
14961
+ if (!env2.variables.some((v) => v.key === key)) {
14962
+ variables.push({ key, value: value2, enabled: true });
14963
+ }
14964
+ }
14965
+ return { ...env2, variables };
14966
+ }
14884
14967
  function resolveEnvironmentById(environments, id2) {
14885
14968
  if (!id2) return null;
14886
14969
  const env2 = environments[id2]?.data;
@@ -15481,7 +15564,7 @@ function useVarNames() {
15481
15564
  const activeCollectionId = useStore$1((s) => s.activeCollectionId);
15482
15565
  const collections = useStore$1((s) => s.collections);
15483
15566
  const globals = useStore$1((s) => s.globals);
15484
- const sessionVars = useStore$1((s) => s.sessionVars);
15567
+ const sessionScriptVars = useStore$1((s) => s.sessionScriptVars);
15485
15568
  const activeTabId = useStore$1((s) => s.activeTabId);
15486
15569
  const tabs = useStore$1((s) => s.tabs);
15487
15570
  const activeEnv = useActiveEnvironment();
@@ -15495,7 +15578,10 @@ function useVarNames() {
15495
15578
  Object.keys(collectFolderVars(tabCol.rootFolder, activeReq.id)).forEach((k) => names.add(k));
15496
15579
  }
15497
15580
  Object.keys(globals).forEach((k) => names.add(k));
15498
- Object.keys(sessionVars).forEach((k) => names.add(k));
15581
+ Object.keys(sessionScriptVars.env).forEach((k) => names.add(k));
15582
+ Object.keys(sessionScriptVars.collection).forEach((k) => names.add(k));
15583
+ Object.keys(sessionScriptVars.folder).forEach((k) => names.add(k));
15584
+ Object.keys(sessionScriptVars.globals).forEach((k) => names.add(k));
15499
15585
  if (activeCollectionId) {
15500
15586
  const col = collections[activeCollectionId]?.data;
15501
15587
  if (col) {
@@ -15524,7 +15610,7 @@ function useVarNames() {
15524
15610
  activeCollectionId,
15525
15611
  collections,
15526
15612
  globals,
15527
- sessionVars,
15613
+ sessionScriptVars,
15528
15614
  activeTabId,
15529
15615
  tabs
15530
15616
  ]);
@@ -15533,18 +15619,11 @@ function useVarValues() {
15533
15619
  const activeCollectionId = useStore$1((s) => s.activeCollectionId);
15534
15620
  const collections = useStore$1((s) => s.collections);
15535
15621
  const globals = useStore$1((s) => s.globals);
15622
+ const session = useStore$1((s) => s.sessionScriptVars);
15536
15623
  const activeTabId = useStore$1((s) => s.activeTabId);
15537
15624
  const tabs = useStore$1((s) => s.tabs);
15538
15625
  const activeEnv = useActiveEnvironment();
15539
- const result = { ...globals };
15540
- if (activeCollectionId) {
15541
- const colVars = collections[activeCollectionId]?.data.collectionVariables ?? {};
15542
- Object.assign(result, colVars);
15543
- }
15544
- const tab = tabs.find((x) => x.id === activeTabId);
15545
- const tabCol = tab?.collectionId ? collections[tab.collectionId]?.data : void 0;
15546
- const activeReq = tab?.requestId && tabCol ? tabCol.requests[tab.requestId] : void 0;
15547
- if (activeReq && tabCol) Object.assign(result, collectFolderVars(tabCol.rootFolder, activeReq.id));
15626
+ const result = { ...globals, ...session.globals };
15548
15627
  for (const v of activeEnv?.variables ?? []) {
15549
15628
  if (!v.enabled || !v.key) continue;
15550
15629
  if (v.secret && v.secretEncrypted) {
@@ -15555,7 +15634,24 @@ function useVarValues() {
15555
15634
  result[v.key] = v.value;
15556
15635
  }
15557
15636
  }
15558
- if (activeReq) Object.assign(result, activeReq.variables ?? {});
15637
+ Object.assign(result, session.env);
15638
+ if (activeCollectionId) {
15639
+ const colVars = collections[activeCollectionId]?.data.collectionVariables ?? {};
15640
+ Object.assign(result, colVars);
15641
+ }
15642
+ Object.assign(result, session.collection);
15643
+ const tab = tabs.find((x) => x.id === activeTabId);
15644
+ const tabCol = tab?.collectionId ? collections[tab.collectionId]?.data : void 0;
15645
+ const activeReq = tab?.requestId && tabCol ? tabCol.requests[tab.requestId] : void 0;
15646
+ if (activeReq && tabCol) Object.assign(result, collectFolderVars(tabCol.rootFolder, activeReq.id));
15647
+ Object.assign(result, session.folder);
15648
+ if (activeReq) {
15649
+ Object.assign(result, activeReq.variables ?? {});
15650
+ if (tab?.exampleId) {
15651
+ const ex = activeReq.examples?.find((e) => e.id === tab.exampleId);
15652
+ if (ex?.request?.variables) Object.assign(result, ex.request.variables);
15653
+ }
15654
+ }
15559
15655
  return result;
15560
15656
  }
15561
15657
  const Collections$6 = "Collections";
@@ -15709,6 +15805,8 @@ const request$6 = "request";
15709
15805
  const folder$6 = "folder";
15710
15806
  const collection$6 = "collection";
15711
15807
  const changed$6 = "changed";
15808
+ const Expand$6 = "Expand";
15809
+ const Collapse$6 = "Collapse";
15712
15810
  const Settings$6 = "Settings";
15713
15811
  const Today$6 = "Today";
15714
15812
  const Yesterday$6 = "Yesterday";
@@ -15882,6 +15980,7 @@ const en = {
15882
15980
  "Connect first to send messages": "Connect first to send messages",
15883
15981
  Send: Send$6,
15884
15982
  "Select a request from the sidebar": "Select a request from the sidebar",
15983
+ "No tabs open. Select a request, folder, or collection from the sidebar.": "No tabs open. Select a request, folder, or collection from the sidebar.",
15885
15984
  ":count requests": ":count requests",
15886
15985
  ":count data row|:count data rows": ":count data row|:count data rows",
15887
15986
  "Measure how much of an OpenAPI spec this workspace tests": "Measure how much of an OpenAPI spec this workspace tests",
@@ -16257,9 +16356,14 @@ const en = {
16257
16356
  Assert: Assert$6,
16258
16357
  "→ variable": "→ variable",
16259
16358
  "→ env": "→ env",
16359
+ "→ coll": "→ coll",
16260
16360
  Extract: Extract$6,
16261
16361
  "Save to variable": "Save to variable",
16262
16362
  "Save to environment": "Save to environment",
16363
+ "Save to collection variable": "Save to collection variable",
16364
+ "Save to folder variable": "Save to folder variable",
16365
+ "Save to global variable": "Save to global variable",
16366
+ "Save to variable (this request only)": "Save to variable (this request only)",
16263
16367
  "Add assertion for this value": "Add assertion for this value",
16264
16368
  "+ insert": "+ insert",
16265
16369
  "undefined": "undefined",
@@ -16493,6 +16597,8 @@ const en = {
16493
16597
  "Clear selection": "Clear selection",
16494
16598
  "Add request": "Add request",
16495
16599
  "Add folder": "Add folder",
16600
+ Expand: Expand$6,
16601
+ Collapse: Collapse$6,
16496
16602
  "Expand all": "Expand all",
16497
16603
  "Collapse all": "Collapse all",
16498
16604
  "Collection data": "Collection data",
@@ -16968,6 +17074,8 @@ const request$5 = "Request";
16968
17074
  const folder$5 = "Ordner";
16969
17075
  const collection$5 = "Sammlung";
16970
17076
  const changed$5 = "geändert";
17077
+ const Expand$5 = "Ausklappen";
17078
+ const Collapse$5 = "Einklappen";
16971
17079
  const Settings$5 = "Einstellungen";
16972
17080
  const Today$5 = "Heute";
16973
17081
  const Yesterday$5 = "Gestern";
@@ -17141,6 +17249,7 @@ const de = {
17141
17249
  "Connect first to send messages": "Zuerst verbinden, um Nachrichten zu senden",
17142
17250
  Send: Send$5,
17143
17251
  "Select a request from the sidebar": "Wählen Sie eine Request aus der Seitenleiste",
17252
+ "No tabs open. Select a request, folder, or collection from the sidebar.": "Keine Tabs geöffnet. Wählen Sie eine Request, einen Ordner oder eine Sammlung aus der Seitenleiste.",
17144
17253
  ":count requests": ":count Requests",
17145
17254
  ":count data row|:count data rows": ":count Datenzeile|:count Datenzeilen",
17146
17255
  "Measure how much of an OpenAPI spec this workspace tests": "Messen, wie viel einer OpenAPI-Spec dieser Arbeitsbereich testet",
@@ -17516,9 +17625,14 @@ const de = {
17516
17625
  Assert: Assert$5,
17517
17626
  "→ variable": "→ Variable",
17518
17627
  "→ env": "→ Umgebung",
17628
+ "→ coll": "→ Sammlung",
17519
17629
  Extract: Extract$5,
17520
17630
  "Save to variable": "In Variable speichern",
17521
17631
  "Save to environment": "In Umgebung speichern",
17632
+ "Save to collection variable": "In Sammlungsvariable speichern",
17633
+ "Save to folder variable": "In Ordnervariable speichern",
17634
+ "Save to global variable": "In globale Variable speichern",
17635
+ "Save to variable (this request only)": "In Variable speichern (nur diese request)",
17522
17636
  "Add assertion for this value": "Assertion für diesen Wert hinzufügen",
17523
17637
  "+ insert": "+ einfügen",
17524
17638
  "undefined": "undefined",
@@ -17752,6 +17866,8 @@ const de = {
17752
17866
  "Clear selection": "Auswahl aufheben",
17753
17867
  "Add request": "Request hinzufügen",
17754
17868
  "Add folder": "Ordner hinzufügen",
17869
+ Expand: Expand$5,
17870
+ Collapse: Collapse$5,
17755
17871
  "Expand all": "Alle ausklappen",
17756
17872
  "Collapse all": "Alle einklappen",
17757
17873
  "Collection data": "Sammlungsdaten",
@@ -18227,6 +18343,8 @@ const request$4 = "request";
18227
18343
  const folder$4 = "dossier";
18228
18344
  const collection$4 = "collection";
18229
18345
  const changed$4 = "modifié";
18346
+ const Expand$4 = "Développer";
18347
+ const Collapse$4 = "Réduire";
18230
18348
  const Settings$4 = "Paramètres";
18231
18349
  const Today$4 = "Aujourd'hui";
18232
18350
  const Yesterday$4 = "Hier";
@@ -18400,6 +18518,7 @@ const fr = {
18400
18518
  "Connect first to send messages": "Connectez-vous d'abord pour envoyer des messages",
18401
18519
  Send: Send$4,
18402
18520
  "Select a request from the sidebar": "Sélectionnez une request dans la barre latérale",
18521
+ "No tabs open. Select a request, folder, or collection from the sidebar.": "Aucun onglet ouvert. Sélectionnez une request, un dossier ou une collection dans la barre latérale.",
18403
18522
  ":count requests": ":count requests",
18404
18523
  ":count data row|:count data rows": ":count ligne de données|:count lignes de données",
18405
18524
  "Measure how much of an OpenAPI spec this workspace tests": "Mesurez quelle part d'une spec OpenAPI cet espace de travail teste",
@@ -18775,9 +18894,14 @@ const fr = {
18775
18894
  Assert: Assert$4,
18776
18895
  "→ variable": "→ variable",
18777
18896
  "→ env": "→ env",
18897
+ "→ coll": "→ coll",
18778
18898
  Extract: Extract$4,
18779
18899
  "Save to variable": "Enregistrer dans une variable",
18780
18900
  "Save to environment": "Enregistrer dans l'environnement",
18901
+ "Save to collection variable": "Enregistrer dans une variable de collection",
18902
+ "Save to folder variable": "Enregistrer dans une variable de dossier",
18903
+ "Save to global variable": "Enregistrer dans une variable globale",
18904
+ "Save to variable (this request only)": "Enregistrer dans une variable (cette request uniquement)",
18781
18905
  "Add assertion for this value": "Ajouter une assertion pour cette valeur",
18782
18906
  "+ insert": "+ insérer",
18783
18907
  "undefined": "undefined",
@@ -19011,6 +19135,8 @@ const fr = {
19011
19135
  "Clear selection": "Effacer la sélection",
19012
19136
  "Add request": "Ajouter une request",
19013
19137
  "Add folder": "Ajouter un dossier",
19138
+ Expand: Expand$4,
19139
+ Collapse: Collapse$4,
19014
19140
  "Expand all": "Tout développer",
19015
19141
  "Collapse all": "Tout réduire",
19016
19142
  "Collection data": "Données de la collection",
@@ -19486,6 +19612,8 @@ const request$3 = "request";
19486
19612
  const folder$3 = "carpeta";
19487
19613
  const collection$3 = "colección";
19488
19614
  const changed$3 = "cambiado";
19615
+ const Expand$3 = "Expandir";
19616
+ const Collapse$3 = "Contraer";
19489
19617
  const Settings$3 = "Ajustes";
19490
19618
  const Today$3 = "Hoy";
19491
19619
  const Yesterday$3 = "Ayer";
@@ -19659,6 +19787,7 @@ const es = {
19659
19787
  "Connect first to send messages": "Conecta primero para enviar mensajes",
19660
19788
  Send: Send$3,
19661
19789
  "Select a request from the sidebar": "Selecciona una request en la barra lateral",
19790
+ "No tabs open. Select a request, folder, or collection from the sidebar.": "No hay pestañas abiertas. Selecciona una request, una carpeta o una colección en la barra lateral.",
19662
19791
  ":count requests": ":count requests",
19663
19792
  ":count data row|:count data rows": ":count fila de datos|:count filas de datos",
19664
19793
  "Measure how much of an OpenAPI spec this workspace tests": "Mide qué parte de una especificación OpenAPI prueba este espacio de trabajo",
@@ -20034,9 +20163,14 @@ const es = {
20034
20163
  Assert: Assert$3,
20035
20164
  "→ variable": "→ variable",
20036
20165
  "→ env": "→ env",
20166
+ "→ coll": "→ coll",
20037
20167
  Extract: Extract$3,
20038
20168
  "Save to variable": "Guardar en variable",
20039
20169
  "Save to environment": "Guardar en entorno",
20170
+ "Save to collection variable": "Guardar en variable de colección",
20171
+ "Save to folder variable": "Guardar en variable de carpeta",
20172
+ "Save to global variable": "Guardar en variable global",
20173
+ "Save to variable (this request only)": "Guardar en variable (solo esta request)",
20040
20174
  "Add assertion for this value": "Añadir aserción para este valor",
20041
20175
  "+ insert": "+ insertar",
20042
20176
  "undefined": "undefined",
@@ -20270,6 +20404,8 @@ const es = {
20270
20404
  "Clear selection": "Borrar selección",
20271
20405
  "Add request": "Añadir request",
20272
20406
  "Add folder": "Añadir carpeta",
20407
+ Expand: Expand$3,
20408
+ Collapse: Collapse$3,
20273
20409
  "Expand all": "Expandir todo",
20274
20410
  "Collapse all": "Contraer todo",
20275
20411
  "Collection data": "Datos de la colección",
@@ -20745,6 +20881,8 @@ const request$2 = "request";
20745
20881
  const folder$2 = "cartella";
20746
20882
  const collection$2 = "raccolta";
20747
20883
  const changed$2 = "modificato";
20884
+ const Expand$2 = "Espandi";
20885
+ const Collapse$2 = "Comprimi";
20748
20886
  const Settings$2 = "Impostazioni";
20749
20887
  const Today$2 = "Oggi";
20750
20888
  const Yesterday$2 = "Ieri";
@@ -20918,6 +21056,7 @@ const it = {
20918
21056
  "Connect first to send messages": "Connettiti prima per inviare messaggi",
20919
21057
  Send: Send$2,
20920
21058
  "Select a request from the sidebar": "Seleziona una request dalla barra laterale",
21059
+ "No tabs open. Select a request, folder, or collection from the sidebar.": "Nessuna scheda aperta. Seleziona una request, una cartella o una raccolta dalla barra laterale.",
20921
21060
  ":count requests": ":count requests",
20922
21061
  ":count data row|:count data rows": ":count riga di dati|:count righe di dati",
20923
21062
  "Measure how much of an OpenAPI spec this workspace tests": "Misura quanta parte di una specifica OpenAPI testa questo workspace",
@@ -21293,9 +21432,14 @@ const it = {
21293
21432
  Assert: Assert$2,
21294
21433
  "→ variable": "→ variabile",
21295
21434
  "→ env": "→ env",
21435
+ "→ coll": "→ coll",
21296
21436
  Extract: Extract$2,
21297
21437
  "Save to variable": "Salva nella variabile",
21298
21438
  "Save to environment": "Salva nell'ambiente",
21439
+ "Save to collection variable": "Salva nella variabile della raccolta",
21440
+ "Save to folder variable": "Salva nella variabile della cartella",
21441
+ "Save to global variable": "Salva nella variabile globale",
21442
+ "Save to variable (this request only)": "Salva nella variabile (solo questa request)",
21299
21443
  "Add assertion for this value": "Aggiungi asserzione per questo valore",
21300
21444
  "+ insert": "+ inserisci",
21301
21445
  "undefined": "undefined",
@@ -21529,6 +21673,8 @@ const it = {
21529
21673
  "Clear selection": "Cancella selezione",
21530
21674
  "Add request": "Aggiungi request",
21531
21675
  "Add folder": "Aggiungi cartella",
21676
+ Expand: Expand$2,
21677
+ Collapse: Collapse$2,
21532
21678
  "Expand all": "Espandi tutto",
21533
21679
  "Collapse all": "Comprimi tutto",
21534
21680
  "Collection data": "Dati della raccolta",
@@ -22004,6 +22150,8 @@ const request$1 = "request";
22004
22150
  const folder$1 = "map";
22005
22151
  const collection$1 = "collectie";
22006
22152
  const changed$1 = "gewijzigd";
22153
+ const Expand$1 = "Uitklappen";
22154
+ const Collapse$1 = "Inklappen";
22007
22155
  const Settings$1 = "Instellingen";
22008
22156
  const Today$1 = "Vandaag";
22009
22157
  const Yesterday$1 = "Gisteren";
@@ -22177,6 +22325,7 @@ const nl = {
22177
22325
  "Connect first to send messages": "Verbind eerst om berichten te verzenden",
22178
22326
  Send: Send$1,
22179
22327
  "Select a request from the sidebar": "Selecteer een request in de zijbalk",
22328
+ "No tabs open. Select a request, folder, or collection from the sidebar.": "Geen tabbladen open. Selecteer een request, map of collectie in de zijbalk.",
22180
22329
  ":count requests": ":count requests",
22181
22330
  ":count data row|:count data rows": ":count datarij|:count datarijen",
22182
22331
  "Measure how much of an OpenAPI spec this workspace tests": "Meet hoeveel van een OpenAPI-spec deze werkruimte test",
@@ -22552,9 +22701,14 @@ const nl = {
22552
22701
  Assert: Assert$1,
22553
22702
  "→ variable": "→ variabele",
22554
22703
  "→ env": "→ env",
22704
+ "→ coll": "→ coll",
22555
22705
  Extract: Extract$1,
22556
22706
  "Save to variable": "Opslaan in variabele",
22557
22707
  "Save to environment": "Opslaan in omgeving",
22708
+ "Save to collection variable": "Opslaan in collectievariabele",
22709
+ "Save to folder variable": "Opslaan in mapvariabele",
22710
+ "Save to global variable": "Opslaan in globale variabele",
22711
+ "Save to variable (this request only)": "Opslaan in variabele (alleen deze request)",
22558
22712
  "Add assertion for this value": "Assertion voor deze waarde toevoegen",
22559
22713
  "+ insert": "+ invoegen",
22560
22714
  "undefined": "undefined",
@@ -22788,6 +22942,8 @@ const nl = {
22788
22942
  "Clear selection": "Selectie wissen",
22789
22943
  "Add request": "Request toevoegen",
22790
22944
  "Add folder": "Map toevoegen",
22945
+ Expand: Expand$1,
22946
+ Collapse: Collapse$1,
22791
22947
  "Expand all": "Alles uitklappen",
22792
22948
  "Collapse all": "Alles inklappen",
22793
22949
  "Collection data": "Collectiedata",
@@ -23263,6 +23419,8 @@ const request = "request";
23263
23419
  const folder = "pasta";
23264
23420
  const collection = "coleção";
23265
23421
  const changed = "alterado";
23422
+ const Expand = "Expandir";
23423
+ const Collapse = "Colapsar";
23266
23424
  const Settings = "Definições";
23267
23425
  const Today = "Hoje";
23268
23426
  const Yesterday = "Ontem";
@@ -23436,6 +23594,7 @@ const pt = {
23436
23594
  "Connect first to send messages": "Ligue-se primeiro para enviar mensagens",
23437
23595
  Send,
23438
23596
  "Select a request from the sidebar": "Selecione um request na barra lateral",
23597
+ "No tabs open. Select a request, folder, or collection from the sidebar.": "Nenhum separador aberto. Selecione um request, uma pasta ou uma coleção na barra lateral.",
23439
23598
  ":count requests": ":count requests",
23440
23599
  ":count data row|:count data rows": ":count linha de dados|:count linhas de dados",
23441
23600
  "Measure how much of an OpenAPI spec this workspace tests": "Meça quanto de uma especificação OpenAPI este espaço de trabalho testa",
@@ -23811,9 +23970,14 @@ const pt = {
23811
23970
  Assert,
23812
23971
  "→ variable": "→ variável",
23813
23972
  "→ env": "→ ambiente",
23973
+ "→ coll": "→ coleção",
23814
23974
  Extract,
23815
23975
  "Save to variable": "Guardar em variável",
23816
23976
  "Save to environment": "Guardar no ambiente",
23977
+ "Save to collection variable": "Guardar em variável de coleção",
23978
+ "Save to folder variable": "Guardar em variável de pasta",
23979
+ "Save to global variable": "Guardar em variável global",
23980
+ "Save to variable (this request only)": "Guardar em variável (apenas este request)",
23817
23981
  "Add assertion for this value": "Adicionar asserção para este valor",
23818
23982
  "+ insert": "+ inserir",
23819
23983
  "undefined": "indefinido",
@@ -24047,6 +24211,8 @@ const pt = {
24047
24211
  "Clear selection": "Limpar seleção",
24048
24212
  "Add request": "Adicionar request",
24049
24213
  "Add folder": "Adicionar pasta",
24214
+ Expand,
24215
+ Collapse,
24050
24216
  "Expand all": "Expandir tudo",
24051
24217
  "Collapse all": "Colapsar tudo",
24052
24218
  "Collection data": "Dados da coleção",
@@ -24970,6 +25136,40 @@ function Modal({
24970
25136
  window.addEventListener("keydown", onKey);
24971
25137
  return () => window.removeEventListener("keydown", onKey);
24972
25138
  }, [closeOnEscape, onClose]);
25139
+ const panelRef = reactExports.useRef(null);
25140
+ const [offset, setOffset] = reactExports.useState({ x: 0, y: 0 });
25141
+ const drag2 = reactExports.useRef(null);
25142
+ const onDragMove = reactExports.useCallback((e) => {
25143
+ const d = drag2.current;
25144
+ if (!d) return;
25145
+ let x = d.baseX + (e.clientX - d.startX);
25146
+ let y = d.baseY + (e.clientY - d.startY);
25147
+ const panel = panelRef.current;
25148
+ if (panel) {
25149
+ const maxX = Math.max(0, (window.innerWidth - panel.offsetWidth) / 2);
25150
+ const maxY = Math.max(0, (window.innerHeight - panel.offsetHeight) / 2);
25151
+ x = Math.min(maxX, Math.max(-maxX, x));
25152
+ y = Math.min(maxY, Math.max(-maxY, y));
25153
+ }
25154
+ setOffset({ x, y });
25155
+ }, []);
25156
+ const endDrag = reactExports.useCallback(() => {
25157
+ drag2.current = null;
25158
+ window.removeEventListener("mousemove", onDragMove);
25159
+ window.removeEventListener("mouseup", endDrag);
25160
+ document.body.style.userSelect = "";
25161
+ }, [onDragMove]);
25162
+ const onPanelMouseDown = reactExports.useCallback((e) => {
25163
+ if (e.button !== 0) return;
25164
+ const el = e.target;
25165
+ if (!el.closest("[data-modal-drag]")) return;
25166
+ if (el.closest('button, a, input, select, textarea, [role="button"], [contenteditable=""], [contenteditable="true"]')) return;
25167
+ drag2.current = { startX: e.clientX, startY: e.clientY, baseX: offset.x, baseY: offset.y };
25168
+ document.body.style.userSelect = "none";
25169
+ window.addEventListener("mousemove", onDragMove);
25170
+ window.addEventListener("mouseup", endDrag);
25171
+ }, [offset.x, offset.y, onDragMove, endDrag]);
25172
+ reactExports.useEffect(() => endDrag, [endDrag]);
24973
25173
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
24974
25174
  "div",
24975
25175
  {
@@ -24986,17 +25186,27 @@ function Modal({
24986
25186
  children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
24987
25187
  "div",
24988
25188
  {
25189
+ ref: panelRef,
24989
25190
  role: "dialog",
24990
25191
  "aria-modal": "true",
24991
25192
  className: panelClassName,
25193
+ style: offset.x || offset.y ? { transform: `translate(${offset.x}px, ${offset.y}px)` } : void 0,
25194
+ onMouseDown: onPanelMouseDown,
24992
25195
  children: [
24993
- title !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-4 py-2.5 border-b border-surface-800 flex-shrink-0", children: [
24994
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
24995
- /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold", children: title }),
24996
- subtitle !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-400 mt-0.5", children: subtitle })
24997
- ] }),
24998
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-400 hover:text-[var(--text-primary)] text-lg leading-none", children: "×" })
24999
- ] }),
25196
+ title !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs(
25197
+ "div",
25198
+ {
25199
+ "data-modal-drag": true,
25200
+ className: "flex items-center justify-between px-4 py-2.5 border-b border-surface-800 flex-shrink-0 cursor-move select-none",
25201
+ children: [
25202
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
25203
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold", children: title }),
25204
+ subtitle !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-400 mt-0.5", children: subtitle })
25205
+ ] }),
25206
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-400 hover:text-[var(--text-primary)] text-lg leading-none cursor-pointer", children: "×" })
25207
+ ]
25208
+ }
25209
+ ),
25000
25210
  children2
25001
25211
  ]
25002
25212
  }
@@ -25703,7 +25913,7 @@ function FolderSettingsModal({ collectionId, folder: folder2, onClose }) {
25703
25913
  overlayClassName: "bg-black/50 z-50 flex items-start justify-center pt-16",
25704
25914
  panelClassName: "w-[600px] bg-surface-900 border border-surface-800 rounded-lg shadow-2xl flex flex-col max-h-[80vh]",
25705
25915
  children: [
25706
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-4 py-2.5 border-b border-surface-800 shrink-0", children: [
25916
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-modal-drag": true, className: "flex items-center justify-between px-4 py-2.5 border-b border-surface-800 shrink-0 cursor-move select-none", children: [
25707
25917
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
25708
25918
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold", children: t("Folder settings") }),
25709
25919
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-600 mt-0.5", children: t(":name - auth and headers inherited by all requests in this folder", { name: folder2.name }) })
@@ -25798,7 +26008,7 @@ function CollectionSettingsModal({ collection: collection2, onClose }) {
25798
26008
  overlayClassName: "bg-black/50 z-50 flex items-start justify-center pt-16",
25799
26009
  panelClassName: "w-[600px] bg-surface-900 border border-surface-800 rounded-lg shadow-2xl flex flex-col max-h-[80vh]",
25800
26010
  children: [
25801
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-4 py-2.5 border-b border-surface-800 shrink-0", children: [
26011
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-modal-drag": true, className: "flex items-center justify-between px-4 py-2.5 border-b border-surface-800 shrink-0 cursor-move select-none", children: [
25802
26012
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
25803
26013
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold", children: t("Collection settings") }),
25804
26014
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-600 mt-0.5", children: t(":name - auth and headers inherited by all requests in this collection", { name: collection2.name }) })
@@ -26064,7 +26274,7 @@ function SchemaSyncModal({
26064
26274
  overlayClassName: "z-50 flex items-center justify-center bg-black/60",
26065
26275
  panelClassName: "bg-surface-900 border border-surface-700 rounded-xl shadow-2xl w-[640px] max-h-[80vh] p-5 flex flex-col gap-4",
26066
26276
  children: [
26067
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
26277
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-modal-drag": true, className: "flex items-center justify-between cursor-move select-none", children: [
26068
26278
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold text-surface-100", children: t("Sync schemas - :name", { name: scopeLabel }) }),
26069
26279
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-500 hover:text-surface-300 text-lg leading-none", children: "×" })
26070
26280
  ] }),
@@ -26159,7 +26369,7 @@ function SchemaSyncModal({
26159
26369
  overlayClassName: "z-50 flex items-center justify-center bg-black/60",
26160
26370
  panelClassName: "bg-surface-900 border border-surface-700 rounded-xl shadow-2xl w-[420px] p-5 flex flex-col gap-4",
26161
26371
  children: [
26162
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
26372
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-modal-drag": true, className: "flex items-center justify-between cursor-move select-none", children: [
26163
26373
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold text-surface-100", children: t("Sync schemas from OpenAPI") }),
26164
26374
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-500 hover:text-surface-300 text-lg leading-none", children: "×" })
26165
26375
  ] }),
@@ -26636,7 +26846,10 @@ async function pushRequestAsMonitor(request2, opts) {
26636
26846
  const collectionVars = {
26637
26847
  ...colEntry?.data.collectionVariables,
26638
26848
  ...s.getInheritedVariables(request2.id),
26639
- ...s.sessionVars
26849
+ ...s.sessionScriptVars.globals,
26850
+ ...s.sessionScriptVars.env,
26851
+ ...s.sessionScriptVars.collection,
26852
+ ...s.sessionScriptVars.folder
26640
26853
  };
26641
26854
  const setup = colEntry ? getHooksForRequest(request2.id, colEntry.data).before : [];
26642
26855
  const environment = resolveEnvironmentById(s.environments, s.activeEnvironmentId);
@@ -27180,6 +27393,14 @@ function RequestRow({
27180
27393
  onDragStart: (e) => {
27181
27394
  e.dataTransfer.effectAllowed = "move";
27182
27395
  dragCtx.setDragging({ type: "request", requestId: reqId, collectionId });
27396
+ if (selected2 && sel.count > 1) {
27397
+ const ghost = document.createElement("div");
27398
+ ghost.textContent = t(":count request|:count requests", { count: sel.count });
27399
+ ghost.style.cssText = "position:absolute;top:-1000px;left:-1000px;padding:4px 8px;font-size:12px;border-radius:4px;background:#1d4ed8;color:#fff;";
27400
+ document.body.appendChild(ghost);
27401
+ e.dataTransfer.setDragImage(ghost, 0, 0);
27402
+ setTimeout(() => ghost.remove(), 0);
27403
+ }
27183
27404
  },
27184
27405
  onDragEnd: () => {
27185
27406
  dragCtx.setDragging(null);
@@ -27507,7 +27728,7 @@ function DropLine({ collectionId, parentFolderId, index: index2, indent }) {
27507
27728
  }
27508
27729
  );
27509
27730
  }
27510
- const SelectionCtx = reactExports.createContext({ active: false, isSelected: () => false, toggle: () => {
27731
+ const SelectionCtx = reactExports.createContext({ active: false, count: 0, isSelected: () => false, toggle: () => {
27511
27732
  }, clear: () => {
27512
27733
  } });
27513
27734
  function TagChips({
@@ -27655,6 +27876,7 @@ function CollectionTree() {
27655
27876
  const selKey = (c, r) => `${c}\0${r}`;
27656
27877
  const selectionCtx = reactExports.useMemo(() => ({
27657
27878
  active: selected2.size > 0,
27879
+ count: selected2.size,
27658
27880
  isSelected: (c, r) => selected2.has(selKey(c, r)),
27659
27881
  toggle: (c, r) => setSelected((prev) => {
27660
27882
  const next = new Set(prev);
@@ -27680,9 +27902,38 @@ function CollectionTree() {
27680
27902
  setPendingConfirm(null);
27681
27903
  } });
27682
27904
  }
27905
+ function orderedSelectedRequests() {
27906
+ const out = [];
27907
+ const walk2 = (collectionId, folder2) => {
27908
+ for (const child of orderedChildren(folder2)) {
27909
+ if (child.type === "request") {
27910
+ if (selected2.has(selKey(collectionId, child.id))) out.push({ collectionId, requestId: child.id });
27911
+ } else {
27912
+ const sub = folder2.folders.find((f) => f.id === child.id);
27913
+ if (sub) walk2(collectionId, sub);
27914
+ }
27915
+ }
27916
+ };
27917
+ for (const { data } of colList) walk2(data.id, data.rootFolder);
27918
+ return out;
27919
+ }
27920
+ function draggedRequests() {
27921
+ if (dragging?.type !== "request") return [];
27922
+ const dragKey = selKey(dragging.collectionId, dragging.requestId);
27923
+ if (selected2.size > 1 && selected2.has(dragKey)) return orderedSelectedRequests();
27924
+ return [{ collectionId: dragging.collectionId, requestId: dragging.requestId }];
27925
+ }
27683
27926
  function onDropRequest(destCollectionId, destFolderId, destIndex) {
27684
- if (dragging?.type !== "request") return;
27685
- moveRequest(dragging.collectionId, dragging.requestId, destCollectionId, destFolderId, destIndex);
27927
+ const reqs = draggedRequests();
27928
+ if (reqs.length === 0) return;
27929
+ reqs.forEach((r, i) => moveRequest(
27930
+ r.collectionId,
27931
+ r.requestId,
27932
+ destCollectionId,
27933
+ destFolderId,
27934
+ destIndex === void 0 ? void 0 : destIndex + i
27935
+ ));
27936
+ if (reqs.length > 1) selectionCtx.clear();
27686
27937
  setDragging(null);
27687
27938
  }
27688
27939
  function onDropFolder(destCollectionId, destParentFolderId, destIndex) {
@@ -27693,12 +27944,22 @@ function CollectionTree() {
27693
27944
  }
27694
27945
  function onReorderChild(destCollectionId, destParentFolderId, destIndex) {
27695
27946
  if (!dragging) return;
27696
- if (dragging.collectionId === destCollectionId) {
27697
- const ref = dragging.type === "folder" ? { type: "folder", id: dragging.folderId } : { type: "request", id: dragging.requestId };
27698
- reorderChild(destCollectionId, ref, destParentFolderId, destIndex);
27699
- } else if (dragging.type === "request") {
27700
- moveRequest(dragging.collectionId, dragging.requestId, destCollectionId, destParentFolderId);
27947
+ if (dragging.type === "folder") {
27948
+ if (dragging.collectionId === destCollectionId) {
27949
+ reorderChild(destCollectionId, { type: "folder", id: dragging.folderId }, destParentFolderId, destIndex);
27950
+ }
27951
+ setDragging(null);
27952
+ return;
27701
27953
  }
27954
+ const reqs = draggedRequests();
27955
+ reqs.forEach((r, i) => {
27956
+ if (r.collectionId === destCollectionId) {
27957
+ reorderChild(destCollectionId, { type: "request", id: r.requestId }, destParentFolderId, destIndex + i);
27958
+ } else {
27959
+ moveRequest(r.collectionId, r.requestId, destCollectionId, destParentFolderId);
27960
+ }
27961
+ });
27962
+ if (reqs.length > 1) selectionCtx.clear();
27702
27963
  setDragging(null);
27703
27964
  }
27704
27965
  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: [
@@ -27933,14 +28194,12 @@ function CollectionNode({
27933
28194
  className: `group flex items-center gap-1 px-2 py-1.5 cursor-pointer hover:bg-surface-800 transition-colors outline-none focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-blue-400 ${panelActive ? "bg-surface-800 text-[var(--text-primary)]" : isActive ? "text-[var(--text-primary)]" : "text-surface-400"} ${col.disabled ? "opacity-50" : ""} ${dropOver ? "outline outline-1 outline-blue-500 rounded" : ""}`,
27934
28195
  role: "button",
27935
28196
  tabIndex: 0,
27936
- onClick: () => {
27937
- onSelectCollection();
27938
- setExpanded((e) => !e);
28197
+ onClick: onSelectCollection,
28198
+ onDoubleClick: (e) => {
28199
+ e.stopPropagation();
28200
+ setRenaming(true);
27939
28201
  },
27940
- onKeyDown: onActivateKey(() => {
27941
- onSelectCollection();
27942
- setExpanded((e) => !e);
27943
- }),
28202
+ onKeyDown: onActivateKey(onSelectCollection),
27944
28203
  onDragOver: dragCtx.dragging ? (e) => {
27945
28204
  e.preventDefault();
27946
28205
  setDropOver(true);
@@ -27953,7 +28212,20 @@ function CollectionNode({
27953
28212
  else dragCtx.onDropRequest(col.id, col.rootFolder.id);
27954
28213
  },
27955
28214
  children: [
27956
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none w-4 h-4 shrink-0 flex items-center justify-center", children: expanded ? "▾" : "▸" }),
28215
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
28216
+ "button",
28217
+ {
28218
+ type: "button",
28219
+ onClick: (e) => {
28220
+ e.stopPropagation();
28221
+ setExpanded((e2) => !e2);
28222
+ },
28223
+ "aria-expanded": expanded,
28224
+ title: expanded ? t("Collapse") : t("Expand"),
28225
+ className: "text-[22px] leading-none w-4 h-4 shrink-0 flex items-center justify-center text-surface-500 hover:text-[var(--text-primary)]",
28226
+ children: expanded ? "▾" : "▸"
28227
+ }
28228
+ ),
27957
28229
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0", children: renaming ? /* @__PURE__ */ jsxRuntimeExports.jsx(
27958
28230
  InlineEdit,
27959
28231
  {
@@ -28048,6 +28320,7 @@ function FolderRow({
28048
28320
  onToggleDisabled,
28049
28321
  onUpdateTags,
28050
28322
  onRun,
28323
+ siblingNames = [],
28051
28324
  children: children2
28052
28325
  }) {
28053
28326
  const t = useT();
@@ -28101,14 +28374,12 @@ function FolderRow({
28101
28374
  style: { paddingLeft: indent },
28102
28375
  role: "button",
28103
28376
  tabIndex: 0,
28104
- onClick: () => {
28105
- openFolderPanel(collectionId, folder2.id);
28106
- setExpanded((e) => !e);
28377
+ onClick: () => openFolderPanel(collectionId, folder2.id),
28378
+ onDoubleClick: (e) => {
28379
+ e.stopPropagation();
28380
+ setRenaming(true);
28107
28381
  },
28108
- onKeyDown: onActivateKey(() => {
28109
- openFolderPanel(collectionId, folder2.id);
28110
- setExpanded((e) => !e);
28111
- }),
28382
+ onKeyDown: onActivateKey(() => openFolderPanel(collectionId, folder2.id)),
28112
28383
  onDragStart: (e) => {
28113
28384
  e.dataTransfer.effectAllowed = "move";
28114
28385
  e.stopPropagation();
@@ -28122,7 +28393,20 @@ function FolderRow({
28122
28393
  onDragLeave: () => setDropInside(false),
28123
28394
  onDrop: handleFolderDrop,
28124
28395
  children: [
28125
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[22px] leading-none w-4 h-4 shrink-0 flex items-center justify-center", children: expanded ? "▾" : "▸" }),
28396
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
28397
+ "button",
28398
+ {
28399
+ type: "button",
28400
+ onClick: (e) => {
28401
+ e.stopPropagation();
28402
+ setExpanded((e2) => !e2);
28403
+ },
28404
+ "aria-expanded": expanded,
28405
+ title: expanded ? t("Collapse") : t("Expand"),
28406
+ className: "text-[22px] leading-none w-4 h-4 shrink-0 flex items-center justify-center text-surface-500 hover:text-[var(--text-primary)]",
28407
+ children: expanded ? "▾" : "▸"
28408
+ }
28409
+ ),
28126
28410
  /* @__PURE__ */ jsxRuntimeExports.jsx(FolderIcon, { className: `shrink-0 ${hasInheritedConfig ? "text-blue-500" : "text-amber-600"}` }),
28127
28411
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [
28128
28412
  renaming ? /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -28134,7 +28418,8 @@ function FolderRow({
28134
28418
  setRenaming(false);
28135
28419
  },
28136
28420
  onCancel: () => setRenaming(false),
28137
- className: "w-full text-xs"
28421
+ className: "w-full text-xs",
28422
+ validate: (v) => siblingNames.filter((n2) => n2 !== folder2.name).includes(v.trim()) ? t('":name" already exists', { name: v.trim() }) : null
28138
28423
  }
28139
28424
  ) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs truncate flex items-center gap-1.5", children: [
28140
28425
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", children: folder2.name }),
@@ -28265,6 +28550,7 @@ function FolderContents({
28265
28550
  depth,
28266
28551
  expandCtrl,
28267
28552
  onRequestExpand,
28553
+ siblingNames: folder2.folders.map((f) => f.name),
28268
28554
  onAddRequest: () => onAddRequest(sub.id),
28269
28555
  onAddFolder: () => onAddFolder(sub.id, "New Folder"),
28270
28556
  onRename: (name) => onRenameFolder(sub.id, name),
@@ -28649,8 +28935,8 @@ function jsonWithComments() {
28649
28935
  function xmlWithComments() {
28650
28936
  return [xml(), commentKeymap];
28651
28937
  }
28652
- const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-BwaRI4Ba.js"), true ? __vite__mapDeps([0,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.GraphQLEditor })));
28653
- const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-DafZPr0j.js"), true ? __vite__mapDeps([3,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.SoapEditor })));
28938
+ const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-TklsnkDw.js"), true ? __vite__mapDeps([0,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.GraphQLEditor })));
28939
+ const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-CllZqWyv.js"), true ? __vite__mapDeps([3,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.SoapEditor })));
28654
28940
  function BodyTab({ request: request2, onChange }) {
28655
28941
  const t = useT();
28656
28942
  const editorFallback = /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 text-xs text-surface-500", children: t("Loading editor…") });
@@ -38773,6 +39059,11 @@ function VariablesTab({ request: request2 }) {
38773
39059
  const collections = useStore$1((s) => s.collections);
38774
39060
  const globals = useStore$1((s) => s.globals);
38775
39061
  const updateRequest = useStore$1((s) => s.updateRequest);
39062
+ const updateExampleRequest = useStore$1((s) => s.updateExampleRequest);
39063
+ const activeExampleId = useStore$1((s) => {
39064
+ const tb = s.tabs.find((x) => x.id === s.activeTabId);
39065
+ return tb?.exampleId ?? null;
39066
+ });
38776
39067
  const activeEnv = useActiveEnvironment();
38777
39068
  const col = activeCollectionId ? collections[activeCollectionId]?.data : void 0;
38778
39069
  const { envDisplay, envKeys, folderVars, collectionVars } = reactExports.useMemo(() => {
@@ -38788,7 +39079,25 @@ function VariablesTab({ request: request2 }) {
38788
39079
  return { envDisplay: envDisplay2, envKeys: envKeys2, folderVars: folderVars2, collectionVars: collectionVars2 };
38789
39080
  }, [activeEnv, col, request2.id]);
38790
39081
  const requestVars = reactExports.useMemo(() => request2.variables ?? {}, [request2.variables]);
38791
- const sourceOf = (name) => name in requestVars ? "request" : name in folderVars ? "folder" : envKeys.has(name) ? "environment" : name in collectionVars ? "collection" : "global";
39082
+ const isExample = !!activeExampleId;
39083
+ const editableSeed = reactExports.useMemo(() => {
39084
+ const base = col?.requests[request2.id];
39085
+ let enabled;
39086
+ let disabled;
39087
+ if (isExample) {
39088
+ const ex = base?.examples?.find((e) => e.id === activeExampleId);
39089
+ enabled = ex?.request?.variables ?? {};
39090
+ disabled = ex?.request?.variablesDisabled ?? {};
39091
+ } else {
39092
+ enabled = base?.variables ?? request2.variables ?? {};
39093
+ disabled = base?.variablesDisabled ?? request2.variablesDisabled ?? {};
39094
+ }
39095
+ return [
39096
+ ...Object.entries(enabled).map(([key, value2]) => ({ key, value: value2, enabled: true })),
39097
+ ...Object.entries(disabled).map(([key, value2]) => ({ key, value: value2, enabled: false }))
39098
+ ];
39099
+ }, [isExample, activeExampleId, col, request2.id, request2.variables, request2.variablesDisabled]);
39100
+ const sourceOf = (name) => name in requestVars ? "request" : name in folderVars ? "folder" : name in collectionVars ? "collection" : envKeys.has(name) ? "environment" : "global";
38792
39101
  const valueOf = (name) => {
38793
39102
  switch (sourceOf(name)) {
38794
39103
  case "request":
@@ -38820,24 +39129,25 @@ function VariablesTab({ request: request2 }) {
38820
39129
  environment: t("environment"),
38821
39130
  request: t("request")
38822
39131
  };
38823
- const [rows, setRows] = reactExports.useState(
38824
- () => Object.entries(requestVars).map(([key, value2]) => ({ key, value: value2 }))
38825
- );
39132
+ const [rows, setRows] = reactExports.useState(() => editableSeed);
38826
39133
  reactExports.useEffect(() => {
38827
- setRows(Object.entries(request2.variables ?? {}).map(([key, value2]) => ({ key, value: value2 })));
38828
- }, [request2.id]);
39134
+ setRows(editableSeed);
39135
+ }, [request2.id, activeExampleId]);
38829
39136
  function persist(next) {
38830
39137
  setRows(next);
38831
- const record = {};
39138
+ const variables = {};
39139
+ const variablesDisabled = {};
38832
39140
  for (const r of next) {
38833
39141
  const k = r.key.trim();
38834
- if (k) record[k] = r.value;
39142
+ if (!k) continue;
39143
+ (r.enabled ? variables : variablesDisabled)[k] = r.value;
38835
39144
  }
38836
- updateRequest(request2.id, { variables: record });
39145
+ if (isExample && activeExampleId) updateExampleRequest(request2.id, activeExampleId, { variables, variablesDisabled });
39146
+ else updateRequest(request2.id, { variables, variablesDisabled });
38837
39147
  }
38838
39148
  const setRow = (i, patch) => persist(rows.map((r, idx) => idx === i ? { ...r, ...patch } : r));
38839
39149
  const removeRow = (i) => persist(rows.filter((_, idx) => idx !== i));
38840
- const addRow = (key = "", value2 = "") => persist([...rows, { key, value: value2 }]);
39150
+ const addRow = (key = "", value2 = "") => persist([...rows, { key, value: value2, enabled: true }]);
38841
39151
  const overrideHere = (name) => {
38842
39152
  if (name in requestVars) return;
38843
39153
  addRow(name, valueOf(name) === "••••••••" ? "" : `{{${name}}}`);
@@ -38846,10 +39156,10 @@ function VariablesTab({ request: request2 }) {
38846
39156
  /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { children: [
38847
39157
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
38848
39158
  /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-[11px] uppercase tracking-wider text-surface-400", children: [
38849
- t("Request variables"),
38850
- rows.filter((r) => r.key.trim()).length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-1.5 text-surface-500", children: [
39159
+ isExample ? t("Example variables") : t("Request variables"),
39160
+ rows.filter((r) => r.enabled && r.key.trim()).length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-1.5 text-surface-500", children: [
38851
39161
  "(",
38852
- rows.filter((r) => r.key.trim()).length,
39162
+ rows.filter((r) => r.enabled && r.key.trim()).length,
38853
39163
  ")"
38854
39164
  ] })
38855
39165
  ] }),
@@ -38858,11 +39168,21 @@ function VariablesTab({ request: request2 }) {
38858
39168
  t("Add variable")
38859
39169
  ] })
38860
39170
  ] }),
38861
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-500 mb-2", children: t("Scoped to this request and its examples. Override environment, folder, collection and global variables with the same name.") }),
39171
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-500 mb-2", children: isExample ? t("Scoped to this example. Override the request’s variables (and environment, folder, collection, global) for this example only.") : t("Scoped to this request and its examples. Override environment, folder, collection and global variables with the same name.") }),
38862
39172
  rows.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col gap-1", children: rows.map((r, i) => {
38863
39173
  const key = r.key.trim();
38864
39174
  const shadows = !!key && (envKeys.has(key) || key in folderVars || key in collectionVars || key in globals);
38865
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [
39175
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `flex items-center gap-1.5 ${r.enabled ? "" : "opacity-50"}`, children: [
39176
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
39177
+ "input",
39178
+ {
39179
+ type: "checkbox",
39180
+ checked: r.enabled,
39181
+ onChange: (e) => setRow(i, { enabled: e.target.checked }),
39182
+ title: r.enabled ? t("Disable") : t("Enable"),
39183
+ className: "shrink-0 accent-blue-500 cursor-pointer"
39184
+ }
39185
+ ),
38866
39186
  /* @__PURE__ */ jsxRuntimeExports.jsx(
38867
39187
  "input",
38868
39188
  {
@@ -40881,7 +41201,7 @@ function RequestBuilder({ request: request2 }) {
40881
41201
  const setTabSending = useStore$1((s) => s.setTabSending);
40882
41202
  const setTabRequestTab = useStore$1((s) => s.setTabRequestTab);
40883
41203
  const addHistoryEntry = useStore$1((s) => s.addHistoryEntry);
40884
- const applyScriptUpdates = useStore$1((s) => s.applyScriptUpdates);
41204
+ const recordScriptSession = useStore$1((s) => s.recordScriptSession);
40885
41205
  const startLiveStream = useStore$1((s) => s.startLiveStream);
40886
41206
  const finishLiveStream = useStore$1((s) => s.finishLiveStream);
40887
41207
  const workspaceSettings = useStore$1((s) => s.workspace?.settings);
@@ -41006,7 +41326,6 @@ function RequestBuilder({ request: request2 }) {
41006
41326
  const collectedHookResults = [];
41007
41327
  try {
41008
41328
  const activeEnv = resolveEnvironmentById(environments, activeEnvironmentId);
41009
- const sessionVars = useStore$1.getState().sessionVars;
41010
41329
  const tls = collectionTls ? { ...workspaceSettings?.tls, ...collectionTls } : workspaceSettings?.tls;
41011
41330
  const basePayload = {
41012
41331
  environment: activeEnv,
@@ -41014,13 +41333,18 @@ function RequestBuilder({ request: request2 }) {
41014
41333
  tls,
41015
41334
  piiMaskPatterns: workspaceSettings?.piiMaskPatterns
41016
41335
  };
41336
+ const session = useStore$1.getState().sessionScriptVars;
41017
41337
  let collectionVars = {
41018
41338
  ...activeCollectionId ? collections[activeCollectionId]?.data.collectionVariables ?? {} : {},
41019
- // Folder-chain variables sit above collection vars and below session/local.
41339
+ ...session.collection
41340
+ };
41341
+ const folderVars = {
41020
41342
  ...useStore$1.getState().getInheritedVariables(request2.id),
41021
- ...sessionVars
41343
+ ...session.folder
41022
41344
  };
41023
- let liveGlobals = { ...globals };
41345
+ let liveGlobals = { ...globals, ...session.globals };
41346
+ let liveLocalVars = {};
41347
+ let liveEnvOverrides = { ...session.env };
41024
41348
  const inherited = useStore$1.getState().getInheritedAuthAndHeaders(request2.id);
41025
41349
  const mergedAuth = authIsConfigured(request2.auth) ? request2.auth : inherited.auth ?? request2.auth;
41026
41350
  const mergedHeaders = [
@@ -41043,21 +41367,25 @@ function RequestBuilder({ request: request2 }) {
41043
41367
  for (const hook of hooks2.before) {
41044
41368
  const start2 = Date.now();
41045
41369
  try {
41046
- const hookEnv = resolveEnvironmentById(
41047
- useStore$1.getState().environments,
41048
- activeEnvironmentId
41049
- );
41050
- const hookSessionVars = useStore$1.getState().sessionVars;
41370
+ const hookEnv = withEnvOverrides(activeEnv, liveEnvOverrides);
41051
41371
  const r = await electron$u.sendRequest({
41052
41372
  ...basePayload,
41053
41373
  environment: hookEnv,
41054
41374
  request: hook,
41055
- collectionVars: { ...collectionVars, ...hookSessionVars },
41375
+ folderVars: useStore$1.getState().getInheritedVariables(hook.id),
41376
+ collectionVars: { ...collectionVars, ...liveLocalVars },
41056
41377
  globals: liveGlobals
41057
41378
  });
41058
- applyScriptUpdates(r.scriptResult);
41059
41379
  collectionVars = { ...collectionVars, ...r.scriptResult.updatedCollectionVars };
41060
41380
  liveGlobals = { ...liveGlobals, ...r.scriptResult.updatedGlobals };
41381
+ liveLocalVars = { ...liveLocalVars, ...r.scriptResult.updatedLocalVars };
41382
+ liveEnvOverrides = { ...liveEnvOverrides, ...r.scriptResult.updatedEnvVars };
41383
+ recordScriptSession({
41384
+ env: r.scriptResult.updatedEnvVars,
41385
+ collection: r.scriptResult.updatedCollectionVars,
41386
+ folder: r.scriptResult.updatedFolderVars,
41387
+ globals: r.scriptResult.updatedGlobals
41388
+ });
41061
41389
  collectedHookResults.push({
41062
41390
  requestId: hook.id,
41063
41391
  name: hook.name,
@@ -41087,11 +41415,7 @@ function RequestBuilder({ request: request2 }) {
41087
41415
  });
41088
41416
  }
41089
41417
  }
41090
- const freshEnv = resolveEnvironmentById(
41091
- useStore$1.getState().environments,
41092
- activeEnvironmentId
41093
- );
41094
- const freshSessionVars = useStore$1.getState().sessionVars;
41418
+ const freshEnv = withEnvOverrides(activeEnv, liveEnvOverrides);
41095
41419
  const streamId = crypto.randomUUID();
41096
41420
  startLiveStream(activeTabId, streamId);
41097
41421
  let result;
@@ -41100,7 +41424,8 @@ function RequestBuilder({ request: request2 }) {
41100
41424
  ...basePayload,
41101
41425
  environment: freshEnv,
41102
41426
  request: mergedRequest,
41103
- collectionVars: { ...collectionVars, ...freshSessionVars },
41427
+ folderVars,
41428
+ collectionVars: { ...collectionVars, ...liveLocalVars },
41104
41429
  globals: liveGlobals,
41105
41430
  streamId,
41106
41431
  ...selectedDataRow() ? { dataRow: selectedDataRow() } : {}
@@ -41109,9 +41434,16 @@ function RequestBuilder({ request: request2 }) {
41109
41434
  finishLiveStream(streamId);
41110
41435
  }
41111
41436
  setTabResponse(activeTabId, result.response, result.scriptResult, result.sentRequest);
41112
- applyScriptUpdates(result.scriptResult);
41113
41437
  collectionVars = { ...collectionVars, ...result.scriptResult.updatedCollectionVars };
41114
41438
  liveGlobals = { ...liveGlobals, ...result.scriptResult.updatedGlobals };
41439
+ liveLocalVars = { ...liveLocalVars, ...result.scriptResult.updatedLocalVars };
41440
+ liveEnvOverrides = { ...liveEnvOverrides, ...result.scriptResult.updatedEnvVars };
41441
+ recordScriptSession({
41442
+ env: result.scriptResult.updatedEnvVars,
41443
+ collection: result.scriptResult.updatedCollectionVars,
41444
+ folder: result.scriptResult.updatedFolderVars,
41445
+ globals: result.scriptResult.updatedGlobals
41446
+ });
41115
41447
  addHistoryEntry({
41116
41448
  id: crypto.randomUUID(),
41117
41449
  timestamp: Date.now(),
@@ -41124,21 +41456,25 @@ function RequestBuilder({ request: request2 }) {
41124
41456
  for (const hook of hooks2.after) {
41125
41457
  const start2 = Date.now();
41126
41458
  try {
41127
- const hookEnv = resolveEnvironmentById(
41128
- useStore$1.getState().environments,
41129
- activeEnvironmentId
41130
- );
41131
- const hookSessionVars = useStore$1.getState().sessionVars;
41459
+ const hookEnv = withEnvOverrides(activeEnv, liveEnvOverrides);
41132
41460
  const r = await electron$u.sendRequest({
41133
41461
  ...basePayload,
41134
41462
  environment: hookEnv,
41135
41463
  request: hook,
41136
- collectionVars: { ...collectionVars, ...hookSessionVars },
41464
+ folderVars: useStore$1.getState().getInheritedVariables(hook.id),
41465
+ collectionVars: { ...collectionVars, ...liveLocalVars },
41137
41466
  globals: liveGlobals
41138
41467
  });
41139
- applyScriptUpdates(r.scriptResult);
41140
41468
  collectionVars = { ...collectionVars, ...r.scriptResult.updatedCollectionVars };
41141
41469
  liveGlobals = { ...liveGlobals, ...r.scriptResult.updatedGlobals };
41470
+ liveLocalVars = { ...liveLocalVars, ...r.scriptResult.updatedLocalVars };
41471
+ liveEnvOverrides = { ...liveEnvOverrides, ...r.scriptResult.updatedEnvVars };
41472
+ recordScriptSession({
41473
+ env: r.scriptResult.updatedEnvVars,
41474
+ collection: r.scriptResult.updatedCollectionVars,
41475
+ folder: r.scriptResult.updatedFolderVars,
41476
+ globals: r.scriptResult.updatedGlobals
41477
+ });
41142
41478
  collectedHookResults.push({
41143
41479
  requestId: hook.id,
41144
41480
  name: hook.name,
@@ -41746,6 +42082,13 @@ function AssertMenu({ state, onClose, onConfirm }) {
41746
42082
  let options = [];
41747
42083
  let jpSiblingKeys = [];
41748
42084
  let jpAvailable = false;
42085
+ const extractScopes = [
42086
+ { label: t("Save to environment"), target: "environment" },
42087
+ { label: t("Save to collection variable"), target: "collectionVariables" },
42088
+ { label: t("Save to folder variable"), target: "folder" },
42089
+ { label: t("Save to global variable"), target: "globals" },
42090
+ { label: t("Save to variable (this request only)"), target: "variables" }
42091
+ ];
41749
42092
  if (state.type === "json") {
41750
42093
  const { path, value: value2, root: root2 } = state;
41751
42094
  const isStr = typeof value2 === "string";
@@ -41871,11 +42214,12 @@ function AssertMenu({ state, onClose, onConfirm }) {
41871
42214
  {
41872
42215
  disabled: !filterKey || !filterVal,
41873
42216
  onClick: () => {
41874
- onConfirm(makeJsonPathExtractSnippet(state.path, filterKey, filterVal, "variables"));
42217
+ onConfirm(makeJsonPathExtractSnippet(state.path, filterKey, filterVal, "environment"));
41875
42218
  onClose();
41876
42219
  },
42220
+ title: t("Save to environment"),
41877
42221
  className: "text-xs px-2 py-1 bg-surface-700 hover:bg-surface-600 disabled:opacity-40 rounded transition-colors",
41878
- children: t("→ variable")
42222
+ children: t("→ env")
41879
42223
  }
41880
42224
  ),
41881
42225
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -41883,11 +42227,12 @@ function AssertMenu({ state, onClose, onConfirm }) {
41883
42227
  {
41884
42228
  disabled: !filterKey || !filterVal,
41885
42229
  onClick: () => {
41886
- onConfirm(makeJsonPathExtractSnippet(state.path, filterKey, filterVal, "environment"));
42230
+ onConfirm(makeJsonPathExtractSnippet(state.path, filterKey, filterVal, "collectionVariables"));
41887
42231
  onClose();
41888
42232
  },
42233
+ title: t("Save to collection variable"),
41889
42234
  className: "text-xs px-2 py-1 bg-surface-700 hover:bg-surface-600 disabled:opacity-40 rounded transition-colors",
41890
- children: t("→ env")
42235
+ children: t("→ coll")
41891
42236
  }
41892
42237
  )
41893
42238
  ] })
@@ -41895,53 +42240,19 @@ function AssertMenu({ state, onClose, onConfirm }) {
41895
42240
  ] }),
41896
42241
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 border-t border-surface-800 pt-1", children: [
41897
42242
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-surface-500 uppercase tracking-wider px-2 py-1", children: t("Extract") }),
41898
- state.type === "json" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
41899
- /* @__PURE__ */ jsxRuntimeExports.jsx(
41900
- "button",
41901
- {
41902
- onClick: () => {
41903
- onConfirm(makeJsonExtractSnippet(state.path, "variables"));
41904
- onClose();
41905
- },
41906
- className: "w-full text-left text-xs text-surface-300 hover:text-white hover:bg-surface-800 rounded px-2 py-1.5 transition-colors",
41907
- children: t("Save to variable")
41908
- }
41909
- ),
41910
- /* @__PURE__ */ jsxRuntimeExports.jsx(
41911
- "button",
41912
- {
41913
- onClick: () => {
41914
- onConfirm(makeJsonExtractSnippet(state.path, "environment"));
41915
- onClose();
41916
- },
41917
- className: "w-full text-left text-xs text-surface-300 hover:text-white hover:bg-surface-800 rounded px-2 py-1.5 transition-colors",
41918
- children: t("Save to environment")
41919
- }
41920
- )
41921
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
41922
- /* @__PURE__ */ jsxRuntimeExports.jsx(
41923
- "button",
41924
- {
41925
- onClick: () => {
41926
- onConfirm(makeXmlExtractSnippet(state.selector, "variables"));
41927
- onClose();
41928
- },
41929
- className: "w-full text-left text-xs text-surface-300 hover:text-white hover:bg-surface-800 rounded px-2 py-1.5 transition-colors",
41930
- children: t("Save to variable")
41931
- }
41932
- ),
41933
- /* @__PURE__ */ jsxRuntimeExports.jsx(
41934
- "button",
41935
- {
41936
- onClick: () => {
41937
- onConfirm(makeXmlExtractSnippet(state.selector, "environment"));
41938
- onClose();
41939
- },
41940
- className: "w-full text-left text-xs text-surface-300 hover:text-white hover:bg-surface-800 rounded px-2 py-1.5 transition-colors",
41941
- children: t("Save to environment")
41942
- }
41943
- )
41944
- ] })
42243
+ extractScopes.map((scope) => /* @__PURE__ */ jsxRuntimeExports.jsx(
42244
+ "button",
42245
+ {
42246
+ onClick: () => {
42247
+ const snippet = state.type === "json" ? makeJsonExtractSnippet(state.path, scope.target) : makeXmlExtractSnippet(state.selector, scope.target);
42248
+ onConfirm(snippet);
42249
+ onClose();
42250
+ },
42251
+ className: "w-full text-left text-xs text-surface-300 hover:text-white hover:bg-surface-800 rounded px-2 py-1.5 transition-colors",
42252
+ children: scope.label
42253
+ },
42254
+ scope.target
42255
+ ))
41945
42256
  ] })
41946
42257
  ]
41947
42258
  }
@@ -45335,7 +45646,7 @@ function WelcomeScreen() {
45335
45646
  )
45336
45647
  ] }),
45337
45648
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-400 text-sm max-w-sm", children: t("Local-first API testing with Robot Framework & Playwright code generation. Secrets stay on your machine.") }),
45338
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t("version :version", { version: "0.8.6" }) })
45649
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t("version :version", { version: "0.8.8" }) })
45339
45650
  ] }),
45340
45651
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 w-64", children: [
45341
45652
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -45452,7 +45763,7 @@ function MasterKeyModal({ onSuccess, onCancel }) {
45452
45763
  overlayClassName: "bg-black/60 z-[60] flex items-center justify-center",
45453
45764
  panelClassName: "bg-surface-900 border border-surface-700 rounded-lg shadow-2xl w-[500px] p-5 flex flex-col gap-4",
45454
45765
  children: [
45455
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
45766
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-modal-drag": true, className: "cursor-move select-none", children: [
45456
45767
  /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-semibold", children: t("Master Password Required") }),
45457
45768
  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-surface-400 mt-1", children: [
45458
45769
  t("Secrets are encrypted with AES-256-GCM using a master password. Set"),
@@ -47237,7 +47548,7 @@ function DocsGeneratorModal({ onClose }) {
47237
47548
  overlayClassName: "z-50 flex items-center justify-center bg-black/60",
47238
47549
  panelClassName: "bg-surface-900 border border-surface-700 rounded-lg shadow-2xl w-[680px] max-h-[80vh] flex flex-col",
47239
47550
  children: [
47240
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-surface-800 flex-shrink-0", children: [
47551
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-modal-drag": true, className: "flex items-center justify-between px-4 py-3 border-b border-surface-800 flex-shrink-0 cursor-move select-none", children: [
47241
47552
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-semibold text-white", children: t("Generate API Documentation") }),
47242
47553
  /* @__PURE__ */ jsxRuntimeExports.jsx(
47243
47554
  "button",
@@ -47858,7 +48169,7 @@ function ImportModal({ onImport, onClose }) {
47858
48169
  overlayClassName: "z-50 flex items-center justify-center bg-black/60",
47859
48170
  panelClassName: "bg-surface-900 border border-surface-700 rounded-xl shadow-2xl w-[640px] max-h-[80vh] p-5 flex flex-col gap-4",
47860
48171
  children: [
47861
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
48172
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { "data-modal-drag": true, className: "flex items-center justify-between cursor-move select-none", children: [
47862
48173
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold text-surface-100", children: t("Import - :name", { name: previewCol.name }) }),
47863
48174
  /* @__PURE__ */ jsxRuntimeExports.jsx(
47864
48175
  "button",
@@ -50391,14 +50702,18 @@ function CollectionPanel() {
50391
50702
  const [activeTab, setActiveTab] = reactExports.useState("documentation");
50392
50703
  const [varRows, setVarRows] = reactExports.useState([]);
50393
50704
  reactExports.useEffect(() => {
50394
- const vars = activeCollectionId ? collections[activeCollectionId]?.data.collectionVariables : void 0;
50395
- setVarRows(Object.entries(vars ?? {}).map(([key, value2]) => ({ key, value: value2, enabled: true })));
50705
+ const data = activeCollectionId ? collections[activeCollectionId]?.data : void 0;
50706
+ setVarRows([
50707
+ ...Object.entries(data?.collectionVariables ?? {}).map(([key, value2]) => ({ key, value: value2, enabled: true })),
50708
+ ...Object.entries(data?.collectionVariablesDisabled ?? {}).map(([key, value2]) => ({ key, value: value2, enabled: false }))
50709
+ ]);
50396
50710
  }, [activeCollectionId]);
50397
50711
  function setVars(rows) {
50398
50712
  setVarRows(rows);
50399
50713
  if (!activeCollectionId) return;
50400
- const variables = Object.fromEntries(rows.filter((r) => r.key.trim()).map((r) => [r.key.trim(), r.value]));
50401
- updateCollectionVariables(activeCollectionId, variables);
50714
+ const variables = Object.fromEntries(rows.filter((r) => r.enabled && r.key.trim()).map((r) => [r.key.trim(), r.value]));
50715
+ const disabled = Object.fromEntries(rows.filter((r) => !r.enabled && r.key.trim()).map((r) => [r.key.trim(), r.value]));
50716
+ updateCollectionVariables(activeCollectionId, variables, disabled);
50402
50717
  }
50403
50718
  if (!activeCollectionId) {
50404
50719
  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-full text-surface-400 text-sm", children: t("Select a request from the sidebar") });
@@ -50479,7 +50794,7 @@ function CollectionPanel() {
50479
50794
  ),
50480
50795
  activeTab === "data" && /* @__PURE__ */ jsxRuntimeExports.jsx(DataSetEditor, { ds, onChange: setDs, exportName: col.name, scopeLabel: "collection" }),
50481
50796
  activeTab === "variables" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 text-xs", children: [
50482
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-500", children: t("Variables scoped to this collection. They are overridden by folder variables, the active environment, and script-set values. Reference them anywhere with :token.", { token: "{{name}}" }) }),
50797
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-500", children: t("Variables scoped to this collection. They override environment and global variables, and are overridden by folder and request variables (and runtime / CLI / data-row values). Reference them anywhere with :token.", { token: "{{name}}" }) }),
50483
50798
  /* @__PURE__ */ jsxRuntimeExports.jsx(KVTable, { rows: varRows, onChange: setVars, keyPlaceholder: t("name"), valuePlaceholder: t("value") }),
50484
50799
  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-surface-600 text-[11px]", children: [
50485
50800
  t("Scripts can also set these at runtime via"),
@@ -50504,7 +50819,10 @@ function FolderPanel() {
50504
50819
  reactExports.useEffect(() => {
50505
50820
  const c = folderPanel ? useStore$1.getState().collections[folderPanel.collectionId]?.data : null;
50506
50821
  const f = c ? findFolder$1(c.rootFolder, folderPanel.folderId) : null;
50507
- setVarRows(Object.entries(f?.variables ?? {}).map(([key, value2]) => ({ key, value: value2, enabled: true })));
50822
+ setVarRows([
50823
+ ...Object.entries(f?.variables ?? {}).map(([key, value2]) => ({ key, value: value2, enabled: true })),
50824
+ ...Object.entries(f?.variablesDisabled ?? {}).map(([key, value2]) => ({ key, value: value2, enabled: false }))
50825
+ ]);
50508
50826
  }, [folderKey]);
50509
50827
  if (!folderPanel) return null;
50510
50828
  const col = collections[folderPanel.collectionId]?.data;
@@ -50515,8 +50833,9 @@ function FolderPanel() {
50515
50833
  const iterCount = ds.rows.length;
50516
50834
  function setVars(rows) {
50517
50835
  setVarRows(rows);
50518
- const variables = Object.fromEntries(rows.filter((r) => r.key.trim()).map((r) => [r.key.trim(), r.value]));
50519
- updateFolder(cid, folder2.id, { variables });
50836
+ const variables = Object.fromEntries(rows.filter((r) => r.enabled && r.key.trim()).map((r) => [r.key.trim(), r.value]));
50837
+ const variablesDisabled = Object.fromEntries(rows.filter((r) => !r.enabled && r.key.trim()).map((r) => [r.key.trim(), r.value]));
50838
+ updateFolder(cid, folder2.id, { variables, variablesDisabled });
50520
50839
  }
50521
50840
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full", children: [
50522
50841
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-6 py-4 border-b border-surface-800 flex-shrink-0 flex items-center justify-between", children: [
@@ -56557,6 +56876,7 @@ const TAB_METHOD_COLORS = {
56557
56876
  };
56558
56877
  const TabRow = React.memo(function TabRow2({
56559
56878
  tabId,
56879
+ kind = "request",
56560
56880
  method,
56561
56881
  name,
56562
56882
  isActive,
@@ -56578,7 +56898,7 @@ const TabRow = React.memo(function TabRow2({
56578
56898
  },
56579
56899
  className: `group flex items-center gap-1.5 px-3 py-1.5 border-r border-surface-800 cursor-pointer min-w-0 max-w-[200px] flex-shrink-0 transition-colors ${isActive ? "bg-surface-900 border-b-2 border-b-blue-500 -mb-px" : "hover:bg-surface-900/50 text-surface-600"}`,
56580
56900
  children: [
56581
- method && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] font-bold shrink-0 ${TAB_METHOD_COLORS[method] ?? "text-gray-400"}`, children: method }),
56901
+ kind === "folder" ? /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3 shrink-0 text-amber-600", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M2 5a2 2 0 012-2h3.5l2 2H16a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V5z" }) }) : kind === "collection" ? /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3 shrink-0 text-blue-400", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M3 4h14v2.5H3V4zm0 4.75h14v2.5H3v-2.5zM3 13.5h14V16H3v-2.5z" }) }) : method ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] font-bold shrink-0 ${TAB_METHOD_COLORS[method] ?? "text-gray-400"}`, children: method }) : null,
56582
56902
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-xs truncate ${isActive ? "text-white" : ""}`, children: name }),
56583
56903
  /* @__PURE__ */ jsxRuntimeExports.jsx(
56584
56904
  "button",
@@ -56822,7 +57142,11 @@ function App() {
56822
57142
  ...o,
56823
57143
  params: o.params ?? [],
56824
57144
  headers: o.headers ?? [],
56825
- body: o.body ?? { mode: "none" }
57145
+ body: o.body ?? { mode: "none" },
57146
+ // Variables are the exception to "replace": an example's own variables
57147
+ // override the request's, but inherit the ones it doesn't define, so an
57148
+ // example can hold its own values without losing the request's others.
57149
+ variables: { ...activeBaseRequest.variables, ...o.variables ?? {} }
56826
57150
  };
56827
57151
  }, [activeBaseRequest, activeTab?.exampleId]);
56828
57152
  const openTabContextMenu = reactExports.useCallback((tabId, x, y) => {
@@ -56854,7 +57178,7 @@ function App() {
56854
57178
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
56855
57179
  /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-50", children: [
56856
57180
  "v",
56857
- "0.8.6"
57181
+ "0.8.8"
56858
57182
  ] }),
56859
57183
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", children: "·" }),
56860
57184
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -57018,14 +57342,27 @@ function App() {
57018
57342
  /* @__PURE__ */ jsxRuntimeExports.jsxs("main", { className: "flex-1 min-w-0 flex flex-col min-h-0", children: [
57019
57343
  tabs.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center border-b border-surface-800 bg-surface-950 flex-shrink-0", children: [
57020
57344
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center overflow-x-auto flex-1 min-w-0", children: tabs.map((tab) => {
57021
- const req = tab.requestId ? requestsById.get(tab.requestId) ?? null : null;
57022
- const exampleName = tab.exampleId ? req?.examples?.find((e) => e.id === tab.exampleId)?.name : null;
57345
+ const kind = tab.kind ?? "request";
57346
+ let name;
57347
+ let method;
57348
+ if (kind === "collection") {
57349
+ name = (tab.collectionId ? collections[tab.collectionId]?.data.name : null) ?? t("Collection");
57350
+ } else if (kind === "folder") {
57351
+ const root2 = tab.collectionId ? collections[tab.collectionId]?.data.rootFolder : void 0;
57352
+ name = (root2 && tab.folderId ? findFolder$1(root2, tab.folderId)?.name : null) ?? t("Folder");
57353
+ } else {
57354
+ const req = tab.requestId ? requestsById.get(tab.requestId) ?? null : null;
57355
+ const exampleName = tab.exampleId ? req?.examples?.find((e) => e.id === tab.exampleId)?.name : null;
57356
+ method = req?.method;
57357
+ name = exampleName ? `${req?.name ?? t("Untitled")} · ${exampleName}` : req?.name ?? t("Untitled");
57358
+ }
57023
57359
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
57024
57360
  TabRow,
57025
57361
  {
57026
57362
  tabId: tab.id,
57027
- method: req?.method,
57028
- name: exampleName ? `${req?.name ?? t("Untitled")} · ${exampleName}` : req?.name ?? t("Untitled"),
57363
+ kind,
57364
+ method,
57365
+ name,
57029
57366
  isActive: tab.id === activeTabId,
57030
57367
  onActivate: setActiveTabId,
57031
57368
  onClose: closeTab,
@@ -57211,7 +57548,7 @@ function App() {
57211
57548
  )
57212
57549
  }
57213
57550
  )
57214
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CollectionPanel, {}) })
57551
+ ] }) : tabs.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 flex items-center justify-center p-6 text-center text-surface-600 text-sm", children: t("No tabs open. Select a request, folder, or collection from the sidebar.") }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CollectionPanel, {}) })
57215
57552
  ] }),
57216
57553
  showGeneratorPanel && /* @__PURE__ */ jsxRuntimeExports.jsx("aside", { className: "w-[480px] flex-shrink-0 border-l border-surface-800 flex flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(GeneratorPanel, {}) })
57217
57554
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(WelcomeScreen, {})