@testsmith/api-spector 0.9.1 → 0.9.3
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/out/main/chunks/{broker-client-JU-AwkVE.js → broker-client-Cl6Fu3oD.js} +1 -1
- package/out/main/chunks/{handle-_4XMUlwm.js → handle-HQp1EXf8.js} +33 -1
- package/out/main/chunks/{import-ujxXe3Uu.js → import-DVpFH9Wb.js} +2 -2
- package/out/main/chunks/{perf-run-BEbf2piB.js → perf-run-BNunvZsG.js} +1 -1
- package/out/main/chunks/{request-exec-DroNv29-.js → request-exec-B8DJ8Id2.js} +1 -1
- package/out/main/chunks/{soap-handler-BF5ii0UV.js → soap-handler-D_Hj9e8S.js} +2 -2
- package/out/main/contract.js +3 -3
- package/out/main/flow.js +3 -3
- package/out/main/index.js +35 -11
- package/out/main/lib.js +2 -2
- package/out/main/perf-worker.js +3 -3
- package/out/main/perf.js +4 -4
- package/out/main/register-handlers.js +217 -5
- package/out/main/runner.js +3 -3
- package/out/main/wsdl.js +3 -3
- package/out/preload/index.js +58 -1
- package/out/renderer/assets/{GraphQLEditor-CJm8glW5.js → GraphQLEditor-J-8g0S0P.js} +1 -1
- package/out/renderer/assets/{SoapEditor-C2eMs7-Z.js → SoapEditor-CmsqdXhh.js} +1 -1
- package/out/renderer/assets/index--T34lt1s.css +627 -0
- package/out/renderer/assets/{index-Bf9-CiTh.js → index-DXMEqli_.js} +833 -147
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
- package/out/renderer/assets/index-C5qn-ccU.css +0 -627
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./GraphQLEditor-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./GraphQLEditor-J-8g0S0P.js","./codemirror-BKmwMUlV.js","./ajv-CJPwFjiP.js","./SoapEditor-CmsqdXhh.js"])))=>i.map(i=>d[i]);
|
|
2
2
|
import { r as requireReact, g as getDefaultExportFromCjs, R as React, a as reactExports, b as autocompletion, h as hoverTooltip, j as jsxRuntimeExports, V as ViewPlugin, E as EditorView, k as keymap, t as toggleComment, D as Decoration, c as RangeSetBuilder, x as xml, d as json, e as ReactCodeMirror, o as oneDark, f as javascript } from "./codemirror-BKmwMUlV.js";
|
|
3
3
|
import { r as requireAjv } from "./ajv-CJPwFjiP.js";
|
|
4
4
|
var client = { exports: {} };
|
|
@@ -13203,7 +13203,8 @@ function baseTab(collectionId) {
|
|
|
13203
13203
|
lastSentRequest: null,
|
|
13204
13204
|
lastHookResults: null,
|
|
13205
13205
|
isSending: false,
|
|
13206
|
-
scriptTab: "post"
|
|
13206
|
+
scriptTab: "post",
|
|
13207
|
+
jqExpr: ""
|
|
13207
13208
|
};
|
|
13208
13209
|
}
|
|
13209
13210
|
function makeTab(requestId, collectionId, opts = {}) {
|
|
@@ -13337,6 +13338,10 @@ const createTabsSlice = (set2, get2) => ({
|
|
|
13337
13338
|
const t = s.tabs.find((x) => x.id === tabId);
|
|
13338
13339
|
if (t) t.scriptTab = scriptTab;
|
|
13339
13340
|
}),
|
|
13341
|
+
setTabJqExpr: (tabId, jqExpr) => set2((s) => {
|
|
13342
|
+
const t = s.tabs.find((x) => x.id === tabId);
|
|
13343
|
+
if (t) t.jqExpr = jqExpr;
|
|
13344
|
+
}),
|
|
13340
13345
|
// ── Navigation ──────────────────────────────────────────────────────────────
|
|
13341
13346
|
setActiveCollection: (id2) => set2((s) => {
|
|
13342
13347
|
s.activeCollectionId = id2;
|
|
@@ -14771,7 +14776,7 @@ const useStore$1 = create$1()(
|
|
|
14771
14776
|
})
|
|
14772
14777
|
}))
|
|
14773
14778
|
);
|
|
14774
|
-
const { electron: electron$
|
|
14779
|
+
const { electron: electron$J } = window;
|
|
14775
14780
|
function useAutoSave() {
|
|
14776
14781
|
const collections = useStore$1((s) => s.collections);
|
|
14777
14782
|
useStore$1((s) => s.environments);
|
|
@@ -14790,7 +14795,7 @@ function useAutoSave() {
|
|
|
14790
14795
|
for (const { relPath, data, dirty } of dirtyCollections) {
|
|
14791
14796
|
if (!dirty) continue;
|
|
14792
14797
|
try {
|
|
14793
|
-
await electron$
|
|
14798
|
+
await electron$J.saveCollection(relPath, data);
|
|
14794
14799
|
markCollectionClean(data.id);
|
|
14795
14800
|
} catch (e) {
|
|
14796
14801
|
console.error("Auto-save failed for", relPath, e);
|
|
@@ -14809,7 +14814,7 @@ function useAutoSave() {
|
|
|
14809
14814
|
for (const { relPath, data, dirty } of dirtyFlows) {
|
|
14810
14815
|
if (!dirty) continue;
|
|
14811
14816
|
try {
|
|
14812
|
-
await electron$
|
|
14817
|
+
await electron$J.saveFlow(relPath, data);
|
|
14813
14818
|
markFlowClean(data.id);
|
|
14814
14819
|
} catch (e) {
|
|
14815
14820
|
console.error("Auto-save failed for", relPath, e);
|
|
@@ -14825,7 +14830,7 @@ function useAutoSave() {
|
|
|
14825
14830
|
if (wsTimerRef.current) clearTimeout(wsTimerRef.current);
|
|
14826
14831
|
wsTimerRef.current = setTimeout(async () => {
|
|
14827
14832
|
try {
|
|
14828
|
-
await electron$
|
|
14833
|
+
await electron$J.saveWorkspace(workspace);
|
|
14829
14834
|
} catch {
|
|
14830
14835
|
}
|
|
14831
14836
|
}, 300);
|
|
@@ -14834,7 +14839,7 @@ function useAutoSave() {
|
|
|
14834
14839
|
};
|
|
14835
14840
|
}, [workspace]);
|
|
14836
14841
|
}
|
|
14837
|
-
const { electron: electron$
|
|
14842
|
+
const { electron: electron$I } = window;
|
|
14838
14843
|
function useWorkspaceLoader() {
|
|
14839
14844
|
const loadCollection = useStore$1((s) => s.loadCollection);
|
|
14840
14845
|
const loadEnvironment = useStore$1((s) => s.loadEnvironment);
|
|
@@ -14861,7 +14866,7 @@ function useWorkspaceLoader() {
|
|
|
14861
14866
|
if (typeof ws.settings?.zoom === "number") setZoom(ws.settings.zoom);
|
|
14862
14867
|
if (ws.settings?.persistHistory) {
|
|
14863
14868
|
try {
|
|
14864
|
-
const entries = await electron$
|
|
14869
|
+
const entries = await electron$I.loadHistory();
|
|
14865
14870
|
useStore$1.getState().setHistory(entries);
|
|
14866
14871
|
} catch {
|
|
14867
14872
|
}
|
|
@@ -14870,14 +14875,14 @@ function useWorkspaceLoader() {
|
|
|
14870
14875
|
}
|
|
14871
14876
|
for (const colPath of ws.collections ?? []) {
|
|
14872
14877
|
try {
|
|
14873
|
-
const col = await electron$
|
|
14878
|
+
const col = await electron$I.loadCollection(colPath);
|
|
14874
14879
|
loadCollection(colPath, col);
|
|
14875
14880
|
} catch {
|
|
14876
14881
|
}
|
|
14877
14882
|
}
|
|
14878
14883
|
for (const envPath of ws.environments ?? []) {
|
|
14879
14884
|
try {
|
|
14880
|
-
const env2 = await electron$
|
|
14885
|
+
const env2 = await electron$I.loadEnvironment(envPath);
|
|
14881
14886
|
loadEnvironment(envPath, env2);
|
|
14882
14887
|
} catch {
|
|
14883
14888
|
}
|
|
@@ -14896,32 +14901,38 @@ function useWorkspaceLoader() {
|
|
|
14896
14901
|
}
|
|
14897
14902
|
for (const relPath of ws.mocks ?? []) {
|
|
14898
14903
|
try {
|
|
14899
|
-
const mockData = await electron$
|
|
14904
|
+
const mockData = await electron$I.loadMock(relPath);
|
|
14900
14905
|
loadMock(relPath, mockData);
|
|
14901
14906
|
} catch {
|
|
14902
14907
|
}
|
|
14903
14908
|
}
|
|
14904
14909
|
for (const relPath of ws.flows ?? []) {
|
|
14905
14910
|
try {
|
|
14906
|
-
const flowData = await electron$
|
|
14911
|
+
const flowData = await electron$I.loadFlow(relPath);
|
|
14907
14912
|
loadFlow(relPath, flowData);
|
|
14908
14913
|
} catch {
|
|
14909
14914
|
}
|
|
14910
14915
|
}
|
|
14911
14916
|
try {
|
|
14912
|
-
const snapshots = await electron$
|
|
14917
|
+
const snapshots = await electron$I.listContractSnapshots(ws.contracts ?? []);
|
|
14913
14918
|
for (const { relPath, snapshot } of snapshots) loadContractSnapshot(relPath, snapshot);
|
|
14914
14919
|
} catch {
|
|
14915
14920
|
}
|
|
14916
14921
|
if ((ws.collections ?? []).length > 0) {
|
|
14917
14922
|
try {
|
|
14918
|
-
const firstCol = await electron$
|
|
14923
|
+
const firstCol = await electron$I.loadCollection(ws.collections[0]);
|
|
14919
14924
|
setActiveCollection(firstCol.id);
|
|
14920
14925
|
} catch {
|
|
14921
14926
|
}
|
|
14922
14927
|
}
|
|
14923
14928
|
}, [loadCollection, loadEnvironment, loadMock, loadFlow, loadContractSnapshot, setActiveCollection, setTheme, setZoom]);
|
|
14924
|
-
|
|
14929
|
+
const reloadWorkspace = reactExports.useCallback(async () => {
|
|
14930
|
+
const path = useStore$1.getState().workspacePath;
|
|
14931
|
+
if (!path) return;
|
|
14932
|
+
const result = await electron$I.openWorkspacePath(path);
|
|
14933
|
+
if (result) await applyWorkspace(result.workspace, result.workspacePath);
|
|
14934
|
+
}, [applyWorkspace]);
|
|
14935
|
+
return { applyWorkspace, reloadWorkspace };
|
|
14925
14936
|
}
|
|
14926
14937
|
var reactDomExports = requireReactDom();
|
|
14927
14938
|
const ReactDOM = /* @__PURE__ */ getDefaultExportFromCjs(reactDomExports);
|
|
@@ -25861,7 +25872,7 @@ function Modal({
|
|
|
25861
25872
|
}
|
|
25862
25873
|
);
|
|
25863
25874
|
}
|
|
25864
|
-
const { electron: electron$
|
|
25875
|
+
const { electron: electron$H } = window;
|
|
25865
25876
|
function Oauth2Form({ auth, onChange }) {
|
|
25866
25877
|
const t = useT();
|
|
25867
25878
|
const activeEnv = useActiveEnvironment();
|
|
@@ -25881,7 +25892,7 @@ function Oauth2Form({ auth, onChange }) {
|
|
|
25881
25892
|
const flow = auth.oauth2Flow ?? "client_credentials";
|
|
25882
25893
|
async function saveSecret(ref) {
|
|
25883
25894
|
if (!secretValue || !ref) return;
|
|
25884
|
-
await electron$
|
|
25895
|
+
await electron$H.setSecret(ref, secretValue);
|
|
25885
25896
|
setSaved(true);
|
|
25886
25897
|
setSecretValue("");
|
|
25887
25898
|
setTimeout(() => setSaved(false), 2e3);
|
|
@@ -25890,7 +25901,7 @@ function Oauth2Form({ auth, onChange }) {
|
|
|
25890
25901
|
setStatus("fetching");
|
|
25891
25902
|
setError("");
|
|
25892
25903
|
try {
|
|
25893
|
-
const result = await electron$
|
|
25904
|
+
const result = await electron$H.oauth2StartFlow(auth, resolveCtx());
|
|
25894
25905
|
onChange({ oauth2CachedToken: result.accessToken, oauth2TokenExpiry: result.expiresAt });
|
|
25895
25906
|
if (result.refreshToken) setRefreshToken(result.refreshToken);
|
|
25896
25907
|
setStatus("ok");
|
|
@@ -25904,7 +25915,7 @@ function Oauth2Form({ auth, onChange }) {
|
|
|
25904
25915
|
setStatus("fetching");
|
|
25905
25916
|
setError("");
|
|
25906
25917
|
try {
|
|
25907
|
-
const result = await electron$
|
|
25918
|
+
const result = await electron$H.oauth2RefreshToken(auth, resolveCtx(), refreshToken);
|
|
25908
25919
|
onChange({ oauth2CachedToken: result.accessToken, oauth2TokenExpiry: result.expiresAt });
|
|
25909
25920
|
if (result.refreshToken) setRefreshToken(result.refreshToken);
|
|
25910
25921
|
setStatus("ok");
|
|
@@ -26764,7 +26775,7 @@ function CollectionSettingsModal({ collection: collection2, onClose }) {
|
|
|
26764
26775
|
}
|
|
26765
26776
|
);
|
|
26766
26777
|
}
|
|
26767
|
-
const { electron: electron$
|
|
26778
|
+
const { electron: electron$G } = window;
|
|
26768
26779
|
function normalisePath(url) {
|
|
26769
26780
|
let path = url.replace(/^\{\{[^}]+\}\}/, "").replace(/^https?:\/\/[^/]+/, "");
|
|
26770
26781
|
if (!path.startsWith("/")) path = "/" + path;
|
|
@@ -26852,7 +26863,7 @@ function SchemaSyncModal({
|
|
|
26852
26863
|
setLoading(true);
|
|
26853
26864
|
setError(null);
|
|
26854
26865
|
try {
|
|
26855
|
-
const entries = await electron$
|
|
26866
|
+
const entries = await electron$G.extractOpenApiSchemas();
|
|
26856
26867
|
if (!entries) {
|
|
26857
26868
|
setLoading(false);
|
|
26858
26869
|
return;
|
|
@@ -26871,7 +26882,7 @@ function SchemaSyncModal({
|
|
|
26871
26882
|
setLoading(true);
|
|
26872
26883
|
setError(null);
|
|
26873
26884
|
try {
|
|
26874
|
-
const entries = await electron$
|
|
26885
|
+
const entries = await electron$G.extractOpenApiSchemasFromUrl(trimmed);
|
|
26875
26886
|
setSpecEntries(entries);
|
|
26876
26887
|
autoSelectChanged(entries);
|
|
26877
26888
|
} catch (err) {
|
|
@@ -26904,7 +26915,7 @@ function SchemaSyncModal({
|
|
|
26904
26915
|
}
|
|
26905
26916
|
const entry = useStore$1.getState().collections[collectionId];
|
|
26906
26917
|
if (entry) {
|
|
26907
|
-
await electron$
|
|
26918
|
+
await electron$G.saveCollection(entry.relPath, entry.data);
|
|
26908
26919
|
markCollectionClean(collectionId);
|
|
26909
26920
|
}
|
|
26910
26921
|
onClose();
|
|
@@ -27417,7 +27428,7 @@ function hasContract(r) {
|
|
|
27417
27428
|
const c = r.contract;
|
|
27418
27429
|
return !!c && (c.statusCode != null || !!c.bodySchema || !!c.bodyMatcher || (c.headers?.length ?? 0) > 0 || (c.providerStates?.length ?? 0) > 0);
|
|
27419
27430
|
}
|
|
27420
|
-
const { electron: electron$
|
|
27431
|
+
const { electron: electron$F } = window;
|
|
27421
27432
|
function cloudEnabled() {
|
|
27422
27433
|
return Boolean(useStore$1.getState().workspace?.settings?.cloud?.enabled);
|
|
27423
27434
|
}
|
|
@@ -27426,7 +27437,7 @@ function assertEnabled() {
|
|
|
27426
27437
|
}
|
|
27427
27438
|
async function pushContractToCloud(requests, opts) {
|
|
27428
27439
|
assertEnabled();
|
|
27429
|
-
return electron$
|
|
27440
|
+
return electron$F.cloudPushPact({
|
|
27430
27441
|
consumer: opts.consumer,
|
|
27431
27442
|
provider: opts.provider,
|
|
27432
27443
|
consumerVersion: opts.version,
|
|
@@ -27435,16 +27446,16 @@ async function pushContractToCloud(requests, opts) {
|
|
|
27435
27446
|
}
|
|
27436
27447
|
async function pushProviderSpecToCloud(opts) {
|
|
27437
27448
|
assertEnabled();
|
|
27438
|
-
return electron$
|
|
27449
|
+
return electron$F.cloudPushSpec(opts);
|
|
27439
27450
|
}
|
|
27440
27451
|
function openCloudMatrix() {
|
|
27441
|
-
void electron$
|
|
27452
|
+
void electron$F.cloudOpenMatrix();
|
|
27442
27453
|
}
|
|
27443
27454
|
async function pushFlowToCloud(flow) {
|
|
27444
27455
|
assertEnabled();
|
|
27445
27456
|
const s = useStore$1.getState();
|
|
27446
27457
|
const environment = resolveEnvironmentById(s.environments, s.activeEnvironmentId);
|
|
27447
|
-
return electron$
|
|
27458
|
+
return electron$F.cloudPushFlow({
|
|
27448
27459
|
flow,
|
|
27449
27460
|
collections: Object.values(s.collections).map((c) => c.data),
|
|
27450
27461
|
flows: Object.values(s.flows).map((f) => f.data),
|
|
@@ -27454,12 +27465,12 @@ async function pushFlowToCloud(flow) {
|
|
|
27454
27465
|
}
|
|
27455
27466
|
async function runFlowInCloud(flow, onStatus) {
|
|
27456
27467
|
assertEnabled();
|
|
27457
|
-
const started = await electron$
|
|
27468
|
+
const started = await electron$F.cloudRunFlow(flow.name);
|
|
27458
27469
|
onStatus?.(started.status);
|
|
27459
27470
|
const deadlineMs = 2 * 60 * 1e3;
|
|
27460
27471
|
const t0 = Date.now();
|
|
27461
27472
|
for (; ; ) {
|
|
27462
|
-
const run = await electron$
|
|
27473
|
+
const run = await electron$F.cloudGetFlowRun({ name: flow.name, runId: started.id });
|
|
27463
27474
|
onStatus?.(run.status);
|
|
27464
27475
|
if (run.status === "passed" || run.status === "failed" || run.status === "error" || run.status === "done") {
|
|
27465
27476
|
if (run.summary) return run.summary;
|
|
@@ -27470,12 +27481,53 @@ async function runFlowInCloud(flow, onStatus) {
|
|
|
27470
27481
|
}
|
|
27471
27482
|
}
|
|
27472
27483
|
function openCloudFlow(flow) {
|
|
27473
|
-
void electron$
|
|
27484
|
+
void electron$F.cloudOpenFlow(flow.name);
|
|
27485
|
+
}
|
|
27486
|
+
async function shareCollectionToCloud(collection2) {
|
|
27487
|
+
assertEnabled();
|
|
27488
|
+
return electron$F.cloudShareCollection(collection2);
|
|
27489
|
+
}
|
|
27490
|
+
async function shareRequestToCloud(request2) {
|
|
27491
|
+
assertEnabled();
|
|
27492
|
+
return electron$F.cloudShareRequest(request2);
|
|
27493
|
+
}
|
|
27494
|
+
function collectFolderRequestIds(folder2) {
|
|
27495
|
+
return [...folder2.requestIds, ...folder2.folders.flatMap(collectFolderRequestIds)];
|
|
27496
|
+
}
|
|
27497
|
+
async function shareFolderToCloud(collection2, folder2) {
|
|
27498
|
+
assertEnabled();
|
|
27499
|
+
const ids = new Set(collectFolderRequestIds(folder2));
|
|
27500
|
+
const requests = {};
|
|
27501
|
+
for (const id2 of ids) {
|
|
27502
|
+
const r = collection2.requests[id2];
|
|
27503
|
+
if (r) requests[id2] = r;
|
|
27504
|
+
}
|
|
27505
|
+
const payload = {
|
|
27506
|
+
version: "1.0",
|
|
27507
|
+
id: folder2.id,
|
|
27508
|
+
name: folder2.name,
|
|
27509
|
+
rootFolder: folder2,
|
|
27510
|
+
requests,
|
|
27511
|
+
collectionVariables: collection2.collectionVariables
|
|
27512
|
+
};
|
|
27513
|
+
return electron$F.cloudShareFolder({ sourceId: folder2.id, name: folder2.name, payload });
|
|
27514
|
+
}
|
|
27515
|
+
async function lookupShare(type, sourceId) {
|
|
27516
|
+
assertEnabled();
|
|
27517
|
+
return electron$F.cloudShareLookup({ type, sourceId });
|
|
27518
|
+
}
|
|
27519
|
+
async function restrictShare(token, expiresDays) {
|
|
27520
|
+
assertEnabled();
|
|
27521
|
+
return electron$F.cloudShareUpdate({ token, expiresDays });
|
|
27522
|
+
}
|
|
27523
|
+
async function revokeShare(token) {
|
|
27524
|
+
assertEnabled();
|
|
27525
|
+
await electron$F.cloudShareRevoke(token);
|
|
27474
27526
|
}
|
|
27475
27527
|
async function getCloudMockRoutes(name) {
|
|
27476
27528
|
if (!cloudEnabled()) return null;
|
|
27477
27529
|
try {
|
|
27478
|
-
const res = await electron$
|
|
27530
|
+
const res = await electron$F.cloudGetMock(name);
|
|
27479
27531
|
return res.exists ? res.routes ?? [] : null;
|
|
27480
27532
|
} catch {
|
|
27481
27533
|
return null;
|
|
@@ -27484,7 +27536,7 @@ async function getCloudMockRoutes(name) {
|
|
|
27484
27536
|
async function pushMockToCloud(server, routeIds) {
|
|
27485
27537
|
assertEnabled();
|
|
27486
27538
|
const routes = routeIds ? (server.routes ?? []).filter((r) => routeIds.includes(r.id)) : server.routes ?? [];
|
|
27487
|
-
return electron$
|
|
27539
|
+
return electron$F.cloudPushMock({ ...server, routes });
|
|
27488
27540
|
}
|
|
27489
27541
|
async function pushRequestAsMonitor(request2, opts) {
|
|
27490
27542
|
assertEnabled();
|
|
@@ -27508,7 +27560,7 @@ async function pushRequestAsMonitor(request2, opts) {
|
|
|
27508
27560
|
...request2.headers
|
|
27509
27561
|
];
|
|
27510
27562
|
const mergedRequest = { ...request2, auth: mergedAuth, headers: mergedHeaders };
|
|
27511
|
-
return electron$
|
|
27563
|
+
return electron$F.cloudPushMonitor(
|
|
27512
27564
|
{
|
|
27513
27565
|
request: mergedRequest,
|
|
27514
27566
|
setup,
|
|
@@ -27926,6 +27978,201 @@ function Toast({ toast }) {
|
|
|
27926
27978
|
if (!toast) return null;
|
|
27927
27979
|
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 });
|
|
27928
27980
|
}
|
|
27981
|
+
function CloudRequiredModal({
|
|
27982
|
+
action,
|
|
27983
|
+
onConnect,
|
|
27984
|
+
onClose
|
|
27985
|
+
}) {
|
|
27986
|
+
const t = useT();
|
|
27987
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
27988
|
+
Modal,
|
|
27989
|
+
{
|
|
27990
|
+
onClose,
|
|
27991
|
+
closeOnBackdrop: true,
|
|
27992
|
+
overlayClassName: "bg-black/50 z-[300] flex items-center justify-center",
|
|
27993
|
+
panelClassName: "bg-surface-900 border border-surface-700 rounded-lg shadow-2xl p-5 w-96 flex flex-col gap-4",
|
|
27994
|
+
children: [
|
|
27995
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
27996
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "shrink-0 w-10 h-10 rounded-full bg-sky-900/40 border border-sky-700/40 flex items-center justify-center text-sky-300", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z" }) }) }),
|
|
27997
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
27998
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold text-white", children: t("Connect to API Spector Cloud") }),
|
|
27999
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-400 mt-0.5", children: t("Sharing needs the cloud") })
|
|
28000
|
+
] })
|
|
28001
|
+
] }),
|
|
28002
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-surface-300 leading-relaxed", children: action ? t("To :action you need to connect this workspace to API Spector Cloud, which hosts the public link.", { action }) : t("Public share links are hosted in API Spector Cloud. Connect this workspace to the cloud to create one.") }),
|
|
28003
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500", children: t("Only request definitions with {{variables}} are shared. Secrets and environment values are never uploaded.") }),
|
|
28004
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
28005
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28006
|
+
"button",
|
|
28007
|
+
{
|
|
28008
|
+
onClick: onClose,
|
|
28009
|
+
className: "px-3 py-1.5 text-xs text-surface-400 hover:text-white transition-colors",
|
|
28010
|
+
children: t("Not now")
|
|
28011
|
+
}
|
|
28012
|
+
),
|
|
28013
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28014
|
+
"button",
|
|
28015
|
+
{
|
|
28016
|
+
onClick: onConnect,
|
|
28017
|
+
className: "px-3 py-1.5 text-xs font-medium text-white bg-sky-700 hover:bg-sky-600 rounded transition-colors",
|
|
28018
|
+
children: t("Open Cloud settings")
|
|
28019
|
+
}
|
|
28020
|
+
)
|
|
28021
|
+
] })
|
|
28022
|
+
]
|
|
28023
|
+
}
|
|
28024
|
+
);
|
|
28025
|
+
}
|
|
28026
|
+
function ShareModal({
|
|
28027
|
+
title,
|
|
28028
|
+
type,
|
|
28029
|
+
sourceId,
|
|
28030
|
+
onCreate,
|
|
28031
|
+
onClose
|
|
28032
|
+
}) {
|
|
28033
|
+
const t = useT();
|
|
28034
|
+
const [loading, setLoading] = reactExports.useState(true);
|
|
28035
|
+
const [busy, setBusy] = reactExports.useState(false);
|
|
28036
|
+
const [error2, setError] = reactExports.useState(null);
|
|
28037
|
+
const [copied, setCopied] = reactExports.useState(false);
|
|
28038
|
+
const [live, setLive] = reactExports.useState(null);
|
|
28039
|
+
const [expiryDays, setExpiryDays] = reactExports.useState(0);
|
|
28040
|
+
reactExports.useEffect(() => {
|
|
28041
|
+
let cancelled = false;
|
|
28042
|
+
(async () => {
|
|
28043
|
+
try {
|
|
28044
|
+
const res = await lookupShare(type, sourceId);
|
|
28045
|
+
if (!cancelled && res.exists && res.token && res.url && res.deep_link) {
|
|
28046
|
+
setLive({ token: res.token, url: res.url, deep_link: res.deep_link, expires_at: res.expires_at ?? null });
|
|
28047
|
+
}
|
|
28048
|
+
} catch (e) {
|
|
28049
|
+
if (!cancelled) setError(e.message);
|
|
28050
|
+
} finally {
|
|
28051
|
+
if (!cancelled) setLoading(false);
|
|
28052
|
+
}
|
|
28053
|
+
})();
|
|
28054
|
+
return () => {
|
|
28055
|
+
cancelled = true;
|
|
28056
|
+
};
|
|
28057
|
+
}, [type, sourceId]);
|
|
28058
|
+
async function run(fn) {
|
|
28059
|
+
setBusy(true);
|
|
28060
|
+
setError(null);
|
|
28061
|
+
try {
|
|
28062
|
+
await fn();
|
|
28063
|
+
} catch (e) {
|
|
28064
|
+
setError(e.message);
|
|
28065
|
+
} finally {
|
|
28066
|
+
setBusy(false);
|
|
28067
|
+
}
|
|
28068
|
+
}
|
|
28069
|
+
const create2 = () => run(async () => {
|
|
28070
|
+
const r = await onCreate();
|
|
28071
|
+
setLive({ token: r.token, url: r.url, deep_link: r.deep_link, expires_at: r.expires_at ?? null });
|
|
28072
|
+
});
|
|
28073
|
+
const applyExpiry = () => run(async () => {
|
|
28074
|
+
if (!live) return;
|
|
28075
|
+
const r = await restrictShare(live.token, expiryDays);
|
|
28076
|
+
setLive({ ...live, expires_at: r.expires_at ?? null });
|
|
28077
|
+
});
|
|
28078
|
+
const revoke = () => run(async () => {
|
|
28079
|
+
if (!live) return;
|
|
28080
|
+
await revokeShare(live.token);
|
|
28081
|
+
setLive(null);
|
|
28082
|
+
});
|
|
28083
|
+
const copy2 = async () => {
|
|
28084
|
+
if (!live) return;
|
|
28085
|
+
try {
|
|
28086
|
+
await navigator.clipboard.writeText(live.url);
|
|
28087
|
+
setCopied(true);
|
|
28088
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
28089
|
+
} catch {
|
|
28090
|
+
}
|
|
28091
|
+
};
|
|
28092
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28093
|
+
Modal,
|
|
28094
|
+
{
|
|
28095
|
+
onClose,
|
|
28096
|
+
title: t("Share: :name", { name: title }),
|
|
28097
|
+
overlayClassName: "bg-black/50 z-[300] flex items-center justify-center",
|
|
28098
|
+
panelClassName: "bg-surface-900 border border-surface-700 rounded-lg shadow-2xl w-[32rem] max-w-[92vw] flex flex-col",
|
|
28099
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-5 flex flex-col gap-4", children: [
|
|
28100
|
+
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-red-400 bg-red-900/30 border border-red-800/40 rounded px-2 py-1.5", children: error2 }),
|
|
28101
|
+
loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-surface-400", children: t("Checking share status…") }) : !live ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
28102
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-surface-300 leading-relaxed", children: type === "request" ? t("Create a public read-only link to this request. Anyone with the link can view it or import it into their own app.") : type === "folder" ? t("Create a public read-only link to this folder. Anyone with the link can view its requests or import them into their own app.") : t("Create a public read-only link to this collection. Anyone with the link can view it or import it into their own app.") }),
|
|
28103
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500", children: t("Only request definitions with {{variables}} are shared. Secrets and environment values are never uploaded.") }),
|
|
28104
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28105
|
+
"button",
|
|
28106
|
+
{
|
|
28107
|
+
onClick: create2,
|
|
28108
|
+
disabled: busy,
|
|
28109
|
+
className: "px-3 py-1.5 text-xs font-medium text-white bg-sky-700 hover:bg-sky-600 disabled:opacity-50 rounded transition-colors",
|
|
28110
|
+
children: busy ? t("Creating…") : t("Create public link")
|
|
28111
|
+
}
|
|
28112
|
+
) })
|
|
28113
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
28114
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
28115
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[11px] uppercase tracking-wide text-surface-500", children: t("Public link") }),
|
|
28116
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
|
|
28117
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28118
|
+
"input",
|
|
28119
|
+
{
|
|
28120
|
+
readOnly: true,
|
|
28121
|
+
value: live.url,
|
|
28122
|
+
onClick: (e) => e.target.select(),
|
|
28123
|
+
className: "flex-1 rounded bg-surface-950 border border-surface-700 px-2 py-1.5 text-xs font-mono text-surface-200"
|
|
28124
|
+
}
|
|
28125
|
+
),
|
|
28126
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: copy2, className: "px-3 py-1.5 text-xs border border-surface-700 rounded text-surface-300 hover:text-white transition-colors", children: copied ? t("Copied") : t("Copy") })
|
|
28127
|
+
] })
|
|
28128
|
+
] }),
|
|
28129
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end gap-2", children: [
|
|
28130
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
|
|
28131
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[11px] uppercase tracking-wide text-surface-500", children: t("Restrict") }),
|
|
28132
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-400 mt-1", children: live.expires_at ? t("Expires :date", { date: new Date(live.expires_at).toLocaleString() }) : t("Never expires") })
|
|
28133
|
+
] }),
|
|
28134
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
28135
|
+
"select",
|
|
28136
|
+
{
|
|
28137
|
+
value: expiryDays,
|
|
28138
|
+
onChange: (e) => setExpiryDays(Number(e.target.value)),
|
|
28139
|
+
className: "rounded bg-surface-950 border border-surface-700 px-2 py-1.5 text-xs text-surface-200",
|
|
28140
|
+
children: [
|
|
28141
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 0, children: t("No expiry") }),
|
|
28142
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 1, children: t("1 day") }),
|
|
28143
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 7, children: t("7 days") }),
|
|
28144
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 30, children: t("30 days") })
|
|
28145
|
+
]
|
|
28146
|
+
}
|
|
28147
|
+
),
|
|
28148
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28149
|
+
"button",
|
|
28150
|
+
{
|
|
28151
|
+
onClick: applyExpiry,
|
|
28152
|
+
disabled: busy,
|
|
28153
|
+
className: "px-3 py-1.5 text-xs border border-surface-700 rounded text-surface-300 hover:text-white disabled:opacity-50 transition-colors",
|
|
28154
|
+
children: t("Apply")
|
|
28155
|
+
}
|
|
28156
|
+
)
|
|
28157
|
+
] }),
|
|
28158
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500", children: t("Only request definitions with {{variables}} are shared. Secrets and environment values are never uploaded.") }),
|
|
28159
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center pt-2 border-t border-surface-800", children: [
|
|
28160
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28161
|
+
"button",
|
|
28162
|
+
{
|
|
28163
|
+
onClick: revoke,
|
|
28164
|
+
disabled: busy,
|
|
28165
|
+
className: "px-3 py-1.5 text-xs text-red-400 hover:text-red-300 disabled:opacity-50 transition-colors",
|
|
28166
|
+
children: t("Revoke link")
|
|
28167
|
+
}
|
|
28168
|
+
),
|
|
28169
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "px-3 py-1.5 text-xs text-surface-400 hover:text-white transition-colors", children: t("Done") })
|
|
28170
|
+
] })
|
|
28171
|
+
] })
|
|
28172
|
+
] })
|
|
28173
|
+
}
|
|
28174
|
+
);
|
|
28175
|
+
}
|
|
27929
28176
|
function requestPath(url) {
|
|
27930
28177
|
const trimmed = url.trim().replace(/^\{\{[^}]+\}\}/, "").replace(/^https?:\/\/[^/]+/i, "");
|
|
27931
28178
|
return trimmed || url.trim();
|
|
@@ -27995,6 +28242,9 @@ function RequestRow({
|
|
|
27995
28242
|
const groupIndent = indent + 14;
|
|
27996
28243
|
const { toast, show } = useToast();
|
|
27997
28244
|
const addSecurityTests = useStore$1((s) => s.addSecurityTests);
|
|
28245
|
+
const openWorkspaceSettings = useStore$1((s) => s.openWorkspaceSettings);
|
|
28246
|
+
const [showCloudRequired, setShowCloudRequired] = reactExports.useState(false);
|
|
28247
|
+
const [showShare, setShowShare] = reactExports.useState(false);
|
|
27998
28248
|
function handleRowClick(e) {
|
|
27999
28249
|
if (e.metaKey || e.ctrlKey) {
|
|
28000
28250
|
e.preventDefault();
|
|
@@ -28014,6 +28264,13 @@ function RequestRow({
|
|
|
28014
28264
|
show(e.message, false);
|
|
28015
28265
|
}
|
|
28016
28266
|
}
|
|
28267
|
+
function openShare() {
|
|
28268
|
+
if (!cloudEnabled()) {
|
|
28269
|
+
setShowCloudRequired(true);
|
|
28270
|
+
return;
|
|
28271
|
+
}
|
|
28272
|
+
setShowShare(true);
|
|
28273
|
+
}
|
|
28017
28274
|
const hookMenuItems = ["beforeAll", "before", "after", "afterAll"].map((ht) => ({
|
|
28018
28275
|
type: "item",
|
|
28019
28276
|
label: (hookType === ht ? "✓ " : " ") + t(HOOK_LABELS[ht]),
|
|
@@ -28154,6 +28411,7 @@ function RequestRow({
|
|
|
28154
28411
|
show(n2 > 0 ? t("Added :count OWASP security tests", { count: n2 }) : t("No security tests generated for this request"), n2 > 0);
|
|
28155
28412
|
} },
|
|
28156
28413
|
...cloudEnabled() ? [{ type: "item", label: t("Push as monitor to cloud"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: pushMonitor }] : [],
|
|
28414
|
+
{ type: "item", label: t("Share request (public link)"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyIcon, {}), onClick: openShare },
|
|
28157
28415
|
{ type: "item", label: disabled ? t("Enable") : t("Disable"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(BanIcon, {}), onClick: onToggleDisabled },
|
|
28158
28416
|
{ type: "separator" },
|
|
28159
28417
|
{ type: "header", label: t("Hook type") },
|
|
@@ -28161,7 +28419,32 @@ function RequestRow({
|
|
|
28161
28419
|
{ type: "separator" },
|
|
28162
28420
|
{ type: "item", label: t("Delete"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(TrashIcon, {}), danger: true, onClick: onDelete }
|
|
28163
28421
|
] }) }),
|
|
28164
|
-
toast && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed bottom-4 right-4 z-[100] w-96", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Toast, { toast }) })
|
|
28422
|
+
toast && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed bottom-4 right-4 z-[100] w-96", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Toast, { toast }) }),
|
|
28423
|
+
showCloudRequired && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28424
|
+
CloudRequiredModal,
|
|
28425
|
+
{
|
|
28426
|
+
action: t("share this request"),
|
|
28427
|
+
onConnect: () => {
|
|
28428
|
+
setShowCloudRequired(false);
|
|
28429
|
+
openWorkspaceSettings("cloud");
|
|
28430
|
+
},
|
|
28431
|
+
onClose: () => setShowCloudRequired(false)
|
|
28432
|
+
}
|
|
28433
|
+
),
|
|
28434
|
+
showShare && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28435
|
+
ShareModal,
|
|
28436
|
+
{
|
|
28437
|
+
title: useStore$1.getState().collections[collectionId]?.data.requests[reqId]?.name ?? "",
|
|
28438
|
+
type: "request",
|
|
28439
|
+
sourceId: reqId,
|
|
28440
|
+
onCreate: () => {
|
|
28441
|
+
const r = useStore$1.getState().collections[collectionId]?.data.requests[reqId];
|
|
28442
|
+
if (!r) throw new Error(t("Request not found"));
|
|
28443
|
+
return shareRequestToCloud(r);
|
|
28444
|
+
},
|
|
28445
|
+
onClose: () => setShowShare(false)
|
|
28446
|
+
}
|
|
28447
|
+
)
|
|
28165
28448
|
]
|
|
28166
28449
|
}
|
|
28167
28450
|
),
|
|
@@ -28822,6 +29105,16 @@ function CollectionNode({
|
|
|
28822
29105
|
const [expandCtrl, setExpandCtrl] = reactExports.useState({ value: true, seq: 0 });
|
|
28823
29106
|
const [dropOver, setDropOver] = reactExports.useState(false);
|
|
28824
29107
|
const dragCtx = reactExports.useContext(DragCtx);
|
|
29108
|
+
const openWorkspaceSettings = useStore$1((s) => s.openWorkspaceSettings);
|
|
29109
|
+
const [showCloudRequired, setShowCloudRequired] = reactExports.useState(false);
|
|
29110
|
+
const [showShare, setShowShare] = reactExports.useState(false);
|
|
29111
|
+
function openShare() {
|
|
29112
|
+
if (!cloudEnabled()) {
|
|
29113
|
+
setShowCloudRequired(true);
|
|
29114
|
+
return;
|
|
29115
|
+
}
|
|
29116
|
+
setShowShare(true);
|
|
29117
|
+
}
|
|
28825
29118
|
function expandAll() {
|
|
28826
29119
|
setExpandCtrl((c) => ({ value: true, seq: c.seq + 1, ids: null }));
|
|
28827
29120
|
}
|
|
@@ -28903,6 +29196,7 @@ function CollectionNode({
|
|
|
28903
29196
|
{ type: "item", label: t("Settings"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(GearIcon, {}), onClick: () => setShowSettings(true) },
|
|
28904
29197
|
{ type: "item", label: t("Sync schemas"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowSchemaSync(true) },
|
|
28905
29198
|
...cloudEnabled() ? [{ type: "item", label: t("Push contract to cloud"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowPushContract(true) }] : [],
|
|
29199
|
+
{ type: "item", label: t("Share collection (public link)"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyIcon, {}), onClick: openShare },
|
|
28906
29200
|
{ type: "item", label: col.disabled ? t("Enable") : t("Disable"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(BanIcon, {}), onClick: onToggleCollectionDisabled },
|
|
28907
29201
|
{ type: "separator" },
|
|
28908
29202
|
{ type: "item", label: t("Delete collection"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(TrashIcon, {}), danger: true, onClick: onDeleteCollection }
|
|
@@ -28947,7 +29241,28 @@ function CollectionNode({
|
|
|
28947
29241
|
}
|
|
28948
29242
|
),
|
|
28949
29243
|
showSettings && /* @__PURE__ */ jsxRuntimeExports.jsx(CollectionSettingsModal, { collection: col, onClose: () => setShowSettings(false) }),
|
|
28950
|
-
showSchemaSync && /* @__PURE__ */ jsxRuntimeExports.jsx(SchemaSyncModal, { collectionId: col.id, scope: { type: "collection" }, onClose: () => setShowSchemaSync(false) })
|
|
29244
|
+
showSchemaSync && /* @__PURE__ */ jsxRuntimeExports.jsx(SchemaSyncModal, { collectionId: col.id, scope: { type: "collection" }, onClose: () => setShowSchemaSync(false) }),
|
|
29245
|
+
showCloudRequired && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29246
|
+
CloudRequiredModal,
|
|
29247
|
+
{
|
|
29248
|
+
action: t("share this collection"),
|
|
29249
|
+
onConnect: () => {
|
|
29250
|
+
setShowCloudRequired(false);
|
|
29251
|
+
openWorkspaceSettings("cloud");
|
|
29252
|
+
},
|
|
29253
|
+
onClose: () => setShowCloudRequired(false)
|
|
29254
|
+
}
|
|
29255
|
+
),
|
|
29256
|
+
showShare && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29257
|
+
ShareModal,
|
|
29258
|
+
{
|
|
29259
|
+
title: col.name,
|
|
29260
|
+
type: "collection",
|
|
29261
|
+
sourceId: col.id,
|
|
29262
|
+
onCreate: () => shareCollectionToCloud(col),
|
|
29263
|
+
onClose: () => setShowShare(false)
|
|
29264
|
+
}
|
|
29265
|
+
)
|
|
28951
29266
|
] });
|
|
28952
29267
|
}
|
|
28953
29268
|
function FolderRow({
|
|
@@ -28991,6 +29306,16 @@ function FolderRow({
|
|
|
28991
29306
|
}));
|
|
28992
29307
|
const [dropInside, setDropInside] = reactExports.useState(false);
|
|
28993
29308
|
const dragCtx = reactExports.useContext(DragCtx);
|
|
29309
|
+
const openWorkspaceSettings = useStore$1((s) => s.openWorkspaceSettings);
|
|
29310
|
+
const [showCloudRequired, setShowCloudRequired] = reactExports.useState(false);
|
|
29311
|
+
const [showShare, setShowShare] = reactExports.useState(false);
|
|
29312
|
+
function openShare() {
|
|
29313
|
+
if (!cloudEnabled()) {
|
|
29314
|
+
setShowCloudRequired(true);
|
|
29315
|
+
return;
|
|
29316
|
+
}
|
|
29317
|
+
setShowShare(true);
|
|
29318
|
+
}
|
|
28994
29319
|
const tags = folder2.tags ?? [];
|
|
28995
29320
|
const indent = indentPx(depth);
|
|
28996
29321
|
const hasInheritedConfig = folder2.auth && folder2.auth.type !== "none" || folder2.headers && folder2.headers.length > 0;
|
|
@@ -29104,6 +29429,7 @@ function FolderRow({
|
|
|
29104
29429
|
{ type: "item", label: t("Settings"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(GearIcon, {}), onClick: () => setShowSettings(true) },
|
|
29105
29430
|
{ type: "item", label: t("Sync schemas"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowSchemaSync(true) },
|
|
29106
29431
|
...cloudEnabled() ? [{ type: "item", label: t("Push contract to cloud"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowPushContract(true) }] : [],
|
|
29432
|
+
{ type: "item", label: t("Share folder (public link)"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyIcon, {}), onClick: openShare },
|
|
29107
29433
|
{ type: "item", label: folder2.disabled ? t("Enable") : t("Disable"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(BanIcon, {}), onClick: onToggleDisabled },
|
|
29108
29434
|
{ type: "separator" },
|
|
29109
29435
|
{ type: "header", label: t("Run folder as hook") },
|
|
@@ -29138,6 +29464,27 @@ function FolderRow({
|
|
|
29138
29464
|
scope: { type: "folder", folderId: folder2.id },
|
|
29139
29465
|
onClose: () => setShowSchemaSync(false)
|
|
29140
29466
|
}
|
|
29467
|
+
),
|
|
29468
|
+
showCloudRequired && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29469
|
+
CloudRequiredModal,
|
|
29470
|
+
{
|
|
29471
|
+
action: t("share this folder"),
|
|
29472
|
+
onConnect: () => {
|
|
29473
|
+
setShowCloudRequired(false);
|
|
29474
|
+
openWorkspaceSettings("cloud");
|
|
29475
|
+
},
|
|
29476
|
+
onClose: () => setShowCloudRequired(false)
|
|
29477
|
+
}
|
|
29478
|
+
),
|
|
29479
|
+
showShare && folderCollection && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29480
|
+
ShareModal,
|
|
29481
|
+
{
|
|
29482
|
+
title: folder2.name,
|
|
29483
|
+
type: "folder",
|
|
29484
|
+
sourceId: folder2.id,
|
|
29485
|
+
onCreate: () => shareFolderToCloud(folderCollection, folder2),
|
|
29486
|
+
onClose: () => setShowShare(false)
|
|
29487
|
+
}
|
|
29141
29488
|
)
|
|
29142
29489
|
] });
|
|
29143
29490
|
}
|
|
@@ -29591,8 +29938,8 @@ function jsonWithComments() {
|
|
|
29591
29938
|
function xmlWithComments() {
|
|
29592
29939
|
return [xml(), commentKeymap];
|
|
29593
29940
|
}
|
|
29594
|
-
const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-
|
|
29595
|
-
const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-
|
|
29941
|
+
const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-J-8g0S0P.js"), true ? __vite__mapDeps([0,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.GraphQLEditor })));
|
|
29942
|
+
const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-CmsqdXhh.js"), true ? __vite__mapDeps([3,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.SoapEditor })));
|
|
29596
29943
|
function BodyTab({ request: request2, onChange }) {
|
|
29597
29944
|
const t = useT();
|
|
29598
29945
|
const editorFallback = /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 text-xs text-surface-500", children: t("Loading editor…") });
|
|
@@ -29690,7 +30037,7 @@ function BodyTab({ request: request2, onChange }) {
|
|
|
29690
30037
|
mode === "soap" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: editorFallback, children: /* @__PURE__ */ jsxRuntimeExports.jsx(SoapEditor, { request: request2, onChange }) }) })
|
|
29691
30038
|
] });
|
|
29692
30039
|
}
|
|
29693
|
-
const { electron: electron$
|
|
30040
|
+
const { electron: electron$E } = window;
|
|
29694
30041
|
function AuthTab({ request: request2, onChange }) {
|
|
29695
30042
|
const auth = request2.auth;
|
|
29696
30043
|
const [secretValue, setSecretValue] = reactExports.useState("");
|
|
@@ -29700,7 +30047,7 @@ function AuthTab({ request: request2, onChange }) {
|
|
|
29700
30047
|
}
|
|
29701
30048
|
async function saveSecret(ref) {
|
|
29702
30049
|
if (!secretValue || !ref) return;
|
|
29703
|
-
await electron$
|
|
30050
|
+
await electron$E.setSecret(ref, secretValue);
|
|
29704
30051
|
setSaved(true);
|
|
29705
30052
|
setSecretValue("");
|
|
29706
30053
|
setTimeout(() => setSaved(false), 2e3);
|
|
@@ -30060,7 +30407,7 @@ function validateBodyAgainstSchema(schema, body) {
|
|
|
30060
30407
|
return { status: "error", message: e instanceof Error ? e.message : String(e) };
|
|
30061
30408
|
}
|
|
30062
30409
|
}
|
|
30063
|
-
const { electron: electron$
|
|
30410
|
+
const { electron: electron$D } = window;
|
|
30064
30411
|
function SchemaTab({ request: request2, onChange }) {
|
|
30065
30412
|
const t = useT();
|
|
30066
30413
|
const activeTab = useStore$1((s) => s.tabs.find((tab) => tab.id === s.activeTabId));
|
|
@@ -30084,7 +30431,7 @@ function SchemaTab({ request: request2, onChange }) {
|
|
|
30084
30431
|
if (!lastResponse?.body) return;
|
|
30085
30432
|
setInferring(true);
|
|
30086
30433
|
try {
|
|
30087
|
-
const schema = await electron$
|
|
30434
|
+
const schema = await electron$D.inferContractSchema(lastResponse.body);
|
|
30088
30435
|
if (schema) setSchema(schema);
|
|
30089
30436
|
} finally {
|
|
30090
30437
|
setInferring(false);
|
|
@@ -39514,7 +39861,7 @@ function DocsEditor({ value: value2, onChange, placeholder, onGenerate, aiAvaila
|
|
|
39514
39861
|
}
|
|
39515
39862
|
const AI_OPENAI_TOKEN_REF = "ai:openai:token";
|
|
39516
39863
|
const DEFAULT_AI_MODEL = "gpt-4o-mini";
|
|
39517
|
-
const { electron: electron$
|
|
39864
|
+
const { electron: electron$C } = window;
|
|
39518
39865
|
const CFG_KEY = STORAGE_KEYS.ai;
|
|
39519
39866
|
function getAiConfig() {
|
|
39520
39867
|
try {
|
|
@@ -39536,7 +39883,7 @@ function invalidateAiAvailable() {
|
|
|
39536
39883
|
async function checkAvailable() {
|
|
39537
39884
|
if (availableCache != null) return availableCache;
|
|
39538
39885
|
try {
|
|
39539
|
-
availableCache = (await electron$
|
|
39886
|
+
availableCache = (await electron$C.hasSecret(AI_OPENAI_TOKEN_REF)).has;
|
|
39540
39887
|
} catch {
|
|
39541
39888
|
availableCache = false;
|
|
39542
39889
|
}
|
|
@@ -39556,7 +39903,7 @@ function useAiAvailable() {
|
|
|
39556
39903
|
return available;
|
|
39557
39904
|
}
|
|
39558
39905
|
async function generateDocs(input) {
|
|
39559
|
-
return electron$
|
|
39906
|
+
return electron$C.generateAiDocs({ ...input, model: getAiConfig().model });
|
|
39560
39907
|
}
|
|
39561
39908
|
function kvLines(label, rows) {
|
|
39562
39909
|
const on = (rows ?? []).filter((r) => r.enabled !== false && r.key);
|
|
@@ -40084,7 +40431,7 @@ function RealtimeTestSection({
|
|
|
40084
40431
|
] })
|
|
40085
40432
|
] });
|
|
40086
40433
|
}
|
|
40087
|
-
const { electron: electron$
|
|
40434
|
+
const { electron: electron$B } = window;
|
|
40088
40435
|
function formatTime$4(ts) {
|
|
40089
40436
|
const d = new Date(ts);
|
|
40090
40437
|
const hh = String(d.getHours()).padStart(2, "0");
|
|
@@ -40114,7 +40461,7 @@ function WebSocketPanel({ request: request2, onChange }) {
|
|
|
40114
40461
|
const url = interp(request2.url).trim();
|
|
40115
40462
|
const headers = {};
|
|
40116
40463
|
for (const h of request2.headers) if (h.enabled && h.key) headers[interp(h.key)] = interp(h.value);
|
|
40117
|
-
return electron$
|
|
40464
|
+
return electron$B.wsTest({
|
|
40118
40465
|
url,
|
|
40119
40466
|
headers,
|
|
40120
40467
|
sendMessage: cfg.sendMessage ? interp(cfg.sendMessage) : void 0,
|
|
@@ -40124,14 +40471,14 @@ function WebSocketPanel({ request: request2, onChange }) {
|
|
|
40124
40471
|
});
|
|
40125
40472
|
});
|
|
40126
40473
|
reactExports.useEffect(() => {
|
|
40127
|
-
electron$
|
|
40474
|
+
electron$B.onWsMessage(({ requestId, message }) => {
|
|
40128
40475
|
addWsMessage(requestId, message);
|
|
40129
40476
|
});
|
|
40130
|
-
electron$
|
|
40477
|
+
electron$B.onWsStatus(({ requestId, status, error: error2 }) => {
|
|
40131
40478
|
setWsStatus(requestId, status, error2);
|
|
40132
40479
|
});
|
|
40133
40480
|
return () => {
|
|
40134
|
-
electron$
|
|
40481
|
+
electron$B.offWsEvents();
|
|
40135
40482
|
};
|
|
40136
40483
|
}, [addWsMessage, setWsStatus]);
|
|
40137
40484
|
reactExports.useEffect(() => {
|
|
@@ -40144,19 +40491,19 @@ function WebSocketPanel({ request: request2, onChange }) {
|
|
|
40144
40491
|
if (h.enabled && h.key) headers[h.key] = h.value;
|
|
40145
40492
|
}
|
|
40146
40493
|
try {
|
|
40147
|
-
await electron$
|
|
40494
|
+
await electron$B.wsConnect(request2.id, request2.url, headers);
|
|
40148
40495
|
} catch (err) {
|
|
40149
40496
|
setWsStatus(request2.id, "error", err instanceof Error ? err.message : String(err));
|
|
40150
40497
|
}
|
|
40151
40498
|
}
|
|
40152
40499
|
async function disconnect() {
|
|
40153
|
-
await electron$
|
|
40500
|
+
await electron$B.wsDisconnect(request2.id);
|
|
40154
40501
|
}
|
|
40155
40502
|
async function sendMessage() {
|
|
40156
40503
|
const text = sendText.trim();
|
|
40157
40504
|
if (!text || !isConnected) return;
|
|
40158
40505
|
try {
|
|
40159
|
-
await electron$
|
|
40506
|
+
await electron$B.wsSend(request2.id, text);
|
|
40160
40507
|
const msg = {
|
|
40161
40508
|
id: crypto.randomUUID(),
|
|
40162
40509
|
direction: "sent",
|
|
@@ -40308,7 +40655,7 @@ function WebSocketPanel({ request: request2, onChange }) {
|
|
|
40308
40655
|
] })
|
|
40309
40656
|
] });
|
|
40310
40657
|
}
|
|
40311
|
-
const { electron: electron$
|
|
40658
|
+
const { electron: electron$A } = window;
|
|
40312
40659
|
function formatTime$3(ts) {
|
|
40313
40660
|
const d = new Date(ts);
|
|
40314
40661
|
const p = (n2, w = 2) => String(n2).padStart(w, "0");
|
|
@@ -40342,7 +40689,7 @@ function SocketIoPanel({ request: request2, onChange }) {
|
|
|
40342
40689
|
const url = interp(request2.url).trim();
|
|
40343
40690
|
const headers = {};
|
|
40344
40691
|
for (const h of request2.headers) if (h.enabled && h.key) headers[interp(h.key)] = interp(h.value);
|
|
40345
|
-
return electron$
|
|
40692
|
+
return electron$A.socketIoTest({
|
|
40346
40693
|
url,
|
|
40347
40694
|
namespace: namespace2,
|
|
40348
40695
|
auth: auth ? interp(auth) : void 0,
|
|
@@ -40361,19 +40708,19 @@ function SocketIoPanel({ request: request2, onChange }) {
|
|
|
40361
40708
|
if (h.enabled && h.key) headers[h.key] = h.value;
|
|
40362
40709
|
}
|
|
40363
40710
|
try {
|
|
40364
|
-
await electron$
|
|
40711
|
+
await electron$A.socketIoConnect(request2.id, { url: request2.url, namespace: namespace2, auth, headers });
|
|
40365
40712
|
} catch (err) {
|
|
40366
40713
|
setStatus(request2.id, "error", err instanceof Error ? err.message : String(err));
|
|
40367
40714
|
}
|
|
40368
40715
|
}
|
|
40369
40716
|
async function disconnect() {
|
|
40370
|
-
await electron$
|
|
40717
|
+
await electron$A.socketIoDisconnect(request2.id);
|
|
40371
40718
|
}
|
|
40372
40719
|
async function emit() {
|
|
40373
40720
|
const event = eventName2.trim();
|
|
40374
40721
|
if (!event || !isConnected) return;
|
|
40375
40722
|
try {
|
|
40376
|
-
await electron$
|
|
40723
|
+
await electron$A.socketIoEmit(request2.id, { event, args: argsText, withAck });
|
|
40377
40724
|
const msg = {
|
|
40378
40725
|
id: crypto.randomUUID(),
|
|
40379
40726
|
direction: "sent",
|
|
@@ -40587,7 +40934,7 @@ function SocketIoPanel({ request: request2, onChange }) {
|
|
|
40587
40934
|
] })
|
|
40588
40935
|
] });
|
|
40589
40936
|
}
|
|
40590
|
-
const { electron: electron$
|
|
40937
|
+
const { electron: electron$z } = window;
|
|
40591
40938
|
function formatTime$2(ts) {
|
|
40592
40939
|
const d = new Date(ts);
|
|
40593
40940
|
const p = (n2, w = 2) => String(n2).padStart(w, "0");
|
|
@@ -40627,7 +40974,7 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
40627
40974
|
return;
|
|
40628
40975
|
}
|
|
40629
40976
|
try {
|
|
40630
|
-
await electron$
|
|
40977
|
+
await electron$z.mqttConnect(request2.id, {
|
|
40631
40978
|
url,
|
|
40632
40979
|
clientId: cfg.clientId ? interp(cfg.clientId) : void 0,
|
|
40633
40980
|
username: cfg.username ? interp(cfg.username) : void 0,
|
|
@@ -40641,13 +40988,13 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
40641
40988
|
}
|
|
40642
40989
|
}
|
|
40643
40990
|
async function disconnect() {
|
|
40644
|
-
await electron$
|
|
40991
|
+
await electron$z.mqttDisconnect(request2.id);
|
|
40645
40992
|
}
|
|
40646
40993
|
async function subscribe() {
|
|
40647
40994
|
const topic = interp(cfg.subscribeTopic ?? "").trim();
|
|
40648
40995
|
if (!topic || !isConnected) return;
|
|
40649
40996
|
try {
|
|
40650
|
-
await electron$
|
|
40997
|
+
await electron$z.mqttSubscribe(request2.id, { topic, qos });
|
|
40651
40998
|
} catch (err) {
|
|
40652
40999
|
setStatus(request2.id, "error", err instanceof Error ? err.message : String(err));
|
|
40653
41000
|
}
|
|
@@ -40655,7 +41002,7 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
40655
41002
|
async function unsubscribe() {
|
|
40656
41003
|
const topic = interp(cfg.subscribeTopic ?? "").trim();
|
|
40657
41004
|
if (!topic || !isConnected) return;
|
|
40658
|
-
await electron$
|
|
41005
|
+
await electron$z.mqttUnsubscribe(request2.id, { topic });
|
|
40659
41006
|
}
|
|
40660
41007
|
async function publish() {
|
|
40661
41008
|
const topic = interp(cfg.publishTopic ?? "").trim();
|
|
@@ -40667,7 +41014,7 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
40667
41014
|
setPublishError("");
|
|
40668
41015
|
const body = interp(payload);
|
|
40669
41016
|
try {
|
|
40670
|
-
await electron$
|
|
41017
|
+
await electron$z.mqttPublish(request2.id, { topic, payload: body, qos, retain: Boolean(cfg.retain) });
|
|
40671
41018
|
addMessage(request2.id, {
|
|
40672
41019
|
id: crypto.randomUUID(),
|
|
40673
41020
|
direction: "sent",
|
|
@@ -40691,7 +41038,7 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
40691
41038
|
setTestRemaining(Math.ceil(collectMs / 1e3));
|
|
40692
41039
|
const countdown = setInterval(() => setTestRemaining((r) => r && r > 1 ? r - 1 : 0), 1e3);
|
|
40693
41040
|
try {
|
|
40694
|
-
const res = await electron$
|
|
41041
|
+
const res = await electron$z.mqttTest({
|
|
40695
41042
|
url,
|
|
40696
41043
|
// The test opens its own connection; never reuse the panel's Client ID,
|
|
40697
41044
|
// or the broker would kick whichever connected first (a clientId clash).
|
|
@@ -41040,7 +41387,7 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
41040
41387
|
] })
|
|
41041
41388
|
] });
|
|
41042
41389
|
}
|
|
41043
|
-
const { electron: electron$
|
|
41390
|
+
const { electron: electron$y } = window;
|
|
41044
41391
|
function formatTime$1(ts) {
|
|
41045
41392
|
const d = new Date(ts);
|
|
41046
41393
|
const p = (n2, w = 2) => String(n2).padStart(w, "0");
|
|
@@ -41076,13 +41423,13 @@ function GrpcPanel({ request: request2, onChange }) {
|
|
|
41076
41423
|
onChange({ body: { ...request2.body, mode: "grpc", grpc: { ...grpc, ...changes } } });
|
|
41077
41424
|
}
|
|
41078
41425
|
reactExports.useEffect(() => {
|
|
41079
|
-
electron$
|
|
41426
|
+
electron$y.onGrpcMessage(({ requestId, message }) => {
|
|
41080
41427
|
addGrpcMessage(requestId, message);
|
|
41081
41428
|
});
|
|
41082
|
-
electron$
|
|
41429
|
+
electron$y.onGrpcStatus(({ requestId, status, code, codeName, error: error2 }) => {
|
|
41083
41430
|
setGrpcStatus(requestId, status, { code, codeName, error: error2 });
|
|
41084
41431
|
});
|
|
41085
|
-
return () => electron$
|
|
41432
|
+
return () => electron$y.offGrpcEvents();
|
|
41086
41433
|
}, [addGrpcMessage, setGrpcStatus]);
|
|
41087
41434
|
reactExports.useEffect(() => {
|
|
41088
41435
|
logEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
@@ -41095,7 +41442,7 @@ function GrpcPanel({ request: request2, onChange }) {
|
|
|
41095
41442
|
if (!grpc.protoSource?.trim() && !grpc.protoPath?.trim()) return;
|
|
41096
41443
|
setLoadingProto(true);
|
|
41097
41444
|
try {
|
|
41098
|
-
const result = await electron$
|
|
41445
|
+
const result = await electron$y.grpcLoadProto({ protoSource: grpc.protoSource, protoPath: grpc.protoPath });
|
|
41099
41446
|
const services = result.services;
|
|
41100
41447
|
setGrpcServices(request2.id, services);
|
|
41101
41448
|
if (services.length && !services.some((s) => s.name === grpc.serviceName)) {
|
|
@@ -41114,7 +41461,7 @@ function GrpcPanel({ request: request2, onChange }) {
|
|
|
41114
41461
|
const metadata = {};
|
|
41115
41462
|
for (const m of grpc.metadata ?? []) if (m.enabled && m.key) metadata[m.key] = m.value;
|
|
41116
41463
|
try {
|
|
41117
|
-
await electron$
|
|
41464
|
+
await electron$y.grpcInvoke(request2.id, {
|
|
41118
41465
|
target: request2.url,
|
|
41119
41466
|
serviceName: grpc.serviceName,
|
|
41120
41467
|
methodName: grpc.methodName,
|
|
@@ -41129,7 +41476,7 @@ function GrpcPanel({ request: request2, onChange }) {
|
|
|
41129
41476
|
}
|
|
41130
41477
|
}
|
|
41131
41478
|
function cancel() {
|
|
41132
|
-
electron$
|
|
41479
|
+
electron$y.grpcCancel(request2.id);
|
|
41133
41480
|
}
|
|
41134
41481
|
const statusColors = {
|
|
41135
41482
|
running: "bg-amber-400",
|
|
@@ -41253,7 +41600,7 @@ function GrpcPanel({ request: request2, onChange }) {
|
|
|
41253
41600
|
] })
|
|
41254
41601
|
] });
|
|
41255
41602
|
}
|
|
41256
|
-
const { electron: electron$
|
|
41603
|
+
const { electron: electron$x } = window;
|
|
41257
41604
|
function isSubscriptionQuery(query) {
|
|
41258
41605
|
return /(^|\n)\s*subscription\b/i.test(query ?? "");
|
|
41259
41606
|
}
|
|
@@ -41302,7 +41649,7 @@ function GraphQlSubscription({ request: request2, gql, onPatch }) {
|
|
|
41302
41649
|
const headers = {};
|
|
41303
41650
|
for (const h of request2.headers) if (h.enabled && h.key) headers[interp(h.key)] = interp(h.value);
|
|
41304
41651
|
try {
|
|
41305
|
-
await electron$
|
|
41652
|
+
await electron$x.graphqlWsSubscribe(request2.id, {
|
|
41306
41653
|
url,
|
|
41307
41654
|
headers,
|
|
41308
41655
|
query: gql.query,
|
|
@@ -41319,7 +41666,7 @@ function GraphQlSubscription({ request: request2, gql, onPatch }) {
|
|
|
41319
41666
|
const url = deriveWsUrl(interp(rawUrl));
|
|
41320
41667
|
const headers = {};
|
|
41321
41668
|
for (const h of request2.headers) if (h.enabled && h.key) headers[interp(h.key)] = interp(h.value);
|
|
41322
|
-
return electron$
|
|
41669
|
+
return electron$x.graphqlWsTest({
|
|
41323
41670
|
url,
|
|
41324
41671
|
headers,
|
|
41325
41672
|
query: gql.query,
|
|
@@ -41354,7 +41701,7 @@ function GraphQlSubscription({ request: request2, gql, onPatch }) {
|
|
|
41354
41701
|
className: "flex-1 bg-surface-800 border border-surface-700 rounded px-2 py-1 text-xs font-mono focus:outline-none focus:border-blue-500 placeholder-surface-600 disabled:opacity-50"
|
|
41355
41702
|
}
|
|
41356
41703
|
),
|
|
41357
|
-
isActive ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => electron$
|
|
41704
|
+
isActive ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => electron$x.graphqlWsStop(request2.id), className: "px-3 py-1 bg-red-700 hover:bg-red-600 rounded text-xs font-medium transition-colors whitespace-nowrap", children: conn.status === "connecting" ? t("Connecting…") : t("Stop") }) : /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: subscribe, className: "px-3 py-1 bg-fuchsia-700 hover:bg-fuchsia-600 rounded text-xs font-medium transition-colors whitespace-nowrap", children: t("Subscribe") })
|
|
41358
41705
|
] }),
|
|
41359
41706
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-shrink-0", children: [
|
|
41360
41707
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () => setShowParams((v) => !v), className: "text-[10px] text-surface-600 hover:text-surface-300 transition-colors", children: [
|
|
@@ -41622,7 +41969,7 @@ function FuzzResultsPanel({ report, onClear }) {
|
|
|
41622
41969
|
] }) })
|
|
41623
41970
|
] });
|
|
41624
41971
|
}
|
|
41625
|
-
const { electron: electron$
|
|
41972
|
+
const { electron: electron$w } = window;
|
|
41626
41973
|
const WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
41627
41974
|
function FuzzModal({ request: request2, onClose }) {
|
|
41628
41975
|
const t = useT();
|
|
@@ -41650,7 +41997,7 @@ function FuzzModal({ request: request2, onClose }) {
|
|
|
41650
41997
|
const env2 = resolveEnvironmentById(environments, activeEnvironmentId);
|
|
41651
41998
|
const envVars = env2 ? Object.fromEntries(env2.variables.filter((v) => v.enabled).map((v) => [v.key, v.value])) : {};
|
|
41652
41999
|
const collectionVars = activeCollectionId ? collections[activeCollectionId]?.data.collectionVariables ?? {} : {};
|
|
41653
|
-
const result = await electron$
|
|
42000
|
+
const result = await electron$w.fuzzContracts({
|
|
41654
42001
|
requests: [request2],
|
|
41655
42002
|
envVars,
|
|
41656
42003
|
collectionVars,
|
|
@@ -41867,7 +42214,7 @@ function resolveAskValues(asks, answers) {
|
|
|
41867
42214
|
for (const a of asks) out[a.key] = answers[a.message] ?? "";
|
|
41868
42215
|
return out;
|
|
41869
42216
|
}
|
|
41870
|
-
const { electron: electron$
|
|
42217
|
+
const { electron: electron$v } = window;
|
|
41871
42218
|
const METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "QUERY"];
|
|
41872
42219
|
const METHOD_COLORS = {
|
|
41873
42220
|
GET: "text-emerald-400",
|
|
@@ -42013,7 +42360,7 @@ function RequestBuilder({ request: request2 }) {
|
|
|
42013
42360
|
const headers = {};
|
|
42014
42361
|
for (const h of request2.headers) if (h.enabled && h.key) headers[interp(h.key)] = interp(h.value);
|
|
42015
42362
|
try {
|
|
42016
|
-
await electron$
|
|
42363
|
+
await electron$v.graphqlWsSubscribe(request2.id, {
|
|
42017
42364
|
url,
|
|
42018
42365
|
headers,
|
|
42019
42366
|
query: gql.query,
|
|
@@ -42074,7 +42421,7 @@ function RequestBuilder({ request: request2 }) {
|
|
|
42074
42421
|
const start2 = Date.now();
|
|
42075
42422
|
try {
|
|
42076
42423
|
const hookEnv = withEnvOverrides(activeEnv, liveEnvOverrides);
|
|
42077
|
-
const r = await electron$
|
|
42424
|
+
const r = await electron$v.sendRequest({
|
|
42078
42425
|
...basePayload,
|
|
42079
42426
|
environment: hookEnv,
|
|
42080
42427
|
request: hook,
|
|
@@ -42126,7 +42473,7 @@ function RequestBuilder({ request: request2 }) {
|
|
|
42126
42473
|
startLiveStream(activeTabId, streamId);
|
|
42127
42474
|
let result;
|
|
42128
42475
|
try {
|
|
42129
|
-
result = await electron$
|
|
42476
|
+
result = await electron$v.sendRequest({
|
|
42130
42477
|
...basePayload,
|
|
42131
42478
|
environment: freshEnv,
|
|
42132
42479
|
request: mergedRequest,
|
|
@@ -42163,7 +42510,7 @@ function RequestBuilder({ request: request2 }) {
|
|
|
42163
42510
|
const start2 = Date.now();
|
|
42164
42511
|
try {
|
|
42165
42512
|
const hookEnv = withEnvOverrides(activeEnv, liveEnvOverrides);
|
|
42166
|
-
const r = await electron$
|
|
42513
|
+
const r = await electron$v.sendRequest({
|
|
42167
42514
|
...basePayload,
|
|
42168
42515
|
environment: hookEnv,
|
|
42169
42516
|
request: hook,
|
|
@@ -43346,7 +43693,7 @@ function Cell({ value: value2, onDrill }) {
|
|
|
43346
43693
|
const text = String(value2);
|
|
43347
43694
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "inline-block max-w-[26rem] truncate align-bottom text-surface-300", title: text.length > 40 ? text : void 0, children: text });
|
|
43348
43695
|
}
|
|
43349
|
-
const { electron: electron$
|
|
43696
|
+
const { electron: electron$u } = window;
|
|
43350
43697
|
const RENDER_TAIL = 500;
|
|
43351
43698
|
const CLOSE_LABEL = {
|
|
43352
43699
|
complete: "closed",
|
|
@@ -43388,7 +43735,7 @@ function StreamView({ events, streaming: streaming2, streamId, streamClose, firs
|
|
|
43388
43735
|
if (!streamId) return;
|
|
43389
43736
|
setStopping(true);
|
|
43390
43737
|
try {
|
|
43391
|
-
await electron$
|
|
43738
|
+
await electron$u.stopStream(streamId);
|
|
43392
43739
|
} catch {
|
|
43393
43740
|
}
|
|
43394
43741
|
}
|
|
@@ -43531,7 +43878,7 @@ function HookResultsPanel({ results }) {
|
|
|
43531
43878
|
}) })
|
|
43532
43879
|
] });
|
|
43533
43880
|
}
|
|
43534
|
-
const { electron: electron$
|
|
43881
|
+
const { electron: electron$t } = window;
|
|
43535
43882
|
function extractPath(url) {
|
|
43536
43883
|
try {
|
|
43537
43884
|
return new URL(url).pathname || "/";
|
|
@@ -43586,14 +43933,14 @@ function SaveAsMockModal({ onClose }) {
|
|
|
43586
43933
|
const entry = state.mocks[serverId];
|
|
43587
43934
|
const updated = { ...entry.data, name: newServerName, port: Number(newServerPort), routes: [route] };
|
|
43588
43935
|
updateMock(serverId, updated);
|
|
43589
|
-
await electron$
|
|
43936
|
+
await electron$t.saveMock(entry.relPath, updated);
|
|
43590
43937
|
const ws = useStore$1.getState().workspace;
|
|
43591
|
-
if (ws) await electron$
|
|
43938
|
+
if (ws) await electron$t.saveWorkspace(ws);
|
|
43592
43939
|
} else {
|
|
43593
43940
|
const entry = useStore$1.getState().mocks[serverId];
|
|
43594
43941
|
const updated = { ...entry.data, routes: [...entry.data.routes, route] };
|
|
43595
43942
|
updateMock(serverId, updated);
|
|
43596
|
-
await electron$
|
|
43943
|
+
await electron$t.saveMock(entry.relPath, updated);
|
|
43597
43944
|
}
|
|
43598
43945
|
onClose();
|
|
43599
43946
|
} finally {
|
|
@@ -44111,7 +44458,7 @@ function validateHttpSemantics(res, opts = {}) {
|
|
|
44111
44458
|
const order = { error: 0, warning: 1, hint: 2 };
|
|
44112
44459
|
return f.sort((a, b) => order[a.severity] - order[b.severity]);
|
|
44113
44460
|
}
|
|
44114
|
-
const { electron: electron$
|
|
44461
|
+
const { electron: electron$s } = window;
|
|
44115
44462
|
function xmlWellFormed(body) {
|
|
44116
44463
|
try {
|
|
44117
44464
|
const doc = new DOMParser().parseFromString(body, "application/xml");
|
|
@@ -44227,6 +44574,7 @@ function ResponseViewer() {
|
|
|
44227
44574
|
const setTabRequestTab = useStore$1((s) => s.setTabRequestTab);
|
|
44228
44575
|
const openContractDesigner = useStore$1((s) => s.openContractDesigner);
|
|
44229
44576
|
const setTabScriptTab = useStore$1((s) => s.setTabScriptTab);
|
|
44577
|
+
const setTabJqExpr = useStore$1((s) => s.setTabJqExpr);
|
|
44230
44578
|
const isSending = activeTab?.isSending ?? false;
|
|
44231
44579
|
const liveStream = useStore$1((s) => s.liveStream);
|
|
44232
44580
|
const streamForTab = liveStream?.tabId === activeTabId ? liveStream : null;
|
|
@@ -44306,7 +44654,7 @@ function ResponseViewer() {
|
|
|
44306
44654
|
const [diffMode, setDiffMode] = reactExports.useState(false);
|
|
44307
44655
|
const [showMockModal, setShowMockModal] = reactExports.useState(false);
|
|
44308
44656
|
const [bodyView, setBodyView] = reactExports.useState("raw");
|
|
44309
|
-
const
|
|
44657
|
+
const jqExpr = activeTab?.jqExpr ?? "";
|
|
44310
44658
|
const [jqResult, setJqResult] = reactExports.useState(null);
|
|
44311
44659
|
const [jqError, setJqError] = reactExports.useState(null);
|
|
44312
44660
|
reactExports.useEffect(() => {
|
|
@@ -44341,7 +44689,7 @@ function ResponseViewer() {
|
|
|
44341
44689
|
const schemaCheck = currentRequest?.schema?.trim() && response && !response.error ? validateBodyAgainstSchema(currentRequest.schema, response.body) : null;
|
|
44342
44690
|
async function saveAsSchema() {
|
|
44343
44691
|
if (!response || !requestId || !activeTabId) return;
|
|
44344
|
-
const schema = response.body ? await electron$
|
|
44692
|
+
const schema = response.body ? await electron$s.inferContractSchema(response.body) : null;
|
|
44345
44693
|
if (!schema) return;
|
|
44346
44694
|
updateRequest(requestId, { schema });
|
|
44347
44695
|
setTabRequestTab(activeTabId, "schema");
|
|
@@ -44548,7 +44896,9 @@ function ResponseViewer() {
|
|
|
44548
44896
|
"input",
|
|
44549
44897
|
{
|
|
44550
44898
|
value: jqExpr,
|
|
44551
|
-
onChange: (e) =>
|
|
44899
|
+
onChange: (e) => {
|
|
44900
|
+
if (activeTabId) setTabJqExpr(activeTabId, e.target.value);
|
|
44901
|
+
},
|
|
44552
44902
|
spellCheck: false,
|
|
44553
44903
|
placeholder: t("jq filter, e.g. .data | map(.id)"),
|
|
44554
44904
|
title: t("Filter this JSON response with a jq expression"),
|
|
@@ -44929,7 +45279,7 @@ function listFolders(root2, depth = 0, out = []) {
|
|
|
44929
45279
|
}
|
|
44930
45280
|
return out;
|
|
44931
45281
|
}
|
|
44932
|
-
const { electron: electron$
|
|
45282
|
+
const { electron: electron$r } = window;
|
|
44933
45283
|
function fmtMs(ms) {
|
|
44934
45284
|
if (ms < 1) return "<1 ms";
|
|
44935
45285
|
if (ms < 1e3) return `${Math.round(ms)} ms`;
|
|
@@ -45120,11 +45470,11 @@ function PerformancePanel() {
|
|
|
45120
45470
|
setError("");
|
|
45121
45471
|
}, [activeId]);
|
|
45122
45472
|
reactExports.useEffect(() => {
|
|
45123
|
-
electron$
|
|
45473
|
+
electron$r.onPerfProgress((p) => {
|
|
45124
45474
|
setProgress(p);
|
|
45125
45475
|
setSamples((s) => [...s, p].slice(-240));
|
|
45126
45476
|
});
|
|
45127
|
-
return () => electron$
|
|
45477
|
+
return () => electron$r.offPerfEvents();
|
|
45128
45478
|
}, []);
|
|
45129
45479
|
const requestOptions = reactExports.useMemo(() => {
|
|
45130
45480
|
const out = [];
|
|
@@ -45171,7 +45521,7 @@ function PerformancePanel() {
|
|
|
45171
45521
|
if (saveTimer2.current) clearTimeout(saveTimer2.current);
|
|
45172
45522
|
saveTimer2.current = setTimeout(() => {
|
|
45173
45523
|
const ws = useStore$1.getState().workspace;
|
|
45174
|
-
if (ws) void electron$
|
|
45524
|
+
if (ws) void electron$r.saveWorkspace(ws);
|
|
45175
45525
|
}, 500);
|
|
45176
45526
|
}
|
|
45177
45527
|
async function run() {
|
|
@@ -45196,7 +45546,7 @@ function PerformancePanel() {
|
|
|
45196
45546
|
collections: Object.values(collections).map((c) => c.data),
|
|
45197
45547
|
...common
|
|
45198
45548
|
};
|
|
45199
|
-
setResult(await electron$
|
|
45549
|
+
setResult(await electron$r.perfRun(payload));
|
|
45200
45550
|
} catch (err) {
|
|
45201
45551
|
setError(err instanceof Error ? err.message : String(err));
|
|
45202
45552
|
} finally {
|
|
@@ -45205,14 +45555,14 @@ function PerformancePanel() {
|
|
|
45205
45555
|
}
|
|
45206
45556
|
}
|
|
45207
45557
|
async function stop() {
|
|
45208
|
-
await electron$
|
|
45558
|
+
await electron$r.perfStop();
|
|
45209
45559
|
}
|
|
45210
45560
|
async function exportReport() {
|
|
45211
45561
|
if (!result || !plan) return;
|
|
45212
45562
|
setExporting(true);
|
|
45213
45563
|
try {
|
|
45214
45564
|
const target = plan.target.kind === "request" ? selectedRequest?.name ?? "request" : selectedFlow?.name ?? "flow";
|
|
45215
|
-
await electron$
|
|
45565
|
+
await electron$r.perfExportHtml(result, { planName: plan.name, target });
|
|
45216
45566
|
} catch (err) {
|
|
45217
45567
|
setError(err instanceof Error ? err.message : String(err));
|
|
45218
45568
|
} finally {
|
|
@@ -45647,7 +45997,7 @@ function PerformancePanel() {
|
|
|
45647
45997
|
!result && !running && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 flex items-center justify-center text-sm text-surface-500", children: t("Set the load and run this plan.") })
|
|
45648
45998
|
] });
|
|
45649
45999
|
}
|
|
45650
|
-
const { electron: electron$
|
|
46000
|
+
const { electron: electron$q } = window;
|
|
45651
46001
|
function makePlan(name) {
|
|
45652
46002
|
return {
|
|
45653
46003
|
id: crypto.randomUUID(),
|
|
@@ -45684,7 +46034,7 @@ function PerfPlansPanel() {
|
|
|
45684
46034
|
const updated = { ...workspace, perfPlans: next };
|
|
45685
46035
|
setWorkspace(updated, workspacePath ?? "");
|
|
45686
46036
|
try {
|
|
45687
|
-
await electron$
|
|
46037
|
+
await electron$q.saveWorkspace(updated);
|
|
45688
46038
|
} catch {
|
|
45689
46039
|
}
|
|
45690
46040
|
}
|
|
@@ -45828,7 +46178,7 @@ class ErrorBoundary extends React.Component {
|
|
|
45828
46178
|
] });
|
|
45829
46179
|
}
|
|
45830
46180
|
}
|
|
45831
|
-
const { electron: electron$
|
|
46181
|
+
const { electron: electron$p } = window;
|
|
45832
46182
|
const TARGETS = [
|
|
45833
46183
|
{ id: "robot_framework", label: "Robot Framework", description: "Python RequestsLibrary keywords + test suite" },
|
|
45834
46184
|
{ id: "playwright_ts", label: "Playwright TS", description: "TypeScript page-object API classes + spec files" },
|
|
@@ -45870,7 +46220,7 @@ function GeneratorPanel() {
|
|
|
45870
46220
|
try {
|
|
45871
46221
|
const col = collections[selectedCollectionId]?.data;
|
|
45872
46222
|
const env2 = resolveEnvironmentById(environments, activeEnvironmentId);
|
|
45873
|
-
const generated = await electron$
|
|
46223
|
+
const generated = await electron$p.generateCode({ collection: col, environment: env2, target });
|
|
45874
46224
|
setFiles(generated);
|
|
45875
46225
|
setSelectedFile(generated[0]?.path ?? null);
|
|
45876
46226
|
} catch (e) {
|
|
@@ -45882,7 +46232,7 @@ function GeneratorPanel() {
|
|
|
45882
46232
|
async function saveZip() {
|
|
45883
46233
|
if (files.length === 0) return;
|
|
45884
46234
|
const col = collections[selectedCollectionId]?.data;
|
|
45885
|
-
await electron$
|
|
46235
|
+
await electron$p.saveGeneratedFilesAsZip(files, col?.name ?? "api-tests", target);
|
|
45886
46236
|
}
|
|
45887
46237
|
const selectedContent = files.find((f) => f.path === selectedFile)?.content ?? "";
|
|
45888
46238
|
const activeTarget = TARGETS.find((tgt) => tgt.id === target);
|
|
@@ -46066,7 +46416,7 @@ function historyToHar(entries, creatorVersion = "1.0") {
|
|
|
46066
46416
|
}
|
|
46067
46417
|
}, null, 2);
|
|
46068
46418
|
}
|
|
46069
|
-
const { electron: electron$
|
|
46419
|
+
const { electron: electron$o } = window;
|
|
46070
46420
|
const STATUS_COLOR = {
|
|
46071
46421
|
"2": "text-emerald-400",
|
|
46072
46422
|
"3": "text-amber-400",
|
|
@@ -46120,7 +46470,7 @@ function HistoryPanel() {
|
|
|
46120
46470
|
}, [history, search]);
|
|
46121
46471
|
async function downloadHar() {
|
|
46122
46472
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replaceAll(/[:T]/g, "-");
|
|
46123
|
-
await electron$
|
|
46473
|
+
await electron$o.saveResults(historyToHar(history), `api-spector-history-${stamp}.har`);
|
|
46124
46474
|
}
|
|
46125
46475
|
function open2(entry) {
|
|
46126
46476
|
setSelected(entry);
|
|
@@ -46248,7 +46598,7 @@ function HistoryRow({
|
|
|
46248
46598
|
}
|
|
46249
46599
|
);
|
|
46250
46600
|
}
|
|
46251
|
-
const { electron: electron$
|
|
46601
|
+
const { electron: electron$n } = window;
|
|
46252
46602
|
function WelcomeScreen() {
|
|
46253
46603
|
const t = useT();
|
|
46254
46604
|
const { applyWorkspace } = useWorkspaceLoader();
|
|
@@ -46261,10 +46611,10 @@ function WelcomeScreen() {
|
|
|
46261
46611
|
const busyRef = reactExports.useRef(false);
|
|
46262
46612
|
const [busy, setBusy] = reactExports.useState(false);
|
|
46263
46613
|
reactExports.useEffect(() => {
|
|
46264
|
-
electron$
|
|
46265
|
-
electron$
|
|
46614
|
+
electron$n.getRecentWorkspaces().then(setRecents).catch(() => setRecents([]));
|
|
46615
|
+
electron$n.getUpdateMode().then((mode) => {
|
|
46266
46616
|
if (mode !== "npm") return;
|
|
46267
|
-
return electron$
|
|
46617
|
+
return electron$n.checkForUpdate().then((info) => {
|
|
46268
46618
|
if (info?.updateAvailable) setUpdate(info);
|
|
46269
46619
|
});
|
|
46270
46620
|
}).catch(() => {
|
|
@@ -46275,7 +46625,7 @@ function WelcomeScreen() {
|
|
|
46275
46625
|
busyRef.current = true;
|
|
46276
46626
|
setBusy(true);
|
|
46277
46627
|
try {
|
|
46278
|
-
const result = await electron$
|
|
46628
|
+
const result = await electron$n.openWorkspace();
|
|
46279
46629
|
if (result) await applyWorkspace(result.workspace, result.workspacePath);
|
|
46280
46630
|
} finally {
|
|
46281
46631
|
busyRef.current = false;
|
|
@@ -46287,7 +46637,7 @@ function WelcomeScreen() {
|
|
|
46287
46637
|
busyRef.current = true;
|
|
46288
46638
|
setBusy(true);
|
|
46289
46639
|
try {
|
|
46290
|
-
const result = await electron$
|
|
46640
|
+
const result = await electron$n.newWorkspace();
|
|
46291
46641
|
if (result) await applyWorkspace(result.workspace, result.workspacePath);
|
|
46292
46642
|
} finally {
|
|
46293
46643
|
busyRef.current = false;
|
|
@@ -46301,7 +46651,7 @@ function WelcomeScreen() {
|
|
|
46301
46651
|
setGitBusy(true);
|
|
46302
46652
|
setGitError(null);
|
|
46303
46653
|
try {
|
|
46304
|
-
const result = await electron$
|
|
46654
|
+
const result = await electron$n.openFromGit(url);
|
|
46305
46655
|
if (!result) return;
|
|
46306
46656
|
await applyWorkspace(result.workspace, result.workspacePath);
|
|
46307
46657
|
} catch (err) {
|
|
@@ -46316,7 +46666,7 @@ function WelcomeScreen() {
|
|
|
46316
46666
|
busyRef.current = true;
|
|
46317
46667
|
setBusy(true);
|
|
46318
46668
|
try {
|
|
46319
|
-
const result = await electron$
|
|
46669
|
+
const result = await electron$n.openWorkspacePath(path);
|
|
46320
46670
|
if (!result) {
|
|
46321
46671
|
setRecents((prev) => prev.filter((r) => r.path !== path));
|
|
46322
46672
|
return;
|
|
@@ -46352,7 +46702,7 @@ function WelcomeScreen() {
|
|
|
46352
46702
|
)
|
|
46353
46703
|
] }),
|
|
46354
46704
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-400 text-sm max-w-sm", children: t("Local-first API testing with Robot Framework & Playwright code generation. Secrets stay on your machine.") }),
|
|
46355
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t("version :version", { version: "0.9.
|
|
46705
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t("version :version", { version: "0.9.3" }) })
|
|
46356
46706
|
] }),
|
|
46357
46707
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 w-64", children: [
|
|
46358
46708
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -46434,7 +46784,7 @@ function WelcomeScreen() {
|
|
|
46434
46784
|
] })
|
|
46435
46785
|
] });
|
|
46436
46786
|
}
|
|
46437
|
-
const { electron: electron$
|
|
46787
|
+
const { electron: electron$m } = window;
|
|
46438
46788
|
const EXAMPLES = [
|
|
46439
46789
|
{
|
|
46440
46790
|
label: "macOS / Linux (~/.zshrc or ~/.bashrc)",
|
|
@@ -46459,7 +46809,7 @@ function MasterKeyModal({ onSuccess, onCancel }) {
|
|
|
46459
46809
|
setError(t("Password cannot be empty."));
|
|
46460
46810
|
return;
|
|
46461
46811
|
}
|
|
46462
|
-
await electron$
|
|
46812
|
+
await electron$m.setMasterKey(password);
|
|
46463
46813
|
onSuccess(password);
|
|
46464
46814
|
}
|
|
46465
46815
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
@@ -46538,7 +46888,7 @@ function MasterKeyModal({ onSuccess, onCancel }) {
|
|
|
46538
46888
|
}
|
|
46539
46889
|
);
|
|
46540
46890
|
}
|
|
46541
|
-
const { electron: electron$
|
|
46891
|
+
const { electron: electron$l } = window;
|
|
46542
46892
|
async function shortHash(value2) {
|
|
46543
46893
|
const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value2));
|
|
46544
46894
|
return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8);
|
|
@@ -46653,12 +47003,12 @@ function EnvironmentEditor({ onClose }) {
|
|
|
46653
47003
|
if (next) setSelectedId(next);
|
|
46654
47004
|
}
|
|
46655
47005
|
async function importFromPostman() {
|
|
46656
|
-
const imported = await electron$
|
|
47006
|
+
const imported = await electron$l.importPostmanEnvironment();
|
|
46657
47007
|
if (!imported) return;
|
|
46658
47008
|
const existingNames = Object.values(useStore$1.getState().environments).map((e) => e.data.name);
|
|
46659
47009
|
const finalEnv = { ...imported, name: uniqueName$1(imported.name || t("Imported Environment"), existingNames) };
|
|
46660
47010
|
const relPath = envRelPath(finalEnv.name, finalEnv.id);
|
|
46661
|
-
await electron$
|
|
47011
|
+
await electron$l.saveEnvironment(relPath, finalEnv);
|
|
46662
47012
|
useStore$1.setState((s) => {
|
|
46663
47013
|
s.environments[finalEnv.id] = { relPath, data: finalEnv };
|
|
46664
47014
|
if (!s.activeEnvironmentId) s.activeEnvironmentId = finalEnv.id;
|
|
@@ -46668,7 +47018,7 @@ function EnvironmentEditor({ onClose }) {
|
|
|
46668
47018
|
return s;
|
|
46669
47019
|
});
|
|
46670
47020
|
const ws = useStore$1.getState().workspace;
|
|
46671
|
-
if (ws) await electron$
|
|
47021
|
+
if (ws) await electron$l.saveWorkspace(ws);
|
|
46672
47022
|
setSelectedId(finalEnv.id);
|
|
46673
47023
|
}
|
|
46674
47024
|
function updateVar(idx, patch) {
|
|
@@ -46721,9 +47071,9 @@ function EnvironmentEditor({ onClose }) {
|
|
|
46721
47071
|
async function saveEncrypted(idx) {
|
|
46722
47072
|
const plaintext = secretInputs[idx] ?? "";
|
|
46723
47073
|
if (!plaintext) return;
|
|
46724
|
-
const { set: set2 } = await electron$
|
|
47074
|
+
const { set: set2 } = await electron$l.checkMasterKey();
|
|
46725
47075
|
if (set2) {
|
|
46726
|
-
applyEncrypted(idx, await electron$
|
|
47076
|
+
applyEncrypted(idx, await electron$l.encryptWithMasterKey(plaintext));
|
|
46727
47077
|
return;
|
|
46728
47078
|
}
|
|
46729
47079
|
setPendingEncryptIdx(idx);
|
|
@@ -46758,9 +47108,9 @@ function EnvironmentEditor({ onClose }) {
|
|
|
46758
47108
|
} : state.workspace
|
|
46759
47109
|
}));
|
|
46760
47110
|
const ws = useStore$1.getState().workspace;
|
|
46761
|
-
if (ws) await electron$
|
|
47111
|
+
if (ws) await electron$l.saveWorkspace(ws);
|
|
46762
47112
|
}
|
|
46763
|
-
await electron$
|
|
47113
|
+
await electron$l.saveEnvironment(newRelPath, env2);
|
|
46764
47114
|
}
|
|
46765
47115
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
46766
47116
|
confirmDialog,
|
|
@@ -47125,7 +47475,7 @@ function EnvironmentEditor({ onClose }) {
|
|
|
47125
47475
|
)
|
|
47126
47476
|
] });
|
|
47127
47477
|
}
|
|
47128
|
-
const { electron: electron$
|
|
47478
|
+
const { electron: electron$k } = window;
|
|
47129
47479
|
function EnvironmentBar({ inline = false }) {
|
|
47130
47480
|
const t = useT();
|
|
47131
47481
|
const environments = useStore$1((s) => s.environments);
|
|
@@ -47141,7 +47491,7 @@ function EnvironmentBar({ inline = false }) {
|
|
|
47141
47491
|
if (id2) {
|
|
47142
47492
|
const hasSecrets = environments[id2]?.data.variables.some((v) => v.enabled && v.secret);
|
|
47143
47493
|
if (hasSecrets) {
|
|
47144
|
-
const { set: set2 } = await electron$
|
|
47494
|
+
const { set: set2 } = await electron$k.checkMasterKey();
|
|
47145
47495
|
if (!set2) {
|
|
47146
47496
|
setPendingEnvId(id2);
|
|
47147
47497
|
return;
|
|
@@ -47348,10 +47698,204 @@ function ProductTour() {
|
|
|
47348
47698
|
)
|
|
47349
47699
|
] });
|
|
47350
47700
|
}
|
|
47701
|
+
const { electron: electron$j } = window;
|
|
47702
|
+
function getSyncSettings() {
|
|
47703
|
+
return useStore$1.getState().workspace?.settings?.sync ?? { mode: "git" };
|
|
47704
|
+
}
|
|
47705
|
+
async function persistSync(patch) {
|
|
47706
|
+
const s = useStore$1.getState();
|
|
47707
|
+
const ws = s.workspace;
|
|
47708
|
+
if (!ws) return;
|
|
47709
|
+
const sync = { ...ws.settings?.sync ?? { mode: "cloud" }, ...patch };
|
|
47710
|
+
const settings = { ...ws.settings, sync };
|
|
47711
|
+
s.updateWorkspaceSettings(settings);
|
|
47712
|
+
await electron$j.saveWorkspace({ ...ws, settings });
|
|
47713
|
+
}
|
|
47714
|
+
async function setSyncMode(mode) {
|
|
47715
|
+
await persistSync({ mode });
|
|
47716
|
+
}
|
|
47717
|
+
function workspaceName(manifestName) {
|
|
47718
|
+
return manifestName.replace(/\.(spector|json)$/i, "") || "Workspace";
|
|
47719
|
+
}
|
|
47720
|
+
async function flushToDisk() {
|
|
47721
|
+
const s = useStore$1.getState();
|
|
47722
|
+
for (const { relPath, data, dirty } of Object.values(s.collections)) {
|
|
47723
|
+
if (!dirty) continue;
|
|
47724
|
+
await electron$j.saveCollection(relPath, data);
|
|
47725
|
+
s.markCollectionClean(data.id);
|
|
47726
|
+
}
|
|
47727
|
+
for (const { relPath, data } of Object.values(s.environments)) {
|
|
47728
|
+
await electron$j.saveEnvironment(relPath, data);
|
|
47729
|
+
}
|
|
47730
|
+
for (const { relPath, data } of Object.values(s.flows)) {
|
|
47731
|
+
await electron$j.saveFlow(relPath, data);
|
|
47732
|
+
}
|
|
47733
|
+
if (s.workspace) await electron$j.saveWorkspace(s.workspace);
|
|
47734
|
+
}
|
|
47735
|
+
async function pushWorkspace() {
|
|
47736
|
+
const sync = getSyncSettings();
|
|
47737
|
+
await flushToDisk();
|
|
47738
|
+
const snap = await electron$j.serializeWorkspace();
|
|
47739
|
+
const files = snap.files ?? {};
|
|
47740
|
+
const collections = Object.keys(files).filter((p) => p.startsWith("collections/")).length;
|
|
47741
|
+
const flows = Object.keys(files).filter((p) => p.startsWith("flows/")).length;
|
|
47742
|
+
if (!sync.cloudWorkspaceId) {
|
|
47743
|
+
const created = await electron$j.cloudWorkspaceCreate({ name: workspaceName(snap.manifestName), payload: snap });
|
|
47744
|
+
await persistSync({ mode: "cloud", cloudWorkspaceId: created.id, baseVersion: created.version });
|
|
47745
|
+
return { ok: true, version: created.version, collections, flows };
|
|
47746
|
+
}
|
|
47747
|
+
const res = await electron$j.cloudWorkspacePush({
|
|
47748
|
+
id: sync.cloudWorkspaceId,
|
|
47749
|
+
baseVersion: sync.baseVersion ?? 0,
|
|
47750
|
+
payload: snap
|
|
47751
|
+
});
|
|
47752
|
+
if (res.conflict) return { ok: false, conflict: true, currentVersion: res.currentVersion };
|
|
47753
|
+
await persistSync({ baseVersion: res.version });
|
|
47754
|
+
return { ok: true, version: res.version ?? 0, collections, flows };
|
|
47755
|
+
}
|
|
47756
|
+
async function pullWorkspace() {
|
|
47757
|
+
const sync = getSyncSettings();
|
|
47758
|
+
if (!sync.cloudWorkspaceId) {
|
|
47759
|
+
throw new Error("This workspace is not linked to a cloud workspace yet. Push it first, or link an existing one.");
|
|
47760
|
+
}
|
|
47761
|
+
const remote = await electron$j.cloudWorkspacePull(sync.cloudWorkspaceId);
|
|
47762
|
+
const payload = remote.payload ?? {};
|
|
47763
|
+
if (!payload.manifest || !payload.files) {
|
|
47764
|
+
throw new Error("The cloud workspace has no snapshot yet. Push from a populated workspace first.");
|
|
47765
|
+
}
|
|
47766
|
+
const applied = await electron$j.applyWorkspaceSnapshot({ manifest: payload.manifest, files: payload.files });
|
|
47767
|
+
return {
|
|
47768
|
+
version: remote.version,
|
|
47769
|
+
filesWritten: applied.filesWritten,
|
|
47770
|
+
collections: applied.collections,
|
|
47771
|
+
workspace: applied.workspace,
|
|
47772
|
+
workspacePath: applied.workspacePath
|
|
47773
|
+
};
|
|
47774
|
+
}
|
|
47775
|
+
async function markPulled(version) {
|
|
47776
|
+
await persistSync({ baseVersion: version });
|
|
47777
|
+
}
|
|
47778
|
+
async function listCloudWorkspaces() {
|
|
47779
|
+
const res = await electron$j.cloudWorkspaceList();
|
|
47780
|
+
return res.workspaces;
|
|
47781
|
+
}
|
|
47782
|
+
async function linkToCloudWorkspace(id2) {
|
|
47783
|
+
await persistSync({ mode: "cloud", cloudWorkspaceId: id2, baseVersion: 0 });
|
|
47784
|
+
}
|
|
47785
|
+
function SyncSettingsPanel() {
|
|
47786
|
+
const t = useT();
|
|
47787
|
+
const { applyWorkspace } = useWorkspaceLoader();
|
|
47788
|
+
const initial = getSyncSettings();
|
|
47789
|
+
const [mode, setMode] = reactExports.useState(initial.mode);
|
|
47790
|
+
const [linked, setLinked] = reactExports.useState(!!initial.cloudWorkspaceId);
|
|
47791
|
+
const [busy, setBusy] = reactExports.useState(false);
|
|
47792
|
+
const [status, setStatus] = reactExports.useState(null);
|
|
47793
|
+
const [remote, setRemote] = reactExports.useState(null);
|
|
47794
|
+
const cloudOn = cloudEnabled();
|
|
47795
|
+
async function changeMode(m) {
|
|
47796
|
+
setMode(m);
|
|
47797
|
+
setStatus(null);
|
|
47798
|
+
try {
|
|
47799
|
+
await setSyncMode(m);
|
|
47800
|
+
} catch (e) {
|
|
47801
|
+
setStatus({ msg: e.message, ok: false });
|
|
47802
|
+
}
|
|
47803
|
+
}
|
|
47804
|
+
async function run(fn) {
|
|
47805
|
+
setBusy(true);
|
|
47806
|
+
setStatus(null);
|
|
47807
|
+
try {
|
|
47808
|
+
setStatus({ msg: await fn(), ok: true });
|
|
47809
|
+
} catch (e) {
|
|
47810
|
+
setStatus({ msg: e.message, ok: false });
|
|
47811
|
+
} finally {
|
|
47812
|
+
setBusy(false);
|
|
47813
|
+
}
|
|
47814
|
+
}
|
|
47815
|
+
const doPush = () => run(async () => {
|
|
47816
|
+
const res = await pushWorkspace();
|
|
47817
|
+
if (!res.ok) throw new Error(t("Someone else pushed changes (cloud is at v:v). Pull first, then push again.", { v: res.currentVersion ?? "?" }));
|
|
47818
|
+
setLinked(true);
|
|
47819
|
+
return t("Pushed :c collection(s) and :f flow(s). Cloud is now at version :v.", { c: res.collections, f: res.flows, v: res.version });
|
|
47820
|
+
});
|
|
47821
|
+
const doPull = () => run(async () => {
|
|
47822
|
+
const r = await pullWorkspace();
|
|
47823
|
+
await applyWorkspace(r.workspace, r.workspacePath);
|
|
47824
|
+
await markPulled(r.version);
|
|
47825
|
+
return t("Pulled version :v: :files file(s), :c collection(s).", { v: r.version, files: r.filesWritten, c: r.collections });
|
|
47826
|
+
});
|
|
47827
|
+
const loadRemote = () => run(async () => {
|
|
47828
|
+
const list = await listCloudWorkspaces();
|
|
47829
|
+
setRemote(list);
|
|
47830
|
+
return t(":n cloud workspace(s) in your organization.", { n: list.length });
|
|
47831
|
+
});
|
|
47832
|
+
const joinExisting = (id2) => run(async () => {
|
|
47833
|
+
await linkToCloudWorkspace(id2);
|
|
47834
|
+
const r = await pullWorkspace();
|
|
47835
|
+
await applyWorkspace(r.workspace, r.workspacePath);
|
|
47836
|
+
await markPulled(r.version);
|
|
47837
|
+
setLinked(true);
|
|
47838
|
+
return t("Linked and pulled: :files file(s), :c collection(s).", { files: r.filesWritten, c: r.collections });
|
|
47839
|
+
});
|
|
47840
|
+
const btn = "px-3 py-1.5 text-xs rounded border border-surface-700 text-surface-200 hover:bg-surface-800 disabled:opacity-50 transition-colors";
|
|
47841
|
+
const btnPrimary = "px-3 py-1.5 text-xs rounded font-medium text-white bg-sky-700 hover:bg-sky-600 disabled:opacity-50 transition-colors";
|
|
47842
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-5 text-sm text-surface-200", children: [
|
|
47843
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
47844
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-semibold text-[var(--text-primary)]", children: t("Workspace sync") }),
|
|
47845
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-400 mt-1", children: t("How this workspace is shared with your team. Git is the default; Cloud lets teams without git collaborate.") })
|
|
47846
|
+
] }),
|
|
47847
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex flex-col gap-1", children: [
|
|
47848
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs uppercase tracking-wide text-surface-500", children: t("Mode") }),
|
|
47849
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
47850
|
+
"select",
|
|
47851
|
+
{
|
|
47852
|
+
value: mode,
|
|
47853
|
+
onChange: (e) => changeMode(e.target.value),
|
|
47854
|
+
className: "rounded bg-surface-950 border border-surface-700 px-2 py-1.5 text-sm w-56",
|
|
47855
|
+
children: [
|
|
47856
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "git", children: t("Git (default) — use the Git panel") }),
|
|
47857
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "cloud", children: t("Cloud — sync through API Spector Cloud") }),
|
|
47858
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "local", children: t("Local only — no sync") })
|
|
47859
|
+
]
|
|
47860
|
+
}
|
|
47861
|
+
)
|
|
47862
|
+
] }),
|
|
47863
|
+
mode === "git" && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-400", children: t("This workspace syncs via Git. Use the Git panel in the sidebar to commit, pull and push.") }),
|
|
47864
|
+
mode === "local" && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-400", children: t("No syncing. Changes stay on this machine.") }),
|
|
47865
|
+
mode === "cloud" && !cloudOn && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-amber-400", children: t("Connect this workspace to API Spector Cloud first (the Cloud tab), then come back to sync.") }),
|
|
47866
|
+
mode === "cloud" && cloudOn && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
47867
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500", children: t("Collections, folders, requests, flows and environments sync. Secret values are never uploaded — each member keeps their own.") }),
|
|
47868
|
+
linked ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
47869
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: btnPrimary, disabled: busy, onClick: doPush, children: t("Push") }),
|
|
47870
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: btn, disabled: busy, onClick: doPull, children: t("Pull") })
|
|
47871
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
47872
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
47873
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: btnPrimary, disabled: busy, onClick: doPush, children: t("Create cloud workspace (push)") }),
|
|
47874
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: btn, disabled: busy, onClick: loadRemote, children: t("Join an existing one") })
|
|
47875
|
+
] }),
|
|
47876
|
+
remote && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded border border-surface-700 divide-y divide-surface-800", children: [
|
|
47877
|
+
remote.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 py-2 text-xs text-surface-500", children: t("No cloud workspaces yet.") }),
|
|
47878
|
+
remote.map((w) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-3 py-2", children: [
|
|
47879
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex-1 truncate", children: [
|
|
47880
|
+
w.name,
|
|
47881
|
+
" ",
|
|
47882
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-500", children: [
|
|
47883
|
+
"v",
|
|
47884
|
+
w.version
|
|
47885
|
+
] })
|
|
47886
|
+
] }),
|
|
47887
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: btn, disabled: busy, onClick: () => joinExisting(w.id), children: t("Join & pull") })
|
|
47888
|
+
] }, w.id))
|
|
47889
|
+
] })
|
|
47890
|
+
] })
|
|
47891
|
+
] }),
|
|
47892
|
+
status && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: `text-xs ${status.ok ? "text-emerald-400" : "text-red-400"}`, children: status.msg })
|
|
47893
|
+
] });
|
|
47894
|
+
}
|
|
47351
47895
|
const { electron: electron$i } = window;
|
|
47352
47896
|
const DEFAULT_PII_PATTERNS = ["authorization", "password", "token", "secret", "api-key", "x-api-key"];
|
|
47353
47897
|
const ZOOM_STEPS = [0.75, 0.9, 1, 1.1, 1.25, 1.5];
|
|
47354
|
-
const SETTINGS_TABS = ["general", "appearance", "proxy", "tls", "privacy", "cloud", "ai", "secrets"];
|
|
47898
|
+
const SETTINGS_TABS = ["general", "appearance", "proxy", "tls", "privacy", "cloud", "sync", "ai", "secrets"];
|
|
47355
47899
|
function WorkspaceSettingsModal({ onClose, initialTab }) {
|
|
47356
47900
|
const workspace = useStore$1((s) => s.workspace);
|
|
47357
47901
|
const updateWorkspaceSettings = useStore$1((s) => s.updateWorkspaceSettings);
|
|
@@ -47559,6 +48103,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
|
|
|
47559
48103
|
{ id: "privacy", label: t("Privacy") },
|
|
47560
48104
|
{ id: "secrets", label: t("Secrets") },
|
|
47561
48105
|
{ id: "cloud", label: t("Cloud") },
|
|
48106
|
+
{ id: "sync", label: t("Sync") },
|
|
47562
48107
|
{ id: "ai", label: t("AI") }
|
|
47563
48108
|
];
|
|
47564
48109
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
@@ -47883,6 +48428,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
|
|
|
47883
48428
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("Reject unauthorized / self-signed certificates") })
|
|
47884
48429
|
] })
|
|
47885
48430
|
] }),
|
|
48431
|
+
activeTab === "sync" && /* @__PURE__ */ jsxRuntimeExports.jsx(SyncSettingsPanel, {}),
|
|
47886
48432
|
activeTab === "ai" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
47887
48433
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-600 text-[11px] leading-relaxed", children: t("Optional. Configure an OpenAI key to generate documentation from the Docs tab of a request, folder, or collection. The key is stored only in your OS keychain and never written to the workspace file or version control.") }),
|
|
47888
48434
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
@@ -54572,6 +55118,16 @@ function ChangesTab({ status, onRefresh }) {
|
|
|
54572
55118
|
setError(String(e));
|
|
54573
55119
|
}
|
|
54574
55120
|
}
|
|
55121
|
+
async function stash() {
|
|
55122
|
+
try {
|
|
55123
|
+
setError(null);
|
|
55124
|
+
await electron$4.gitStash();
|
|
55125
|
+
showToast(t("Changes stashed - restore them from the Branches tab"), true);
|
|
55126
|
+
onRefresh();
|
|
55127
|
+
} catch (e) {
|
|
55128
|
+
setError(String(e));
|
|
55129
|
+
}
|
|
55130
|
+
}
|
|
54575
55131
|
async function fetch() {
|
|
54576
55132
|
setFetching(true);
|
|
54577
55133
|
try {
|
|
@@ -54624,6 +55180,7 @@ function ChangesTab({ status, onRefresh }) {
|
|
|
54624
55180
|
}
|
|
54625
55181
|
const allUnstaged = [...status.unstaged, ...status.untracked];
|
|
54626
55182
|
const hasStaged = status.staged.length > 0;
|
|
55183
|
+
const isDirty = hasStaged || status.unstaged.length > 0 || status.untracked.length > 0;
|
|
54627
55184
|
const needsPush = status.ahead > 0;
|
|
54628
55185
|
const needsPull = status.behind > 0;
|
|
54629
55186
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
@@ -54880,15 +55437,27 @@ function ChangesTab({ status, onRefresh }) {
|
|
|
54880
55437
|
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"
|
|
54881
55438
|
}
|
|
54882
55439
|
),
|
|
54883
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
54884
|
-
|
|
54885
|
-
|
|
54886
|
-
|
|
54887
|
-
|
|
54888
|
-
|
|
54889
|
-
|
|
54890
|
-
|
|
54891
|
-
|
|
55440
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
55441
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55442
|
+
"button",
|
|
55443
|
+
{
|
|
55444
|
+
onClick: commit,
|
|
55445
|
+
disabled: !message.trim() || !hasStaged,
|
|
55446
|
+
className: "flex-1 py-1.5 bg-blue-600 hover:bg-blue-500 disabled:opacity-40 disabled:cursor-not-allowed rounded text-xs font-medium transition-colors",
|
|
55447
|
+
children: hasStaged ? t("Commit (:count)", { count: status.staged.length }) : t("Commit")
|
|
55448
|
+
}
|
|
55449
|
+
),
|
|
55450
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55451
|
+
"button",
|
|
55452
|
+
{
|
|
55453
|
+
onClick: stash,
|
|
55454
|
+
disabled: !isDirty,
|
|
55455
|
+
title: t("Park all uncommitted changes - restore them later from the Branches tab"),
|
|
55456
|
+
className: "px-3 py-1.5 bg-surface-800 hover:bg-surface-700 border border-surface-700 disabled:opacity-40 disabled:cursor-not-allowed rounded text-xs font-medium text-surface-200 transition-colors",
|
|
55457
|
+
children: t("Stash")
|
|
55458
|
+
}
|
|
55459
|
+
)
|
|
55460
|
+
] })
|
|
54892
55461
|
] })
|
|
54893
55462
|
] });
|
|
54894
55463
|
}
|
|
@@ -54916,6 +55485,8 @@ function BranchesTab({ onRefresh }) {
|
|
|
54916
55485
|
const t = useT();
|
|
54917
55486
|
const [branches, setBranches] = reactExports.useState([]);
|
|
54918
55487
|
const [remotes, setRemotes] = reactExports.useState([]);
|
|
55488
|
+
const [stashes, setStashes] = reactExports.useState([]);
|
|
55489
|
+
const [info, setInfo] = reactExports.useState(null);
|
|
54919
55490
|
const [loading, setLoading] = reactExports.useState(true);
|
|
54920
55491
|
const [newBranch, setNewBranch] = reactExports.useState("");
|
|
54921
55492
|
const [creating, setCreating] = reactExports.useState(false);
|
|
@@ -54929,9 +55500,10 @@ function BranchesTab({ onRefresh }) {
|
|
|
54929
55500
|
const [filter2, setFilter] = reactExports.useState("");
|
|
54930
55501
|
const load2 = reactExports.useCallback(() => {
|
|
54931
55502
|
setLoadError(null);
|
|
54932
|
-
Promise.all([electron$4.gitBranches(), electron$4.gitRemotes()]).then(([b, r]) => {
|
|
55503
|
+
Promise.all([electron$4.gitBranches(), electron$4.gitRemotes(), electron$4.gitStashList()]).then(([b, r, s]) => {
|
|
54933
55504
|
setBranches(b);
|
|
54934
55505
|
setRemotes(r);
|
|
55506
|
+
setStashes(s);
|
|
54935
55507
|
}).catch((err) => {
|
|
54936
55508
|
console.warn("GitPanel: failed to load branches/remotes", err);
|
|
54937
55509
|
setLoadError(err instanceof Error ? err.message : String(err));
|
|
@@ -54940,13 +55512,34 @@ function BranchesTab({ onRefresh }) {
|
|
|
54940
55512
|
reactExports.useEffect(() => {
|
|
54941
55513
|
load2();
|
|
54942
55514
|
}, [load2]);
|
|
55515
|
+
function isDirtyTreeError(msg) {
|
|
55516
|
+
return /overwritten by (checkout|merge)|commit your changes or stash/i.test(msg);
|
|
55517
|
+
}
|
|
55518
|
+
async function checkoutOrStash(localName, create2) {
|
|
55519
|
+
try {
|
|
55520
|
+
await electron$4.gitCheckout(localName, create2);
|
|
55521
|
+
return true;
|
|
55522
|
+
} catch (e) {
|
|
55523
|
+
const msg = String(e);
|
|
55524
|
+
if (!isDirtyTreeError(msg)) throw e;
|
|
55525
|
+
if (!confirm(t('You have uncommitted changes that would be lost switching to ":name". Stash them and switch?', { name: localName }))) {
|
|
55526
|
+
return false;
|
|
55527
|
+
}
|
|
55528
|
+
await electron$4.gitStash(t("Auto-stash before switching to :name", { name: localName }));
|
|
55529
|
+
await electron$4.gitCheckout(localName, create2);
|
|
55530
|
+
setInfo(t("Your changes were stashed. Restore them from the Stashes list below when you return."));
|
|
55531
|
+
return true;
|
|
55532
|
+
}
|
|
55533
|
+
}
|
|
54943
55534
|
async function checkout(name, remote2) {
|
|
54944
55535
|
try {
|
|
54945
55536
|
setError(null);
|
|
55537
|
+
setInfo(null);
|
|
54946
55538
|
const localName = remote2 ? name.replace(/^origin\//, "") : name;
|
|
54947
|
-
await
|
|
54948
|
-
|
|
54949
|
-
|
|
55539
|
+
if (await checkoutOrStash(localName, false)) {
|
|
55540
|
+
load2();
|
|
55541
|
+
onRefresh();
|
|
55542
|
+
}
|
|
54950
55543
|
} catch (e) {
|
|
54951
55544
|
setError(String(e));
|
|
54952
55545
|
}
|
|
@@ -54955,15 +55548,39 @@ function BranchesTab({ onRefresh }) {
|
|
|
54955
55548
|
if (!newBranch.trim()) return;
|
|
54956
55549
|
try {
|
|
54957
55550
|
setError(null);
|
|
54958
|
-
|
|
54959
|
-
|
|
54960
|
-
|
|
55551
|
+
setInfo(null);
|
|
55552
|
+
if (await checkoutOrStash(newBranch.trim(), true)) {
|
|
55553
|
+
setNewBranch("");
|
|
55554
|
+
setCreating(false);
|
|
55555
|
+
load2();
|
|
55556
|
+
onRefresh();
|
|
55557
|
+
}
|
|
55558
|
+
} catch (e) {
|
|
55559
|
+
setError(String(e));
|
|
55560
|
+
}
|
|
55561
|
+
}
|
|
55562
|
+
async function popStash(ref) {
|
|
55563
|
+
try {
|
|
55564
|
+
setError(null);
|
|
55565
|
+
setInfo(null);
|
|
55566
|
+
await electron$4.gitStashPop(ref);
|
|
54961
55567
|
load2();
|
|
54962
55568
|
onRefresh();
|
|
54963
55569
|
} catch (e) {
|
|
54964
55570
|
setError(String(e));
|
|
54965
55571
|
}
|
|
54966
55572
|
}
|
|
55573
|
+
async function dropStash(ref) {
|
|
55574
|
+
if (!confirm(t("Discard stashed changes (:ref)? This cannot be undone.", { ref }))) return;
|
|
55575
|
+
try {
|
|
55576
|
+
setError(null);
|
|
55577
|
+
setInfo(null);
|
|
55578
|
+
await electron$4.gitStashDrop(ref);
|
|
55579
|
+
load2();
|
|
55580
|
+
} catch (e) {
|
|
55581
|
+
setError(String(e));
|
|
55582
|
+
}
|
|
55583
|
+
}
|
|
54967
55584
|
async function addRemote() {
|
|
54968
55585
|
if (!remoteName.trim() || !remoteUrl.trim()) return;
|
|
54969
55586
|
try {
|
|
@@ -55022,7 +55639,8 @@ function BranchesTab({ onRefresh }) {
|
|
|
55022
55639
|
const remote = branches.filter((b) => b.remote && (!q || b.name.toLowerCase().includes(q)));
|
|
55023
55640
|
if (loading) return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 px-3 py-4", children: t("Loading…") });
|
|
55024
55641
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0 overflow-y-auto", children: [
|
|
55025
|
-
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-red-400 px-3 py-1 truncate", children: error2 }),
|
|
55642
|
+
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-red-400 px-3 py-1 truncate", title: error2, children: error2 }),
|
|
55643
|
+
info && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-blue-300 px-3 py-1 bg-blue-900/20 border-b border-surface-800", children: info }),
|
|
55026
55644
|
loadError && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-amber-400 px-3 py-1 truncate", title: loadError, children: [
|
|
55027
55645
|
t("Couldn't load git state:"),
|
|
55028
55646
|
" ",
|
|
@@ -55114,6 +55732,37 @@ function BranchesTab({ onRefresh }) {
|
|
|
55114
55732
|
))
|
|
55115
55733
|
] }),
|
|
55116
55734
|
q && local.length === 0 && remote.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "px-3 py-3 text-[11px] text-surface-500", children: t('No branches match ":filter".', { filter: filter2 }) }),
|
|
55735
|
+
stashes.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "border-t border-surface-800 mt-1", children: [
|
|
55736
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "px-3 py-1.5 text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: t("Stashes") }),
|
|
55737
|
+
stashes.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "group flex items-center gap-2 px-3 py-1.5 text-xs text-surface-300 hover:bg-surface-800/50", children: [
|
|
55738
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-[10px] text-surface-500 shrink-0", children: s.ref }),
|
|
55739
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "truncate flex-1", title: s.branch ? t("on :branch: :message", { branch: s.branch, message: s.message }) : s.message, children: [
|
|
55740
|
+
s.message,
|
|
55741
|
+
s.branch && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-600", children: [
|
|
55742
|
+
" ",
|
|
55743
|
+
t("(on :branch)", { branch: s.branch })
|
|
55744
|
+
] })
|
|
55745
|
+
] }),
|
|
55746
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55747
|
+
"button",
|
|
55748
|
+
{
|
|
55749
|
+
onClick: () => popStash(s.ref),
|
|
55750
|
+
className: "opacity-0 group-hover:opacity-100 text-[10px] text-blue-400 hover:text-blue-300 transition-all shrink-0",
|
|
55751
|
+
title: t("Restore these changes onto the current branch"),
|
|
55752
|
+
children: t("Pop")
|
|
55753
|
+
}
|
|
55754
|
+
),
|
|
55755
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55756
|
+
"button",
|
|
55757
|
+
{
|
|
55758
|
+
onClick: () => dropStash(s.ref),
|
|
55759
|
+
className: "opacity-0 group-hover:opacity-100 text-[10px] text-surface-500 hover:text-red-400 transition-all shrink-0",
|
|
55760
|
+
title: t("Discard this stash"),
|
|
55761
|
+
children: "✕"
|
|
55762
|
+
}
|
|
55763
|
+
)
|
|
55764
|
+
] }, s.ref))
|
|
55765
|
+
] }),
|
|
55117
55766
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "border-t border-surface-800 mt-1", children: [
|
|
55118
55767
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-1.5 flex items-center justify-between", children: [
|
|
55119
55768
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: t("Remotes") }),
|
|
@@ -57912,6 +58561,43 @@ function App() {
|
|
|
57912
58561
|
});
|
|
57913
58562
|
return () => electron.offOpenFromGit();
|
|
57914
58563
|
}, [applyWorkspace]);
|
|
58564
|
+
reactExports.useEffect(() => {
|
|
58565
|
+
electron.onImportShare(async (token) => {
|
|
58566
|
+
try {
|
|
58567
|
+
const { type, name, payload } = await electron.cloudImportShare(token);
|
|
58568
|
+
let collection2;
|
|
58569
|
+
if (type === "request") {
|
|
58570
|
+
const r = payload;
|
|
58571
|
+
const reqId = r.id || crypto.randomUUID();
|
|
58572
|
+
const req = { ...r, id: reqId };
|
|
58573
|
+
collection2 = {
|
|
58574
|
+
version: "1.0",
|
|
58575
|
+
id: crypto.randomUUID(),
|
|
58576
|
+
name: name || req.name || "Shared request",
|
|
58577
|
+
rootFolder: { id: crypto.randomUUID(), name: "", folders: [], requestIds: [reqId] },
|
|
58578
|
+
requests: { [reqId]: req }
|
|
58579
|
+
};
|
|
58580
|
+
} else {
|
|
58581
|
+
collection2 = { ...payload, id: crypto.randomUUID() };
|
|
58582
|
+
}
|
|
58583
|
+
const store = useStore$1.getState();
|
|
58584
|
+
const id2 = store.addCollectionObject(collection2);
|
|
58585
|
+
try {
|
|
58586
|
+
const entry = useStore$1.getState().collections[id2];
|
|
58587
|
+
if (entry && useStore$1.getState().workspace) {
|
|
58588
|
+
await electron.saveCollection(entry.relPath, entry.data);
|
|
58589
|
+
await electron.saveWorkspace(useStore$1.getState().workspace);
|
|
58590
|
+
}
|
|
58591
|
+
} catch (persistErr) {
|
|
58592
|
+
console.error("Imported shared collection but could not save it yet:", persistErr);
|
|
58593
|
+
}
|
|
58594
|
+
setSidebarTab("collections");
|
|
58595
|
+
} catch (err) {
|
|
58596
|
+
console.error("Import from share link failed:", err);
|
|
58597
|
+
}
|
|
58598
|
+
});
|
|
58599
|
+
return () => electron.offImportShare();
|
|
58600
|
+
}, [setSidebarTab]);
|
|
57915
58601
|
reactExports.useEffect(() => {
|
|
57916
58602
|
electron.onMockHit(addMockHit);
|
|
57917
58603
|
return () => electron.offMockHit();
|
|
@@ -58080,7 +58766,7 @@ function App() {
|
|
|
58080
58766
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-accent)" }, children: "Spector" }),
|
|
58081
58767
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal", style: { color: "var(--text-muted)" }, children: [
|
|
58082
58768
|
"v",
|
|
58083
|
-
"0.9.
|
|
58769
|
+
"0.9.3"
|
|
58084
58770
|
] }),
|
|
58085
58771
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", "aria-hidden": "true", children: "·" }),
|
|
58086
58772
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|