@testsmith/api-spector 0.0.2 → 0.0.4

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.
@@ -9168,18 +9168,20 @@ function IconBtn({
9168
9168
  danger = false,
9169
9169
  alwaysVisible = false
9170
9170
  }) {
9171
- return /* @__PURE__ */ jsxRuntimeExports.jsx(
9172
- "button",
9173
- {
9174
- title: title2,
9175
- onClick: (e) => {
9176
- e.stopPropagation();
9177
- onClick(e);
9178
- },
9179
- className: `px-1 py-0.5 rounded transition-colors ${alwaysVisible ? "" : "opacity-0 group-hover:opacity-100"} ${danger ? "hover:text-red-400" : "hover:text-blue-400"} text-surface-400`,
9180
- children
9181
- }
9182
- );
9171
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative group/tip", children: [
9172
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
9173
+ "button",
9174
+ {
9175
+ onClick: (e) => {
9176
+ e.stopPropagation();
9177
+ onClick(e);
9178
+ },
9179
+ className: `px-1 py-0.5 rounded transition-all ${alwaysVisible ? "" : "opacity-0 group-hover:opacity-100"} ${danger ? "hover:text-red-400" : "hover:text-blue-400"} text-surface-400 hover:scale-150`,
9180
+ children
9181
+ }
9182
+ ),
9183
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pointer-events-none absolute bottom-full left-1/2 -translate-x-1/2 mb-1 z-50 hidden group-hover/tip:block", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "whitespace-nowrap rounded px-1.5 py-0.5 text-[10px] bg-[#1e1b2e] text-gray-300 border border-white/10 shadow-lg", children: title2 }) })
9184
+ ] });
9183
9185
  }
9184
9186
  function RunBtn({ onClick }) {
9185
9187
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -9291,6 +9293,13 @@ function CollectionNode({
9291
9293
  }) {
9292
9294
  const [expanded, setExpanded] = reactExports.useState(true);
9293
9295
  const [renaming, setRenaming] = reactExports.useState(false);
9296
+ const [expandCtrl, setExpandCtrl] = reactExports.useState({ value: true, seq: 0 });
9297
+ function expandAll() {
9298
+ setExpandCtrl((c) => ({ value: true, seq: c.seq + 1 }));
9299
+ }
9300
+ function collapseAll() {
9301
+ setExpandCtrl((c) => ({ value: false, seq: c.seq + 1 }));
9302
+ }
9294
9303
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
9295
9304
  /* @__PURE__ */ jsxRuntimeExports.jsxs(
9296
9305
  "div",
@@ -9317,6 +9326,8 @@ function CollectionNode({
9317
9326
  ) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-semibold truncate block", children: col.name }) }),
9318
9327
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center shrink-0 gap-0", children: [
9319
9328
  /* @__PURE__ */ jsxRuntimeExports.jsx(RunBtn, { onClick: onRunCollection }),
9329
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Expand all folders", onClick: expandAll, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExpandAllIcon, {}) }),
9330
+ /* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Collapse all folders", onClick: collapseAll, children: /* @__PURE__ */ jsxRuntimeExports.jsx(CollapseAllIcon, {}) }),
9320
9331
  /* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Collection data (iterations)", onClick: onSelectCollection, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TableIcon, {}) }),
9321
9332
  /* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Add request", onClick: () => onAddRequest(col.rootFolder.id), children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "+" }) }),
9322
9333
  /* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Add folder", onClick: () => onAddFolder(col.rootFolder.id, "New Folder"), children: /* @__PURE__ */ jsxRuntimeExports.jsx(FolderIcon, {}) }),
@@ -9334,6 +9345,7 @@ function CollectionNode({
9334
9345
  requests: col.requests,
9335
9346
  activeRequestId,
9336
9347
  depth: 0,
9348
+ expandCtrl,
9337
9349
  onSelectRequest,
9338
9350
  onAddRequest,
9339
9351
  onAddFolder,
@@ -9353,6 +9365,7 @@ function FolderRow({
9353
9365
  folder,
9354
9366
  collectionId,
9355
9367
  depth,
9368
+ expandCtrl,
9356
9369
  onAddRequest,
9357
9370
  onAddFolder,
9358
9371
  onRename,
@@ -9362,6 +9375,9 @@ function FolderRow({
9362
9375
  children
9363
9376
  }) {
9364
9377
  const [expanded, setExpanded] = reactExports.useState(true);
9378
+ reactExports.useEffect(() => {
9379
+ if (expandCtrl.seq > 0) setExpanded(expandCtrl.value);
9380
+ }, [expandCtrl.seq]);
9365
9381
  const [renaming, setRenaming] = reactExports.useState(false);
9366
9382
  const [showSettings, setShowSettings] = reactExports.useState(false);
9367
9383
  const tags2 = folder.tags ?? [];
@@ -9430,6 +9446,7 @@ function FolderContents({
9430
9446
  requests,
9431
9447
  activeRequestId,
9432
9448
  depth,
9449
+ expandCtrl,
9433
9450
  onSelectRequest,
9434
9451
  onAddRequest,
9435
9452
  onAddFolder,
@@ -9449,6 +9466,7 @@ function FolderContents({
9449
9466
  folder: sub,
9450
9467
  collectionId,
9451
9468
  depth: depth + 1,
9469
+ expandCtrl,
9452
9470
  onAddRequest: () => onAddRequest(sub.id),
9453
9471
  onAddFolder: () => onAddFolder(sub.id, "New Folder"),
9454
9472
  onRename: (name2) => onRenameFolder(sub.id, name2),
@@ -9463,6 +9481,7 @@ function FolderContents({
9463
9481
  requests,
9464
9482
  activeRequestId,
9465
9483
  depth: depth + 1,
9484
+ expandCtrl,
9466
9485
  onSelectRequest,
9467
9486
  onAddRequest,
9468
9487
  onAddFolder,
@@ -9576,6 +9595,12 @@ function CopyIcon() {
9576
9595
  function KeyIcon() {
9577
9596
  return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M15 7a4 4 0 110 8 4 4 0 010-8zm-7 8l-1 1m0 0l-1 1m1-1l1 1M3 20l5-5" }) });
9578
9597
  }
9598
+ function ExpandAllIcon() {
9599
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h8M4 18h16M15 15l3 3 3-3" }) });
9600
+ }
9601
+ function CollapseAllIcon() {
9602
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", strokeWidth: 2, viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 6h16M4 12h8M4 18h16M21 12l-3-3-3 3" }) });
9603
+ }
9579
9604
  function ParamsTab({ request, onChange }) {
9580
9605
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
9581
9606
  KVTable,
@@ -48189,7 +48214,11 @@ function App() {
48189
48214
  docsModalOpen && /* @__PURE__ */ jsxRuntimeExports.jsx(DocsGeneratorModal, { onClose: () => setDocsModalOpen(false) }),
48190
48215
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "drag-region flex-shrink-0 bg-surface-950 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "no-drag text-[11px] font-medium tracking-widest select-none", style: { color: "var(--text-muted)" }, children: [
48191
48216
  "api ",
48192
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" })
48217
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
48218
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-50", children: [
48219
+ "v",
48220
+ "0.0.4"
48221
+ ] })
48193
48222
  ] }) }),
48194
48223
  /* @__PURE__ */ jsxRuntimeExports.jsx(Toolbar, { onOpenDocs: () => setDocsModalOpen(true) }),
48195
48224
  workspace ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 min-h-0", children: [
@@ -510,6 +510,9 @@ video {
510
510
  white-space: nowrap;
511
511
  border-width: 0;
512
512
  }
513
+ .pointer-events-none {
514
+ pointer-events: none;
515
+ }
513
516
  .visible {
514
517
  visibility: visible;
515
518
  }
@@ -531,9 +534,15 @@ video {
531
534
  .inset-0 {
532
535
  inset: 0px;
533
536
  }
537
+ .bottom-full {
538
+ bottom: 100%;
539
+ }
534
540
  .left-0 {
535
541
  left: 0px;
536
542
  }
543
+ .left-1\/2 {
544
+ left: 50%;
545
+ }
537
546
  .right-0 {
538
547
  right: 0px;
539
548
  }
@@ -867,6 +876,10 @@ video {
867
876
  .border-collapse {
868
877
  border-collapse: collapse;
869
878
  }
879
+ .-translate-x-1\/2 {
880
+ --tw-translate-x: -50%;
881
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
882
+ }
870
883
  .transform {
871
884
  transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
872
885
  }
@@ -1089,6 +1102,9 @@ video {
1089
1102
  .border-transparent {
1090
1103
  border-color: transparent;
1091
1104
  }
1105
+ .border-white\/10 {
1106
+ border-color: rgb(255 255 255 / 0.1);
1107
+ }
1092
1108
  .border-yellow-800 {
1093
1109
  --tw-border-opacity: 1;
1094
1110
  border-color: rgb(133 77 14 / var(--tw-border-opacity, 1));
@@ -1096,6 +1112,10 @@ video {
1096
1112
  .border-b-blue-500 {
1097
1113
  border-bottom-color: var(--ts-blue-500);
1098
1114
  }
1115
+ .bg-\[\#1e1b2e\] {
1116
+ --tw-bg-opacity: 1;
1117
+ background-color: rgb(30 27 46 / var(--tw-bg-opacity, 1));
1118
+ }
1099
1119
  .bg-amber-400 {
1100
1120
  --tw-bg-opacity: 1;
1101
1121
  background-color: rgb(251 191 36 / var(--tw-bg-opacity, 1));
@@ -1498,6 +1518,10 @@ video {
1498
1518
  --tw-text-opacity: 1;
1499
1519
  color: rgb(16 185 129 / var(--tw-text-opacity, 1));
1500
1520
  }
1521
+ .text-gray-300 {
1522
+ --tw-text-opacity: 1;
1523
+ color: rgb(209 213 219 / var(--tw-text-opacity, 1));
1524
+ }
1501
1525
  .text-gray-400 {
1502
1526
  --tw-text-opacity: 1;
1503
1527
  color: rgb(156 163 175 / var(--tw-text-opacity, 1));
@@ -1560,11 +1584,19 @@ video {
1560
1584
  .opacity-30 {
1561
1585
  opacity: 0.3;
1562
1586
  }
1587
+ .opacity-50 {
1588
+ opacity: 0.5;
1589
+ }
1563
1590
  .shadow-2xl {
1564
1591
  --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
1565
1592
  --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);
1566
1593
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
1567
1594
  }
1595
+ .shadow-lg {
1596
+ --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
1597
+ --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
1598
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
1599
+ }
1568
1600
  .shadow-xl {
1569
1601
  --tw-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);
1570
1602
  --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);
@@ -1742,6 +1774,10 @@ body {
1742
1774
  :root.light .text-amber-300 { color: #b45309 !important; } /* amber-700 */
1743
1775
  :root.light .text-amber-400 { color: #d97706 !important; } /* amber-500 */ .last\:border-0:last-child {
1744
1776
  border-width: 0px;
1777
+ } .hover\:scale-150:hover {
1778
+ --tw-scale-x: 1.5;
1779
+ --tw-scale-y: 1.5;
1780
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
1745
1781
  } .hover\:border-blue-500:hover {
1746
1782
  border-color: var(--ts-blue-500);
1747
1783
  } .hover\:border-surface-500:hover {
@@ -1817,6 +1853,8 @@ body {
1817
1853
  opacity: 0.4;
1818
1854
  } .disabled\:opacity-50:disabled {
1819
1855
  opacity: 0.5;
1856
+ } .group\/tip:hover .group-hover\/tip\:block {
1857
+ display: block;
1820
1858
  } .group:hover .group-hover\:opacity-100 {
1821
1859
  opacity: 1;
1822
1860
  } @media (min-width: 1024px) {
@@ -1,13 +1,16 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>api Spector</title>
7
- <script type="module" crossorigin src="./assets/index-CHCrooIl.js"></script>
8
- <link rel="stylesheet" crossorigin href="./assets/index-B_l1FCkO.css">
9
- </head>
10
- <body>
11
- <div id="root"></div>
12
- </body>
13
- </html>
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>api Spector</title>
8
+ <script type="module" crossorigin src="./assets/index-BbhJgjM1.js"></script>
9
+ <link rel="stylesheet" crossorigin href="./assets/index-C1Q1TfC-.css">
10
+ </head>
11
+
12
+ <body>
13
+ <div id="root"></div>
14
+ </body>
15
+
16
+ </html>
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@testsmith/api-spector",
3
3
  "productName": "api Spector",
4
- "version": "0.0.2",
5
- "description": "Local-first API testing tool inspect, test and mock APIs",
4
+ "version": "0.0.4",
5
+ "description": "Local-first API testing tool to inspect, test and mock APIs",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/testsmith-io/api-spector"
package/readme.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # api Spector
2
2
 
3
- Local-first API testing tool. Inspect, test and mock APIs secrets stay on your machine.
3
+ Local-first API testing tool. Inspect, test and mock APIs. Secrets stay on your machine.
4
4
 
5
5
  - GUI built with Electron + React
6
6
  - CLI for running tests and mock servers in CI/CD pipelines
@@ -57,7 +57,7 @@ Keeps running until `Ctrl+C`.
57
57
 
58
58
  ## Workspaces
59
59
 
60
- A workspace is a `.spector` file that references your collections, environments and mock servers. Safe to commit to Git secrets are encrypted, not stored in plain text.
60
+ A workspace is a `.spector` file that references your collections, environments and mock servers. Safe to commit to Git. Secrets are encrypted, not stored in plain text.
61
61
 
62
62
  ```
63
63
  my-project/
@@ -78,12 +78,12 @@ Secret variables are encrypted with AES-256-GCM using a master password. Set `AP
78
78
  export API_SPECTOR_MASTER_KEY="your-password"
79
79
  ```
80
80
 
81
- **Windows PowerShell profile:**
81
+ **Windows (PowerShell profile):**
82
82
  ```powershell
83
83
  $env:API_SPECTOR_MASTER_KEY = "your-password"
84
84
  ```
85
85
 
86
- **Windows Command Prompt (permanent):**
86
+ **Windows (Command Prompt, permanent):**
87
87
  ```cmd
88
88
  setx API_SPECTOR_MASTER_KEY "your-password"
89
89
  ```