@testsmith/api-spector 0.0.9 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +6 -2
- package/out/main/chunks/{mock-server-C0RlwZf_.js → mock-server-Cx-xG4pJ.js} +8 -3
- package/out/main/index.js +122 -2
- package/out/main/mock.js +41 -4
- package/out/main/runner.js +11 -2
- package/out/preload/index.js +20 -0
- package/out/renderer/assets/{index-C67sPzTG.js → index-B7b-1sj6.js} +1159 -146
- package/out/renderer/assets/index-QI8AWMd3.css +2 -0
- package/out/renderer/index.html +2 -2
- package/package.json +2 -1
- package/out/renderer/assets/index-YkI5DFME.css +0 -2
|
@@ -13374,6 +13374,14 @@ function removeFolderById(parent, folderId) {
|
|
|
13374
13374
|
}
|
|
13375
13375
|
return false;
|
|
13376
13376
|
}
|
|
13377
|
+
function findFolderParent(root2, folderId) {
|
|
13378
|
+
for (const sub of root2.folders) {
|
|
13379
|
+
if (sub.id === folderId) return root2;
|
|
13380
|
+
const found = findFolderParent(sub, folderId);
|
|
13381
|
+
if (found) return found;
|
|
13382
|
+
}
|
|
13383
|
+
return null;
|
|
13384
|
+
}
|
|
13377
13385
|
function findFolderPath(root2, requestId) {
|
|
13378
13386
|
if (root2.requestIds.includes(requestId)) return [root2];
|
|
13379
13387
|
for (const sub of root2.folders) {
|
|
@@ -13579,6 +13587,34 @@ const useStore = create()(
|
|
|
13579
13587
|
s.workspace.collections = s.workspace.collections.map((p) => p === oldRelPath ? newRelPath : p);
|
|
13580
13588
|
}
|
|
13581
13589
|
}),
|
|
13590
|
+
duplicateCollection: (id2) => set2((s) => {
|
|
13591
|
+
const entry = s.collections[id2];
|
|
13592
|
+
if (!entry) return;
|
|
13593
|
+
const orig = entry.data;
|
|
13594
|
+
const existingNames = Object.values(s.collections).map((c) => c.data.name);
|
|
13595
|
+
const newName = uniqueName(orig.name + " (copy)", existingNames);
|
|
13596
|
+
const newId = v4();
|
|
13597
|
+
const copy = JSON.parse(JSON.stringify(orig));
|
|
13598
|
+
copy.id = newId;
|
|
13599
|
+
copy.name = newName;
|
|
13600
|
+
const reqIdMap = {};
|
|
13601
|
+
Object.keys(copy.requests).forEach((oldReqId) => {
|
|
13602
|
+
const newReqId = v4();
|
|
13603
|
+
reqIdMap[oldReqId] = newReqId;
|
|
13604
|
+
copy.requests[newReqId] = { ...copy.requests[oldReqId], id: newReqId };
|
|
13605
|
+
delete copy.requests[oldReqId];
|
|
13606
|
+
});
|
|
13607
|
+
function remapFolder(f) {
|
|
13608
|
+
f.id = v4();
|
|
13609
|
+
f.requestIds = f.requestIds.map((rid) => reqIdMap[rid] ?? rid);
|
|
13610
|
+
f.folders.forEach(remapFolder);
|
|
13611
|
+
}
|
|
13612
|
+
remapFolder(copy.rootFolder);
|
|
13613
|
+
const relPath = colRelPath(newName, newId);
|
|
13614
|
+
s.collections[newId] = { relPath, data: copy, dirty: true };
|
|
13615
|
+
s.activeCollectionId = newId;
|
|
13616
|
+
if (s.workspace) s.workspace.collections.push(relPath);
|
|
13617
|
+
}),
|
|
13582
13618
|
deleteCollection: (id2) => set2((s) => {
|
|
13583
13619
|
const relPath = s.collections[id2]?.relPath;
|
|
13584
13620
|
delete s.collections[id2];
|
|
@@ -13625,6 +13661,32 @@ const useStore = create()(
|
|
|
13625
13661
|
s.collections[collectionId].dirty = true;
|
|
13626
13662
|
}
|
|
13627
13663
|
}),
|
|
13664
|
+
duplicateFolder: (collectionId, folderId) => set2((s) => {
|
|
13665
|
+
const col = s.collections[collectionId]?.data;
|
|
13666
|
+
if (!col) return;
|
|
13667
|
+
const orig = findFolder(col.rootFolder, folderId);
|
|
13668
|
+
if (!orig) return;
|
|
13669
|
+
const copy = JSON.parse(JSON.stringify(orig));
|
|
13670
|
+
copy.name = orig.name + " (copy)";
|
|
13671
|
+
function remapRequests(f) {
|
|
13672
|
+
f.requestIds = f.requestIds.map((oldId) => {
|
|
13673
|
+
const newId = v4();
|
|
13674
|
+
col.requests[newId] = { ...JSON.parse(JSON.stringify(col.requests[oldId])), id: newId };
|
|
13675
|
+
return newId;
|
|
13676
|
+
});
|
|
13677
|
+
f.folders.forEach(remapRequests);
|
|
13678
|
+
}
|
|
13679
|
+
remapRequests(copy);
|
|
13680
|
+
function reIdFolders(f) {
|
|
13681
|
+
f.id = v4();
|
|
13682
|
+
f.folders.forEach(reIdFolders);
|
|
13683
|
+
}
|
|
13684
|
+
reIdFolders(copy);
|
|
13685
|
+
const parent = findFolderParent(col.rootFolder, folderId) ?? col.rootFolder;
|
|
13686
|
+
const idx = parent.folders.findIndex((f) => f.id === folderId);
|
|
13687
|
+
parent.folders.splice(idx + 1, 0, copy);
|
|
13688
|
+
s.collections[collectionId].dirty = true;
|
|
13689
|
+
}),
|
|
13628
13690
|
deleteFolder: (collectionId, folderId) => set2((s) => {
|
|
13629
13691
|
const col = s.collections[collectionId]?.data;
|
|
13630
13692
|
if (!col) return;
|
|
@@ -13921,7 +13983,7 @@ const useStore = create()(
|
|
|
13921
13983
|
})
|
|
13922
13984
|
}))
|
|
13923
13985
|
);
|
|
13924
|
-
const { electron: electron$
|
|
13986
|
+
const { electron: electron$m } = window;
|
|
13925
13987
|
function useAutoSave() {
|
|
13926
13988
|
const collections = useStore((s) => s.collections);
|
|
13927
13989
|
useStore((s) => s.environments);
|
|
@@ -13937,7 +13999,7 @@ function useAutoSave() {
|
|
|
13937
13999
|
for (const { relPath, data, dirty } of dirtyCollections) {
|
|
13938
14000
|
if (!dirty) continue;
|
|
13939
14001
|
try {
|
|
13940
|
-
await electron$
|
|
14002
|
+
await electron$m.saveCollection(relPath, data);
|
|
13941
14003
|
markCollectionClean(data.id);
|
|
13942
14004
|
} catch (e) {
|
|
13943
14005
|
console.error("Auto-save failed for", relPath, e);
|
|
@@ -13953,7 +14015,7 @@ function useAutoSave() {
|
|
|
13953
14015
|
if (wsTimerRef.current) clearTimeout(wsTimerRef.current);
|
|
13954
14016
|
wsTimerRef.current = setTimeout(async () => {
|
|
13955
14017
|
try {
|
|
13956
|
-
await electron$
|
|
14018
|
+
await electron$m.saveWorkspace(workspace);
|
|
13957
14019
|
} catch {
|
|
13958
14020
|
}
|
|
13959
14021
|
}, 300);
|
|
@@ -13962,7 +14024,7 @@ function useAutoSave() {
|
|
|
13962
14024
|
};
|
|
13963
14025
|
}, [workspace]);
|
|
13964
14026
|
}
|
|
13965
|
-
const { electron: electron$
|
|
14027
|
+
const { electron: electron$l } = window;
|
|
13966
14028
|
function useWorkspaceLoader() {
|
|
13967
14029
|
const loadCollection = useStore((s) => s.loadCollection);
|
|
13968
14030
|
const loadEnvironment = useStore((s) => s.loadEnvironment);
|
|
@@ -13981,28 +14043,28 @@ function useWorkspaceLoader() {
|
|
|
13981
14043
|
});
|
|
13982
14044
|
for (const colPath of ws2.collections) {
|
|
13983
14045
|
try {
|
|
13984
|
-
const col = await electron$
|
|
14046
|
+
const col = await electron$l.loadCollection(colPath);
|
|
13985
14047
|
loadCollection(colPath, col);
|
|
13986
14048
|
} catch {
|
|
13987
14049
|
}
|
|
13988
14050
|
}
|
|
13989
14051
|
for (const envPath of ws2.environments) {
|
|
13990
14052
|
try {
|
|
13991
|
-
const env = await electron$
|
|
14053
|
+
const env = await electron$l.loadEnvironment(envPath);
|
|
13992
14054
|
loadEnvironment(envPath, env);
|
|
13993
14055
|
} catch {
|
|
13994
14056
|
}
|
|
13995
14057
|
}
|
|
13996
14058
|
for (const relPath of ws2.mocks ?? []) {
|
|
13997
14059
|
try {
|
|
13998
|
-
const mockData = await electron$
|
|
14060
|
+
const mockData = await electron$l.loadMock(relPath);
|
|
13999
14061
|
loadMock(relPath, mockData);
|
|
14000
14062
|
} catch {
|
|
14001
14063
|
}
|
|
14002
14064
|
}
|
|
14003
14065
|
if (ws2.collections.length > 0) {
|
|
14004
14066
|
try {
|
|
14005
|
-
const firstCol = await electron$
|
|
14067
|
+
const firstCol = await electron$l.loadCollection(ws2.collections[0]);
|
|
14006
14068
|
setActiveCollection(firstCol.id);
|
|
14007
14069
|
} catch {
|
|
14008
14070
|
}
|
|
@@ -39703,6 +39765,33 @@ const FAKER_SUB = {
|
|
|
39703
39765
|
{ label: "words", type: "function", detail: "(count)", info: "Multiple lorem words" },
|
|
39704
39766
|
{ label: "sentence", type: "function", detail: "()", info: "Lorem sentence" },
|
|
39705
39767
|
{ label: "paragraph", type: "function", detail: "()", info: "Lorem paragraph" }
|
|
39768
|
+
],
|
|
39769
|
+
location: [
|
|
39770
|
+
{ label: "city", type: "function", detail: "()", info: "Random city name" },
|
|
39771
|
+
{ label: "country", type: "function", detail: "()", info: "Random country name" },
|
|
39772
|
+
{ label: "countryCode", type: "function", detail: "()", info: "Two-letter country code" },
|
|
39773
|
+
{ label: "state", type: "function", detail: "()", info: "US state name" },
|
|
39774
|
+
{ label: "streetAddress", type: "function", detail: "()", info: "Street address" },
|
|
39775
|
+
{ label: "zipCode", type: "function", detail: "()", info: "ZIP / postal code" },
|
|
39776
|
+
{ label: "latitude", type: "function", detail: "()", info: "Random latitude" },
|
|
39777
|
+
{ label: "longitude", type: "function", detail: "()", info: "Random longitude" }
|
|
39778
|
+
],
|
|
39779
|
+
finance: [
|
|
39780
|
+
{ label: "iban", type: "function", detail: "()", info: "IBAN number" },
|
|
39781
|
+
{ label: "bic", type: "function", detail: "()", info: "BIC / SWIFT code" },
|
|
39782
|
+
{ label: "accountNumber", type: "function", detail: "()", info: "Bank account number" },
|
|
39783
|
+
{ label: "amount", type: "function", detail: "({ min, max })", info: "Random monetary amount" },
|
|
39784
|
+
{ label: "currencyCode", type: "function", detail: "()", info: "Currency code (USD, EUR, …)" },
|
|
39785
|
+
{ label: "currencyName", type: "function", detail: "()", info: "Currency name" },
|
|
39786
|
+
{ label: "creditCardNumber", type: "function", detail: "()", info: "Credit card number" },
|
|
39787
|
+
{ label: "pin", type: "function", detail: "()", info: "Numeric PIN" },
|
|
39788
|
+
{ label: "bitcoinAddress", type: "function", detail: "()", info: "Bitcoin address" }
|
|
39789
|
+
],
|
|
39790
|
+
color: [
|
|
39791
|
+
{ label: "human", type: "function", detail: "()", info: 'Human-readable color name (e.g. "red")' },
|
|
39792
|
+
{ label: "hex", type: "function", detail: "()", info: "Hex color string (e.g. #a3f1c2)" },
|
|
39793
|
+
{ label: "rgb", type: "function", detail: "()", info: "CSS rgb() string" },
|
|
39794
|
+
{ label: "hsl", type: "function", detail: "()", info: "CSS hsl() string" }
|
|
39706
39795
|
]
|
|
39707
39796
|
};
|
|
39708
39797
|
function makeAtCompletionSource(varNames) {
|
|
@@ -40949,6 +41038,8 @@ function CollectionTree() {
|
|
|
40949
41038
|
const renameRequest = useStore((s) => s.renameRequest);
|
|
40950
41039
|
const deleteRequest = useStore((s) => s.deleteRequest);
|
|
40951
41040
|
const duplicateRequest = useStore((s) => s.duplicateRequest);
|
|
41041
|
+
const duplicateCollection = useStore((s) => s.duplicateCollection);
|
|
41042
|
+
const duplicateFolder = useStore((s) => s.duplicateFolder);
|
|
40952
41043
|
const updateFolderTags = useStore((s) => s.updateFolderTags);
|
|
40953
41044
|
const updateRequestTags = useStore((s) => s.updateRequestTags);
|
|
40954
41045
|
const openRunner = useStore((s) => s.openRunner);
|
|
@@ -40983,8 +41074,10 @@ function CollectionTree() {
|
|
|
40983
41074
|
onAddFolder: (parentId, name2) => addFolder(col.id, parentId, name2),
|
|
40984
41075
|
onRenameCollection: (name2) => renameCollection(col.id, name2),
|
|
40985
41076
|
onDeleteCollection: () => confirmThen(`Delete collection "${col.name}"?`, () => deleteCollection(col.id)),
|
|
41077
|
+
onDuplicateCollection: () => duplicateCollection(col.id),
|
|
40986
41078
|
onRenameFolder: (folderId, name2) => renameFolder(col.id, folderId, name2),
|
|
40987
41079
|
onDeleteFolder: (folderId) => confirmThen("Delete this folder and all its requests?", () => deleteFolder(col.id, folderId)),
|
|
41080
|
+
onDuplicateFolder: (folderId) => duplicateFolder(col.id, folderId),
|
|
40988
41081
|
onRenameRequest: renameRequest,
|
|
40989
41082
|
onDeleteRequest: (reqId) => deleteRequest(col.id, reqId),
|
|
40990
41083
|
onDuplicateRequest: (reqId) => duplicateRequest(col.id, reqId),
|
|
@@ -41014,8 +41107,10 @@ function CollectionNode({
|
|
|
41014
41107
|
onAddFolder,
|
|
41015
41108
|
onRenameCollection,
|
|
41016
41109
|
onDeleteCollection,
|
|
41110
|
+
onDuplicateCollection,
|
|
41017
41111
|
onRenameFolder,
|
|
41018
41112
|
onDeleteFolder,
|
|
41113
|
+
onDuplicateFolder,
|
|
41019
41114
|
onRenameRequest,
|
|
41020
41115
|
onDeleteRequest,
|
|
41021
41116
|
onDuplicateRequest,
|
|
@@ -41070,6 +41165,7 @@ function CollectionNode({
|
|
|
41070
41165
|
/* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Add request", onClick: () => onAddRequest(col.rootFolder.id), alwaysVisible: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs", children: "+" }) }),
|
|
41071
41166
|
/* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Add folder", onClick: () => onAddFolder(col.rootFolder.id, "New Folder"), alwaysVisible: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(FolderIcon, {}) }),
|
|
41072
41167
|
/* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Rename", onClick: () => setRenaming(true), alwaysVisible: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(PencilIcon, {}) }),
|
|
41168
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Duplicate collection", onClick: onDuplicateCollection, alwaysVisible: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyIcon, {}) }),
|
|
41073
41169
|
/* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Delete collection", onClick: onDeleteCollection, danger: true, alwaysVisible: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TrashIcon, {}) })
|
|
41074
41170
|
] })
|
|
41075
41171
|
]
|
|
@@ -41089,6 +41185,7 @@ function CollectionNode({
|
|
|
41089
41185
|
onAddFolder,
|
|
41090
41186
|
onRenameFolder,
|
|
41091
41187
|
onDeleteFolder,
|
|
41188
|
+
onDuplicateFolder,
|
|
41092
41189
|
onRenameRequest,
|
|
41093
41190
|
onDeleteRequest,
|
|
41094
41191
|
onDuplicateRequest,
|
|
@@ -41109,6 +41206,7 @@ function FolderRow({
|
|
|
41109
41206
|
onAddFolder,
|
|
41110
41207
|
onRename,
|
|
41111
41208
|
onDelete,
|
|
41209
|
+
onDuplicate,
|
|
41112
41210
|
onUpdateTags,
|
|
41113
41211
|
onRun,
|
|
41114
41212
|
children
|
|
@@ -41163,6 +41261,7 @@ function FolderRow({
|
|
|
41163
41261
|
}, alwaysVisible: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TagChips, { tags: [], onRemove: () => {
|
|
41164
41262
|
}, onAdd: (tag) => onUpdateTags([...tags2, tag]) }) }),
|
|
41165
41263
|
/* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Rename", onClick: () => setRenaming(true), alwaysVisible: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(PencilIcon, {}) }),
|
|
41264
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Duplicate folder", onClick: onDuplicate, alwaysVisible: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyIcon, {}) }),
|
|
41166
41265
|
/* @__PURE__ */ jsxRuntimeExports.jsx(IconBtn, { title: "Delete folder", onClick: onDelete, danger: true, alwaysVisible: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(TrashIcon, {}) })
|
|
41167
41266
|
] })
|
|
41168
41267
|
]
|
|
@@ -41191,6 +41290,7 @@ function FolderContents({
|
|
|
41191
41290
|
onAddFolder,
|
|
41192
41291
|
onRenameFolder,
|
|
41193
41292
|
onDeleteFolder,
|
|
41293
|
+
onDuplicateFolder,
|
|
41194
41294
|
onRenameRequest,
|
|
41195
41295
|
onDeleteRequest,
|
|
41196
41296
|
onDuplicateRequest,
|
|
@@ -41210,6 +41310,7 @@ function FolderContents({
|
|
|
41210
41310
|
onAddFolder: () => onAddFolder(sub.id, "New Folder"),
|
|
41211
41311
|
onRename: (name2) => onRenameFolder(sub.id, name2),
|
|
41212
41312
|
onDelete: () => onDeleteFolder(sub.id),
|
|
41313
|
+
onDuplicate: () => onDuplicateFolder(sub.id),
|
|
41213
41314
|
onUpdateTags: (tags2) => onUpdateFolderTags(sub.id, tags2),
|
|
41214
41315
|
onRun: () => onRunFolder(sub.id),
|
|
41215
41316
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -41226,6 +41327,7 @@ function FolderContents({
|
|
|
41226
41327
|
onAddFolder,
|
|
41227
41328
|
onRenameFolder,
|
|
41228
41329
|
onDeleteFolder,
|
|
41330
|
+
onDuplicateFolder,
|
|
41229
41331
|
onRenameRequest,
|
|
41230
41332
|
onDeleteRequest,
|
|
41231
41333
|
onDuplicateRequest,
|
|
@@ -42144,7 +42246,7 @@ const autoCloseTags = /* @__PURE__ */ EditorView.inputHandler.of((view, from, to
|
|
|
42144
42246
|
]);
|
|
42145
42247
|
return true;
|
|
42146
42248
|
});
|
|
42147
|
-
const { electron: electron$
|
|
42249
|
+
const { electron: electron$k } = window;
|
|
42148
42250
|
function SoapEditor({ request, onChange }) {
|
|
42149
42251
|
const soap = request.body.soap ?? {
|
|
42150
42252
|
wsdlUrl: "",
|
|
@@ -42161,7 +42263,7 @@ function SoapEditor({ request, onChange }) {
|
|
|
42161
42263
|
setFetching(true);
|
|
42162
42264
|
setFetchError(null);
|
|
42163
42265
|
try {
|
|
42164
|
-
const result = await electron$
|
|
42266
|
+
const result = await electron$k.wsdlFetch(soap.wsdlUrl.trim());
|
|
42165
42267
|
setOperations(result.operations);
|
|
42166
42268
|
if (result.operations.length > 0) {
|
|
42167
42269
|
const first = result.operations[0];
|
|
@@ -42321,7 +42423,7 @@ function BodyTab({ request, onChange }) {
|
|
|
42321
42423
|
mode === "soap" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SoapEditor, { request, onChange }) })
|
|
42322
42424
|
] });
|
|
42323
42425
|
}
|
|
42324
|
-
const { electron: electron$
|
|
42426
|
+
const { electron: electron$j } = window;
|
|
42325
42427
|
const AUTH_TYPES = ["none", "bearer", "basic", "digest", "ntlm", "apikey", "oauth2"];
|
|
42326
42428
|
function AuthTab({ request, onChange }) {
|
|
42327
42429
|
const auth = request.auth;
|
|
@@ -42335,7 +42437,7 @@ function AuthTab({ request, onChange }) {
|
|
|
42335
42437
|
}
|
|
42336
42438
|
async function saveSecret(ref2) {
|
|
42337
42439
|
if (!secretValue || !ref2) return;
|
|
42338
|
-
await electron$
|
|
42440
|
+
await electron$j.setSecret(ref2, secretValue);
|
|
42339
42441
|
setSaved(true);
|
|
42340
42442
|
setSecretValue("");
|
|
42341
42443
|
setTimeout(() => setSaved(false), 2e3);
|
|
@@ -42346,14 +42448,14 @@ function AuthTab({ request, onChange }) {
|
|
|
42346
42448
|
try {
|
|
42347
42449
|
const vars = {};
|
|
42348
42450
|
if (auth.oauth2Flow === "authorization_code") {
|
|
42349
|
-
const result = await electron$
|
|
42451
|
+
const result = await electron$j.oauth2StartFlow(auth, vars);
|
|
42350
42452
|
setAuth({
|
|
42351
42453
|
oauth2CachedToken: result.accessToken,
|
|
42352
42454
|
oauth2TokenExpiry: result.expiresAt
|
|
42353
42455
|
});
|
|
42354
42456
|
if (result.refreshToken) setOauth2RT(result.refreshToken);
|
|
42355
42457
|
} else {
|
|
42356
|
-
const result = await electron$
|
|
42458
|
+
const result = await electron$j.oauth2StartFlow(auth, vars);
|
|
42357
42459
|
setAuth({
|
|
42358
42460
|
oauth2CachedToken: result.accessToken,
|
|
42359
42461
|
oauth2TokenExpiry: result.expiresAt
|
|
@@ -42371,7 +42473,7 @@ function AuthTab({ request, onChange }) {
|
|
|
42371
42473
|
setOauth2Status("fetching");
|
|
42372
42474
|
setOauth2Error("");
|
|
42373
42475
|
try {
|
|
42374
|
-
const result = await electron$
|
|
42476
|
+
const result = await electron$j.oauth2RefreshToken(auth, {}, oauth2RefreshToken);
|
|
42375
42477
|
setAuth({
|
|
42376
42478
|
oauth2CachedToken: result.accessToken,
|
|
42377
42479
|
oauth2TokenExpiry: result.expiresAt
|
|
@@ -49368,7 +49470,7 @@ function SchemaTab({ request, onChange }) {
|
|
|
49368
49470
|
] }) })
|
|
49369
49471
|
] });
|
|
49370
49472
|
}
|
|
49371
|
-
const { electron: electron$
|
|
49473
|
+
const { electron: electron$i } = window;
|
|
49372
49474
|
const EMPTY = { statusCode: 200, headers: [], bodySchema: "" };
|
|
49373
49475
|
function ContractTab({ request, onChange }) {
|
|
49374
49476
|
const activeTab = useStore((s) => s.tabs.find((t2) => t2.id === s.activeTabId));
|
|
@@ -49382,7 +49484,7 @@ function ContractTab({ request, onChange }) {
|
|
|
49382
49484
|
if (!lastResponse?.body) return;
|
|
49383
49485
|
setInferring(true);
|
|
49384
49486
|
try {
|
|
49385
|
-
const schema = await electron$
|
|
49487
|
+
const schema = await electron$i.inferContractSchema(lastResponse.body);
|
|
49386
49488
|
if (schema) update({ bodySchema: schema });
|
|
49387
49489
|
} finally {
|
|
49388
49490
|
setInferring(false);
|
|
@@ -49490,7 +49592,7 @@ function ContractTab({ request, onChange }) {
|
|
|
49490
49592
|
] })
|
|
49491
49593
|
] });
|
|
49492
49594
|
}
|
|
49493
|
-
const { electron: electron$
|
|
49595
|
+
const { electron: electron$h } = window;
|
|
49494
49596
|
function formatTime$1(ts) {
|
|
49495
49597
|
const d = new Date(ts);
|
|
49496
49598
|
const hh = String(d.getHours()).padStart(2, "0");
|
|
@@ -49510,14 +49612,14 @@ function WebSocketPanel({ request }) {
|
|
|
49510
49612
|
const [sendText, setSendText] = reactExports.useState("");
|
|
49511
49613
|
const logEndRef = reactExports.useRef(null);
|
|
49512
49614
|
reactExports.useEffect(() => {
|
|
49513
|
-
electron$
|
|
49615
|
+
electron$h.onWsMessage(({ requestId, message }) => {
|
|
49514
49616
|
addWsMessage(requestId, message);
|
|
49515
49617
|
});
|
|
49516
|
-
electron$
|
|
49618
|
+
electron$h.onWsStatus(({ requestId, status, error: error2 }) => {
|
|
49517
49619
|
setWsStatus(requestId, status, error2);
|
|
49518
49620
|
});
|
|
49519
49621
|
return () => {
|
|
49520
|
-
electron$
|
|
49622
|
+
electron$h.offWsEvents();
|
|
49521
49623
|
};
|
|
49522
49624
|
}, [addWsMessage, setWsStatus]);
|
|
49523
49625
|
reactExports.useEffect(() => {
|
|
@@ -49530,19 +49632,19 @@ function WebSocketPanel({ request }) {
|
|
|
49530
49632
|
if (h.enabled && h.key) headers[h.key] = h.value;
|
|
49531
49633
|
}
|
|
49532
49634
|
try {
|
|
49533
|
-
await electron$
|
|
49635
|
+
await electron$h.wsConnect(request.id, request.url, headers);
|
|
49534
49636
|
} catch (err) {
|
|
49535
49637
|
setWsStatus(request.id, "error", err instanceof Error ? err.message : String(err));
|
|
49536
49638
|
}
|
|
49537
49639
|
}
|
|
49538
49640
|
async function disconnect() {
|
|
49539
|
-
await electron$
|
|
49641
|
+
await electron$h.wsDisconnect(request.id);
|
|
49540
49642
|
}
|
|
49541
49643
|
async function sendMessage() {
|
|
49542
49644
|
const text = sendText.trim();
|
|
49543
49645
|
if (!text || !isConnected) return;
|
|
49544
49646
|
try {
|
|
49545
|
-
await electron$
|
|
49647
|
+
await electron$h.wsSend(request.id, text);
|
|
49546
49648
|
const msg = {
|
|
49547
49649
|
id: crypto.randomUUID(),
|
|
49548
49650
|
direction: "sent",
|
|
@@ -49645,7 +49747,7 @@ function WebSocketPanel({ request }) {
|
|
|
49645
49747
|
] })
|
|
49646
49748
|
] });
|
|
49647
49749
|
}
|
|
49648
|
-
const { electron: electron$
|
|
49750
|
+
const { electron: electron$g } = window;
|
|
49649
49751
|
const METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
49650
49752
|
const METHOD_COLORS = {
|
|
49651
49753
|
GET: "text-emerald-400",
|
|
@@ -49699,7 +49801,7 @@ function RequestBuilder({ request }) {
|
|
|
49699
49801
|
auth: mergedAuth,
|
|
49700
49802
|
headers: mergedHeaders
|
|
49701
49803
|
};
|
|
49702
|
-
const result = await electron$
|
|
49804
|
+
const result = await electron$g.sendRequest({
|
|
49703
49805
|
request: mergedRequest,
|
|
49704
49806
|
environment: activeEnv,
|
|
49705
49807
|
collectionVars,
|
|
@@ -50348,7 +50450,7 @@ function InteractiveBody({ body, contentType, onAssert }) {
|
|
|
50348
50450
|
treeContent
|
|
50349
50451
|
] });
|
|
50350
50452
|
}
|
|
50351
|
-
const { electron: electron$
|
|
50453
|
+
const { electron: electron$f } = window;
|
|
50352
50454
|
function prettyJson(raw) {
|
|
50353
50455
|
try {
|
|
50354
50456
|
return JSON.stringify(JSON.parse(raw), null, 2);
|
|
@@ -50434,14 +50536,14 @@ function SaveAsMockModal({ onClose }) {
|
|
|
50434
50536
|
const entry = state.mocks[serverId];
|
|
50435
50537
|
const updated = { ...entry.data, name: newServerName, port: Number(newServerPort), routes: [route] };
|
|
50436
50538
|
updateMock(serverId, updated);
|
|
50437
|
-
await electron$
|
|
50539
|
+
await electron$f.saveMock(entry.relPath, updated);
|
|
50438
50540
|
const ws2 = useStore.getState().workspace;
|
|
50439
|
-
if (ws2) await electron$
|
|
50541
|
+
if (ws2) await electron$f.saveWorkspace(ws2);
|
|
50440
50542
|
} else {
|
|
50441
50543
|
const entry = useStore.getState().mocks[serverId];
|
|
50442
50544
|
const updated = { ...entry.data, routes: [...entry.data.routes, route] };
|
|
50443
50545
|
updateMock(serverId, updated);
|
|
50444
|
-
await electron$
|
|
50546
|
+
await electron$f.saveMock(entry.relPath, updated);
|
|
50445
50547
|
}
|
|
50446
50548
|
onClose();
|
|
50447
50549
|
} finally {
|
|
@@ -50672,7 +50774,7 @@ function ResponseViewer() {
|
|
|
50672
50774
|
const [contractToast, setContractToast] = reactExports.useState(false);
|
|
50673
50775
|
async function saveAsContract() {
|
|
50674
50776
|
if (!response || !requestId || !activeTabId) return;
|
|
50675
|
-
const schema = response.body ? await electron$
|
|
50777
|
+
const schema = response.body ? await electron$f.inferContractSchema(response.body) : null;
|
|
50676
50778
|
const contentType2 = response.headers["content-type"];
|
|
50677
50779
|
const headers = contentType2 ? [{ key: "content-type", value: contentType2, required: true }] : [];
|
|
50678
50780
|
updateRequest(requestId, {
|
|
@@ -50915,7 +51017,7 @@ function ConsolePanel({ scriptResult }) {
|
|
|
50915
51017
|
i
|
|
50916
51018
|
)) });
|
|
50917
51019
|
}
|
|
50918
|
-
const { electron: electron$
|
|
51020
|
+
const { electron: electron$e } = window;
|
|
50919
51021
|
const TARGETS = [
|
|
50920
51022
|
{ id: "robot_framework", label: "Robot Framework", description: "Python RequestsLibrary keywords + test suite" },
|
|
50921
51023
|
{ id: "playwright_ts", label: "Playwright TS", description: "TypeScript page-object API classes + spec files" },
|
|
@@ -50946,7 +51048,7 @@ function GeneratorPanel() {
|
|
|
50946
51048
|
try {
|
|
50947
51049
|
const col = collections[selectedCollectionId]?.data;
|
|
50948
51050
|
const env = activeEnvironmentId ? environments[activeEnvironmentId]?.data ?? null : null;
|
|
50949
|
-
const generated = await electron$
|
|
51051
|
+
const generated = await electron$e.generateCode({ collection: col, environment: env, target });
|
|
50950
51052
|
setFiles(generated);
|
|
50951
51053
|
setSelectedFile(generated[0]?.path ?? null);
|
|
50952
51054
|
} catch (e) {
|
|
@@ -50958,7 +51060,7 @@ function GeneratorPanel() {
|
|
|
50958
51060
|
async function saveZip() {
|
|
50959
51061
|
if (files.length === 0) return;
|
|
50960
51062
|
const col = collections[selectedCollectionId]?.data;
|
|
50961
|
-
await electron$
|
|
51063
|
+
await electron$e.saveGeneratedFilesAsZip(files, col?.name ?? "api-tests", target);
|
|
50962
51064
|
}
|
|
50963
51065
|
const selectedContent = files.find((f) => f.path === selectedFile)?.content ?? "";
|
|
50964
51066
|
const activeTarget = TARGETS.find((t2) => t2.id === target);
|
|
@@ -51182,16 +51284,16 @@ function HistoryRow({
|
|
|
51182
51284
|
}
|
|
51183
51285
|
);
|
|
51184
51286
|
}
|
|
51185
|
-
const { electron: electron$
|
|
51287
|
+
const { electron: electron$d } = window;
|
|
51186
51288
|
function WelcomeScreen() {
|
|
51187
51289
|
const { applyWorkspace } = useWorkspaceLoader();
|
|
51188
51290
|
async function openWorkspace() {
|
|
51189
|
-
const result = await electron$
|
|
51291
|
+
const result = await electron$d.openWorkspace();
|
|
51190
51292
|
if (!result) return;
|
|
51191
51293
|
await applyWorkspace(result.workspace, result.workspacePath);
|
|
51192
51294
|
}
|
|
51193
51295
|
async function newWorkspace() {
|
|
51194
|
-
const result = await electron$
|
|
51296
|
+
const result = await electron$d.newWorkspace();
|
|
51195
51297
|
if (!result) return;
|
|
51196
51298
|
await applyWorkspace(result.workspace, result.workspacePath);
|
|
51197
51299
|
}
|
|
@@ -51225,7 +51327,7 @@ function WelcomeScreen() {
|
|
|
51225
51327
|
] })
|
|
51226
51328
|
] });
|
|
51227
51329
|
}
|
|
51228
|
-
const { electron: electron$
|
|
51330
|
+
const { electron: electron$c } = window;
|
|
51229
51331
|
const EXAMPLES = [
|
|
51230
51332
|
{
|
|
51231
51333
|
label: "macOS / Linux (~/.zshrc or ~/.bashrc)",
|
|
@@ -51249,7 +51351,7 @@ function MasterKeyModal({ onSuccess, onCancel }) {
|
|
|
51249
51351
|
setError("Password cannot be empty.");
|
|
51250
51352
|
return;
|
|
51251
51353
|
}
|
|
51252
|
-
await electron$
|
|
51354
|
+
await electron$c.setMasterKey(password);
|
|
51253
51355
|
onSuccess(password);
|
|
51254
51356
|
}
|
|
51255
51357
|
function copy(idx, text) {
|
|
@@ -51339,7 +51441,7 @@ function MasterKeyModal({ onSuccess, onCancel }) {
|
|
|
51339
51441
|
}
|
|
51340
51442
|
);
|
|
51341
51443
|
}
|
|
51342
|
-
const { electron: electron$
|
|
51444
|
+
const { electron: electron$b } = window;
|
|
51343
51445
|
async function shortHash(value) {
|
|
51344
51446
|
const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
|
|
51345
51447
|
return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8);
|
|
@@ -51440,7 +51542,7 @@ function EnvironmentEditor({ onClose }) {
|
|
|
51440
51542
|
async function saveEncrypted(idx) {
|
|
51441
51543
|
const plaintext = secretInputs[idx] ?? "";
|
|
51442
51544
|
if (!plaintext) return;
|
|
51443
|
-
const { set: set2 } = await electron$
|
|
51545
|
+
const { set: set2 } = await electron$b.checkMasterKey();
|
|
51444
51546
|
if (!set2) {
|
|
51445
51547
|
setPendingEncryptIdx(idx);
|
|
51446
51548
|
return;
|
|
@@ -51477,9 +51579,9 @@ function EnvironmentEditor({ onClose }) {
|
|
|
51477
51579
|
} : state.workspace
|
|
51478
51580
|
}));
|
|
51479
51581
|
const ws2 = useStore.getState().workspace;
|
|
51480
|
-
if (ws2) await electron$
|
|
51582
|
+
if (ws2) await electron$b.saveWorkspace(ws2);
|
|
51481
51583
|
}
|
|
51482
|
-
await electron$
|
|
51584
|
+
await electron$b.saveEnvironment(newRelPath, env);
|
|
51483
51585
|
}
|
|
51484
51586
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
51485
51587
|
pendingEncryptIdx !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -51763,7 +51865,7 @@ function EnvironmentEditor({ onClose }) {
|
|
|
51763
51865
|
)
|
|
51764
51866
|
] });
|
|
51765
51867
|
}
|
|
51766
|
-
const { electron: electron$
|
|
51868
|
+
const { electron: electron$a } = window;
|
|
51767
51869
|
function EnvironmentBar({ inline = false }) {
|
|
51768
51870
|
const environments = useStore((s) => s.environments);
|
|
51769
51871
|
const activeEnvironmentId = useStore((s) => s.activeEnvironmentId);
|
|
@@ -51777,7 +51879,7 @@ function EnvironmentBar({ inline = false }) {
|
|
|
51777
51879
|
if (id2) {
|
|
51778
51880
|
const hasSecrets = environments[id2]?.data.variables.some((v) => v.enabled && v.secret);
|
|
51779
51881
|
if (hasSecrets) {
|
|
51780
|
-
const { set: set2 } = await electron$
|
|
51882
|
+
const { set: set2 } = await electron$a.checkMasterKey();
|
|
51781
51883
|
if (!set2) {
|
|
51782
51884
|
setPendingEnvId(id2);
|
|
51783
51885
|
return;
|
|
@@ -51831,7 +51933,7 @@ function EnvironmentBar({ inline = false }) {
|
|
|
51831
51933
|
controls
|
|
51832
51934
|
] });
|
|
51833
51935
|
}
|
|
51834
|
-
const { electron: electron$
|
|
51936
|
+
const { electron: electron$9 } = window;
|
|
51835
51937
|
const DEFAULT_PII_PATTERNS = ["authorization", "password", "token", "secret", "api-key", "x-api-key"];
|
|
51836
51938
|
function WorkspaceSettingsModal({ onClose }) {
|
|
51837
51939
|
const workspace = useStore((s) => s.workspace);
|
|
@@ -51877,7 +51979,7 @@ function WorkspaceSettingsModal({ onClose }) {
|
|
|
51877
51979
|
settings.piiMaskPatterns = patterns;
|
|
51878
51980
|
updateWorkspaceSettings(settings);
|
|
51879
51981
|
const updated = useStore.getState().workspace;
|
|
51880
|
-
if (updated) await electron$
|
|
51982
|
+
if (updated) await electron$9.saveWorkspace(updated);
|
|
51881
51983
|
onClose();
|
|
51882
51984
|
}
|
|
51883
51985
|
const tabs = [
|
|
@@ -52075,7 +52177,7 @@ function WorkspaceSettingsModal({ onClose }) {
|
|
|
52075
52177
|
}
|
|
52076
52178
|
);
|
|
52077
52179
|
}
|
|
52078
|
-
const { electron: electron$
|
|
52180
|
+
const { electron: electron$8 } = window;
|
|
52079
52181
|
function DocsGeneratorModal({ onClose }) {
|
|
52080
52182
|
const collections = useStore((s) => s.collections);
|
|
52081
52183
|
const collectionList = Object.values(collections);
|
|
@@ -52104,9 +52206,9 @@ function DocsGeneratorModal({ onClose }) {
|
|
|
52104
52206
|
setGenerating(true);
|
|
52105
52207
|
setError(null);
|
|
52106
52208
|
try {
|
|
52107
|
-
const content2 = await electron$
|
|
52209
|
+
const content2 = await electron$8.generateDocs(buildPayload());
|
|
52108
52210
|
const filename = format2 === "html" ? "api-docs.html" : "api-docs.md";
|
|
52109
|
-
await electron$
|
|
52211
|
+
await electron$8.saveResults(content2, filename);
|
|
52110
52212
|
} catch (err) {
|
|
52111
52213
|
setError(err instanceof Error ? err.message : String(err));
|
|
52112
52214
|
} finally {
|
|
@@ -52117,7 +52219,7 @@ function DocsGeneratorModal({ onClose }) {
|
|
|
52117
52219
|
setGenerating(true);
|
|
52118
52220
|
setError(null);
|
|
52119
52221
|
try {
|
|
52120
|
-
const content2 = await electron$
|
|
52222
|
+
const content2 = await electron$8.generateDocs(buildPayload());
|
|
52121
52223
|
setPreview(content2);
|
|
52122
52224
|
} catch (err) {
|
|
52123
52225
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -52233,7 +52335,7 @@ function DocsGeneratorModal({ onClose }) {
|
|
|
52233
52335
|
] })
|
|
52234
52336
|
] }) });
|
|
52235
52337
|
}
|
|
52236
|
-
const { electron: electron$
|
|
52338
|
+
const { electron: electron$7 } = window;
|
|
52237
52339
|
const OPTIONS = [
|
|
52238
52340
|
{ id: "postman", label: "Postman", description: "Collection v2.1 JSON" },
|
|
52239
52341
|
{ id: "openapi", label: "OpenAPI", description: "JSON or YAML (v3.x)", supportsUrl: true },
|
|
@@ -52251,10 +52353,10 @@ function ImportModal({ onImport, onClose }) {
|
|
|
52251
52353
|
setError(null);
|
|
52252
52354
|
try {
|
|
52253
52355
|
let col = null;
|
|
52254
|
-
if (opt.id === "postman") col = await electron$
|
|
52255
|
-
if (opt.id === "openapi") col = await electron$
|
|
52256
|
-
if (opt.id === "insomnia") col = await electron$
|
|
52257
|
-
if (opt.id === "bruno") col = await electron$
|
|
52356
|
+
if (opt.id === "postman") col = await electron$7.importPostman();
|
|
52357
|
+
if (opt.id === "openapi") col = await electron$7.importOpenApi();
|
|
52358
|
+
if (opt.id === "insomnia") col = await electron$7.importInsomnia();
|
|
52359
|
+
if (opt.id === "bruno") col = await electron$7.importBruno();
|
|
52258
52360
|
onImport(col);
|
|
52259
52361
|
onClose();
|
|
52260
52362
|
} catch (err) {
|
|
@@ -52269,7 +52371,7 @@ function ImportModal({ onImport, onClose }) {
|
|
|
52269
52371
|
setLoading(true);
|
|
52270
52372
|
setError(null);
|
|
52271
52373
|
try {
|
|
52272
|
-
const col = await electron$
|
|
52374
|
+
const col = await electron$7.importOpenApiFromUrl(trimmed);
|
|
52273
52375
|
onImport(col);
|
|
52274
52376
|
onClose();
|
|
52275
52377
|
} catch (err) {
|
|
@@ -52364,7 +52466,7 @@ function ImportModal({ onImport, onClose }) {
|
|
|
52364
52466
|
}
|
|
52365
52467
|
) });
|
|
52366
52468
|
}
|
|
52367
|
-
const { electron: electron$
|
|
52469
|
+
const { electron: electron$6 } = window;
|
|
52368
52470
|
const ZOOM_STEPS = [0.75, 0.9, 1, 1.1, 1.25, 1.5];
|
|
52369
52471
|
function PreferencesPopover() {
|
|
52370
52472
|
const theme2 = useStore((s) => s.theme);
|
|
@@ -52470,13 +52572,13 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
|
|
|
52470
52572
|
try {
|
|
52471
52573
|
for (const { relPath, data, dirty } of Object.values(collections)) {
|
|
52472
52574
|
if (!dirty) continue;
|
|
52473
|
-
await electron$
|
|
52575
|
+
await electron$6.saveCollection(relPath, data);
|
|
52474
52576
|
markCollectionClean(data.id);
|
|
52475
52577
|
}
|
|
52476
52578
|
for (const { relPath, data } of Object.values(environments)) {
|
|
52477
|
-
await electron$
|
|
52579
|
+
await electron$6.saveEnvironment(relPath, data);
|
|
52478
52580
|
}
|
|
52479
|
-
if (workspace) await electron$
|
|
52581
|
+
if (workspace) await electron$6.saveWorkspace(workspace);
|
|
52480
52582
|
} finally {
|
|
52481
52583
|
setSaving(false);
|
|
52482
52584
|
}
|
|
@@ -52484,14 +52586,14 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
|
|
|
52484
52586
|
async function afterImport(col) {
|
|
52485
52587
|
if (!col) return;
|
|
52486
52588
|
const relPath = colRelPath(col.name, col.id);
|
|
52487
|
-
await electron$
|
|
52589
|
+
await electron$6.saveCollection(relPath, col);
|
|
52488
52590
|
loadCollection(relPath, col);
|
|
52489
52591
|
setActiveCollection(col.id);
|
|
52490
52592
|
const ws2 = useStore.getState().workspace;
|
|
52491
52593
|
if (ws2 && !ws2.collections.includes(relPath)) {
|
|
52492
52594
|
const updated = { ...ws2, collections: [...ws2.collections, relPath] };
|
|
52493
52595
|
useStore.setState({ workspace: updated });
|
|
52494
|
-
await electron$
|
|
52596
|
+
await electron$6.saveWorkspace(updated);
|
|
52495
52597
|
}
|
|
52496
52598
|
}
|
|
52497
52599
|
if (!workspace) return null;
|
|
@@ -52557,7 +52659,7 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
|
|
|
52557
52659
|
"button",
|
|
52558
52660
|
{
|
|
52559
52661
|
onClick: async () => {
|
|
52560
|
-
const result = await electron$
|
|
52662
|
+
const result = await electron$6.openWorkspace();
|
|
52561
52663
|
if (result) await applyWorkspace(result.workspace, result.workspacePath);
|
|
52562
52664
|
},
|
|
52563
52665
|
className: "px-2.5 py-1 text-xs bg-surface-800 hover:bg-surface-700 rounded transition-colors",
|
|
@@ -52569,7 +52671,7 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
|
|
|
52569
52671
|
"button",
|
|
52570
52672
|
{
|
|
52571
52673
|
onClick: async () => {
|
|
52572
|
-
const result = await electron$
|
|
52674
|
+
const result = await electron$6.newWorkspace();
|
|
52573
52675
|
if (result) await applyWorkspace(result.workspace, result.workspacePath);
|
|
52574
52676
|
},
|
|
52575
52677
|
className: "px-2.5 py-1 text-xs bg-surface-800 hover:bg-surface-700 rounded transition-colors",
|
|
@@ -52581,7 +52683,7 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
|
|
|
52581
52683
|
"button",
|
|
52582
52684
|
{
|
|
52583
52685
|
onClick: async () => {
|
|
52584
|
-
await electron$
|
|
52686
|
+
await electron$6.closeWorkspace();
|
|
52585
52687
|
closeWorkspace();
|
|
52586
52688
|
},
|
|
52587
52689
|
className: "px-2.5 py-1 text-xs bg-surface-800 hover:bg-surface-700 rounded transition-colors",
|
|
@@ -52978,7 +53080,7 @@ api-tests:
|
|
|
52978
53080
|
function EmptyState({ message }) {
|
|
52979
53081
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-24 text-surface-400 text-xs", children: message });
|
|
52980
53082
|
}
|
|
52981
|
-
const { electron: electron$
|
|
53083
|
+
const { electron: electron$5 } = window;
|
|
52982
53084
|
function collectRequests(collectionId, folderId, filterTags) {
|
|
52983
53085
|
const state = useStore.getState();
|
|
52984
53086
|
const col = state.collections[collectionId]?.data;
|
|
@@ -53074,13 +53176,13 @@ function RunnerModal() {
|
|
|
53074
53176
|
setSummary(null);
|
|
53075
53177
|
setRunnerRunning(true);
|
|
53076
53178
|
progressIdxRef.current = 0;
|
|
53077
|
-
electron$
|
|
53179
|
+
electron$5.onRunProgress((result) => {
|
|
53078
53180
|
const idx = progressIdxRef.current;
|
|
53079
53181
|
patchRunnerResult(idx, result);
|
|
53080
53182
|
if (result.status !== "running") progressIdxRef.current++;
|
|
53081
53183
|
});
|
|
53082
53184
|
try {
|
|
53083
|
-
const s = await electron$
|
|
53185
|
+
const s = await electron$5.runCollection({
|
|
53084
53186
|
items: items2,
|
|
53085
53187
|
environment: env,
|
|
53086
53188
|
globals,
|
|
@@ -53091,7 +53193,7 @@ function RunnerModal() {
|
|
|
53091
53193
|
});
|
|
53092
53194
|
setSummary(s);
|
|
53093
53195
|
} finally {
|
|
53094
|
-
electron$
|
|
53196
|
+
electron$5.offRunProgress();
|
|
53095
53197
|
setRunnerRunning(false);
|
|
53096
53198
|
}
|
|
53097
53199
|
}, [collectionId, folderId, filterTags, selectedEnvId, environments, globals, colEntry, requestDelay, workspaceSettings, setRunnerResults, patchRunnerResult, setRunnerRunning]);
|
|
@@ -53304,7 +53406,7 @@ function RunnerModal() {
|
|
|
53304
53406
|
};
|
|
53305
53407
|
const content2 = exportFormat === "junit" ? buildJUnitReport(runnerResults, summary, meta2) : exportFormat === "html" ? buildHtmlReport(runnerResults, summary, meta2) : buildJsonReport(runnerResults, summary, meta2);
|
|
53306
53408
|
const ext = exportFormat === "junit" ? "xml" : exportFormat === "html" ? "html" : "json";
|
|
53307
|
-
electron$
|
|
53409
|
+
electron$5.saveResults(content2, `spector-results.${ext}`);
|
|
53308
53410
|
},
|
|
53309
53411
|
className: "px-2.5 py-0.5 bg-surface-800 hover:bg-surface-700 rounded transition-colors text-[11px] whitespace-nowrap",
|
|
53310
53412
|
children: "Export results"
|
|
@@ -53522,38 +53624,48 @@ function CollectionPanel() {
|
|
|
53522
53624
|
] })
|
|
53523
53625
|
] });
|
|
53524
53626
|
}
|
|
53525
|
-
const { electron: electron$
|
|
53627
|
+
const { electron: electron$4 } = window;
|
|
53526
53628
|
function MockPanel() {
|
|
53527
53629
|
const mocks = useStore((s) => s.mocks);
|
|
53528
53630
|
const activeMockId = useStore((s) => s.activeMockId);
|
|
53529
53631
|
const setActiveMock = useStore((s) => s.setActiveMockId);
|
|
53530
53632
|
const addMock = useStore((s) => s.addMock);
|
|
53633
|
+
const deleteMock = useStore((s) => s.deleteMock);
|
|
53531
53634
|
const setRunning = useStore((s) => s.setMockRunning);
|
|
53532
53635
|
const mockList = Object.values(mocks);
|
|
53533
53636
|
async function handleAddMock() {
|
|
53534
53637
|
addMock();
|
|
53535
53638
|
const ws2 = useStore.getState().workspace;
|
|
53536
|
-
if (ws2) await electron$
|
|
53639
|
+
if (ws2) await electron$4.saveWorkspace(ws2);
|
|
53537
53640
|
const state = useStore.getState();
|
|
53538
53641
|
const newId = state.activeMockId;
|
|
53539
53642
|
if (newId) {
|
|
53540
53643
|
const entry = state.mocks[newId];
|
|
53541
|
-
await electron$
|
|
53644
|
+
await electron$4.saveMock(entry.relPath, entry.data);
|
|
53542
53645
|
setActiveMock(newId);
|
|
53543
53646
|
}
|
|
53544
53647
|
}
|
|
53648
|
+
async function handleDelete(e, mockId) {
|
|
53649
|
+
e.stopPropagation();
|
|
53650
|
+
const entry = useStore.getState().mocks[mockId];
|
|
53651
|
+
if (!entry) return;
|
|
53652
|
+
if (entry.running) await electron$4.mockStop(mockId);
|
|
53653
|
+
deleteMock(mockId);
|
|
53654
|
+
const ws2 = useStore.getState().workspace;
|
|
53655
|
+
if (ws2) await electron$4.saveWorkspace(ws2);
|
|
53656
|
+
}
|
|
53545
53657
|
async function toggleRunning(e, mockId) {
|
|
53546
53658
|
e.stopPropagation();
|
|
53547
53659
|
const entry = useStore.getState().mocks[mockId];
|
|
53548
53660
|
if (!entry) return;
|
|
53549
53661
|
try {
|
|
53550
53662
|
if (entry.running) {
|
|
53551
|
-
await electron$
|
|
53663
|
+
await electron$4.mockStop(mockId);
|
|
53552
53664
|
setRunning(mockId, false);
|
|
53553
53665
|
} else {
|
|
53554
53666
|
const latest2 = useStore.getState().mocks[mockId].data;
|
|
53555
|
-
await electron$
|
|
53556
|
-
await electron$
|
|
53667
|
+
await electron$4.saveMock(entry.relPath, latest2);
|
|
53668
|
+
await electron$4.mockStart(latest2);
|
|
53557
53669
|
setRunning(mockId, true);
|
|
53558
53670
|
}
|
|
53559
53671
|
} catch {
|
|
@@ -53602,15 +53714,26 @@ function MockPanel() {
|
|
|
53602
53714
|
(mock.routes ?? []).length !== 1 ? "s" : ""
|
|
53603
53715
|
] })
|
|
53604
53716
|
] }),
|
|
53605
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
53606
|
-
|
|
53607
|
-
|
|
53608
|
-
|
|
53609
|
-
|
|
53610
|
-
|
|
53611
|
-
|
|
53612
|
-
|
|
53613
|
-
|
|
53717
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [
|
|
53718
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
53719
|
+
"button",
|
|
53720
|
+
{
|
|
53721
|
+
onClick: (e) => toggleRunning(e, mock.id),
|
|
53722
|
+
className: `text-[10px] px-1.5 py-0.5 rounded transition-colors ${entry.running ? "text-emerald-400 hover:text-red-400" : "text-surface-400 hover:text-emerald-400 opacity-0 group-hover:opacity-100"}`,
|
|
53723
|
+
title: entry.running ? "Stop" : "Start",
|
|
53724
|
+
children: entry.running ? "■" : "▶"
|
|
53725
|
+
}
|
|
53726
|
+
),
|
|
53727
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
53728
|
+
"button",
|
|
53729
|
+
{
|
|
53730
|
+
onClick: (e) => handleDelete(e, mock.id),
|
|
53731
|
+
className: "text-[10px] px-1 py-0.5 rounded text-surface-500 hover:text-red-400 opacity-0 group-hover:opacity-100 transition-colors",
|
|
53732
|
+
title: "Delete",
|
|
53733
|
+
children: "✕"
|
|
53734
|
+
}
|
|
53735
|
+
)
|
|
53736
|
+
] })
|
|
53614
53737
|
]
|
|
53615
53738
|
},
|
|
53616
53739
|
mock.id
|
|
@@ -53618,12 +53741,13 @@ function MockPanel() {
|
|
|
53618
53741
|
}) })
|
|
53619
53742
|
] });
|
|
53620
53743
|
}
|
|
53621
|
-
const { electron: electron$
|
|
53744
|
+
const { electron: electron$3 } = window;
|
|
53622
53745
|
const METHODS_PLUS_ANY = ["ANY", "GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
53623
53746
|
function RouteRow({
|
|
53624
53747
|
route,
|
|
53625
53748
|
onSave,
|
|
53626
53749
|
onDelete,
|
|
53750
|
+
onDuplicate,
|
|
53627
53751
|
initialEditing = false
|
|
53628
53752
|
}) {
|
|
53629
53753
|
const [editing, setEditing] = reactExports.useState(initialEditing);
|
|
@@ -53663,6 +53787,15 @@ function RouteRow({
|
|
|
53663
53787
|
children: "Edit"
|
|
53664
53788
|
}
|
|
53665
53789
|
),
|
|
53790
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
53791
|
+
"button",
|
|
53792
|
+
{
|
|
53793
|
+
onClick: onDuplicate,
|
|
53794
|
+
className: "opacity-0 group-hover:opacity-100 text-xs text-surface-600 hover:text-blue-400 transition-opacity",
|
|
53795
|
+
title: "Duplicate route",
|
|
53796
|
+
children: "⧉"
|
|
53797
|
+
}
|
|
53798
|
+
),
|
|
53666
53799
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
53667
53800
|
"button",
|
|
53668
53801
|
{
|
|
@@ -53733,11 +53866,17 @@ function RouteRow({
|
|
|
53733
53866
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-surface-600", children: [
|
|
53734
53867
|
"Use ",
|
|
53735
53868
|
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-surface-400", children: "{{faker.person.firstName()}}" }),
|
|
53736
|
-
"
|
|
53737
|
-
|
|
53738
|
-
|
|
53739
|
-
|
|
53740
|
-
|
|
53869
|
+
pathParamNames.map((p) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
53870
|
+
", ",
|
|
53871
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-blue-400/80", children: `{{request.params.${p}}}` })
|
|
53872
|
+
] }, p)),
|
|
53873
|
+
pathParamNames.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
53874
|
+
", ",
|
|
53875
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-surface-400", children: "{{request.params.id}}" }),
|
|
53876
|
+
" ",
|
|
53877
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-700", children: "(add :id to path)" })
|
|
53878
|
+
] }),
|
|
53879
|
+
", ",
|
|
53741
53880
|
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-surface-400", children: "{{request.query.search}}" })
|
|
53742
53881
|
] })
|
|
53743
53882
|
] }),
|
|
@@ -53887,6 +54026,55 @@ function timeAgo(ts) {
|
|
|
53887
54026
|
if (s < 3600) return `${Math.floor(s / 60)}m ago`;
|
|
53888
54027
|
return `${Math.floor(s / 3600)}h ago`;
|
|
53889
54028
|
}
|
|
54029
|
+
function HitRow({ hit, matched }) {
|
|
54030
|
+
const [open, setOpen] = reactExports.useState(false);
|
|
54031
|
+
const unmatched = !hit.matchedRouteId;
|
|
54032
|
+
const prettyBody = reactExports.useMemo(() => {
|
|
54033
|
+
if (!hit.responseBody) return null;
|
|
54034
|
+
try {
|
|
54035
|
+
return JSON.stringify(JSON.parse(hit.responseBody), null, 2);
|
|
54036
|
+
} catch {
|
|
54037
|
+
return hit.responseBody;
|
|
54038
|
+
}
|
|
54039
|
+
}, [hit.responseBody]);
|
|
54040
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `border-b border-surface-800/40 ${unmatched ? "bg-red-950/20" : ""}`, children: [
|
|
54041
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54042
|
+
"button",
|
|
54043
|
+
{
|
|
54044
|
+
onClick: () => setOpen((o) => !o),
|
|
54045
|
+
className: `w-full flex items-center gap-3 px-4 py-2 text-sm font-mono text-left ${unmatched ? "" : "hover:bg-surface-800/20"} transition-colors`,
|
|
54046
|
+
children: [
|
|
54047
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-600 text-[10px] w-3 shrink-0", children: open ? "▾" : "▸" }),
|
|
54048
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-bold w-16 shrink-0 text-xs ${getMethodColor(hit.method)}`, children: hit.method }),
|
|
54049
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-surface-200", title: hit.path, children: hit.path }),
|
|
54050
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-32 shrink-0 truncate text-surface-600 text-xs font-sans", title: matched?.description ?? matched?.path ?? "", children: unmatched ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-400", children: "no match" }) : matched?.description || matched?.path || "—" }),
|
|
54051
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-12 text-right shrink-0 text-xs ${hit.status < 300 ? "text-emerald-400" : hit.status < 400 ? "text-amber-400" : "text-red-400"}`, children: hit.status }),
|
|
54052
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "w-14 text-right shrink-0 text-surface-600 text-xs", children: [
|
|
54053
|
+
hit.durationMs,
|
|
54054
|
+
"ms"
|
|
54055
|
+
] }),
|
|
54056
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-20 text-right shrink-0 text-surface-400 text-xs", children: timeAgo(hit.timestamp) })
|
|
54057
|
+
]
|
|
54058
|
+
}
|
|
54059
|
+
),
|
|
54060
|
+
open && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pb-3 bg-surface-900/60 border-t border-surface-800/40", children: [
|
|
54061
|
+
hit.responseHeaders && Object.keys(hit.responseHeaders).length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2", children: [
|
|
54062
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] uppercase tracking-wider text-surface-600 mb-1", children: "Response headers" }),
|
|
54063
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-mono text-xs space-y-0.5", children: Object.entries(hit.responseHeaders).map(([k, v]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
54064
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-400 shrink-0", children: [
|
|
54065
|
+
k,
|
|
54066
|
+
":"
|
|
54067
|
+
] }),
|
|
54068
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-300 break-all", children: v })
|
|
54069
|
+
] }, k)) })
|
|
54070
|
+
] }),
|
|
54071
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2", children: [
|
|
54072
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] uppercase tracking-wider text-surface-600 mb-1", children: "Response body" }),
|
|
54073
|
+
prettyBody ? /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-xs text-surface-300 bg-surface-950 rounded p-2 overflow-x-auto max-h-60 overflow-y-auto whitespace-pre-wrap break-all", children: prettyBody }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-surface-600 italic", children: "empty" })
|
|
54074
|
+
] })
|
|
54075
|
+
] })
|
|
54076
|
+
] });
|
|
54077
|
+
}
|
|
53890
54078
|
function RequestLog({ serverId, routes, running }) {
|
|
53891
54079
|
const hits = useStore((s) => s.mockLogs[serverId]) ?? [];
|
|
53892
54080
|
const clearLogs = useStore((s) => s.clearMockLogs);
|
|
@@ -53918,6 +54106,7 @@ function RequestLog({ serverId, routes, running }) {
|
|
|
53918
54106
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-600 mt-1", children: "Waiting for incoming requests…" })
|
|
53919
54107
|
] }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
53920
54108
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 px-4 py-1.5 border-b border-surface-800 text-[10px] uppercase tracking-wider text-surface-400 sticky top-0 bg-surface-950", children: [
|
|
54109
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-3 shrink-0" }),
|
|
53921
54110
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-16 shrink-0", children: "Method" }),
|
|
53922
54111
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1", children: "Path" }),
|
|
53923
54112
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-32 shrink-0", children: "Matched route" }),
|
|
@@ -53925,28 +54114,14 @@ function RequestLog({ serverId, routes, running }) {
|
|
|
53925
54114
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-14 text-right shrink-0", children: "Duration" }),
|
|
53926
54115
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-20 text-right shrink-0", children: "Time" })
|
|
53927
54116
|
] }),
|
|
53928
|
-
hits.map((hit) =>
|
|
53929
|
-
|
|
53930
|
-
|
|
53931
|
-
|
|
53932
|
-
|
|
53933
|
-
|
|
53934
|
-
|
|
53935
|
-
|
|
53936
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-bold w-16 shrink-0 text-xs ${getMethodColor(hit.method)}`, children: hit.method }),
|
|
53937
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-surface-200", title: hit.path, children: hit.path }),
|
|
53938
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-32 shrink-0 truncate text-surface-600 text-xs font-sans", title: matched?.description ?? matched?.path ?? "", children: unmatched ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-400", children: "no match" }) : matched?.description || matched?.path || "—" }),
|
|
53939
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-12 text-right shrink-0 text-xs ${hit.status < 300 ? "text-emerald-400" : hit.status < 400 ? "text-amber-400" : "text-red-400"}`, children: hit.status }),
|
|
53940
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "w-14 text-right shrink-0 text-surface-600 text-xs", children: [
|
|
53941
|
-
hit.durationMs,
|
|
53942
|
-
"ms"
|
|
53943
|
-
] }),
|
|
53944
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-20 text-right shrink-0 text-surface-400 text-xs", title: String(hit.timestamp), children: timeAgo(hit.timestamp) })
|
|
53945
|
-
]
|
|
53946
|
-
},
|
|
53947
|
-
hit.id
|
|
53948
|
-
);
|
|
53949
|
-
})
|
|
54117
|
+
hits.map((hit) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54118
|
+
HitRow,
|
|
54119
|
+
{
|
|
54120
|
+
hit,
|
|
54121
|
+
matched: hit.matchedRouteId ? routeMap.get(hit.matchedRouteId) : null
|
|
54122
|
+
},
|
|
54123
|
+
hit.id
|
|
54124
|
+
))
|
|
53950
54125
|
] })
|
|
53951
54126
|
] });
|
|
53952
54127
|
}
|
|
@@ -53968,20 +54143,20 @@ function MockDetailPanel({ mockId }) {
|
|
|
53968
54143
|
const routes = mock.routes ?? [];
|
|
53969
54144
|
async function save(updated) {
|
|
53970
54145
|
updateMock(mock.id, updated);
|
|
53971
|
-
await electron$
|
|
53972
|
-
if (running) await electron$
|
|
53973
|
-
if (workspace) await electron$
|
|
54146
|
+
await electron$3.saveMock(entry.relPath, updated);
|
|
54147
|
+
if (running) await electron$3.mockUpdateRoutes(mock.id, updated.routes ?? []);
|
|
54148
|
+
if (workspace) await electron$3.saveWorkspace(workspace);
|
|
53974
54149
|
}
|
|
53975
54150
|
async function toggleRunning() {
|
|
53976
54151
|
setError(null);
|
|
53977
54152
|
try {
|
|
53978
54153
|
if (running) {
|
|
53979
|
-
await electron$
|
|
54154
|
+
await electron$3.mockStop(mock.id);
|
|
53980
54155
|
setRunning(mock.id, false);
|
|
53981
54156
|
} else {
|
|
53982
54157
|
const latest2 = useStore.getState().mocks[mock.id].data;
|
|
53983
|
-
await electron$
|
|
53984
|
-
await electron$
|
|
54158
|
+
await electron$3.saveMock(entry.relPath, latest2);
|
|
54159
|
+
await electron$3.mockStart(latest2);
|
|
53985
54160
|
setRunning(mock.id, true);
|
|
53986
54161
|
}
|
|
53987
54162
|
} catch (e) {
|
|
@@ -54076,19 +54251,25 @@ function MockDetailPanel({ mockId }) {
|
|
|
54076
54251
|
"⚠ ",
|
|
54077
54252
|
error2
|
|
54078
54253
|
] }),
|
|
54079
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
54080
|
-
|
|
54081
|
-
|
|
54082
|
-
|
|
54083
|
-
|
|
54084
|
-
|
|
54085
|
-
|
|
54086
|
-
|
|
54254
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative group/cli flex items-center", children: [
|
|
54255
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54256
|
+
"button",
|
|
54257
|
+
{
|
|
54258
|
+
onClick: toggleRunning,
|
|
54259
|
+
className: `px-3 py-1.5 rounded text-sm font-medium transition-colors ${running ? "bg-emerald-900/40 text-emerald-400 hover:bg-red-900/40 hover:text-red-400 border border-emerald-800/50" : "bg-surface-800 hover:bg-surface-700 text-surface-300 border border-surface-700"}`,
|
|
54260
|
+
children: running ? "● Running" : "▶ Start"
|
|
54261
|
+
}
|
|
54262
|
+
),
|
|
54263
|
+
!running && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pointer-events-none absolute bottom-full right-0 mb-2 hidden group-hover/cli:block z-50", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-[#1e1b2e] border border-white/10 rounded px-2.5 py-1.5 shadow-xl text-[11px] text-surface-300 whitespace-nowrap", children: [
|
|
54264
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500 mr-1", children: "or run from CLI:" }),
|
|
54265
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-blue-300", children: "npx api-spector mock --workspace <path>" })
|
|
54266
|
+
] }) })
|
|
54267
|
+
] }),
|
|
54087
54268
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54088
54269
|
"button",
|
|
54089
54270
|
{
|
|
54090
54271
|
onClick: () => {
|
|
54091
|
-
if (running) electron$
|
|
54272
|
+
if (running) electron$3.mockStop(mock.id);
|
|
54092
54273
|
deleteMock(mock.id);
|
|
54093
54274
|
setActive2(null);
|
|
54094
54275
|
},
|
|
@@ -54132,6 +54313,12 @@ function MockDetailPanel({ mockId }) {
|
|
|
54132
54313
|
setNewRouteId(null);
|
|
54133
54314
|
},
|
|
54134
54315
|
onDelete: () => save({ ...mock, routes: routes.filter((r) => r.id !== route.id) }),
|
|
54316
|
+
onDuplicate: () => {
|
|
54317
|
+
const copy = { ...route, id: v4() };
|
|
54318
|
+
const idx = routes.indexOf(route);
|
|
54319
|
+
const next = [...routes.slice(0, idx + 1), copy, ...routes.slice(idx + 1)];
|
|
54320
|
+
save({ ...mock, routes: next });
|
|
54321
|
+
},
|
|
54135
54322
|
initialEditing: route.id === newRouteId
|
|
54136
54323
|
},
|
|
54137
54324
|
route.id
|
|
@@ -54149,7 +54336,7 @@ function MockDetailPanel({ mockId }) {
|
|
|
54149
54336
|
] })
|
|
54150
54337
|
] });
|
|
54151
54338
|
}
|
|
54152
|
-
const { electron: electron$
|
|
54339
|
+
const { electron: electron$2 } = window;
|
|
54153
54340
|
function ContractPanel() {
|
|
54154
54341
|
const collections = useStore((s) => s.collections);
|
|
54155
54342
|
const environments = useStore((s) => s.environments);
|
|
@@ -54180,7 +54367,7 @@ function ContractPanel() {
|
|
|
54180
54367
|
setReport(null);
|
|
54181
54368
|
try {
|
|
54182
54369
|
const requests = mode === "provider" ? allRequests : contractRequests;
|
|
54183
|
-
const result = await electron$
|
|
54370
|
+
const result = await electron$2.runContracts({
|
|
54184
54371
|
mode,
|
|
54185
54372
|
requests,
|
|
54186
54373
|
envVars,
|
|
@@ -54378,6 +54565,812 @@ function ContractResultsPanel() {
|
|
|
54378
54565
|
})() })
|
|
54379
54566
|
] });
|
|
54380
54567
|
}
|
|
54568
|
+
const { electron: electron$1 } = window;
|
|
54569
|
+
function useToast() {
|
|
54570
|
+
const [toast, setToast] = reactExports.useState(null);
|
|
54571
|
+
const timer = reactExports.useRef(null);
|
|
54572
|
+
function show(msg, ok) {
|
|
54573
|
+
if (timer.current) clearTimeout(timer.current);
|
|
54574
|
+
setToast({ msg, ok });
|
|
54575
|
+
timer.current = setTimeout(() => setToast(null), 3e3);
|
|
54576
|
+
}
|
|
54577
|
+
return { toast, show };
|
|
54578
|
+
}
|
|
54579
|
+
function Toast({ toast }) {
|
|
54580
|
+
if (!toast) return null;
|
|
54581
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `mx-3 mb-2 px-2 py-1.5 rounded text-[11px] flex-shrink-0 ${toast.ok ? "bg-emerald-900/50 text-emerald-300 border border-emerald-800/50" : "bg-red-900/50 text-red-300 border border-red-800/50"}`, children: toast.msg });
|
|
54582
|
+
}
|
|
54583
|
+
function StatusBadge({ status }) {
|
|
54584
|
+
const map = {
|
|
54585
|
+
modified: { label: "M", color: "text-amber-400" },
|
|
54586
|
+
added: { label: "A", color: "text-emerald-400" },
|
|
54587
|
+
deleted: { label: "D", color: "text-red-400" },
|
|
54588
|
+
renamed: { label: "R", color: "text-blue-400" },
|
|
54589
|
+
untracked: { label: "?", color: "text-surface-500" }
|
|
54590
|
+
};
|
|
54591
|
+
const { label, color } = map[status] ?? { label: "?", color: "text-surface-500" };
|
|
54592
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-mono text-[11px] font-bold w-4 shrink-0 ${color}`, children: label });
|
|
54593
|
+
}
|
|
54594
|
+
function DiffViewer({ diff }) {
|
|
54595
|
+
if (!diff) return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 p-3", children: "No changes." });
|
|
54596
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-[11px] font-mono overflow-auto p-3 leading-relaxed", children: diff.split("\n").map((line, i) => {
|
|
54597
|
+
const cls = line.startsWith("+") && !line.startsWith("+++") ? "text-emerald-400" : line.startsWith("-") && !line.startsWith("---") ? "text-red-400" : line.startsWith("@@") ? "text-blue-400" : "text-surface-400";
|
|
54598
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cls, children: line || " " }, i);
|
|
54599
|
+
}) });
|
|
54600
|
+
}
|
|
54601
|
+
function ChangesTab({ status, onRefresh }) {
|
|
54602
|
+
const [message, setMessage] = reactExports.useState("");
|
|
54603
|
+
const [diffFile, setDiffFile] = reactExports.useState(null);
|
|
54604
|
+
const [diff, setDiff] = reactExports.useState("");
|
|
54605
|
+
const [diffStaged, setDiffStaged] = reactExports.useState(false);
|
|
54606
|
+
const [error2, setError] = reactExports.useState(null);
|
|
54607
|
+
const [pushing, setPushing] = reactExports.useState(false);
|
|
54608
|
+
const [pulling, setPulling] = reactExports.useState(false);
|
|
54609
|
+
const { toast, show: showToast } = useToast();
|
|
54610
|
+
async function showDiff(file, staged) {
|
|
54611
|
+
setDiffFile(file.path);
|
|
54612
|
+
setDiffStaged(staged);
|
|
54613
|
+
try {
|
|
54614
|
+
const d = staged ? await electron$1.gitDiffStaged(file.path) : await electron$1.gitDiff(file.path);
|
|
54615
|
+
setDiff(d);
|
|
54616
|
+
} catch {
|
|
54617
|
+
setDiff("");
|
|
54618
|
+
}
|
|
54619
|
+
}
|
|
54620
|
+
async function stage(paths) {
|
|
54621
|
+
try {
|
|
54622
|
+
await electron$1.gitStage(paths);
|
|
54623
|
+
onRefresh();
|
|
54624
|
+
} catch (e) {
|
|
54625
|
+
setError(String(e));
|
|
54626
|
+
}
|
|
54627
|
+
}
|
|
54628
|
+
async function unstage(paths) {
|
|
54629
|
+
try {
|
|
54630
|
+
await electron$1.gitUnstage(paths);
|
|
54631
|
+
onRefresh();
|
|
54632
|
+
} catch (e) {
|
|
54633
|
+
setError(String(e));
|
|
54634
|
+
}
|
|
54635
|
+
}
|
|
54636
|
+
async function stageAll() {
|
|
54637
|
+
try {
|
|
54638
|
+
await electron$1.gitStageAll();
|
|
54639
|
+
onRefresh();
|
|
54640
|
+
} catch (e) {
|
|
54641
|
+
setError(String(e));
|
|
54642
|
+
}
|
|
54643
|
+
}
|
|
54644
|
+
async function commit() {
|
|
54645
|
+
if (!message.trim()) return;
|
|
54646
|
+
try {
|
|
54647
|
+
setError(null);
|
|
54648
|
+
await electron$1.gitCommit(message.trim());
|
|
54649
|
+
setMessage("");
|
|
54650
|
+
onRefresh();
|
|
54651
|
+
} catch (e) {
|
|
54652
|
+
setError(String(e));
|
|
54653
|
+
}
|
|
54654
|
+
}
|
|
54655
|
+
async function pull() {
|
|
54656
|
+
setPulling(true);
|
|
54657
|
+
try {
|
|
54658
|
+
await electron$1.gitPull();
|
|
54659
|
+
showToast("Pull successful", true);
|
|
54660
|
+
onRefresh();
|
|
54661
|
+
} catch (e) {
|
|
54662
|
+
showToast(String(e), false);
|
|
54663
|
+
} finally {
|
|
54664
|
+
setPulling(false);
|
|
54665
|
+
}
|
|
54666
|
+
}
|
|
54667
|
+
async function push2() {
|
|
54668
|
+
setPushing(true);
|
|
54669
|
+
try {
|
|
54670
|
+
await electron$1.gitPush(!status.remote);
|
|
54671
|
+
showToast("Push successful", true);
|
|
54672
|
+
onRefresh();
|
|
54673
|
+
} catch (e) {
|
|
54674
|
+
showToast(String(e), false);
|
|
54675
|
+
} finally {
|
|
54676
|
+
setPushing(false);
|
|
54677
|
+
}
|
|
54678
|
+
}
|
|
54679
|
+
const allUnstaged = [...status.unstaged, ...status.untracked];
|
|
54680
|
+
const hasStaged = status.staged.length > 0;
|
|
54681
|
+
const needsPush = status.ahead > 0;
|
|
54682
|
+
const needsPull = status.behind > 0;
|
|
54683
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
54684
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-2 border-b border-surface-800 flex items-center gap-2 flex-shrink-0", children: [
|
|
54685
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[11px] font-mono text-blue-300 truncate flex-1", children: [
|
|
54686
|
+
"⎇ ",
|
|
54687
|
+
status.branch || "no branch"
|
|
54688
|
+
] }),
|
|
54689
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54690
|
+
"button",
|
|
54691
|
+
{
|
|
54692
|
+
onClick: pull,
|
|
54693
|
+
disabled: pulling,
|
|
54694
|
+
title: needsPull ? `Pull (${status.behind} behind)` : "Pull",
|
|
54695
|
+
className: `flex items-center gap-0.5 text-xs px-1.5 py-0.5 rounded transition-colors disabled:opacity-40 ${needsPull ? "text-amber-300 bg-amber-900/30 hover:bg-amber-900/50" : "text-surface-400 hover:text-white"}`,
|
|
54696
|
+
children: [
|
|
54697
|
+
"↓",
|
|
54698
|
+
needsPull ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px]", children: status.behind }) : null
|
|
54699
|
+
]
|
|
54700
|
+
}
|
|
54701
|
+
),
|
|
54702
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54703
|
+
"button",
|
|
54704
|
+
{
|
|
54705
|
+
onClick: push2,
|
|
54706
|
+
disabled: pushing,
|
|
54707
|
+
title: needsPush ? `Push (${status.ahead} unpushed)` : status.remote ? "Push" : "Push & set upstream",
|
|
54708
|
+
className: `flex items-center gap-0.5 text-xs px-1.5 py-0.5 rounded transition-colors disabled:opacity-40 ${needsPush ? "text-blue-300 bg-blue-900/30 hover:bg-blue-900/50" : "text-surface-400 hover:text-white"}`,
|
|
54709
|
+
children: [
|
|
54710
|
+
"↑",
|
|
54711
|
+
needsPush ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px]", children: status.ahead }) : null
|
|
54712
|
+
]
|
|
54713
|
+
}
|
|
54714
|
+
)
|
|
54715
|
+
] }),
|
|
54716
|
+
status.remote && (needsPush ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mx-3 mt-2 px-2 py-1.5 rounded text-[11px] bg-blue-900/20 text-blue-300 border border-blue-800/40 flex items-center justify-between flex-shrink-0", children: [
|
|
54717
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
54718
|
+
status.ahead,
|
|
54719
|
+
" commit",
|
|
54720
|
+
status.ahead !== 1 ? "s" : "",
|
|
54721
|
+
" to push"
|
|
54722
|
+
] }),
|
|
54723
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54724
|
+
"button",
|
|
54725
|
+
{
|
|
54726
|
+
onClick: push2,
|
|
54727
|
+
disabled: pushing,
|
|
54728
|
+
className: "text-blue-400 hover:text-blue-200 font-medium disabled:opacity-40",
|
|
54729
|
+
children: "Push ↑"
|
|
54730
|
+
}
|
|
54731
|
+
)
|
|
54732
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-3 mt-2 px-2 py-1 rounded text-[11px] text-surface-600 border border-surface-800 flex-shrink-0", children: "✓ Nothing to push" })),
|
|
54733
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Toast, { toast }),
|
|
54734
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-h-0 overflow-y-auto", children: [
|
|
54735
|
+
hasStaged && /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { children: [
|
|
54736
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-1.5 flex items-center justify-between", children: [
|
|
54737
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: [
|
|
54738
|
+
"Staged (",
|
|
54739
|
+
status.staged.length,
|
|
54740
|
+
")"
|
|
54741
|
+
] }),
|
|
54742
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54743
|
+
"button",
|
|
54744
|
+
{
|
|
54745
|
+
onClick: () => unstage(status.staged.map((f) => f.path)),
|
|
54746
|
+
className: "text-[10px] text-surface-500 hover:text-white transition-colors",
|
|
54747
|
+
children: "Unstage all"
|
|
54748
|
+
}
|
|
54749
|
+
)
|
|
54750
|
+
] }),
|
|
54751
|
+
status.staged.map((f) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54752
|
+
"div",
|
|
54753
|
+
{
|
|
54754
|
+
className: `flex items-center gap-2 px-3 py-1 hover:bg-surface-800/50 cursor-pointer group text-xs ${diffFile === f.path && diffStaged ? "bg-surface-800" : ""}`,
|
|
54755
|
+
onClick: () => showDiff(f, true),
|
|
54756
|
+
children: [
|
|
54757
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusBadge, { status: f.status }),
|
|
54758
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-surface-200", children: f.path }),
|
|
54759
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54760
|
+
"button",
|
|
54761
|
+
{
|
|
54762
|
+
onClick: (e) => {
|
|
54763
|
+
e.stopPropagation();
|
|
54764
|
+
unstage([f.path]);
|
|
54765
|
+
},
|
|
54766
|
+
className: "opacity-0 group-hover:opacity-100 text-surface-500 hover:text-amber-400 transition-all text-[10px]",
|
|
54767
|
+
title: "Unstage",
|
|
54768
|
+
children: "−"
|
|
54769
|
+
}
|
|
54770
|
+
)
|
|
54771
|
+
]
|
|
54772
|
+
},
|
|
54773
|
+
f.path
|
|
54774
|
+
))
|
|
54775
|
+
] }),
|
|
54776
|
+
allUnstaged.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { children: [
|
|
54777
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-1.5 flex items-center justify-between", children: [
|
|
54778
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: [
|
|
54779
|
+
"Changes (",
|
|
54780
|
+
allUnstaged.length,
|
|
54781
|
+
")"
|
|
54782
|
+
] }),
|
|
54783
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54784
|
+
"button",
|
|
54785
|
+
{
|
|
54786
|
+
onClick: stageAll,
|
|
54787
|
+
className: "text-[10px] text-surface-500 hover:text-white transition-colors",
|
|
54788
|
+
children: "Stage all"
|
|
54789
|
+
}
|
|
54790
|
+
)
|
|
54791
|
+
] }),
|
|
54792
|
+
allUnstaged.map((f) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54793
|
+
"div",
|
|
54794
|
+
{
|
|
54795
|
+
className: `flex items-center gap-2 px-3 py-1 hover:bg-surface-800/50 cursor-pointer group text-xs ${diffFile === f.path && !diffStaged ? "bg-surface-800" : ""}`,
|
|
54796
|
+
onClick: () => showDiff(f, false),
|
|
54797
|
+
children: [
|
|
54798
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(StatusBadge, { status: f.status }),
|
|
54799
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-surface-200", children: f.path }),
|
|
54800
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54801
|
+
"button",
|
|
54802
|
+
{
|
|
54803
|
+
onClick: (e) => {
|
|
54804
|
+
e.stopPropagation();
|
|
54805
|
+
stage([f.path]);
|
|
54806
|
+
},
|
|
54807
|
+
className: "opacity-0 group-hover:opacity-100 text-surface-500 hover:text-emerald-400 transition-all text-[10px]",
|
|
54808
|
+
title: "Stage",
|
|
54809
|
+
children: "+"
|
|
54810
|
+
}
|
|
54811
|
+
)
|
|
54812
|
+
]
|
|
54813
|
+
},
|
|
54814
|
+
f.path
|
|
54815
|
+
))
|
|
54816
|
+
] }),
|
|
54817
|
+
status.staged.length === 0 && allUnstaged.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 px-3 py-4", children: "Working tree clean." })
|
|
54818
|
+
] }),
|
|
54819
|
+
diffFile && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-surface-800 flex flex-col max-h-48 min-h-0", children: [
|
|
54820
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-1 flex items-center justify-between flex-shrink-0 border-b border-surface-800", children: [
|
|
54821
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-mono text-surface-400 truncate", children: diffFile }),
|
|
54822
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setDiffFile(null), className: "text-surface-600 hover:text-white text-xs ml-2", children: "✕" })
|
|
54823
|
+
] }),
|
|
54824
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-auto flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(DiffViewer, { diff }) })
|
|
54825
|
+
] }),
|
|
54826
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-surface-800 p-3 flex-shrink-0 flex flex-col gap-2", children: [
|
|
54827
|
+
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-red-400 truncate", title: error2, children: error2 }),
|
|
54828
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54829
|
+
"textarea",
|
|
54830
|
+
{
|
|
54831
|
+
value: message,
|
|
54832
|
+
onChange: (e) => setMessage(e.target.value),
|
|
54833
|
+
onKeyDown: (e) => {
|
|
54834
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) commit();
|
|
54835
|
+
},
|
|
54836
|
+
placeholder: "Commit message… (⌘↵ to commit)",
|
|
54837
|
+
rows: 2,
|
|
54838
|
+
className: "w-full bg-surface-800 border border-surface-700 rounded px-2 py-1.5 text-xs resize-none focus:outline-none focus:border-blue-500 placeholder-surface-600"
|
|
54839
|
+
}
|
|
54840
|
+
),
|
|
54841
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54842
|
+
"button",
|
|
54843
|
+
{
|
|
54844
|
+
onClick: commit,
|
|
54845
|
+
disabled: !message.trim() || !hasStaged,
|
|
54846
|
+
className: "w-full py-1.5 bg-blue-600 hover:bg-blue-500 disabled:opacity-40 disabled:cursor-not-allowed rounded text-xs font-medium transition-colors",
|
|
54847
|
+
children: [
|
|
54848
|
+
"Commit",
|
|
54849
|
+
hasStaged ? ` (${status.staged.length})` : ""
|
|
54850
|
+
]
|
|
54851
|
+
}
|
|
54852
|
+
)
|
|
54853
|
+
] })
|
|
54854
|
+
] });
|
|
54855
|
+
}
|
|
54856
|
+
function LogTab() {
|
|
54857
|
+
const [commits, setCommits] = reactExports.useState([]);
|
|
54858
|
+
const [loading, setLoading] = reactExports.useState(true);
|
|
54859
|
+
reactExports.useEffect(() => {
|
|
54860
|
+
electron$1.gitLog(100).then(setCommits).catch(() => setCommits([])).finally(() => setLoading(false));
|
|
54861
|
+
}, []);
|
|
54862
|
+
if (loading) return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 px-3 py-4", children: "Loading…" });
|
|
54863
|
+
if (commits.length === 0) return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 px-3 py-4", children: "No commits yet." });
|
|
54864
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto", children: commits.map((c) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-2 border-b border-surface-800/50 hover:bg-surface-800/30", children: [
|
|
54865
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-2", children: [
|
|
54866
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-mono text-surface-600 shrink-0 mt-0.5", children: c.short }),
|
|
54867
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-surface-200 flex-1 line-clamp-2", children: c.message })
|
|
54868
|
+
] }),
|
|
54869
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-0.5 pl-9 flex gap-2 text-[10px] text-surface-600", children: [
|
|
54870
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: c.author }),
|
|
54871
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: new Date(c.date).toLocaleDateString() })
|
|
54872
|
+
] })
|
|
54873
|
+
] }, c.hash)) });
|
|
54874
|
+
}
|
|
54875
|
+
function BranchesTab({ onRefresh }) {
|
|
54876
|
+
const [branches, setBranches] = reactExports.useState([]);
|
|
54877
|
+
const [remotes, setRemotes] = reactExports.useState([]);
|
|
54878
|
+
const [loading, setLoading] = reactExports.useState(true);
|
|
54879
|
+
const [newBranch, setNewBranch] = reactExports.useState("");
|
|
54880
|
+
const [creating, setCreating] = reactExports.useState(false);
|
|
54881
|
+
const [addingRemote, setAddingRemote] = reactExports.useState(false);
|
|
54882
|
+
const [editingRemote, setEditingRemote] = reactExports.useState(null);
|
|
54883
|
+
const [remoteName, setRemoteName] = reactExports.useState("origin");
|
|
54884
|
+
const [remoteUrl, setRemoteUrl] = reactExports.useState("");
|
|
54885
|
+
const [editUrl, setEditUrl] = reactExports.useState("");
|
|
54886
|
+
const [error2, setError] = reactExports.useState(null);
|
|
54887
|
+
const load = reactExports.useCallback(() => {
|
|
54888
|
+
Promise.all([electron$1.gitBranches(), electron$1.gitRemotes()]).then(([b, r]) => {
|
|
54889
|
+
setBranches(b);
|
|
54890
|
+
setRemotes(r);
|
|
54891
|
+
}).catch(() => {
|
|
54892
|
+
}).finally(() => setLoading(false));
|
|
54893
|
+
}, []);
|
|
54894
|
+
reactExports.useEffect(() => {
|
|
54895
|
+
load();
|
|
54896
|
+
}, [load]);
|
|
54897
|
+
async function checkout(name2, remote2) {
|
|
54898
|
+
try {
|
|
54899
|
+
setError(null);
|
|
54900
|
+
const localName = remote2 ? name2.replace(/^origin\//, "") : name2;
|
|
54901
|
+
await electron$1.gitCheckout(localName, false);
|
|
54902
|
+
load();
|
|
54903
|
+
onRefresh();
|
|
54904
|
+
} catch (e) {
|
|
54905
|
+
setError(String(e));
|
|
54906
|
+
}
|
|
54907
|
+
}
|
|
54908
|
+
async function createBranch() {
|
|
54909
|
+
if (!newBranch.trim()) return;
|
|
54910
|
+
try {
|
|
54911
|
+
setError(null);
|
|
54912
|
+
await electron$1.gitCheckout(newBranch.trim(), true);
|
|
54913
|
+
setNewBranch("");
|
|
54914
|
+
setCreating(false);
|
|
54915
|
+
load();
|
|
54916
|
+
onRefresh();
|
|
54917
|
+
} catch (e) {
|
|
54918
|
+
setError(String(e));
|
|
54919
|
+
}
|
|
54920
|
+
}
|
|
54921
|
+
async function addRemote() {
|
|
54922
|
+
if (!remoteName.trim() || !remoteUrl.trim()) return;
|
|
54923
|
+
try {
|
|
54924
|
+
setError(null);
|
|
54925
|
+
await electron$1.gitAddRemote(remoteName.trim(), remoteUrl.trim());
|
|
54926
|
+
setRemoteName("origin");
|
|
54927
|
+
setRemoteUrl("");
|
|
54928
|
+
setAddingRemote(false);
|
|
54929
|
+
load();
|
|
54930
|
+
} catch (e) {
|
|
54931
|
+
setError(String(e));
|
|
54932
|
+
}
|
|
54933
|
+
}
|
|
54934
|
+
function startEdit(r) {
|
|
54935
|
+
setEditingRemote(r.name);
|
|
54936
|
+
setEditUrl(r.url);
|
|
54937
|
+
}
|
|
54938
|
+
async function saveRemoteUrl(name2) {
|
|
54939
|
+
if (!editUrl.trim()) return;
|
|
54940
|
+
try {
|
|
54941
|
+
setError(null);
|
|
54942
|
+
await electron$1.gitSetRemoteUrl(name2, editUrl.trim());
|
|
54943
|
+
setEditingRemote(null);
|
|
54944
|
+
load();
|
|
54945
|
+
} catch (e) {
|
|
54946
|
+
setError(String(e));
|
|
54947
|
+
}
|
|
54948
|
+
}
|
|
54949
|
+
async function removeRemote(name2) {
|
|
54950
|
+
try {
|
|
54951
|
+
setError(null);
|
|
54952
|
+
await electron$1.gitRemoveRemote(name2);
|
|
54953
|
+
load();
|
|
54954
|
+
} catch (e) {
|
|
54955
|
+
setError(String(e));
|
|
54956
|
+
}
|
|
54957
|
+
}
|
|
54958
|
+
const local = branches.filter((b) => !b.remote);
|
|
54959
|
+
const remote = branches.filter((b) => b.remote);
|
|
54960
|
+
if (loading) return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 px-3 py-4", children: "Loading…" });
|
|
54961
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0 overflow-y-auto", children: [
|
|
54962
|
+
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-red-400 px-3 py-1 truncate", children: error2 }),
|
|
54963
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 py-2 border-b border-surface-800", children: creating ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1.5", children: [
|
|
54964
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54965
|
+
"input",
|
|
54966
|
+
{
|
|
54967
|
+
autoFocus: true,
|
|
54968
|
+
value: newBranch,
|
|
54969
|
+
onChange: (e) => setNewBranch(e.target.value),
|
|
54970
|
+
onKeyDown: (e) => {
|
|
54971
|
+
if (e.key === "Enter") createBranch();
|
|
54972
|
+
if (e.key === "Escape") setCreating(false);
|
|
54973
|
+
},
|
|
54974
|
+
placeholder: "branch-name",
|
|
54975
|
+
className: "flex-1 bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs focus:outline-none focus:border-blue-500 placeholder-surface-600"
|
|
54976
|
+
}
|
|
54977
|
+
),
|
|
54978
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: createBranch, className: "text-xs text-blue-400 hover:text-blue-300 px-1", children: "Create" }),
|
|
54979
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setCreating(false), className: "text-xs text-surface-500 hover:text-white px-1", children: "✕" })
|
|
54980
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setCreating(true), className: "text-[11px] text-blue-400 hover:text-blue-300 transition-colors", children: "+ New branch" }) }),
|
|
54981
|
+
local.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { children: [
|
|
54982
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "px-3 py-1.5 text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: "Local" }),
|
|
54983
|
+
local.map((b) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54984
|
+
"button",
|
|
54985
|
+
{
|
|
54986
|
+
onClick: () => !b.current && checkout(b.name, false),
|
|
54987
|
+
className: `w-full flex items-center gap-2 px-3 py-1.5 text-left text-xs transition-colors ${b.current ? "text-blue-300 cursor-default" : "text-surface-300 hover:bg-surface-800/50"}`,
|
|
54988
|
+
children: [
|
|
54989
|
+
b.current ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-blue-400 text-[10px]", children: "●" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-3" }),
|
|
54990
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: b.name })
|
|
54991
|
+
]
|
|
54992
|
+
},
|
|
54993
|
+
b.name
|
|
54994
|
+
))
|
|
54995
|
+
] }),
|
|
54996
|
+
remote.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { children: [
|
|
54997
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "px-3 py-1.5 text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: "Remote branches" }),
|
|
54998
|
+
remote.map((b) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54999
|
+
"button",
|
|
55000
|
+
{
|
|
55001
|
+
onClick: () => checkout(b.name, true),
|
|
55002
|
+
className: "w-full flex items-center gap-2 px-3 py-1.5 text-left text-xs text-surface-400 hover:bg-surface-800/50 hover:text-surface-200 transition-colors",
|
|
55003
|
+
children: [
|
|
55004
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-3" }),
|
|
55005
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono", children: b.name })
|
|
55006
|
+
]
|
|
55007
|
+
},
|
|
55008
|
+
b.name
|
|
55009
|
+
))
|
|
55010
|
+
] }),
|
|
55011
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "border-t border-surface-800 mt-1", children: [
|
|
55012
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-1.5 flex items-center justify-between", children: [
|
|
55013
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: "Remotes" }),
|
|
55014
|
+
!addingRemote && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setAddingRemote(true), className: "text-[10px] text-blue-400 hover:text-blue-300 transition-colors", children: "+ Add" })
|
|
55015
|
+
] }),
|
|
55016
|
+
remotes.map((r) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 py-1 group", children: editingRemote === r.name ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
55017
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-mono text-surface-400", children: r.name }),
|
|
55018
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1.5", children: [
|
|
55019
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55020
|
+
"input",
|
|
55021
|
+
{
|
|
55022
|
+
autoFocus: true,
|
|
55023
|
+
value: editUrl,
|
|
55024
|
+
onChange: (e) => setEditUrl(e.target.value),
|
|
55025
|
+
onKeyDown: (e) => {
|
|
55026
|
+
if (e.key === "Enter") saveRemoteUrl(r.name);
|
|
55027
|
+
if (e.key === "Escape") setEditingRemote(null);
|
|
55028
|
+
},
|
|
55029
|
+
className: "flex-1 bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs focus:outline-none focus:border-blue-500"
|
|
55030
|
+
}
|
|
55031
|
+
),
|
|
55032
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => saveRemoteUrl(r.name), className: "text-xs text-blue-400 hover:text-blue-300 px-1", children: "Save" }),
|
|
55033
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setEditingRemote(null), className: "text-xs text-surface-500 hover:text-white px-1", children: "✕" })
|
|
55034
|
+
] })
|
|
55035
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
55036
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-mono text-surface-300 shrink-0", children: r.name }),
|
|
55037
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-mono text-surface-600 truncate flex-1", children: r.url }),
|
|
55038
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55039
|
+
"button",
|
|
55040
|
+
{
|
|
55041
|
+
onClick: () => startEdit(r),
|
|
55042
|
+
className: "opacity-0 group-hover:opacity-100 text-[10px] text-surface-500 hover:text-blue-400 transition-all shrink-0",
|
|
55043
|
+
title: "Edit URL",
|
|
55044
|
+
children: "✎"
|
|
55045
|
+
}
|
|
55046
|
+
),
|
|
55047
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55048
|
+
"button",
|
|
55049
|
+
{
|
|
55050
|
+
onClick: () => removeRemote(r.name),
|
|
55051
|
+
className: "opacity-0 group-hover:opacity-100 text-[10px] text-surface-500 hover:text-red-400 transition-all shrink-0",
|
|
55052
|
+
title: "Remove remote",
|
|
55053
|
+
children: "✕"
|
|
55054
|
+
}
|
|
55055
|
+
)
|
|
55056
|
+
] }) }, r.name)),
|
|
55057
|
+
remotes.length === 0 && !addingRemote && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "px-3 pb-2 text-[11px] text-surface-600", children: "No remotes configured." }),
|
|
55058
|
+
addingRemote && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 pb-3 flex flex-col gap-1.5", children: [
|
|
55059
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55060
|
+
"input",
|
|
55061
|
+
{
|
|
55062
|
+
value: remoteName,
|
|
55063
|
+
onChange: (e) => setRemoteName(e.target.value),
|
|
55064
|
+
placeholder: "name (e.g. origin)",
|
|
55065
|
+
className: "w-full bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs focus:outline-none focus:border-blue-500 placeholder-surface-600"
|
|
55066
|
+
}
|
|
55067
|
+
),
|
|
55068
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55069
|
+
"input",
|
|
55070
|
+
{
|
|
55071
|
+
autoFocus: true,
|
|
55072
|
+
value: remoteUrl,
|
|
55073
|
+
onChange: (e) => setRemoteUrl(e.target.value),
|
|
55074
|
+
onKeyDown: (e) => {
|
|
55075
|
+
if (e.key === "Enter") addRemote();
|
|
55076
|
+
if (e.key === "Escape") setAddingRemote(false);
|
|
55077
|
+
},
|
|
55078
|
+
placeholder: "git@github.com:user/repo.git",
|
|
55079
|
+
className: "w-full bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs focus:outline-none focus:border-blue-500 placeholder-surface-600"
|
|
55080
|
+
}
|
|
55081
|
+
),
|
|
55082
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
55083
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: addRemote, className: "text-xs text-blue-400 hover:text-blue-300 transition-colors", children: "Add remote" }),
|
|
55084
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => setAddingRemote(false), className: "text-xs text-surface-500 hover:text-white transition-colors", children: "Cancel" })
|
|
55085
|
+
] })
|
|
55086
|
+
] })
|
|
55087
|
+
] })
|
|
55088
|
+
] });
|
|
55089
|
+
}
|
|
55090
|
+
function detectPlatform(remotes) {
|
|
55091
|
+
const urls = remotes.map((r) => r.url.toLowerCase()).join(" ");
|
|
55092
|
+
if (urls.includes("github.com")) return "github";
|
|
55093
|
+
if (urls.includes("gitlab.com") || urls.includes("gitlab.")) return "gitlab";
|
|
55094
|
+
if (urls.includes("dev.azure.com") || urls.includes("visualstudio.com")) return "azure";
|
|
55095
|
+
return "unknown";
|
|
55096
|
+
}
|
|
55097
|
+
const NODE_LTS = "lts/*";
|
|
55098
|
+
function generateCiContent(platform, envName, tags2, secretVars) {
|
|
55099
|
+
const runCmd = [
|
|
55100
|
+
"api-spector run --workspace .",
|
|
55101
|
+
envName ? `--environment "${envName}"` : "",
|
|
55102
|
+
tags2 ? `--tags "${tags2}"` : "",
|
|
55103
|
+
"--output results.json"
|
|
55104
|
+
].filter(Boolean).join(" ");
|
|
55105
|
+
if (platform === "github") {
|
|
55106
|
+
const secretHint = secretVars.length ? ` # ⚠ Add these secrets in: Settings → Secrets and variables → Actions
|
|
55107
|
+
` + secretVars.map((v) => ` # ${v}`).join("\n") + "\n" : "";
|
|
55108
|
+
const envBlock = secretVars.length ? "\n env:\n" + secretVars.map((v) => ` ${v}: \${{ secrets.${v} }}`).join("\n") : "";
|
|
55109
|
+
return `name: API Tests
|
|
55110
|
+
|
|
55111
|
+
on:
|
|
55112
|
+
push:
|
|
55113
|
+
branches: [main]
|
|
55114
|
+
pull_request:
|
|
55115
|
+
|
|
55116
|
+
jobs:
|
|
55117
|
+
api-tests:
|
|
55118
|
+
runs-on: ubuntu-latest
|
|
55119
|
+
steps:
|
|
55120
|
+
- uses: actions/checkout@v4
|
|
55121
|
+
- uses: actions/setup-node@v4
|
|
55122
|
+
with:
|
|
55123
|
+
node-version: '${NODE_LTS}'
|
|
55124
|
+
- run: npm install -g @testsmith/api-spector
|
|
55125
|
+
${secretHint} - name: Run API tests
|
|
55126
|
+
run: ${runCmd}${envBlock}
|
|
55127
|
+
- name: Upload test results
|
|
55128
|
+
if: always()
|
|
55129
|
+
uses: actions/upload-artifact@v4
|
|
55130
|
+
with:
|
|
55131
|
+
name: api-test-results
|
|
55132
|
+
path: results.json
|
|
55133
|
+
`;
|
|
55134
|
+
}
|
|
55135
|
+
if (platform === "gitlab") {
|
|
55136
|
+
const secretHint = secretVars.length ? ` # ⚠ Add these in: Settings → CI/CD → Variables
|
|
55137
|
+
` + secretVars.map((v) => ` # ${v}`).join("\n") + "\n" : "";
|
|
55138
|
+
const envBlock = secretVars.length ? "\n variables:\n" + secretVars.map((v) => ` ${v}: $${v}`).join("\n") : "";
|
|
55139
|
+
return `api-tests:
|
|
55140
|
+
image: node:${NODE_LTS}
|
|
55141
|
+
stage: test
|
|
55142
|
+
before_script:
|
|
55143
|
+
- npm install -g @testsmith/api-spector
|
|
55144
|
+
${secretHint} script:
|
|
55145
|
+
- ${runCmd}${envBlock}
|
|
55146
|
+
artifacts:
|
|
55147
|
+
when: always
|
|
55148
|
+
paths:
|
|
55149
|
+
- results.json
|
|
55150
|
+
expire_in: 30 days
|
|
55151
|
+
`;
|
|
55152
|
+
}
|
|
55153
|
+
if (platform === "azure") {
|
|
55154
|
+
const secretHint = secretVars.length ? ` # ⚠ Add these in: Pipelines → Library → Variable groups (mark as secret)
|
|
55155
|
+
` + secretVars.map((v) => ` # ${v}`).join("\n") + "\n" : "";
|
|
55156
|
+
const envBlock = secretVars.length ? "\n env:\n" + secretVars.map((v) => ` ${v}: $(${v})`).join("\n") : "";
|
|
55157
|
+
return `trigger:
|
|
55158
|
+
- main
|
|
55159
|
+
|
|
55160
|
+
pool:
|
|
55161
|
+
vmImage: ubuntu-latest
|
|
55162
|
+
|
|
55163
|
+
steps:
|
|
55164
|
+
- task: NodeTool@0
|
|
55165
|
+
inputs:
|
|
55166
|
+
versionSpec: '${NODE_LTS}.x'
|
|
55167
|
+
displayName: 'Use Node.js ${NODE_LTS}'
|
|
55168
|
+
- script: npm install -g @testsmith/api-spector
|
|
55169
|
+
displayName: 'Install api Spector'
|
|
55170
|
+
${secretHint} - script: ${runCmd}
|
|
55171
|
+
displayName: 'Run API tests'${envBlock}
|
|
55172
|
+
- publish: results.json
|
|
55173
|
+
artifact: api-test-results
|
|
55174
|
+
displayName: 'Upload test results'
|
|
55175
|
+
condition: always()
|
|
55176
|
+
`;
|
|
55177
|
+
}
|
|
55178
|
+
return `# Unsupported platform — adapt as needed
|
|
55179
|
+
# ${runCmd}
|
|
55180
|
+
`;
|
|
55181
|
+
}
|
|
55182
|
+
function ciFilePath(platform) {
|
|
55183
|
+
if (platform === "github") return ".github/workflows/api-tests.yml";
|
|
55184
|
+
if (platform === "gitlab") return ".gitlab-ci.yml";
|
|
55185
|
+
if (platform === "azure") return "azure-pipelines.yml";
|
|
55186
|
+
return "ci.yml";
|
|
55187
|
+
}
|
|
55188
|
+
function CiTab() {
|
|
55189
|
+
const environments = useStore((s) => s.environments);
|
|
55190
|
+
const envList = Object.values(environments);
|
|
55191
|
+
const [remotes, setRemotes] = reactExports.useState([]);
|
|
55192
|
+
const [platform, setPlatform] = reactExports.useState("unknown");
|
|
55193
|
+
const [envId, setEnvId] = reactExports.useState("");
|
|
55194
|
+
const [tags2, setTags] = reactExports.useState("");
|
|
55195
|
+
const [preview, setPreview] = reactExports.useState("");
|
|
55196
|
+
const [written, setWritten] = reactExports.useState(false);
|
|
55197
|
+
const [error2, setError] = reactExports.useState(null);
|
|
55198
|
+
reactExports.useEffect(() => {
|
|
55199
|
+
electron$1.gitRemotes().then((r) => {
|
|
55200
|
+
setRemotes(r);
|
|
55201
|
+
const detected = detectPlatform(r);
|
|
55202
|
+
setPlatform(detected);
|
|
55203
|
+
}).catch(() => {
|
|
55204
|
+
});
|
|
55205
|
+
}, []);
|
|
55206
|
+
reactExports.useEffect(() => {
|
|
55207
|
+
const env = envList.find((e) => e.data.id === envId);
|
|
55208
|
+
const secretVars = env ? env.data.variables.filter((v) => v.secret && v.enabled).map((v) => v.key) : [];
|
|
55209
|
+
const envName = env?.data.name ?? "";
|
|
55210
|
+
setPreview(generateCiContent(platform, envName, tags2, secretVars));
|
|
55211
|
+
setWritten(false);
|
|
55212
|
+
}, [platform, envId, tags2, environments]);
|
|
55213
|
+
async function write() {
|
|
55214
|
+
try {
|
|
55215
|
+
setError(null);
|
|
55216
|
+
await electron$1.gitWriteCiFile(ciFilePath(platform), preview);
|
|
55217
|
+
setWritten(true);
|
|
55218
|
+
} catch (e) {
|
|
55219
|
+
setError(String(e));
|
|
55220
|
+
}
|
|
55221
|
+
}
|
|
55222
|
+
const platformLabels = {
|
|
55223
|
+
github: "GitHub Actions",
|
|
55224
|
+
gitlab: "GitLab CI",
|
|
55225
|
+
azure: "Azure Pipelines",
|
|
55226
|
+
unknown: "Unknown"
|
|
55227
|
+
};
|
|
55228
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0 overflow-y-auto", children: [
|
|
55229
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-3 flex flex-col gap-3 border-b border-surface-800", children: [
|
|
55230
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
55231
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: "Platform" }),
|
|
55232
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55233
|
+
"select",
|
|
55234
|
+
{
|
|
55235
|
+
value: platform,
|
|
55236
|
+
onChange: (e) => setPlatform(e.target.value),
|
|
55237
|
+
className: "bg-surface-800 border border-surface-700 rounded px-2 py-1.5 text-xs focus:outline-none focus:border-blue-500",
|
|
55238
|
+
children: ["github", "gitlab", "azure"].map((p) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: p, children: platformLabels[p] }, p))
|
|
55239
|
+
}
|
|
55240
|
+
),
|
|
55241
|
+
remotes.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-surface-600", children: [
|
|
55242
|
+
"Detected from remote: ",
|
|
55243
|
+
platformLabels[detectPlatform(remotes)]
|
|
55244
|
+
] })
|
|
55245
|
+
] }),
|
|
55246
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
55247
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: "Environment" }),
|
|
55248
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
55249
|
+
"select",
|
|
55250
|
+
{
|
|
55251
|
+
value: envId,
|
|
55252
|
+
onChange: (e) => setEnvId(e.target.value),
|
|
55253
|
+
className: "bg-surface-800 border border-surface-700 rounded px-2 py-1.5 text-xs focus:outline-none focus:border-blue-500",
|
|
55254
|
+
children: [
|
|
55255
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: "— none —" }),
|
|
55256
|
+
envList.map((e) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: e.data.id, children: e.data.name }, e.data.id))
|
|
55257
|
+
]
|
|
55258
|
+
}
|
|
55259
|
+
),
|
|
55260
|
+
envId && (() => {
|
|
55261
|
+
const env = envList.find((e) => e.data.id === envId);
|
|
55262
|
+
const secrets = env?.data.variables.filter((v) => v.secret && v.enabled) ?? [];
|
|
55263
|
+
return secrets.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-amber-400/80", children: [
|
|
55264
|
+
secrets.length,
|
|
55265
|
+
" secret variable",
|
|
55266
|
+
secrets.length !== 1 ? "s" : "",
|
|
55267
|
+
" will be mapped to CI secrets"
|
|
55268
|
+
] }) : null;
|
|
55269
|
+
})()
|
|
55270
|
+
] }),
|
|
55271
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
55272
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: "Tags (optional)" }),
|
|
55273
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55274
|
+
"input",
|
|
55275
|
+
{
|
|
55276
|
+
value: tags2,
|
|
55277
|
+
onChange: (e) => setTags(e.target.value),
|
|
55278
|
+
placeholder: "e.g. smoke, regression",
|
|
55279
|
+
className: "bg-surface-800 border border-surface-700 rounded px-2 py-1.5 text-xs focus:outline-none focus:border-blue-500 placeholder-surface-600"
|
|
55280
|
+
}
|
|
55281
|
+
)
|
|
55282
|
+
] }),
|
|
55283
|
+
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-red-400", children: error2 }),
|
|
55284
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
55285
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
55286
|
+
"button",
|
|
55287
|
+
{
|
|
55288
|
+
onClick: write,
|
|
55289
|
+
className: "flex-1 py-1.5 bg-blue-600 hover:bg-blue-500 rounded text-xs font-medium transition-colors",
|
|
55290
|
+
children: [
|
|
55291
|
+
"Write ",
|
|
55292
|
+
ciFilePath(platform)
|
|
55293
|
+
]
|
|
55294
|
+
}
|
|
55295
|
+
),
|
|
55296
|
+
written && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] text-emerald-400", children: "✓ Written" })
|
|
55297
|
+
] })
|
|
55298
|
+
] }),
|
|
55299
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 overflow-auto", children: [
|
|
55300
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "px-3 pt-2 pb-1 text-[10px] uppercase tracking-widest text-surface-600 font-semibold", children: "Preview" }),
|
|
55301
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "px-3 pb-3 text-[10px] font-mono text-surface-400 leading-relaxed whitespace-pre-wrap", children: preview })
|
|
55302
|
+
] })
|
|
55303
|
+
] });
|
|
55304
|
+
}
|
|
55305
|
+
function GitPanel() {
|
|
55306
|
+
const [isRepo, setIsRepo] = reactExports.useState(null);
|
|
55307
|
+
const [status, setStatus] = reactExports.useState(null);
|
|
55308
|
+
const [tab, setTab] = reactExports.useState("changes");
|
|
55309
|
+
const [loading, setLoading] = reactExports.useState(true);
|
|
55310
|
+
const refresh = reactExports.useCallback(async () => {
|
|
55311
|
+
try {
|
|
55312
|
+
const repo = await electron$1.gitIsRepo();
|
|
55313
|
+
setIsRepo(repo);
|
|
55314
|
+
if (repo) setStatus(await electron$1.gitStatus());
|
|
55315
|
+
} catch {
|
|
55316
|
+
setIsRepo(false);
|
|
55317
|
+
} finally {
|
|
55318
|
+
setLoading(false);
|
|
55319
|
+
}
|
|
55320
|
+
}, []);
|
|
55321
|
+
reactExports.useEffect(() => {
|
|
55322
|
+
refresh();
|
|
55323
|
+
}, [refresh]);
|
|
55324
|
+
if (loading) {
|
|
55325
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 flex items-center justify-center text-xs text-surface-500", children: "Loading…" });
|
|
55326
|
+
}
|
|
55327
|
+
if (!isRepo) {
|
|
55328
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center gap-3 px-4 text-center", children: [
|
|
55329
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-400", children: "Not a git repository." }),
|
|
55330
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55331
|
+
"button",
|
|
55332
|
+
{
|
|
55333
|
+
onClick: async () => {
|
|
55334
|
+
await electron$1.gitInit();
|
|
55335
|
+
refresh();
|
|
55336
|
+
},
|
|
55337
|
+
className: "px-3 py-1.5 bg-surface-800 hover:bg-surface-700 rounded text-xs transition-colors",
|
|
55338
|
+
children: "git init"
|
|
55339
|
+
}
|
|
55340
|
+
)
|
|
55341
|
+
] });
|
|
55342
|
+
}
|
|
55343
|
+
const totalChanges = status ? status.staged.length + status.unstaged.length + status.untracked.length : 0;
|
|
55344
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
55345
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex border-b border-surface-800 flex-shrink-0", children: [
|
|
55346
|
+
["changes", "log", "branches", "ci"].map((t2) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
55347
|
+
"button",
|
|
55348
|
+
{
|
|
55349
|
+
onClick: () => setTab(t2),
|
|
55350
|
+
className: `flex-1 py-1.5 text-[11px] capitalize transition-colors border-b-2 -mb-px ${tab === t2 ? "border-blue-500 text-white" : "border-transparent text-surface-400 hover:text-white"}`,
|
|
55351
|
+
children: [
|
|
55352
|
+
t2,
|
|
55353
|
+
t2 === "changes" && totalChanges > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-1 bg-surface-700 text-surface-300 rounded px-1 text-[9px]", children: totalChanges })
|
|
55354
|
+
]
|
|
55355
|
+
},
|
|
55356
|
+
t2
|
|
55357
|
+
)),
|
|
55358
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55359
|
+
"button",
|
|
55360
|
+
{
|
|
55361
|
+
onClick: refresh,
|
|
55362
|
+
title: "Refresh",
|
|
55363
|
+
className: "px-2 text-surface-600 hover:text-surface-300 transition-colors border-b-2 border-transparent -mb-px",
|
|
55364
|
+
children: "↺"
|
|
55365
|
+
}
|
|
55366
|
+
)
|
|
55367
|
+
] }),
|
|
55368
|
+
tab === "changes" && status && /* @__PURE__ */ jsxRuntimeExports.jsx(ChangesTab, { status, onRefresh: refresh }),
|
|
55369
|
+
tab === "log" && /* @__PURE__ */ jsxRuntimeExports.jsx(LogTab, {}),
|
|
55370
|
+
tab === "branches" && /* @__PURE__ */ jsxRuntimeExports.jsx(BranchesTab, { onRefresh: refresh }),
|
|
55371
|
+
tab === "ci" && /* @__PURE__ */ jsxRuntimeExports.jsx(CiTab, {})
|
|
55372
|
+
] });
|
|
55373
|
+
}
|
|
54381
55374
|
function CommandPalette() {
|
|
54382
55375
|
const open = useStore((s) => s.commandPaletteOpen);
|
|
54383
55376
|
const setOpen = useStore((s) => s.setCommandPaletteOpen);
|
|
@@ -54528,6 +55521,15 @@ function IconMock() {
|
|
|
54528
55521
|
function IconContract() {
|
|
54529
55522
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { viewBox: "0 0 20 20", fill: "currentColor", width: "18", height: "18", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { fillRule: "evenodd", d: "M10 2a1 1 0 011 1v1.323l3.954 1.582 1.599-.8a1 1 0 01.894 1.79l-1.233.616 1.738 5.42a1 1 0 01-.285 1.05A3.989 3.989 0 0115 14a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.715-5.349L11 5.477V17H13a1 1 0 110 2H7a1 1 0 110-2h2V5.477L6.237 6.582l1.715 5.349a1 1 0 01-.285 1.05A3.989 3.989 0 015 14a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.738-5.42-1.233-.617a1 1 0 01.894-1.788l1.599.799L9 3.323V3a1 1 0 011-1z", clipRule: "evenodd" }) });
|
|
54530
55523
|
}
|
|
55524
|
+
function IconGit() {
|
|
55525
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", width: "18", height: "18", children: [
|
|
55526
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "6", cy: "6", r: "2.5" }),
|
|
55527
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "6", cy: "18", r: "2.5" }),
|
|
55528
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "18", cy: "6", r: "2.5" }),
|
|
55529
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "6", y1: "8.5", x2: "6", y2: "15.5" }),
|
|
55530
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M6 8.5 C6 13 18 10 18 8.5" })
|
|
55531
|
+
] });
|
|
55532
|
+
}
|
|
54531
55533
|
function ActivityBarBtn({
|
|
54532
55534
|
active,
|
|
54533
55535
|
onClick,
|
|
@@ -54535,18 +55537,20 @@ function ActivityBarBtn({
|
|
|
54535
55537
|
badge,
|
|
54536
55538
|
children
|
|
54537
55539
|
}) {
|
|
54538
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54539
|
-
|
|
54540
|
-
|
|
54541
|
-
|
|
54542
|
-
|
|
54543
|
-
|
|
54544
|
-
|
|
54545
|
-
|
|
54546
|
-
|
|
54547
|
-
|
|
54548
|
-
|
|
54549
|
-
|
|
55540
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative group/ab", children: [
|
|
55541
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
55542
|
+
"button",
|
|
55543
|
+
{
|
|
55544
|
+
onClick,
|
|
55545
|
+
className: `relative w-10 h-10 flex items-center justify-center rounded transition-colors ${active ? "text-white bg-surface-800" : "text-surface-600 hover:text-surface-300 hover:bg-surface-800/50"}`,
|
|
55546
|
+
children: [
|
|
55547
|
+
children,
|
|
55548
|
+
badge !== void 0 && badge > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "absolute top-1 right-1 text-[9px] bg-surface-600 text-white rounded-full w-3.5 h-3.5 flex items-center justify-center font-medium leading-none", children: badge > 9 ? "9+" : badge })
|
|
55549
|
+
]
|
|
55550
|
+
}
|
|
55551
|
+
),
|
|
55552
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "pointer-events-none absolute left-full top-1/2 -translate-y-1/2 ml-2 z-50 hidden group-hover/ab:block", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "whitespace-nowrap rounded px-2 py-1 text-[11px] bg-[#1e1b2e] text-gray-200 border border-white/10 shadow-lg", children: title2 }) })
|
|
55553
|
+
] });
|
|
54550
55554
|
}
|
|
54551
55555
|
const TAB_METHOD_COLORS = {
|
|
54552
55556
|
GET: "text-emerald-400",
|
|
@@ -54634,7 +55638,7 @@ function App() {
|
|
|
54634
55638
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
|
|
54635
55639
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-50", children: [
|
|
54636
55640
|
"v",
|
|
54637
|
-
"0.
|
|
55641
|
+
"0.1.1"
|
|
54638
55642
|
] })
|
|
54639
55643
|
] }) }),
|
|
54640
55644
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Toolbar, { onOpenDocs: () => setDocsModalOpen(true) }),
|
|
@@ -54676,11 +55680,20 @@ function App() {
|
|
|
54676
55680
|
title: "Contract testing",
|
|
54677
55681
|
children: /* @__PURE__ */ jsxRuntimeExports.jsx(IconContract, {})
|
|
54678
55682
|
}
|
|
55683
|
+
),
|
|
55684
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55685
|
+
ActivityBarBtn,
|
|
55686
|
+
{
|
|
55687
|
+
active: sidebarOpen && sidebarTab === "git",
|
|
55688
|
+
onClick: () => selectPanel("git"),
|
|
55689
|
+
title: "Git",
|
|
55690
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(IconGit, {})
|
|
55691
|
+
}
|
|
54679
55692
|
)
|
|
54680
55693
|
] }),
|
|
54681
55694
|
sidebarOpen ? /* @__PURE__ */ jsxRuntimeExports.jsxs("aside", { className: "w-64 flex-shrink-0 border-r border-surface-800 flex flex-col overflow-hidden", children: [
|
|
54682
55695
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-2 flex items-center justify-between border-b border-surface-800 flex-shrink-0", children: [
|
|
54683
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-surface-600", children: sidebarTab === "collections" ? "Collections" : sidebarTab === "history" ? "History" : sidebarTab === "mocks" ? "Mocks" : "Contracts" }),
|
|
55696
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-surface-600", children: sidebarTab === "collections" ? "Collections" : sidebarTab === "history" ? "History" : sidebarTab === "mocks" ? "Mocks" : sidebarTab === "git" ? "Git" : "Contracts" }),
|
|
54684
55697
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
54685
55698
|
sidebarTab === "history" && historyCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] bg-surface-700 text-surface-400 rounded px-1.5 py-0.5", children: historyCount }),
|
|
54686
55699
|
sidebarTab === "collections" && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -54703,7 +55716,7 @@ function App() {
|
|
|
54703
55716
|
)
|
|
54704
55717
|
] })
|
|
54705
55718
|
] }),
|
|
54706
|
-
sidebarTab === "collections" ? /* @__PURE__ */ jsxRuntimeExports.jsx(CollectionTree, {}) : sidebarTab === "history" ? /* @__PURE__ */ jsxRuntimeExports.jsx(HistoryPanel, {}) : sidebarTab === "mocks" ? /* @__PURE__ */ jsxRuntimeExports.jsx(MockPanel, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(ContractPanel, {})
|
|
55719
|
+
sidebarTab === "collections" ? /* @__PURE__ */ jsxRuntimeExports.jsx(CollectionTree, {}) : sidebarTab === "history" ? /* @__PURE__ */ jsxRuntimeExports.jsx(HistoryPanel, {}) : sidebarTab === "mocks" ? /* @__PURE__ */ jsxRuntimeExports.jsx(MockPanel, {}) : sidebarTab === "git" ? /* @__PURE__ */ jsxRuntimeExports.jsx(GitPanel, {}) : /* @__PURE__ */ jsxRuntimeExports.jsx(ContractPanel, {})
|
|
54707
55720
|
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54708
55721
|
"button",
|
|
54709
55722
|
{
|