@testsmith/api-spector 0.9.1 → 0.9.2
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-RRDuQogA.js} +1 -1
- package/out/renderer/assets/{SoapEditor-C2eMs7-Z.js → SoapEditor-BncNQmjP.js} +1 -1
- package/out/renderer/assets/index--T34lt1s.css +627 -0
- package/out/renderer/assets/{index-Bf9-CiTh.js → index-C6_D_4og.js} +822 -144
- 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-RRDuQogA.js","./codemirror-BKmwMUlV.js","./ajv-CJPwFjiP.js","./SoapEditor-BncNQmjP.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: {} };
|
|
@@ -14771,7 +14771,7 @@ const useStore$1 = create$1()(
|
|
|
14771
14771
|
})
|
|
14772
14772
|
}))
|
|
14773
14773
|
);
|
|
14774
|
-
const { electron: electron$
|
|
14774
|
+
const { electron: electron$J } = window;
|
|
14775
14775
|
function useAutoSave() {
|
|
14776
14776
|
const collections = useStore$1((s) => s.collections);
|
|
14777
14777
|
useStore$1((s) => s.environments);
|
|
@@ -14790,7 +14790,7 @@ function useAutoSave() {
|
|
|
14790
14790
|
for (const { relPath, data, dirty } of dirtyCollections) {
|
|
14791
14791
|
if (!dirty) continue;
|
|
14792
14792
|
try {
|
|
14793
|
-
await electron$
|
|
14793
|
+
await electron$J.saveCollection(relPath, data);
|
|
14794
14794
|
markCollectionClean(data.id);
|
|
14795
14795
|
} catch (e) {
|
|
14796
14796
|
console.error("Auto-save failed for", relPath, e);
|
|
@@ -14809,7 +14809,7 @@ function useAutoSave() {
|
|
|
14809
14809
|
for (const { relPath, data, dirty } of dirtyFlows) {
|
|
14810
14810
|
if (!dirty) continue;
|
|
14811
14811
|
try {
|
|
14812
|
-
await electron$
|
|
14812
|
+
await electron$J.saveFlow(relPath, data);
|
|
14813
14813
|
markFlowClean(data.id);
|
|
14814
14814
|
} catch (e) {
|
|
14815
14815
|
console.error("Auto-save failed for", relPath, e);
|
|
@@ -14825,7 +14825,7 @@ function useAutoSave() {
|
|
|
14825
14825
|
if (wsTimerRef.current) clearTimeout(wsTimerRef.current);
|
|
14826
14826
|
wsTimerRef.current = setTimeout(async () => {
|
|
14827
14827
|
try {
|
|
14828
|
-
await electron$
|
|
14828
|
+
await electron$J.saveWorkspace(workspace);
|
|
14829
14829
|
} catch {
|
|
14830
14830
|
}
|
|
14831
14831
|
}, 300);
|
|
@@ -14834,7 +14834,7 @@ function useAutoSave() {
|
|
|
14834
14834
|
};
|
|
14835
14835
|
}, [workspace]);
|
|
14836
14836
|
}
|
|
14837
|
-
const { electron: electron$
|
|
14837
|
+
const { electron: electron$I } = window;
|
|
14838
14838
|
function useWorkspaceLoader() {
|
|
14839
14839
|
const loadCollection = useStore$1((s) => s.loadCollection);
|
|
14840
14840
|
const loadEnvironment = useStore$1((s) => s.loadEnvironment);
|
|
@@ -14861,7 +14861,7 @@ function useWorkspaceLoader() {
|
|
|
14861
14861
|
if (typeof ws.settings?.zoom === "number") setZoom(ws.settings.zoom);
|
|
14862
14862
|
if (ws.settings?.persistHistory) {
|
|
14863
14863
|
try {
|
|
14864
|
-
const entries = await electron$
|
|
14864
|
+
const entries = await electron$I.loadHistory();
|
|
14865
14865
|
useStore$1.getState().setHistory(entries);
|
|
14866
14866
|
} catch {
|
|
14867
14867
|
}
|
|
@@ -14870,14 +14870,14 @@ function useWorkspaceLoader() {
|
|
|
14870
14870
|
}
|
|
14871
14871
|
for (const colPath of ws.collections ?? []) {
|
|
14872
14872
|
try {
|
|
14873
|
-
const col = await electron$
|
|
14873
|
+
const col = await electron$I.loadCollection(colPath);
|
|
14874
14874
|
loadCollection(colPath, col);
|
|
14875
14875
|
} catch {
|
|
14876
14876
|
}
|
|
14877
14877
|
}
|
|
14878
14878
|
for (const envPath of ws.environments ?? []) {
|
|
14879
14879
|
try {
|
|
14880
|
-
const env2 = await electron$
|
|
14880
|
+
const env2 = await electron$I.loadEnvironment(envPath);
|
|
14881
14881
|
loadEnvironment(envPath, env2);
|
|
14882
14882
|
} catch {
|
|
14883
14883
|
}
|
|
@@ -14896,32 +14896,38 @@ function useWorkspaceLoader() {
|
|
|
14896
14896
|
}
|
|
14897
14897
|
for (const relPath of ws.mocks ?? []) {
|
|
14898
14898
|
try {
|
|
14899
|
-
const mockData = await electron$
|
|
14899
|
+
const mockData = await electron$I.loadMock(relPath);
|
|
14900
14900
|
loadMock(relPath, mockData);
|
|
14901
14901
|
} catch {
|
|
14902
14902
|
}
|
|
14903
14903
|
}
|
|
14904
14904
|
for (const relPath of ws.flows ?? []) {
|
|
14905
14905
|
try {
|
|
14906
|
-
const flowData = await electron$
|
|
14906
|
+
const flowData = await electron$I.loadFlow(relPath);
|
|
14907
14907
|
loadFlow(relPath, flowData);
|
|
14908
14908
|
} catch {
|
|
14909
14909
|
}
|
|
14910
14910
|
}
|
|
14911
14911
|
try {
|
|
14912
|
-
const snapshots = await electron$
|
|
14912
|
+
const snapshots = await electron$I.listContractSnapshots(ws.contracts ?? []);
|
|
14913
14913
|
for (const { relPath, snapshot } of snapshots) loadContractSnapshot(relPath, snapshot);
|
|
14914
14914
|
} catch {
|
|
14915
14915
|
}
|
|
14916
14916
|
if ((ws.collections ?? []).length > 0) {
|
|
14917
14917
|
try {
|
|
14918
|
-
const firstCol = await electron$
|
|
14918
|
+
const firstCol = await electron$I.loadCollection(ws.collections[0]);
|
|
14919
14919
|
setActiveCollection(firstCol.id);
|
|
14920
14920
|
} catch {
|
|
14921
14921
|
}
|
|
14922
14922
|
}
|
|
14923
14923
|
}, [loadCollection, loadEnvironment, loadMock, loadFlow, loadContractSnapshot, setActiveCollection, setTheme, setZoom]);
|
|
14924
|
-
|
|
14924
|
+
const reloadWorkspace = reactExports.useCallback(async () => {
|
|
14925
|
+
const path = useStore$1.getState().workspacePath;
|
|
14926
|
+
if (!path) return;
|
|
14927
|
+
const result = await electron$I.openWorkspacePath(path);
|
|
14928
|
+
if (result) await applyWorkspace(result.workspace, result.workspacePath);
|
|
14929
|
+
}, [applyWorkspace]);
|
|
14930
|
+
return { applyWorkspace, reloadWorkspace };
|
|
14925
14931
|
}
|
|
14926
14932
|
var reactDomExports = requireReactDom();
|
|
14927
14933
|
const ReactDOM = /* @__PURE__ */ getDefaultExportFromCjs(reactDomExports);
|
|
@@ -25861,7 +25867,7 @@ function Modal({
|
|
|
25861
25867
|
}
|
|
25862
25868
|
);
|
|
25863
25869
|
}
|
|
25864
|
-
const { electron: electron$
|
|
25870
|
+
const { electron: electron$H } = window;
|
|
25865
25871
|
function Oauth2Form({ auth, onChange }) {
|
|
25866
25872
|
const t = useT();
|
|
25867
25873
|
const activeEnv = useActiveEnvironment();
|
|
@@ -25881,7 +25887,7 @@ function Oauth2Form({ auth, onChange }) {
|
|
|
25881
25887
|
const flow = auth.oauth2Flow ?? "client_credentials";
|
|
25882
25888
|
async function saveSecret(ref) {
|
|
25883
25889
|
if (!secretValue || !ref) return;
|
|
25884
|
-
await electron$
|
|
25890
|
+
await electron$H.setSecret(ref, secretValue);
|
|
25885
25891
|
setSaved(true);
|
|
25886
25892
|
setSecretValue("");
|
|
25887
25893
|
setTimeout(() => setSaved(false), 2e3);
|
|
@@ -25890,7 +25896,7 @@ function Oauth2Form({ auth, onChange }) {
|
|
|
25890
25896
|
setStatus("fetching");
|
|
25891
25897
|
setError("");
|
|
25892
25898
|
try {
|
|
25893
|
-
const result = await electron$
|
|
25899
|
+
const result = await electron$H.oauth2StartFlow(auth, resolveCtx());
|
|
25894
25900
|
onChange({ oauth2CachedToken: result.accessToken, oauth2TokenExpiry: result.expiresAt });
|
|
25895
25901
|
if (result.refreshToken) setRefreshToken(result.refreshToken);
|
|
25896
25902
|
setStatus("ok");
|
|
@@ -25904,7 +25910,7 @@ function Oauth2Form({ auth, onChange }) {
|
|
|
25904
25910
|
setStatus("fetching");
|
|
25905
25911
|
setError("");
|
|
25906
25912
|
try {
|
|
25907
|
-
const result = await electron$
|
|
25913
|
+
const result = await electron$H.oauth2RefreshToken(auth, resolveCtx(), refreshToken);
|
|
25908
25914
|
onChange({ oauth2CachedToken: result.accessToken, oauth2TokenExpiry: result.expiresAt });
|
|
25909
25915
|
if (result.refreshToken) setRefreshToken(result.refreshToken);
|
|
25910
25916
|
setStatus("ok");
|
|
@@ -26764,7 +26770,7 @@ function CollectionSettingsModal({ collection: collection2, onClose }) {
|
|
|
26764
26770
|
}
|
|
26765
26771
|
);
|
|
26766
26772
|
}
|
|
26767
|
-
const { electron: electron$
|
|
26773
|
+
const { electron: electron$G } = window;
|
|
26768
26774
|
function normalisePath(url) {
|
|
26769
26775
|
let path = url.replace(/^\{\{[^}]+\}\}/, "").replace(/^https?:\/\/[^/]+/, "");
|
|
26770
26776
|
if (!path.startsWith("/")) path = "/" + path;
|
|
@@ -26852,7 +26858,7 @@ function SchemaSyncModal({
|
|
|
26852
26858
|
setLoading(true);
|
|
26853
26859
|
setError(null);
|
|
26854
26860
|
try {
|
|
26855
|
-
const entries = await electron$
|
|
26861
|
+
const entries = await electron$G.extractOpenApiSchemas();
|
|
26856
26862
|
if (!entries) {
|
|
26857
26863
|
setLoading(false);
|
|
26858
26864
|
return;
|
|
@@ -26871,7 +26877,7 @@ function SchemaSyncModal({
|
|
|
26871
26877
|
setLoading(true);
|
|
26872
26878
|
setError(null);
|
|
26873
26879
|
try {
|
|
26874
|
-
const entries = await electron$
|
|
26880
|
+
const entries = await electron$G.extractOpenApiSchemasFromUrl(trimmed);
|
|
26875
26881
|
setSpecEntries(entries);
|
|
26876
26882
|
autoSelectChanged(entries);
|
|
26877
26883
|
} catch (err) {
|
|
@@ -26904,7 +26910,7 @@ function SchemaSyncModal({
|
|
|
26904
26910
|
}
|
|
26905
26911
|
const entry = useStore$1.getState().collections[collectionId];
|
|
26906
26912
|
if (entry) {
|
|
26907
|
-
await electron$
|
|
26913
|
+
await electron$G.saveCollection(entry.relPath, entry.data);
|
|
26908
26914
|
markCollectionClean(collectionId);
|
|
26909
26915
|
}
|
|
26910
26916
|
onClose();
|
|
@@ -27417,7 +27423,7 @@ function hasContract(r) {
|
|
|
27417
27423
|
const c = r.contract;
|
|
27418
27424
|
return !!c && (c.statusCode != null || !!c.bodySchema || !!c.bodyMatcher || (c.headers?.length ?? 0) > 0 || (c.providerStates?.length ?? 0) > 0);
|
|
27419
27425
|
}
|
|
27420
|
-
const { electron: electron$
|
|
27426
|
+
const { electron: electron$F } = window;
|
|
27421
27427
|
function cloudEnabled() {
|
|
27422
27428
|
return Boolean(useStore$1.getState().workspace?.settings?.cloud?.enabled);
|
|
27423
27429
|
}
|
|
@@ -27426,7 +27432,7 @@ function assertEnabled() {
|
|
|
27426
27432
|
}
|
|
27427
27433
|
async function pushContractToCloud(requests, opts) {
|
|
27428
27434
|
assertEnabled();
|
|
27429
|
-
return electron$
|
|
27435
|
+
return electron$F.cloudPushPact({
|
|
27430
27436
|
consumer: opts.consumer,
|
|
27431
27437
|
provider: opts.provider,
|
|
27432
27438
|
consumerVersion: opts.version,
|
|
@@ -27435,16 +27441,16 @@ async function pushContractToCloud(requests, opts) {
|
|
|
27435
27441
|
}
|
|
27436
27442
|
async function pushProviderSpecToCloud(opts) {
|
|
27437
27443
|
assertEnabled();
|
|
27438
|
-
return electron$
|
|
27444
|
+
return electron$F.cloudPushSpec(opts);
|
|
27439
27445
|
}
|
|
27440
27446
|
function openCloudMatrix() {
|
|
27441
|
-
void electron$
|
|
27447
|
+
void electron$F.cloudOpenMatrix();
|
|
27442
27448
|
}
|
|
27443
27449
|
async function pushFlowToCloud(flow) {
|
|
27444
27450
|
assertEnabled();
|
|
27445
27451
|
const s = useStore$1.getState();
|
|
27446
27452
|
const environment = resolveEnvironmentById(s.environments, s.activeEnvironmentId);
|
|
27447
|
-
return electron$
|
|
27453
|
+
return electron$F.cloudPushFlow({
|
|
27448
27454
|
flow,
|
|
27449
27455
|
collections: Object.values(s.collections).map((c) => c.data),
|
|
27450
27456
|
flows: Object.values(s.flows).map((f) => f.data),
|
|
@@ -27454,12 +27460,12 @@ async function pushFlowToCloud(flow) {
|
|
|
27454
27460
|
}
|
|
27455
27461
|
async function runFlowInCloud(flow, onStatus) {
|
|
27456
27462
|
assertEnabled();
|
|
27457
|
-
const started = await electron$
|
|
27463
|
+
const started = await electron$F.cloudRunFlow(flow.name);
|
|
27458
27464
|
onStatus?.(started.status);
|
|
27459
27465
|
const deadlineMs = 2 * 60 * 1e3;
|
|
27460
27466
|
const t0 = Date.now();
|
|
27461
27467
|
for (; ; ) {
|
|
27462
|
-
const run = await electron$
|
|
27468
|
+
const run = await electron$F.cloudGetFlowRun({ name: flow.name, runId: started.id });
|
|
27463
27469
|
onStatus?.(run.status);
|
|
27464
27470
|
if (run.status === "passed" || run.status === "failed" || run.status === "error" || run.status === "done") {
|
|
27465
27471
|
if (run.summary) return run.summary;
|
|
@@ -27470,12 +27476,53 @@ async function runFlowInCloud(flow, onStatus) {
|
|
|
27470
27476
|
}
|
|
27471
27477
|
}
|
|
27472
27478
|
function openCloudFlow(flow) {
|
|
27473
|
-
void electron$
|
|
27479
|
+
void electron$F.cloudOpenFlow(flow.name);
|
|
27480
|
+
}
|
|
27481
|
+
async function shareCollectionToCloud(collection2) {
|
|
27482
|
+
assertEnabled();
|
|
27483
|
+
return electron$F.cloudShareCollection(collection2);
|
|
27484
|
+
}
|
|
27485
|
+
async function shareRequestToCloud(request2) {
|
|
27486
|
+
assertEnabled();
|
|
27487
|
+
return electron$F.cloudShareRequest(request2);
|
|
27488
|
+
}
|
|
27489
|
+
function collectFolderRequestIds(folder2) {
|
|
27490
|
+
return [...folder2.requestIds, ...folder2.folders.flatMap(collectFolderRequestIds)];
|
|
27491
|
+
}
|
|
27492
|
+
async function shareFolderToCloud(collection2, folder2) {
|
|
27493
|
+
assertEnabled();
|
|
27494
|
+
const ids = new Set(collectFolderRequestIds(folder2));
|
|
27495
|
+
const requests = {};
|
|
27496
|
+
for (const id2 of ids) {
|
|
27497
|
+
const r = collection2.requests[id2];
|
|
27498
|
+
if (r) requests[id2] = r;
|
|
27499
|
+
}
|
|
27500
|
+
const payload = {
|
|
27501
|
+
version: "1.0",
|
|
27502
|
+
id: folder2.id,
|
|
27503
|
+
name: folder2.name,
|
|
27504
|
+
rootFolder: folder2,
|
|
27505
|
+
requests,
|
|
27506
|
+
collectionVariables: collection2.collectionVariables
|
|
27507
|
+
};
|
|
27508
|
+
return electron$F.cloudShareFolder({ sourceId: folder2.id, name: folder2.name, payload });
|
|
27509
|
+
}
|
|
27510
|
+
async function lookupShare(type, sourceId) {
|
|
27511
|
+
assertEnabled();
|
|
27512
|
+
return electron$F.cloudShareLookup({ type, sourceId });
|
|
27513
|
+
}
|
|
27514
|
+
async function restrictShare(token, expiresDays) {
|
|
27515
|
+
assertEnabled();
|
|
27516
|
+
return electron$F.cloudShareUpdate({ token, expiresDays });
|
|
27517
|
+
}
|
|
27518
|
+
async function revokeShare(token) {
|
|
27519
|
+
assertEnabled();
|
|
27520
|
+
await electron$F.cloudShareRevoke(token);
|
|
27474
27521
|
}
|
|
27475
27522
|
async function getCloudMockRoutes(name) {
|
|
27476
27523
|
if (!cloudEnabled()) return null;
|
|
27477
27524
|
try {
|
|
27478
|
-
const res = await electron$
|
|
27525
|
+
const res = await electron$F.cloudGetMock(name);
|
|
27479
27526
|
return res.exists ? res.routes ?? [] : null;
|
|
27480
27527
|
} catch {
|
|
27481
27528
|
return null;
|
|
@@ -27484,7 +27531,7 @@ async function getCloudMockRoutes(name) {
|
|
|
27484
27531
|
async function pushMockToCloud(server, routeIds) {
|
|
27485
27532
|
assertEnabled();
|
|
27486
27533
|
const routes = routeIds ? (server.routes ?? []).filter((r) => routeIds.includes(r.id)) : server.routes ?? [];
|
|
27487
|
-
return electron$
|
|
27534
|
+
return electron$F.cloudPushMock({ ...server, routes });
|
|
27488
27535
|
}
|
|
27489
27536
|
async function pushRequestAsMonitor(request2, opts) {
|
|
27490
27537
|
assertEnabled();
|
|
@@ -27508,7 +27555,7 @@ async function pushRequestAsMonitor(request2, opts) {
|
|
|
27508
27555
|
...request2.headers
|
|
27509
27556
|
];
|
|
27510
27557
|
const mergedRequest = { ...request2, auth: mergedAuth, headers: mergedHeaders };
|
|
27511
|
-
return electron$
|
|
27558
|
+
return electron$F.cloudPushMonitor(
|
|
27512
27559
|
{
|
|
27513
27560
|
request: mergedRequest,
|
|
27514
27561
|
setup,
|
|
@@ -27926,6 +27973,201 @@ function Toast({ toast }) {
|
|
|
27926
27973
|
if (!toast) return null;
|
|
27927
27974
|
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
27975
|
}
|
|
27976
|
+
function CloudRequiredModal({
|
|
27977
|
+
action,
|
|
27978
|
+
onConnect,
|
|
27979
|
+
onClose
|
|
27980
|
+
}) {
|
|
27981
|
+
const t = useT();
|
|
27982
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
27983
|
+
Modal,
|
|
27984
|
+
{
|
|
27985
|
+
onClose,
|
|
27986
|
+
closeOnBackdrop: true,
|
|
27987
|
+
overlayClassName: "bg-black/50 z-[300] flex items-center justify-center",
|
|
27988
|
+
panelClassName: "bg-surface-900 border border-surface-700 rounded-lg shadow-2xl p-5 w-96 flex flex-col gap-4",
|
|
27989
|
+
children: [
|
|
27990
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
27991
|
+
/* @__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" }) }) }),
|
|
27992
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
27993
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold text-white", children: t("Connect to API Spector Cloud") }),
|
|
27994
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-400 mt-0.5", children: t("Sharing needs the cloud") })
|
|
27995
|
+
] })
|
|
27996
|
+
] }),
|
|
27997
|
+
/* @__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.") }),
|
|
27998
|
+
/* @__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.") }),
|
|
27999
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2", children: [
|
|
28000
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28001
|
+
"button",
|
|
28002
|
+
{
|
|
28003
|
+
onClick: onClose,
|
|
28004
|
+
className: "px-3 py-1.5 text-xs text-surface-400 hover:text-white transition-colors",
|
|
28005
|
+
children: t("Not now")
|
|
28006
|
+
}
|
|
28007
|
+
),
|
|
28008
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28009
|
+
"button",
|
|
28010
|
+
{
|
|
28011
|
+
onClick: onConnect,
|
|
28012
|
+
className: "px-3 py-1.5 text-xs font-medium text-white bg-sky-700 hover:bg-sky-600 rounded transition-colors",
|
|
28013
|
+
children: t("Open Cloud settings")
|
|
28014
|
+
}
|
|
28015
|
+
)
|
|
28016
|
+
] })
|
|
28017
|
+
]
|
|
28018
|
+
}
|
|
28019
|
+
);
|
|
28020
|
+
}
|
|
28021
|
+
function ShareModal({
|
|
28022
|
+
title,
|
|
28023
|
+
type,
|
|
28024
|
+
sourceId,
|
|
28025
|
+
onCreate,
|
|
28026
|
+
onClose
|
|
28027
|
+
}) {
|
|
28028
|
+
const t = useT();
|
|
28029
|
+
const [loading, setLoading] = reactExports.useState(true);
|
|
28030
|
+
const [busy, setBusy] = reactExports.useState(false);
|
|
28031
|
+
const [error2, setError] = reactExports.useState(null);
|
|
28032
|
+
const [copied, setCopied] = reactExports.useState(false);
|
|
28033
|
+
const [live, setLive] = reactExports.useState(null);
|
|
28034
|
+
const [expiryDays, setExpiryDays] = reactExports.useState(0);
|
|
28035
|
+
reactExports.useEffect(() => {
|
|
28036
|
+
let cancelled = false;
|
|
28037
|
+
(async () => {
|
|
28038
|
+
try {
|
|
28039
|
+
const res = await lookupShare(type, sourceId);
|
|
28040
|
+
if (!cancelled && res.exists && res.token && res.url && res.deep_link) {
|
|
28041
|
+
setLive({ token: res.token, url: res.url, deep_link: res.deep_link, expires_at: res.expires_at ?? null });
|
|
28042
|
+
}
|
|
28043
|
+
} catch (e) {
|
|
28044
|
+
if (!cancelled) setError(e.message);
|
|
28045
|
+
} finally {
|
|
28046
|
+
if (!cancelled) setLoading(false);
|
|
28047
|
+
}
|
|
28048
|
+
})();
|
|
28049
|
+
return () => {
|
|
28050
|
+
cancelled = true;
|
|
28051
|
+
};
|
|
28052
|
+
}, [type, sourceId]);
|
|
28053
|
+
async function run(fn) {
|
|
28054
|
+
setBusy(true);
|
|
28055
|
+
setError(null);
|
|
28056
|
+
try {
|
|
28057
|
+
await fn();
|
|
28058
|
+
} catch (e) {
|
|
28059
|
+
setError(e.message);
|
|
28060
|
+
} finally {
|
|
28061
|
+
setBusy(false);
|
|
28062
|
+
}
|
|
28063
|
+
}
|
|
28064
|
+
const create2 = () => run(async () => {
|
|
28065
|
+
const r = await onCreate();
|
|
28066
|
+
setLive({ token: r.token, url: r.url, deep_link: r.deep_link, expires_at: r.expires_at ?? null });
|
|
28067
|
+
});
|
|
28068
|
+
const applyExpiry = () => run(async () => {
|
|
28069
|
+
if (!live) return;
|
|
28070
|
+
const r = await restrictShare(live.token, expiryDays);
|
|
28071
|
+
setLive({ ...live, expires_at: r.expires_at ?? null });
|
|
28072
|
+
});
|
|
28073
|
+
const revoke = () => run(async () => {
|
|
28074
|
+
if (!live) return;
|
|
28075
|
+
await revokeShare(live.token);
|
|
28076
|
+
setLive(null);
|
|
28077
|
+
});
|
|
28078
|
+
const copy2 = async () => {
|
|
28079
|
+
if (!live) return;
|
|
28080
|
+
try {
|
|
28081
|
+
await navigator.clipboard.writeText(live.url);
|
|
28082
|
+
setCopied(true);
|
|
28083
|
+
setTimeout(() => setCopied(false), 2e3);
|
|
28084
|
+
} catch {
|
|
28085
|
+
}
|
|
28086
|
+
};
|
|
28087
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28088
|
+
Modal,
|
|
28089
|
+
{
|
|
28090
|
+
onClose,
|
|
28091
|
+
title: t("Share: :name", { name: title }),
|
|
28092
|
+
overlayClassName: "bg-black/50 z-[300] flex items-center justify-center",
|
|
28093
|
+
panelClassName: "bg-surface-900 border border-surface-700 rounded-lg shadow-2xl w-[32rem] max-w-[92vw] flex flex-col",
|
|
28094
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-5 flex flex-col gap-4", children: [
|
|
28095
|
+
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 }),
|
|
28096
|
+
loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm text-surface-400", children: t("Checking share status…") }) : !live ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
28097
|
+
/* @__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.") }),
|
|
28098
|
+
/* @__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.") }),
|
|
28099
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28100
|
+
"button",
|
|
28101
|
+
{
|
|
28102
|
+
onClick: create2,
|
|
28103
|
+
disabled: busy,
|
|
28104
|
+
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",
|
|
28105
|
+
children: busy ? t("Creating…") : t("Create public link")
|
|
28106
|
+
}
|
|
28107
|
+
) })
|
|
28108
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
28109
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
28110
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[11px] uppercase tracking-wide text-surface-500", children: t("Public link") }),
|
|
28111
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex items-center gap-2", children: [
|
|
28112
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28113
|
+
"input",
|
|
28114
|
+
{
|
|
28115
|
+
readOnly: true,
|
|
28116
|
+
value: live.url,
|
|
28117
|
+
onClick: (e) => e.target.select(),
|
|
28118
|
+
className: "flex-1 rounded bg-surface-950 border border-surface-700 px-2 py-1.5 text-xs font-mono text-surface-200"
|
|
28119
|
+
}
|
|
28120
|
+
),
|
|
28121
|
+
/* @__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") })
|
|
28122
|
+
] })
|
|
28123
|
+
] }),
|
|
28124
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end gap-2", children: [
|
|
28125
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
|
|
28126
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[11px] uppercase tracking-wide text-surface-500", children: t("Restrict") }),
|
|
28127
|
+
/* @__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") })
|
|
28128
|
+
] }),
|
|
28129
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
28130
|
+
"select",
|
|
28131
|
+
{
|
|
28132
|
+
value: expiryDays,
|
|
28133
|
+
onChange: (e) => setExpiryDays(Number(e.target.value)),
|
|
28134
|
+
className: "rounded bg-surface-950 border border-surface-700 px-2 py-1.5 text-xs text-surface-200",
|
|
28135
|
+
children: [
|
|
28136
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 0, children: t("No expiry") }),
|
|
28137
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 1, children: t("1 day") }),
|
|
28138
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 7, children: t("7 days") }),
|
|
28139
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 30, children: t("30 days") })
|
|
28140
|
+
]
|
|
28141
|
+
}
|
|
28142
|
+
),
|
|
28143
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28144
|
+
"button",
|
|
28145
|
+
{
|
|
28146
|
+
onClick: applyExpiry,
|
|
28147
|
+
disabled: busy,
|
|
28148
|
+
className: "px-3 py-1.5 text-xs border border-surface-700 rounded text-surface-300 hover:text-white disabled:opacity-50 transition-colors",
|
|
28149
|
+
children: t("Apply")
|
|
28150
|
+
}
|
|
28151
|
+
)
|
|
28152
|
+
] }),
|
|
28153
|
+
/* @__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.") }),
|
|
28154
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center pt-2 border-t border-surface-800", children: [
|
|
28155
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28156
|
+
"button",
|
|
28157
|
+
{
|
|
28158
|
+
onClick: revoke,
|
|
28159
|
+
disabled: busy,
|
|
28160
|
+
className: "px-3 py-1.5 text-xs text-red-400 hover:text-red-300 disabled:opacity-50 transition-colors",
|
|
28161
|
+
children: t("Revoke link")
|
|
28162
|
+
}
|
|
28163
|
+
),
|
|
28164
|
+
/* @__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") })
|
|
28165
|
+
] })
|
|
28166
|
+
] })
|
|
28167
|
+
] })
|
|
28168
|
+
}
|
|
28169
|
+
);
|
|
28170
|
+
}
|
|
27929
28171
|
function requestPath(url) {
|
|
27930
28172
|
const trimmed = url.trim().replace(/^\{\{[^}]+\}\}/, "").replace(/^https?:\/\/[^/]+/i, "");
|
|
27931
28173
|
return trimmed || url.trim();
|
|
@@ -27995,6 +28237,9 @@ function RequestRow({
|
|
|
27995
28237
|
const groupIndent = indent + 14;
|
|
27996
28238
|
const { toast, show } = useToast();
|
|
27997
28239
|
const addSecurityTests = useStore$1((s) => s.addSecurityTests);
|
|
28240
|
+
const openWorkspaceSettings = useStore$1((s) => s.openWorkspaceSettings);
|
|
28241
|
+
const [showCloudRequired, setShowCloudRequired] = reactExports.useState(false);
|
|
28242
|
+
const [showShare, setShowShare] = reactExports.useState(false);
|
|
27998
28243
|
function handleRowClick(e) {
|
|
27999
28244
|
if (e.metaKey || e.ctrlKey) {
|
|
28000
28245
|
e.preventDefault();
|
|
@@ -28014,6 +28259,13 @@ function RequestRow({
|
|
|
28014
28259
|
show(e.message, false);
|
|
28015
28260
|
}
|
|
28016
28261
|
}
|
|
28262
|
+
function openShare() {
|
|
28263
|
+
if (!cloudEnabled()) {
|
|
28264
|
+
setShowCloudRequired(true);
|
|
28265
|
+
return;
|
|
28266
|
+
}
|
|
28267
|
+
setShowShare(true);
|
|
28268
|
+
}
|
|
28017
28269
|
const hookMenuItems = ["beforeAll", "before", "after", "afterAll"].map((ht) => ({
|
|
28018
28270
|
type: "item",
|
|
28019
28271
|
label: (hookType === ht ? "✓ " : " ") + t(HOOK_LABELS[ht]),
|
|
@@ -28154,6 +28406,7 @@ function RequestRow({
|
|
|
28154
28406
|
show(n2 > 0 ? t("Added :count OWASP security tests", { count: n2 }) : t("No security tests generated for this request"), n2 > 0);
|
|
28155
28407
|
} },
|
|
28156
28408
|
...cloudEnabled() ? [{ type: "item", label: t("Push as monitor to cloud"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: pushMonitor }] : [],
|
|
28409
|
+
{ type: "item", label: t("Share request (public link)"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyIcon, {}), onClick: openShare },
|
|
28157
28410
|
{ type: "item", label: disabled ? t("Enable") : t("Disable"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(BanIcon, {}), onClick: onToggleDisabled },
|
|
28158
28411
|
{ type: "separator" },
|
|
28159
28412
|
{ type: "header", label: t("Hook type") },
|
|
@@ -28161,7 +28414,32 @@ function RequestRow({
|
|
|
28161
28414
|
{ type: "separator" },
|
|
28162
28415
|
{ type: "item", label: t("Delete"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(TrashIcon, {}), danger: true, onClick: onDelete }
|
|
28163
28416
|
] }) }),
|
|
28164
|
-
toast && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed bottom-4 right-4 z-[100] w-96", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Toast, { toast }) })
|
|
28417
|
+
toast && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed bottom-4 right-4 z-[100] w-96", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Toast, { toast }) }),
|
|
28418
|
+
showCloudRequired && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28419
|
+
CloudRequiredModal,
|
|
28420
|
+
{
|
|
28421
|
+
action: t("share this request"),
|
|
28422
|
+
onConnect: () => {
|
|
28423
|
+
setShowCloudRequired(false);
|
|
28424
|
+
openWorkspaceSettings("cloud");
|
|
28425
|
+
},
|
|
28426
|
+
onClose: () => setShowCloudRequired(false)
|
|
28427
|
+
}
|
|
28428
|
+
),
|
|
28429
|
+
showShare && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28430
|
+
ShareModal,
|
|
28431
|
+
{
|
|
28432
|
+
title: useStore$1.getState().collections[collectionId]?.data.requests[reqId]?.name ?? "",
|
|
28433
|
+
type: "request",
|
|
28434
|
+
sourceId: reqId,
|
|
28435
|
+
onCreate: () => {
|
|
28436
|
+
const r = useStore$1.getState().collections[collectionId]?.data.requests[reqId];
|
|
28437
|
+
if (!r) throw new Error(t("Request not found"));
|
|
28438
|
+
return shareRequestToCloud(r);
|
|
28439
|
+
},
|
|
28440
|
+
onClose: () => setShowShare(false)
|
|
28441
|
+
}
|
|
28442
|
+
)
|
|
28165
28443
|
]
|
|
28166
28444
|
}
|
|
28167
28445
|
),
|
|
@@ -28822,6 +29100,16 @@ function CollectionNode({
|
|
|
28822
29100
|
const [expandCtrl, setExpandCtrl] = reactExports.useState({ value: true, seq: 0 });
|
|
28823
29101
|
const [dropOver, setDropOver] = reactExports.useState(false);
|
|
28824
29102
|
const dragCtx = reactExports.useContext(DragCtx);
|
|
29103
|
+
const openWorkspaceSettings = useStore$1((s) => s.openWorkspaceSettings);
|
|
29104
|
+
const [showCloudRequired, setShowCloudRequired] = reactExports.useState(false);
|
|
29105
|
+
const [showShare, setShowShare] = reactExports.useState(false);
|
|
29106
|
+
function openShare() {
|
|
29107
|
+
if (!cloudEnabled()) {
|
|
29108
|
+
setShowCloudRequired(true);
|
|
29109
|
+
return;
|
|
29110
|
+
}
|
|
29111
|
+
setShowShare(true);
|
|
29112
|
+
}
|
|
28825
29113
|
function expandAll() {
|
|
28826
29114
|
setExpandCtrl((c) => ({ value: true, seq: c.seq + 1, ids: null }));
|
|
28827
29115
|
}
|
|
@@ -28903,6 +29191,7 @@ function CollectionNode({
|
|
|
28903
29191
|
{ type: "item", label: t("Settings"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(GearIcon, {}), onClick: () => setShowSettings(true) },
|
|
28904
29192
|
{ type: "item", label: t("Sync schemas"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowSchemaSync(true) },
|
|
28905
29193
|
...cloudEnabled() ? [{ type: "item", label: t("Push contract to cloud"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowPushContract(true) }] : [],
|
|
29194
|
+
{ type: "item", label: t("Share collection (public link)"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyIcon, {}), onClick: openShare },
|
|
28906
29195
|
{ type: "item", label: col.disabled ? t("Enable") : t("Disable"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(BanIcon, {}), onClick: onToggleCollectionDisabled },
|
|
28907
29196
|
{ type: "separator" },
|
|
28908
29197
|
{ type: "item", label: t("Delete collection"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(TrashIcon, {}), danger: true, onClick: onDeleteCollection }
|
|
@@ -28947,7 +29236,28 @@ function CollectionNode({
|
|
|
28947
29236
|
}
|
|
28948
29237
|
),
|
|
28949
29238
|
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) })
|
|
29239
|
+
showSchemaSync && /* @__PURE__ */ jsxRuntimeExports.jsx(SchemaSyncModal, { collectionId: col.id, scope: { type: "collection" }, onClose: () => setShowSchemaSync(false) }),
|
|
29240
|
+
showCloudRequired && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29241
|
+
CloudRequiredModal,
|
|
29242
|
+
{
|
|
29243
|
+
action: t("share this collection"),
|
|
29244
|
+
onConnect: () => {
|
|
29245
|
+
setShowCloudRequired(false);
|
|
29246
|
+
openWorkspaceSettings("cloud");
|
|
29247
|
+
},
|
|
29248
|
+
onClose: () => setShowCloudRequired(false)
|
|
29249
|
+
}
|
|
29250
|
+
),
|
|
29251
|
+
showShare && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29252
|
+
ShareModal,
|
|
29253
|
+
{
|
|
29254
|
+
title: col.name,
|
|
29255
|
+
type: "collection",
|
|
29256
|
+
sourceId: col.id,
|
|
29257
|
+
onCreate: () => shareCollectionToCloud(col),
|
|
29258
|
+
onClose: () => setShowShare(false)
|
|
29259
|
+
}
|
|
29260
|
+
)
|
|
28951
29261
|
] });
|
|
28952
29262
|
}
|
|
28953
29263
|
function FolderRow({
|
|
@@ -28991,6 +29301,16 @@ function FolderRow({
|
|
|
28991
29301
|
}));
|
|
28992
29302
|
const [dropInside, setDropInside] = reactExports.useState(false);
|
|
28993
29303
|
const dragCtx = reactExports.useContext(DragCtx);
|
|
29304
|
+
const openWorkspaceSettings = useStore$1((s) => s.openWorkspaceSettings);
|
|
29305
|
+
const [showCloudRequired, setShowCloudRequired] = reactExports.useState(false);
|
|
29306
|
+
const [showShare, setShowShare] = reactExports.useState(false);
|
|
29307
|
+
function openShare() {
|
|
29308
|
+
if (!cloudEnabled()) {
|
|
29309
|
+
setShowCloudRequired(true);
|
|
29310
|
+
return;
|
|
29311
|
+
}
|
|
29312
|
+
setShowShare(true);
|
|
29313
|
+
}
|
|
28994
29314
|
const tags = folder2.tags ?? [];
|
|
28995
29315
|
const indent = indentPx(depth);
|
|
28996
29316
|
const hasInheritedConfig = folder2.auth && folder2.auth.type !== "none" || folder2.headers && folder2.headers.length > 0;
|
|
@@ -29104,6 +29424,7 @@ function FolderRow({
|
|
|
29104
29424
|
{ type: "item", label: t("Settings"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(GearIcon, {}), onClick: () => setShowSettings(true) },
|
|
29105
29425
|
{ type: "item", label: t("Sync schemas"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowSchemaSync(true) },
|
|
29106
29426
|
...cloudEnabled() ? [{ type: "item", label: t("Push contract to cloud"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(SyncIcon, {}), onClick: () => setShowPushContract(true) }] : [],
|
|
29427
|
+
{ type: "item", label: t("Share folder (public link)"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(CopyIcon, {}), onClick: openShare },
|
|
29107
29428
|
{ type: "item", label: folder2.disabled ? t("Enable") : t("Disable"), icon: /* @__PURE__ */ jsxRuntimeExports.jsx(BanIcon, {}), onClick: onToggleDisabled },
|
|
29108
29429
|
{ type: "separator" },
|
|
29109
29430
|
{ type: "header", label: t("Run folder as hook") },
|
|
@@ -29138,6 +29459,27 @@ function FolderRow({
|
|
|
29138
29459
|
scope: { type: "folder", folderId: folder2.id },
|
|
29139
29460
|
onClose: () => setShowSchemaSync(false)
|
|
29140
29461
|
}
|
|
29462
|
+
),
|
|
29463
|
+
showCloudRequired && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29464
|
+
CloudRequiredModal,
|
|
29465
|
+
{
|
|
29466
|
+
action: t("share this folder"),
|
|
29467
|
+
onConnect: () => {
|
|
29468
|
+
setShowCloudRequired(false);
|
|
29469
|
+
openWorkspaceSettings("cloud");
|
|
29470
|
+
},
|
|
29471
|
+
onClose: () => setShowCloudRequired(false)
|
|
29472
|
+
}
|
|
29473
|
+
),
|
|
29474
|
+
showShare && folderCollection && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
29475
|
+
ShareModal,
|
|
29476
|
+
{
|
|
29477
|
+
title: folder2.name,
|
|
29478
|
+
type: "folder",
|
|
29479
|
+
sourceId: folder2.id,
|
|
29480
|
+
onCreate: () => shareFolderToCloud(folderCollection, folder2),
|
|
29481
|
+
onClose: () => setShowShare(false)
|
|
29482
|
+
}
|
|
29141
29483
|
)
|
|
29142
29484
|
] });
|
|
29143
29485
|
}
|
|
@@ -29591,8 +29933,8 @@ function jsonWithComments() {
|
|
|
29591
29933
|
function xmlWithComments() {
|
|
29592
29934
|
return [xml(), commentKeymap];
|
|
29593
29935
|
}
|
|
29594
|
-
const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-
|
|
29595
|
-
const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-
|
|
29936
|
+
const GraphQLEditor = reactExports.lazy(() => __vitePreload(() => import("./GraphQLEditor-RRDuQogA.js"), true ? __vite__mapDeps([0,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.GraphQLEditor })));
|
|
29937
|
+
const SoapEditor = reactExports.lazy(() => __vitePreload(() => import("./SoapEditor-BncNQmjP.js"), true ? __vite__mapDeps([3,1,2]) : void 0, import.meta.url).then((m) => ({ default: m.SoapEditor })));
|
|
29596
29938
|
function BodyTab({ request: request2, onChange }) {
|
|
29597
29939
|
const t = useT();
|
|
29598
29940
|
const editorFallback = /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 text-xs text-surface-500", children: t("Loading editor…") });
|
|
@@ -29690,7 +30032,7 @@ function BodyTab({ request: request2, onChange }) {
|
|
|
29690
30032
|
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
30033
|
] });
|
|
29692
30034
|
}
|
|
29693
|
-
const { electron: electron$
|
|
30035
|
+
const { electron: electron$E } = window;
|
|
29694
30036
|
function AuthTab({ request: request2, onChange }) {
|
|
29695
30037
|
const auth = request2.auth;
|
|
29696
30038
|
const [secretValue, setSecretValue] = reactExports.useState("");
|
|
@@ -29700,7 +30042,7 @@ function AuthTab({ request: request2, onChange }) {
|
|
|
29700
30042
|
}
|
|
29701
30043
|
async function saveSecret(ref) {
|
|
29702
30044
|
if (!secretValue || !ref) return;
|
|
29703
|
-
await electron$
|
|
30045
|
+
await electron$E.setSecret(ref, secretValue);
|
|
29704
30046
|
setSaved(true);
|
|
29705
30047
|
setSecretValue("");
|
|
29706
30048
|
setTimeout(() => setSaved(false), 2e3);
|
|
@@ -30060,7 +30402,7 @@ function validateBodyAgainstSchema(schema, body) {
|
|
|
30060
30402
|
return { status: "error", message: e instanceof Error ? e.message : String(e) };
|
|
30061
30403
|
}
|
|
30062
30404
|
}
|
|
30063
|
-
const { electron: electron$
|
|
30405
|
+
const { electron: electron$D } = window;
|
|
30064
30406
|
function SchemaTab({ request: request2, onChange }) {
|
|
30065
30407
|
const t = useT();
|
|
30066
30408
|
const activeTab = useStore$1((s) => s.tabs.find((tab) => tab.id === s.activeTabId));
|
|
@@ -30084,7 +30426,7 @@ function SchemaTab({ request: request2, onChange }) {
|
|
|
30084
30426
|
if (!lastResponse?.body) return;
|
|
30085
30427
|
setInferring(true);
|
|
30086
30428
|
try {
|
|
30087
|
-
const schema = await electron$
|
|
30429
|
+
const schema = await electron$D.inferContractSchema(lastResponse.body);
|
|
30088
30430
|
if (schema) setSchema(schema);
|
|
30089
30431
|
} finally {
|
|
30090
30432
|
setInferring(false);
|
|
@@ -39514,7 +39856,7 @@ function DocsEditor({ value: value2, onChange, placeholder, onGenerate, aiAvaila
|
|
|
39514
39856
|
}
|
|
39515
39857
|
const AI_OPENAI_TOKEN_REF = "ai:openai:token";
|
|
39516
39858
|
const DEFAULT_AI_MODEL = "gpt-4o-mini";
|
|
39517
|
-
const { electron: electron$
|
|
39859
|
+
const { electron: electron$C } = window;
|
|
39518
39860
|
const CFG_KEY = STORAGE_KEYS.ai;
|
|
39519
39861
|
function getAiConfig() {
|
|
39520
39862
|
try {
|
|
@@ -39536,7 +39878,7 @@ function invalidateAiAvailable() {
|
|
|
39536
39878
|
async function checkAvailable() {
|
|
39537
39879
|
if (availableCache != null) return availableCache;
|
|
39538
39880
|
try {
|
|
39539
|
-
availableCache = (await electron$
|
|
39881
|
+
availableCache = (await electron$C.hasSecret(AI_OPENAI_TOKEN_REF)).has;
|
|
39540
39882
|
} catch {
|
|
39541
39883
|
availableCache = false;
|
|
39542
39884
|
}
|
|
@@ -39556,7 +39898,7 @@ function useAiAvailable() {
|
|
|
39556
39898
|
return available;
|
|
39557
39899
|
}
|
|
39558
39900
|
async function generateDocs(input) {
|
|
39559
|
-
return electron$
|
|
39901
|
+
return electron$C.generateAiDocs({ ...input, model: getAiConfig().model });
|
|
39560
39902
|
}
|
|
39561
39903
|
function kvLines(label, rows) {
|
|
39562
39904
|
const on = (rows ?? []).filter((r) => r.enabled !== false && r.key);
|
|
@@ -40084,7 +40426,7 @@ function RealtimeTestSection({
|
|
|
40084
40426
|
] })
|
|
40085
40427
|
] });
|
|
40086
40428
|
}
|
|
40087
|
-
const { electron: electron$
|
|
40429
|
+
const { electron: electron$B } = window;
|
|
40088
40430
|
function formatTime$4(ts) {
|
|
40089
40431
|
const d = new Date(ts);
|
|
40090
40432
|
const hh = String(d.getHours()).padStart(2, "0");
|
|
@@ -40114,7 +40456,7 @@ function WebSocketPanel({ request: request2, onChange }) {
|
|
|
40114
40456
|
const url = interp(request2.url).trim();
|
|
40115
40457
|
const headers = {};
|
|
40116
40458
|
for (const h of request2.headers) if (h.enabled && h.key) headers[interp(h.key)] = interp(h.value);
|
|
40117
|
-
return electron$
|
|
40459
|
+
return electron$B.wsTest({
|
|
40118
40460
|
url,
|
|
40119
40461
|
headers,
|
|
40120
40462
|
sendMessage: cfg.sendMessage ? interp(cfg.sendMessage) : void 0,
|
|
@@ -40124,14 +40466,14 @@ function WebSocketPanel({ request: request2, onChange }) {
|
|
|
40124
40466
|
});
|
|
40125
40467
|
});
|
|
40126
40468
|
reactExports.useEffect(() => {
|
|
40127
|
-
electron$
|
|
40469
|
+
electron$B.onWsMessage(({ requestId, message }) => {
|
|
40128
40470
|
addWsMessage(requestId, message);
|
|
40129
40471
|
});
|
|
40130
|
-
electron$
|
|
40472
|
+
electron$B.onWsStatus(({ requestId, status, error: error2 }) => {
|
|
40131
40473
|
setWsStatus(requestId, status, error2);
|
|
40132
40474
|
});
|
|
40133
40475
|
return () => {
|
|
40134
|
-
electron$
|
|
40476
|
+
electron$B.offWsEvents();
|
|
40135
40477
|
};
|
|
40136
40478
|
}, [addWsMessage, setWsStatus]);
|
|
40137
40479
|
reactExports.useEffect(() => {
|
|
@@ -40144,19 +40486,19 @@ function WebSocketPanel({ request: request2, onChange }) {
|
|
|
40144
40486
|
if (h.enabled && h.key) headers[h.key] = h.value;
|
|
40145
40487
|
}
|
|
40146
40488
|
try {
|
|
40147
|
-
await electron$
|
|
40489
|
+
await electron$B.wsConnect(request2.id, request2.url, headers);
|
|
40148
40490
|
} catch (err) {
|
|
40149
40491
|
setWsStatus(request2.id, "error", err instanceof Error ? err.message : String(err));
|
|
40150
40492
|
}
|
|
40151
40493
|
}
|
|
40152
40494
|
async function disconnect() {
|
|
40153
|
-
await electron$
|
|
40495
|
+
await electron$B.wsDisconnect(request2.id);
|
|
40154
40496
|
}
|
|
40155
40497
|
async function sendMessage() {
|
|
40156
40498
|
const text = sendText.trim();
|
|
40157
40499
|
if (!text || !isConnected) return;
|
|
40158
40500
|
try {
|
|
40159
|
-
await electron$
|
|
40501
|
+
await electron$B.wsSend(request2.id, text);
|
|
40160
40502
|
const msg = {
|
|
40161
40503
|
id: crypto.randomUUID(),
|
|
40162
40504
|
direction: "sent",
|
|
@@ -40308,7 +40650,7 @@ function WebSocketPanel({ request: request2, onChange }) {
|
|
|
40308
40650
|
] })
|
|
40309
40651
|
] });
|
|
40310
40652
|
}
|
|
40311
|
-
const { electron: electron$
|
|
40653
|
+
const { electron: electron$A } = window;
|
|
40312
40654
|
function formatTime$3(ts) {
|
|
40313
40655
|
const d = new Date(ts);
|
|
40314
40656
|
const p = (n2, w = 2) => String(n2).padStart(w, "0");
|
|
@@ -40342,7 +40684,7 @@ function SocketIoPanel({ request: request2, onChange }) {
|
|
|
40342
40684
|
const url = interp(request2.url).trim();
|
|
40343
40685
|
const headers = {};
|
|
40344
40686
|
for (const h of request2.headers) if (h.enabled && h.key) headers[interp(h.key)] = interp(h.value);
|
|
40345
|
-
return electron$
|
|
40687
|
+
return electron$A.socketIoTest({
|
|
40346
40688
|
url,
|
|
40347
40689
|
namespace: namespace2,
|
|
40348
40690
|
auth: auth ? interp(auth) : void 0,
|
|
@@ -40361,19 +40703,19 @@ function SocketIoPanel({ request: request2, onChange }) {
|
|
|
40361
40703
|
if (h.enabled && h.key) headers[h.key] = h.value;
|
|
40362
40704
|
}
|
|
40363
40705
|
try {
|
|
40364
|
-
await electron$
|
|
40706
|
+
await electron$A.socketIoConnect(request2.id, { url: request2.url, namespace: namespace2, auth, headers });
|
|
40365
40707
|
} catch (err) {
|
|
40366
40708
|
setStatus(request2.id, "error", err instanceof Error ? err.message : String(err));
|
|
40367
40709
|
}
|
|
40368
40710
|
}
|
|
40369
40711
|
async function disconnect() {
|
|
40370
|
-
await electron$
|
|
40712
|
+
await electron$A.socketIoDisconnect(request2.id);
|
|
40371
40713
|
}
|
|
40372
40714
|
async function emit() {
|
|
40373
40715
|
const event = eventName2.trim();
|
|
40374
40716
|
if (!event || !isConnected) return;
|
|
40375
40717
|
try {
|
|
40376
|
-
await electron$
|
|
40718
|
+
await electron$A.socketIoEmit(request2.id, { event, args: argsText, withAck });
|
|
40377
40719
|
const msg = {
|
|
40378
40720
|
id: crypto.randomUUID(),
|
|
40379
40721
|
direction: "sent",
|
|
@@ -40587,7 +40929,7 @@ function SocketIoPanel({ request: request2, onChange }) {
|
|
|
40587
40929
|
] })
|
|
40588
40930
|
] });
|
|
40589
40931
|
}
|
|
40590
|
-
const { electron: electron$
|
|
40932
|
+
const { electron: electron$z } = window;
|
|
40591
40933
|
function formatTime$2(ts) {
|
|
40592
40934
|
const d = new Date(ts);
|
|
40593
40935
|
const p = (n2, w = 2) => String(n2).padStart(w, "0");
|
|
@@ -40627,7 +40969,7 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
40627
40969
|
return;
|
|
40628
40970
|
}
|
|
40629
40971
|
try {
|
|
40630
|
-
await electron$
|
|
40972
|
+
await electron$z.mqttConnect(request2.id, {
|
|
40631
40973
|
url,
|
|
40632
40974
|
clientId: cfg.clientId ? interp(cfg.clientId) : void 0,
|
|
40633
40975
|
username: cfg.username ? interp(cfg.username) : void 0,
|
|
@@ -40641,13 +40983,13 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
40641
40983
|
}
|
|
40642
40984
|
}
|
|
40643
40985
|
async function disconnect() {
|
|
40644
|
-
await electron$
|
|
40986
|
+
await electron$z.mqttDisconnect(request2.id);
|
|
40645
40987
|
}
|
|
40646
40988
|
async function subscribe() {
|
|
40647
40989
|
const topic = interp(cfg.subscribeTopic ?? "").trim();
|
|
40648
40990
|
if (!topic || !isConnected) return;
|
|
40649
40991
|
try {
|
|
40650
|
-
await electron$
|
|
40992
|
+
await electron$z.mqttSubscribe(request2.id, { topic, qos });
|
|
40651
40993
|
} catch (err) {
|
|
40652
40994
|
setStatus(request2.id, "error", err instanceof Error ? err.message : String(err));
|
|
40653
40995
|
}
|
|
@@ -40655,7 +40997,7 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
40655
40997
|
async function unsubscribe() {
|
|
40656
40998
|
const topic = interp(cfg.subscribeTopic ?? "").trim();
|
|
40657
40999
|
if (!topic || !isConnected) return;
|
|
40658
|
-
await electron$
|
|
41000
|
+
await electron$z.mqttUnsubscribe(request2.id, { topic });
|
|
40659
41001
|
}
|
|
40660
41002
|
async function publish() {
|
|
40661
41003
|
const topic = interp(cfg.publishTopic ?? "").trim();
|
|
@@ -40667,7 +41009,7 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
40667
41009
|
setPublishError("");
|
|
40668
41010
|
const body = interp(payload);
|
|
40669
41011
|
try {
|
|
40670
|
-
await electron$
|
|
41012
|
+
await electron$z.mqttPublish(request2.id, { topic, payload: body, qos, retain: Boolean(cfg.retain) });
|
|
40671
41013
|
addMessage(request2.id, {
|
|
40672
41014
|
id: crypto.randomUUID(),
|
|
40673
41015
|
direction: "sent",
|
|
@@ -40691,7 +41033,7 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
40691
41033
|
setTestRemaining(Math.ceil(collectMs / 1e3));
|
|
40692
41034
|
const countdown = setInterval(() => setTestRemaining((r) => r && r > 1 ? r - 1 : 0), 1e3);
|
|
40693
41035
|
try {
|
|
40694
|
-
const res = await electron$
|
|
41036
|
+
const res = await electron$z.mqttTest({
|
|
40695
41037
|
url,
|
|
40696
41038
|
// The test opens its own connection; never reuse the panel's Client ID,
|
|
40697
41039
|
// or the broker would kick whichever connected first (a clientId clash).
|
|
@@ -41040,7 +41382,7 @@ function MqttPanel({ request: request2, onChange }) {
|
|
|
41040
41382
|
] })
|
|
41041
41383
|
] });
|
|
41042
41384
|
}
|
|
41043
|
-
const { electron: electron$
|
|
41385
|
+
const { electron: electron$y } = window;
|
|
41044
41386
|
function formatTime$1(ts) {
|
|
41045
41387
|
const d = new Date(ts);
|
|
41046
41388
|
const p = (n2, w = 2) => String(n2).padStart(w, "0");
|
|
@@ -41076,13 +41418,13 @@ function GrpcPanel({ request: request2, onChange }) {
|
|
|
41076
41418
|
onChange({ body: { ...request2.body, mode: "grpc", grpc: { ...grpc, ...changes } } });
|
|
41077
41419
|
}
|
|
41078
41420
|
reactExports.useEffect(() => {
|
|
41079
|
-
electron$
|
|
41421
|
+
electron$y.onGrpcMessage(({ requestId, message }) => {
|
|
41080
41422
|
addGrpcMessage(requestId, message);
|
|
41081
41423
|
});
|
|
41082
|
-
electron$
|
|
41424
|
+
electron$y.onGrpcStatus(({ requestId, status, code, codeName, error: error2 }) => {
|
|
41083
41425
|
setGrpcStatus(requestId, status, { code, codeName, error: error2 });
|
|
41084
41426
|
});
|
|
41085
|
-
return () => electron$
|
|
41427
|
+
return () => electron$y.offGrpcEvents();
|
|
41086
41428
|
}, [addGrpcMessage, setGrpcStatus]);
|
|
41087
41429
|
reactExports.useEffect(() => {
|
|
41088
41430
|
logEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
@@ -41095,7 +41437,7 @@ function GrpcPanel({ request: request2, onChange }) {
|
|
|
41095
41437
|
if (!grpc.protoSource?.trim() && !grpc.protoPath?.trim()) return;
|
|
41096
41438
|
setLoadingProto(true);
|
|
41097
41439
|
try {
|
|
41098
|
-
const result = await electron$
|
|
41440
|
+
const result = await electron$y.grpcLoadProto({ protoSource: grpc.protoSource, protoPath: grpc.protoPath });
|
|
41099
41441
|
const services = result.services;
|
|
41100
41442
|
setGrpcServices(request2.id, services);
|
|
41101
41443
|
if (services.length && !services.some((s) => s.name === grpc.serviceName)) {
|
|
@@ -41114,7 +41456,7 @@ function GrpcPanel({ request: request2, onChange }) {
|
|
|
41114
41456
|
const metadata = {};
|
|
41115
41457
|
for (const m of grpc.metadata ?? []) if (m.enabled && m.key) metadata[m.key] = m.value;
|
|
41116
41458
|
try {
|
|
41117
|
-
await electron$
|
|
41459
|
+
await electron$y.grpcInvoke(request2.id, {
|
|
41118
41460
|
target: request2.url,
|
|
41119
41461
|
serviceName: grpc.serviceName,
|
|
41120
41462
|
methodName: grpc.methodName,
|
|
@@ -41129,7 +41471,7 @@ function GrpcPanel({ request: request2, onChange }) {
|
|
|
41129
41471
|
}
|
|
41130
41472
|
}
|
|
41131
41473
|
function cancel() {
|
|
41132
|
-
electron$
|
|
41474
|
+
electron$y.grpcCancel(request2.id);
|
|
41133
41475
|
}
|
|
41134
41476
|
const statusColors = {
|
|
41135
41477
|
running: "bg-amber-400",
|
|
@@ -41253,7 +41595,7 @@ function GrpcPanel({ request: request2, onChange }) {
|
|
|
41253
41595
|
] })
|
|
41254
41596
|
] });
|
|
41255
41597
|
}
|
|
41256
|
-
const { electron: electron$
|
|
41598
|
+
const { electron: electron$x } = window;
|
|
41257
41599
|
function isSubscriptionQuery(query) {
|
|
41258
41600
|
return /(^|\n)\s*subscription\b/i.test(query ?? "");
|
|
41259
41601
|
}
|
|
@@ -41302,7 +41644,7 @@ function GraphQlSubscription({ request: request2, gql, onPatch }) {
|
|
|
41302
41644
|
const headers = {};
|
|
41303
41645
|
for (const h of request2.headers) if (h.enabled && h.key) headers[interp(h.key)] = interp(h.value);
|
|
41304
41646
|
try {
|
|
41305
|
-
await electron$
|
|
41647
|
+
await electron$x.graphqlWsSubscribe(request2.id, {
|
|
41306
41648
|
url,
|
|
41307
41649
|
headers,
|
|
41308
41650
|
query: gql.query,
|
|
@@ -41319,7 +41661,7 @@ function GraphQlSubscription({ request: request2, gql, onPatch }) {
|
|
|
41319
41661
|
const url = deriveWsUrl(interp(rawUrl));
|
|
41320
41662
|
const headers = {};
|
|
41321
41663
|
for (const h of request2.headers) if (h.enabled && h.key) headers[interp(h.key)] = interp(h.value);
|
|
41322
|
-
return electron$
|
|
41664
|
+
return electron$x.graphqlWsTest({
|
|
41323
41665
|
url,
|
|
41324
41666
|
headers,
|
|
41325
41667
|
query: gql.query,
|
|
@@ -41354,7 +41696,7 @@ function GraphQlSubscription({ request: request2, gql, onPatch }) {
|
|
|
41354
41696
|
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
41697
|
}
|
|
41356
41698
|
),
|
|
41357
|
-
isActive ? /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => electron$
|
|
41699
|
+
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
41700
|
] }),
|
|
41359
41701
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-shrink-0", children: [
|
|
41360
41702
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { onClick: () => setShowParams((v) => !v), className: "text-[10px] text-surface-600 hover:text-surface-300 transition-colors", children: [
|
|
@@ -41622,7 +41964,7 @@ function FuzzResultsPanel({ report, onClear }) {
|
|
|
41622
41964
|
] }) })
|
|
41623
41965
|
] });
|
|
41624
41966
|
}
|
|
41625
|
-
const { electron: electron$
|
|
41967
|
+
const { electron: electron$w } = window;
|
|
41626
41968
|
const WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
41627
41969
|
function FuzzModal({ request: request2, onClose }) {
|
|
41628
41970
|
const t = useT();
|
|
@@ -41650,7 +41992,7 @@ function FuzzModal({ request: request2, onClose }) {
|
|
|
41650
41992
|
const env2 = resolveEnvironmentById(environments, activeEnvironmentId);
|
|
41651
41993
|
const envVars = env2 ? Object.fromEntries(env2.variables.filter((v) => v.enabled).map((v) => [v.key, v.value])) : {};
|
|
41652
41994
|
const collectionVars = activeCollectionId ? collections[activeCollectionId]?.data.collectionVariables ?? {} : {};
|
|
41653
|
-
const result = await electron$
|
|
41995
|
+
const result = await electron$w.fuzzContracts({
|
|
41654
41996
|
requests: [request2],
|
|
41655
41997
|
envVars,
|
|
41656
41998
|
collectionVars,
|
|
@@ -41867,7 +42209,7 @@ function resolveAskValues(asks, answers) {
|
|
|
41867
42209
|
for (const a of asks) out[a.key] = answers[a.message] ?? "";
|
|
41868
42210
|
return out;
|
|
41869
42211
|
}
|
|
41870
|
-
const { electron: electron$
|
|
42212
|
+
const { electron: electron$v } = window;
|
|
41871
42213
|
const METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS", "QUERY"];
|
|
41872
42214
|
const METHOD_COLORS = {
|
|
41873
42215
|
GET: "text-emerald-400",
|
|
@@ -42013,7 +42355,7 @@ function RequestBuilder({ request: request2 }) {
|
|
|
42013
42355
|
const headers = {};
|
|
42014
42356
|
for (const h of request2.headers) if (h.enabled && h.key) headers[interp(h.key)] = interp(h.value);
|
|
42015
42357
|
try {
|
|
42016
|
-
await electron$
|
|
42358
|
+
await electron$v.graphqlWsSubscribe(request2.id, {
|
|
42017
42359
|
url,
|
|
42018
42360
|
headers,
|
|
42019
42361
|
query: gql.query,
|
|
@@ -42074,7 +42416,7 @@ function RequestBuilder({ request: request2 }) {
|
|
|
42074
42416
|
const start2 = Date.now();
|
|
42075
42417
|
try {
|
|
42076
42418
|
const hookEnv = withEnvOverrides(activeEnv, liveEnvOverrides);
|
|
42077
|
-
const r = await electron$
|
|
42419
|
+
const r = await electron$v.sendRequest({
|
|
42078
42420
|
...basePayload,
|
|
42079
42421
|
environment: hookEnv,
|
|
42080
42422
|
request: hook,
|
|
@@ -42126,7 +42468,7 @@ function RequestBuilder({ request: request2 }) {
|
|
|
42126
42468
|
startLiveStream(activeTabId, streamId);
|
|
42127
42469
|
let result;
|
|
42128
42470
|
try {
|
|
42129
|
-
result = await electron$
|
|
42471
|
+
result = await electron$v.sendRequest({
|
|
42130
42472
|
...basePayload,
|
|
42131
42473
|
environment: freshEnv,
|
|
42132
42474
|
request: mergedRequest,
|
|
@@ -42163,7 +42505,7 @@ function RequestBuilder({ request: request2 }) {
|
|
|
42163
42505
|
const start2 = Date.now();
|
|
42164
42506
|
try {
|
|
42165
42507
|
const hookEnv = withEnvOverrides(activeEnv, liveEnvOverrides);
|
|
42166
|
-
const r = await electron$
|
|
42508
|
+
const r = await electron$v.sendRequest({
|
|
42167
42509
|
...basePayload,
|
|
42168
42510
|
environment: hookEnv,
|
|
42169
42511
|
request: hook,
|
|
@@ -43346,7 +43688,7 @@ function Cell({ value: value2, onDrill }) {
|
|
|
43346
43688
|
const text = String(value2);
|
|
43347
43689
|
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
43690
|
}
|
|
43349
|
-
const { electron: electron$
|
|
43691
|
+
const { electron: electron$u } = window;
|
|
43350
43692
|
const RENDER_TAIL = 500;
|
|
43351
43693
|
const CLOSE_LABEL = {
|
|
43352
43694
|
complete: "closed",
|
|
@@ -43388,7 +43730,7 @@ function StreamView({ events, streaming: streaming2, streamId, streamClose, firs
|
|
|
43388
43730
|
if (!streamId) return;
|
|
43389
43731
|
setStopping(true);
|
|
43390
43732
|
try {
|
|
43391
|
-
await electron$
|
|
43733
|
+
await electron$u.stopStream(streamId);
|
|
43392
43734
|
} catch {
|
|
43393
43735
|
}
|
|
43394
43736
|
}
|
|
@@ -43531,7 +43873,7 @@ function HookResultsPanel({ results }) {
|
|
|
43531
43873
|
}) })
|
|
43532
43874
|
] });
|
|
43533
43875
|
}
|
|
43534
|
-
const { electron: electron$
|
|
43876
|
+
const { electron: electron$t } = window;
|
|
43535
43877
|
function extractPath(url) {
|
|
43536
43878
|
try {
|
|
43537
43879
|
return new URL(url).pathname || "/";
|
|
@@ -43586,14 +43928,14 @@ function SaveAsMockModal({ onClose }) {
|
|
|
43586
43928
|
const entry = state.mocks[serverId];
|
|
43587
43929
|
const updated = { ...entry.data, name: newServerName, port: Number(newServerPort), routes: [route] };
|
|
43588
43930
|
updateMock(serverId, updated);
|
|
43589
|
-
await electron$
|
|
43931
|
+
await electron$t.saveMock(entry.relPath, updated);
|
|
43590
43932
|
const ws = useStore$1.getState().workspace;
|
|
43591
|
-
if (ws) await electron$
|
|
43933
|
+
if (ws) await electron$t.saveWorkspace(ws);
|
|
43592
43934
|
} else {
|
|
43593
43935
|
const entry = useStore$1.getState().mocks[serverId];
|
|
43594
43936
|
const updated = { ...entry.data, routes: [...entry.data.routes, route] };
|
|
43595
43937
|
updateMock(serverId, updated);
|
|
43596
|
-
await electron$
|
|
43938
|
+
await electron$t.saveMock(entry.relPath, updated);
|
|
43597
43939
|
}
|
|
43598
43940
|
onClose();
|
|
43599
43941
|
} finally {
|
|
@@ -44111,7 +44453,7 @@ function validateHttpSemantics(res, opts = {}) {
|
|
|
44111
44453
|
const order = { error: 0, warning: 1, hint: 2 };
|
|
44112
44454
|
return f.sort((a, b) => order[a.severity] - order[b.severity]);
|
|
44113
44455
|
}
|
|
44114
|
-
const { electron: electron$
|
|
44456
|
+
const { electron: electron$s } = window;
|
|
44115
44457
|
function xmlWellFormed(body) {
|
|
44116
44458
|
try {
|
|
44117
44459
|
const doc = new DOMParser().parseFromString(body, "application/xml");
|
|
@@ -44341,7 +44683,7 @@ function ResponseViewer() {
|
|
|
44341
44683
|
const schemaCheck = currentRequest?.schema?.trim() && response && !response.error ? validateBodyAgainstSchema(currentRequest.schema, response.body) : null;
|
|
44342
44684
|
async function saveAsSchema() {
|
|
44343
44685
|
if (!response || !requestId || !activeTabId) return;
|
|
44344
|
-
const schema = response.body ? await electron$
|
|
44686
|
+
const schema = response.body ? await electron$s.inferContractSchema(response.body) : null;
|
|
44345
44687
|
if (!schema) return;
|
|
44346
44688
|
updateRequest(requestId, { schema });
|
|
44347
44689
|
setTabRequestTab(activeTabId, "schema");
|
|
@@ -44929,7 +45271,7 @@ function listFolders(root2, depth = 0, out = []) {
|
|
|
44929
45271
|
}
|
|
44930
45272
|
return out;
|
|
44931
45273
|
}
|
|
44932
|
-
const { electron: electron$
|
|
45274
|
+
const { electron: electron$r } = window;
|
|
44933
45275
|
function fmtMs(ms) {
|
|
44934
45276
|
if (ms < 1) return "<1 ms";
|
|
44935
45277
|
if (ms < 1e3) return `${Math.round(ms)} ms`;
|
|
@@ -45120,11 +45462,11 @@ function PerformancePanel() {
|
|
|
45120
45462
|
setError("");
|
|
45121
45463
|
}, [activeId]);
|
|
45122
45464
|
reactExports.useEffect(() => {
|
|
45123
|
-
electron$
|
|
45465
|
+
electron$r.onPerfProgress((p) => {
|
|
45124
45466
|
setProgress(p);
|
|
45125
45467
|
setSamples((s) => [...s, p].slice(-240));
|
|
45126
45468
|
});
|
|
45127
|
-
return () => electron$
|
|
45469
|
+
return () => electron$r.offPerfEvents();
|
|
45128
45470
|
}, []);
|
|
45129
45471
|
const requestOptions = reactExports.useMemo(() => {
|
|
45130
45472
|
const out = [];
|
|
@@ -45171,7 +45513,7 @@ function PerformancePanel() {
|
|
|
45171
45513
|
if (saveTimer2.current) clearTimeout(saveTimer2.current);
|
|
45172
45514
|
saveTimer2.current = setTimeout(() => {
|
|
45173
45515
|
const ws = useStore$1.getState().workspace;
|
|
45174
|
-
if (ws) void electron$
|
|
45516
|
+
if (ws) void electron$r.saveWorkspace(ws);
|
|
45175
45517
|
}, 500);
|
|
45176
45518
|
}
|
|
45177
45519
|
async function run() {
|
|
@@ -45196,7 +45538,7 @@ function PerformancePanel() {
|
|
|
45196
45538
|
collections: Object.values(collections).map((c) => c.data),
|
|
45197
45539
|
...common
|
|
45198
45540
|
};
|
|
45199
|
-
setResult(await electron$
|
|
45541
|
+
setResult(await electron$r.perfRun(payload));
|
|
45200
45542
|
} catch (err) {
|
|
45201
45543
|
setError(err instanceof Error ? err.message : String(err));
|
|
45202
45544
|
} finally {
|
|
@@ -45205,14 +45547,14 @@ function PerformancePanel() {
|
|
|
45205
45547
|
}
|
|
45206
45548
|
}
|
|
45207
45549
|
async function stop() {
|
|
45208
|
-
await electron$
|
|
45550
|
+
await electron$r.perfStop();
|
|
45209
45551
|
}
|
|
45210
45552
|
async function exportReport() {
|
|
45211
45553
|
if (!result || !plan) return;
|
|
45212
45554
|
setExporting(true);
|
|
45213
45555
|
try {
|
|
45214
45556
|
const target = plan.target.kind === "request" ? selectedRequest?.name ?? "request" : selectedFlow?.name ?? "flow";
|
|
45215
|
-
await electron$
|
|
45557
|
+
await electron$r.perfExportHtml(result, { planName: plan.name, target });
|
|
45216
45558
|
} catch (err) {
|
|
45217
45559
|
setError(err instanceof Error ? err.message : String(err));
|
|
45218
45560
|
} finally {
|
|
@@ -45647,7 +45989,7 @@ function PerformancePanel() {
|
|
|
45647
45989
|
!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
45990
|
] });
|
|
45649
45991
|
}
|
|
45650
|
-
const { electron: electron$
|
|
45992
|
+
const { electron: electron$q } = window;
|
|
45651
45993
|
function makePlan(name) {
|
|
45652
45994
|
return {
|
|
45653
45995
|
id: crypto.randomUUID(),
|
|
@@ -45684,7 +46026,7 @@ function PerfPlansPanel() {
|
|
|
45684
46026
|
const updated = { ...workspace, perfPlans: next };
|
|
45685
46027
|
setWorkspace(updated, workspacePath ?? "");
|
|
45686
46028
|
try {
|
|
45687
|
-
await electron$
|
|
46029
|
+
await electron$q.saveWorkspace(updated);
|
|
45688
46030
|
} catch {
|
|
45689
46031
|
}
|
|
45690
46032
|
}
|
|
@@ -45828,7 +46170,7 @@ class ErrorBoundary extends React.Component {
|
|
|
45828
46170
|
] });
|
|
45829
46171
|
}
|
|
45830
46172
|
}
|
|
45831
|
-
const { electron: electron$
|
|
46173
|
+
const { electron: electron$p } = window;
|
|
45832
46174
|
const TARGETS = [
|
|
45833
46175
|
{ id: "robot_framework", label: "Robot Framework", description: "Python RequestsLibrary keywords + test suite" },
|
|
45834
46176
|
{ id: "playwright_ts", label: "Playwright TS", description: "TypeScript page-object API classes + spec files" },
|
|
@@ -45870,7 +46212,7 @@ function GeneratorPanel() {
|
|
|
45870
46212
|
try {
|
|
45871
46213
|
const col = collections[selectedCollectionId]?.data;
|
|
45872
46214
|
const env2 = resolveEnvironmentById(environments, activeEnvironmentId);
|
|
45873
|
-
const generated = await electron$
|
|
46215
|
+
const generated = await electron$p.generateCode({ collection: col, environment: env2, target });
|
|
45874
46216
|
setFiles(generated);
|
|
45875
46217
|
setSelectedFile(generated[0]?.path ?? null);
|
|
45876
46218
|
} catch (e) {
|
|
@@ -45882,7 +46224,7 @@ function GeneratorPanel() {
|
|
|
45882
46224
|
async function saveZip() {
|
|
45883
46225
|
if (files.length === 0) return;
|
|
45884
46226
|
const col = collections[selectedCollectionId]?.data;
|
|
45885
|
-
await electron$
|
|
46227
|
+
await electron$p.saveGeneratedFilesAsZip(files, col?.name ?? "api-tests", target);
|
|
45886
46228
|
}
|
|
45887
46229
|
const selectedContent = files.find((f) => f.path === selectedFile)?.content ?? "";
|
|
45888
46230
|
const activeTarget = TARGETS.find((tgt) => tgt.id === target);
|
|
@@ -46066,7 +46408,7 @@ function historyToHar(entries, creatorVersion = "1.0") {
|
|
|
46066
46408
|
}
|
|
46067
46409
|
}, null, 2);
|
|
46068
46410
|
}
|
|
46069
|
-
const { electron: electron$
|
|
46411
|
+
const { electron: electron$o } = window;
|
|
46070
46412
|
const STATUS_COLOR = {
|
|
46071
46413
|
"2": "text-emerald-400",
|
|
46072
46414
|
"3": "text-amber-400",
|
|
@@ -46120,7 +46462,7 @@ function HistoryPanel() {
|
|
|
46120
46462
|
}, [history, search]);
|
|
46121
46463
|
async function downloadHar() {
|
|
46122
46464
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replaceAll(/[:T]/g, "-");
|
|
46123
|
-
await electron$
|
|
46465
|
+
await electron$o.saveResults(historyToHar(history), `api-spector-history-${stamp}.har`);
|
|
46124
46466
|
}
|
|
46125
46467
|
function open2(entry) {
|
|
46126
46468
|
setSelected(entry);
|
|
@@ -46248,7 +46590,7 @@ function HistoryRow({
|
|
|
46248
46590
|
}
|
|
46249
46591
|
);
|
|
46250
46592
|
}
|
|
46251
|
-
const { electron: electron$
|
|
46593
|
+
const { electron: electron$n } = window;
|
|
46252
46594
|
function WelcomeScreen() {
|
|
46253
46595
|
const t = useT();
|
|
46254
46596
|
const { applyWorkspace } = useWorkspaceLoader();
|
|
@@ -46261,10 +46603,10 @@ function WelcomeScreen() {
|
|
|
46261
46603
|
const busyRef = reactExports.useRef(false);
|
|
46262
46604
|
const [busy, setBusy] = reactExports.useState(false);
|
|
46263
46605
|
reactExports.useEffect(() => {
|
|
46264
|
-
electron$
|
|
46265
|
-
electron$
|
|
46606
|
+
electron$n.getRecentWorkspaces().then(setRecents).catch(() => setRecents([]));
|
|
46607
|
+
electron$n.getUpdateMode().then((mode) => {
|
|
46266
46608
|
if (mode !== "npm") return;
|
|
46267
|
-
return electron$
|
|
46609
|
+
return electron$n.checkForUpdate().then((info) => {
|
|
46268
46610
|
if (info?.updateAvailable) setUpdate(info);
|
|
46269
46611
|
});
|
|
46270
46612
|
}).catch(() => {
|
|
@@ -46275,7 +46617,7 @@ function WelcomeScreen() {
|
|
|
46275
46617
|
busyRef.current = true;
|
|
46276
46618
|
setBusy(true);
|
|
46277
46619
|
try {
|
|
46278
|
-
const result = await electron$
|
|
46620
|
+
const result = await electron$n.openWorkspace();
|
|
46279
46621
|
if (result) await applyWorkspace(result.workspace, result.workspacePath);
|
|
46280
46622
|
} finally {
|
|
46281
46623
|
busyRef.current = false;
|
|
@@ -46287,7 +46629,7 @@ function WelcomeScreen() {
|
|
|
46287
46629
|
busyRef.current = true;
|
|
46288
46630
|
setBusy(true);
|
|
46289
46631
|
try {
|
|
46290
|
-
const result = await electron$
|
|
46632
|
+
const result = await electron$n.newWorkspace();
|
|
46291
46633
|
if (result) await applyWorkspace(result.workspace, result.workspacePath);
|
|
46292
46634
|
} finally {
|
|
46293
46635
|
busyRef.current = false;
|
|
@@ -46301,7 +46643,7 @@ function WelcomeScreen() {
|
|
|
46301
46643
|
setGitBusy(true);
|
|
46302
46644
|
setGitError(null);
|
|
46303
46645
|
try {
|
|
46304
|
-
const result = await electron$
|
|
46646
|
+
const result = await electron$n.openFromGit(url);
|
|
46305
46647
|
if (!result) return;
|
|
46306
46648
|
await applyWorkspace(result.workspace, result.workspacePath);
|
|
46307
46649
|
} catch (err) {
|
|
@@ -46316,7 +46658,7 @@ function WelcomeScreen() {
|
|
|
46316
46658
|
busyRef.current = true;
|
|
46317
46659
|
setBusy(true);
|
|
46318
46660
|
try {
|
|
46319
|
-
const result = await electron$
|
|
46661
|
+
const result = await electron$n.openWorkspacePath(path);
|
|
46320
46662
|
if (!result) {
|
|
46321
46663
|
setRecents((prev) => prev.filter((r) => r.path !== path));
|
|
46322
46664
|
return;
|
|
@@ -46352,7 +46694,7 @@ function WelcomeScreen() {
|
|
|
46352
46694
|
)
|
|
46353
46695
|
] }),
|
|
46354
46696
|
/* @__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.
|
|
46697
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: t("version :version", { version: "0.9.2" }) })
|
|
46356
46698
|
] }),
|
|
46357
46699
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 w-64", children: [
|
|
46358
46700
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -46434,7 +46776,7 @@ function WelcomeScreen() {
|
|
|
46434
46776
|
] })
|
|
46435
46777
|
] });
|
|
46436
46778
|
}
|
|
46437
|
-
const { electron: electron$
|
|
46779
|
+
const { electron: electron$m } = window;
|
|
46438
46780
|
const EXAMPLES = [
|
|
46439
46781
|
{
|
|
46440
46782
|
label: "macOS / Linux (~/.zshrc or ~/.bashrc)",
|
|
@@ -46459,7 +46801,7 @@ function MasterKeyModal({ onSuccess, onCancel }) {
|
|
|
46459
46801
|
setError(t("Password cannot be empty."));
|
|
46460
46802
|
return;
|
|
46461
46803
|
}
|
|
46462
|
-
await electron$
|
|
46804
|
+
await electron$m.setMasterKey(password);
|
|
46463
46805
|
onSuccess(password);
|
|
46464
46806
|
}
|
|
46465
46807
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
@@ -46538,7 +46880,7 @@ function MasterKeyModal({ onSuccess, onCancel }) {
|
|
|
46538
46880
|
}
|
|
46539
46881
|
);
|
|
46540
46882
|
}
|
|
46541
|
-
const { electron: electron$
|
|
46883
|
+
const { electron: electron$l } = window;
|
|
46542
46884
|
async function shortHash(value2) {
|
|
46543
46885
|
const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value2));
|
|
46544
46886
|
return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8);
|
|
@@ -46653,12 +46995,12 @@ function EnvironmentEditor({ onClose }) {
|
|
|
46653
46995
|
if (next) setSelectedId(next);
|
|
46654
46996
|
}
|
|
46655
46997
|
async function importFromPostman() {
|
|
46656
|
-
const imported = await electron$
|
|
46998
|
+
const imported = await electron$l.importPostmanEnvironment();
|
|
46657
46999
|
if (!imported) return;
|
|
46658
47000
|
const existingNames = Object.values(useStore$1.getState().environments).map((e) => e.data.name);
|
|
46659
47001
|
const finalEnv = { ...imported, name: uniqueName$1(imported.name || t("Imported Environment"), existingNames) };
|
|
46660
47002
|
const relPath = envRelPath(finalEnv.name, finalEnv.id);
|
|
46661
|
-
await electron$
|
|
47003
|
+
await electron$l.saveEnvironment(relPath, finalEnv);
|
|
46662
47004
|
useStore$1.setState((s) => {
|
|
46663
47005
|
s.environments[finalEnv.id] = { relPath, data: finalEnv };
|
|
46664
47006
|
if (!s.activeEnvironmentId) s.activeEnvironmentId = finalEnv.id;
|
|
@@ -46668,7 +47010,7 @@ function EnvironmentEditor({ onClose }) {
|
|
|
46668
47010
|
return s;
|
|
46669
47011
|
});
|
|
46670
47012
|
const ws = useStore$1.getState().workspace;
|
|
46671
|
-
if (ws) await electron$
|
|
47013
|
+
if (ws) await electron$l.saveWorkspace(ws);
|
|
46672
47014
|
setSelectedId(finalEnv.id);
|
|
46673
47015
|
}
|
|
46674
47016
|
function updateVar(idx, patch) {
|
|
@@ -46721,9 +47063,9 @@ function EnvironmentEditor({ onClose }) {
|
|
|
46721
47063
|
async function saveEncrypted(idx) {
|
|
46722
47064
|
const plaintext = secretInputs[idx] ?? "";
|
|
46723
47065
|
if (!plaintext) return;
|
|
46724
|
-
const { set: set2 } = await electron$
|
|
47066
|
+
const { set: set2 } = await electron$l.checkMasterKey();
|
|
46725
47067
|
if (set2) {
|
|
46726
|
-
applyEncrypted(idx, await electron$
|
|
47068
|
+
applyEncrypted(idx, await electron$l.encryptWithMasterKey(plaintext));
|
|
46727
47069
|
return;
|
|
46728
47070
|
}
|
|
46729
47071
|
setPendingEncryptIdx(idx);
|
|
@@ -46758,9 +47100,9 @@ function EnvironmentEditor({ onClose }) {
|
|
|
46758
47100
|
} : state.workspace
|
|
46759
47101
|
}));
|
|
46760
47102
|
const ws = useStore$1.getState().workspace;
|
|
46761
|
-
if (ws) await electron$
|
|
47103
|
+
if (ws) await electron$l.saveWorkspace(ws);
|
|
46762
47104
|
}
|
|
46763
|
-
await electron$
|
|
47105
|
+
await electron$l.saveEnvironment(newRelPath, env2);
|
|
46764
47106
|
}
|
|
46765
47107
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
46766
47108
|
confirmDialog,
|
|
@@ -47125,7 +47467,7 @@ function EnvironmentEditor({ onClose }) {
|
|
|
47125
47467
|
)
|
|
47126
47468
|
] });
|
|
47127
47469
|
}
|
|
47128
|
-
const { electron: electron$
|
|
47470
|
+
const { electron: electron$k } = window;
|
|
47129
47471
|
function EnvironmentBar({ inline = false }) {
|
|
47130
47472
|
const t = useT();
|
|
47131
47473
|
const environments = useStore$1((s) => s.environments);
|
|
@@ -47141,7 +47483,7 @@ function EnvironmentBar({ inline = false }) {
|
|
|
47141
47483
|
if (id2) {
|
|
47142
47484
|
const hasSecrets = environments[id2]?.data.variables.some((v) => v.enabled && v.secret);
|
|
47143
47485
|
if (hasSecrets) {
|
|
47144
|
-
const { set: set2 } = await electron$
|
|
47486
|
+
const { set: set2 } = await electron$k.checkMasterKey();
|
|
47145
47487
|
if (!set2) {
|
|
47146
47488
|
setPendingEnvId(id2);
|
|
47147
47489
|
return;
|
|
@@ -47348,10 +47690,204 @@ function ProductTour() {
|
|
|
47348
47690
|
)
|
|
47349
47691
|
] });
|
|
47350
47692
|
}
|
|
47693
|
+
const { electron: electron$j } = window;
|
|
47694
|
+
function getSyncSettings() {
|
|
47695
|
+
return useStore$1.getState().workspace?.settings?.sync ?? { mode: "git" };
|
|
47696
|
+
}
|
|
47697
|
+
async function persistSync(patch) {
|
|
47698
|
+
const s = useStore$1.getState();
|
|
47699
|
+
const ws = s.workspace;
|
|
47700
|
+
if (!ws) return;
|
|
47701
|
+
const sync = { ...ws.settings?.sync ?? { mode: "cloud" }, ...patch };
|
|
47702
|
+
const settings = { ...ws.settings, sync };
|
|
47703
|
+
s.updateWorkspaceSettings(settings);
|
|
47704
|
+
await electron$j.saveWorkspace({ ...ws, settings });
|
|
47705
|
+
}
|
|
47706
|
+
async function setSyncMode(mode) {
|
|
47707
|
+
await persistSync({ mode });
|
|
47708
|
+
}
|
|
47709
|
+
function workspaceName(manifestName) {
|
|
47710
|
+
return manifestName.replace(/\.(spector|json)$/i, "") || "Workspace";
|
|
47711
|
+
}
|
|
47712
|
+
async function flushToDisk() {
|
|
47713
|
+
const s = useStore$1.getState();
|
|
47714
|
+
for (const { relPath, data, dirty } of Object.values(s.collections)) {
|
|
47715
|
+
if (!dirty) continue;
|
|
47716
|
+
await electron$j.saveCollection(relPath, data);
|
|
47717
|
+
s.markCollectionClean(data.id);
|
|
47718
|
+
}
|
|
47719
|
+
for (const { relPath, data } of Object.values(s.environments)) {
|
|
47720
|
+
await electron$j.saveEnvironment(relPath, data);
|
|
47721
|
+
}
|
|
47722
|
+
for (const { relPath, data } of Object.values(s.flows)) {
|
|
47723
|
+
await electron$j.saveFlow(relPath, data);
|
|
47724
|
+
}
|
|
47725
|
+
if (s.workspace) await electron$j.saveWorkspace(s.workspace);
|
|
47726
|
+
}
|
|
47727
|
+
async function pushWorkspace() {
|
|
47728
|
+
const sync = getSyncSettings();
|
|
47729
|
+
await flushToDisk();
|
|
47730
|
+
const snap = await electron$j.serializeWorkspace();
|
|
47731
|
+
const files = snap.files ?? {};
|
|
47732
|
+
const collections = Object.keys(files).filter((p) => p.startsWith("collections/")).length;
|
|
47733
|
+
const flows = Object.keys(files).filter((p) => p.startsWith("flows/")).length;
|
|
47734
|
+
if (!sync.cloudWorkspaceId) {
|
|
47735
|
+
const created = await electron$j.cloudWorkspaceCreate({ name: workspaceName(snap.manifestName), payload: snap });
|
|
47736
|
+
await persistSync({ mode: "cloud", cloudWorkspaceId: created.id, baseVersion: created.version });
|
|
47737
|
+
return { ok: true, version: created.version, collections, flows };
|
|
47738
|
+
}
|
|
47739
|
+
const res = await electron$j.cloudWorkspacePush({
|
|
47740
|
+
id: sync.cloudWorkspaceId,
|
|
47741
|
+
baseVersion: sync.baseVersion ?? 0,
|
|
47742
|
+
payload: snap
|
|
47743
|
+
});
|
|
47744
|
+
if (res.conflict) return { ok: false, conflict: true, currentVersion: res.currentVersion };
|
|
47745
|
+
await persistSync({ baseVersion: res.version });
|
|
47746
|
+
return { ok: true, version: res.version ?? 0, collections, flows };
|
|
47747
|
+
}
|
|
47748
|
+
async function pullWorkspace() {
|
|
47749
|
+
const sync = getSyncSettings();
|
|
47750
|
+
if (!sync.cloudWorkspaceId) {
|
|
47751
|
+
throw new Error("This workspace is not linked to a cloud workspace yet. Push it first, or link an existing one.");
|
|
47752
|
+
}
|
|
47753
|
+
const remote = await electron$j.cloudWorkspacePull(sync.cloudWorkspaceId);
|
|
47754
|
+
const payload = remote.payload ?? {};
|
|
47755
|
+
if (!payload.manifest || !payload.files) {
|
|
47756
|
+
throw new Error("The cloud workspace has no snapshot yet. Push from a populated workspace first.");
|
|
47757
|
+
}
|
|
47758
|
+
const applied = await electron$j.applyWorkspaceSnapshot({ manifest: payload.manifest, files: payload.files });
|
|
47759
|
+
return {
|
|
47760
|
+
version: remote.version,
|
|
47761
|
+
filesWritten: applied.filesWritten,
|
|
47762
|
+
collections: applied.collections,
|
|
47763
|
+
workspace: applied.workspace,
|
|
47764
|
+
workspacePath: applied.workspacePath
|
|
47765
|
+
};
|
|
47766
|
+
}
|
|
47767
|
+
async function markPulled(version) {
|
|
47768
|
+
await persistSync({ baseVersion: version });
|
|
47769
|
+
}
|
|
47770
|
+
async function listCloudWorkspaces() {
|
|
47771
|
+
const res = await electron$j.cloudWorkspaceList();
|
|
47772
|
+
return res.workspaces;
|
|
47773
|
+
}
|
|
47774
|
+
async function linkToCloudWorkspace(id2) {
|
|
47775
|
+
await persistSync({ mode: "cloud", cloudWorkspaceId: id2, baseVersion: 0 });
|
|
47776
|
+
}
|
|
47777
|
+
function SyncSettingsPanel() {
|
|
47778
|
+
const t = useT();
|
|
47779
|
+
const { applyWorkspace } = useWorkspaceLoader();
|
|
47780
|
+
const initial = getSyncSettings();
|
|
47781
|
+
const [mode, setMode] = reactExports.useState(initial.mode);
|
|
47782
|
+
const [linked, setLinked] = reactExports.useState(!!initial.cloudWorkspaceId);
|
|
47783
|
+
const [busy, setBusy] = reactExports.useState(false);
|
|
47784
|
+
const [status, setStatus] = reactExports.useState(null);
|
|
47785
|
+
const [remote, setRemote] = reactExports.useState(null);
|
|
47786
|
+
const cloudOn = cloudEnabled();
|
|
47787
|
+
async function changeMode(m) {
|
|
47788
|
+
setMode(m);
|
|
47789
|
+
setStatus(null);
|
|
47790
|
+
try {
|
|
47791
|
+
await setSyncMode(m);
|
|
47792
|
+
} catch (e) {
|
|
47793
|
+
setStatus({ msg: e.message, ok: false });
|
|
47794
|
+
}
|
|
47795
|
+
}
|
|
47796
|
+
async function run(fn) {
|
|
47797
|
+
setBusy(true);
|
|
47798
|
+
setStatus(null);
|
|
47799
|
+
try {
|
|
47800
|
+
setStatus({ msg: await fn(), ok: true });
|
|
47801
|
+
} catch (e) {
|
|
47802
|
+
setStatus({ msg: e.message, ok: false });
|
|
47803
|
+
} finally {
|
|
47804
|
+
setBusy(false);
|
|
47805
|
+
}
|
|
47806
|
+
}
|
|
47807
|
+
const doPush = () => run(async () => {
|
|
47808
|
+
const res = await pushWorkspace();
|
|
47809
|
+
if (!res.ok) throw new Error(t("Someone else pushed changes (cloud is at v:v). Pull first, then push again.", { v: res.currentVersion ?? "?" }));
|
|
47810
|
+
setLinked(true);
|
|
47811
|
+
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 });
|
|
47812
|
+
});
|
|
47813
|
+
const doPull = () => run(async () => {
|
|
47814
|
+
const r = await pullWorkspace();
|
|
47815
|
+
await applyWorkspace(r.workspace, r.workspacePath);
|
|
47816
|
+
await markPulled(r.version);
|
|
47817
|
+
return t("Pulled version :v: :files file(s), :c collection(s).", { v: r.version, files: r.filesWritten, c: r.collections });
|
|
47818
|
+
});
|
|
47819
|
+
const loadRemote = () => run(async () => {
|
|
47820
|
+
const list = await listCloudWorkspaces();
|
|
47821
|
+
setRemote(list);
|
|
47822
|
+
return t(":n cloud workspace(s) in your organization.", { n: list.length });
|
|
47823
|
+
});
|
|
47824
|
+
const joinExisting = (id2) => run(async () => {
|
|
47825
|
+
await linkToCloudWorkspace(id2);
|
|
47826
|
+
const r = await pullWorkspace();
|
|
47827
|
+
await applyWorkspace(r.workspace, r.workspacePath);
|
|
47828
|
+
await markPulled(r.version);
|
|
47829
|
+
setLinked(true);
|
|
47830
|
+
return t("Linked and pulled: :files file(s), :c collection(s).", { files: r.filesWritten, c: r.collections });
|
|
47831
|
+
});
|
|
47832
|
+
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";
|
|
47833
|
+
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";
|
|
47834
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-5 text-sm text-surface-200", children: [
|
|
47835
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
47836
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-semibold text-[var(--text-primary)]", children: t("Workspace sync") }),
|
|
47837
|
+
/* @__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.") })
|
|
47838
|
+
] }),
|
|
47839
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex flex-col gap-1", children: [
|
|
47840
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs uppercase tracking-wide text-surface-500", children: t("Mode") }),
|
|
47841
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
47842
|
+
"select",
|
|
47843
|
+
{
|
|
47844
|
+
value: mode,
|
|
47845
|
+
onChange: (e) => changeMode(e.target.value),
|
|
47846
|
+
className: "rounded bg-surface-950 border border-surface-700 px-2 py-1.5 text-sm w-56",
|
|
47847
|
+
children: [
|
|
47848
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "git", children: t("Git (default) — use the Git panel") }),
|
|
47849
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "cloud", children: t("Cloud — sync through API Spector Cloud") }),
|
|
47850
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "local", children: t("Local only — no sync") })
|
|
47851
|
+
]
|
|
47852
|
+
}
|
|
47853
|
+
)
|
|
47854
|
+
] }),
|
|
47855
|
+
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.") }),
|
|
47856
|
+
mode === "local" && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-400", children: t("No syncing. Changes stay on this machine.") }),
|
|
47857
|
+
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.") }),
|
|
47858
|
+
mode === "cloud" && cloudOn && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
47859
|
+
/* @__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.") }),
|
|
47860
|
+
linked ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
47861
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: btnPrimary, disabled: busy, onClick: doPush, children: t("Push") }),
|
|
47862
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: btn, disabled: busy, onClick: doPull, children: t("Pull") })
|
|
47863
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
47864
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
47865
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: btnPrimary, disabled: busy, onClick: doPush, children: t("Create cloud workspace (push)") }),
|
|
47866
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: btn, disabled: busy, onClick: loadRemote, children: t("Join an existing one") })
|
|
47867
|
+
] }),
|
|
47868
|
+
remote && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "rounded border border-surface-700 divide-y divide-surface-800", children: [
|
|
47869
|
+
remote.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 py-2 text-xs text-surface-500", children: t("No cloud workspaces yet.") }),
|
|
47870
|
+
remote.map((w) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-3 py-2", children: [
|
|
47871
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex-1 truncate", children: [
|
|
47872
|
+
w.name,
|
|
47873
|
+
" ",
|
|
47874
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-500", children: [
|
|
47875
|
+
"v",
|
|
47876
|
+
w.version
|
|
47877
|
+
] })
|
|
47878
|
+
] }),
|
|
47879
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: btn, disabled: busy, onClick: () => joinExisting(w.id), children: t("Join & pull") })
|
|
47880
|
+
] }, w.id))
|
|
47881
|
+
] })
|
|
47882
|
+
] })
|
|
47883
|
+
] }),
|
|
47884
|
+
status && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: `text-xs ${status.ok ? "text-emerald-400" : "text-red-400"}`, children: status.msg })
|
|
47885
|
+
] });
|
|
47886
|
+
}
|
|
47351
47887
|
const { electron: electron$i } = window;
|
|
47352
47888
|
const DEFAULT_PII_PATTERNS = ["authorization", "password", "token", "secret", "api-key", "x-api-key"];
|
|
47353
47889
|
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"];
|
|
47890
|
+
const SETTINGS_TABS = ["general", "appearance", "proxy", "tls", "privacy", "cloud", "sync", "ai", "secrets"];
|
|
47355
47891
|
function WorkspaceSettingsModal({ onClose, initialTab }) {
|
|
47356
47892
|
const workspace = useStore$1((s) => s.workspace);
|
|
47357
47893
|
const updateWorkspaceSettings = useStore$1((s) => s.updateWorkspaceSettings);
|
|
@@ -47559,6 +48095,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
|
|
|
47559
48095
|
{ id: "privacy", label: t("Privacy") },
|
|
47560
48096
|
{ id: "secrets", label: t("Secrets") },
|
|
47561
48097
|
{ id: "cloud", label: t("Cloud") },
|
|
48098
|
+
{ id: "sync", label: t("Sync") },
|
|
47562
48099
|
{ id: "ai", label: t("AI") }
|
|
47563
48100
|
];
|
|
47564
48101
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
@@ -47883,6 +48420,7 @@ function WorkspaceSettingsModal({ onClose, initialTab }) {
|
|
|
47883
48420
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("Reject unauthorized / self-signed certificates") })
|
|
47884
48421
|
] })
|
|
47885
48422
|
] }),
|
|
48423
|
+
activeTab === "sync" && /* @__PURE__ */ jsxRuntimeExports.jsx(SyncSettingsPanel, {}),
|
|
47886
48424
|
activeTab === "ai" && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
47887
48425
|
/* @__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
48426
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
@@ -54572,6 +55110,16 @@ function ChangesTab({ status, onRefresh }) {
|
|
|
54572
55110
|
setError(String(e));
|
|
54573
55111
|
}
|
|
54574
55112
|
}
|
|
55113
|
+
async function stash() {
|
|
55114
|
+
try {
|
|
55115
|
+
setError(null);
|
|
55116
|
+
await electron$4.gitStash();
|
|
55117
|
+
showToast(t("Changes stashed - restore them from the Branches tab"), true);
|
|
55118
|
+
onRefresh();
|
|
55119
|
+
} catch (e) {
|
|
55120
|
+
setError(String(e));
|
|
55121
|
+
}
|
|
55122
|
+
}
|
|
54575
55123
|
async function fetch() {
|
|
54576
55124
|
setFetching(true);
|
|
54577
55125
|
try {
|
|
@@ -54624,6 +55172,7 @@ function ChangesTab({ status, onRefresh }) {
|
|
|
54624
55172
|
}
|
|
54625
55173
|
const allUnstaged = [...status.unstaged, ...status.untracked];
|
|
54626
55174
|
const hasStaged = status.staged.length > 0;
|
|
55175
|
+
const isDirty = hasStaged || status.unstaged.length > 0 || status.untracked.length > 0;
|
|
54627
55176
|
const needsPush = status.ahead > 0;
|
|
54628
55177
|
const needsPull = status.behind > 0;
|
|
54629
55178
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
@@ -54880,15 +55429,27 @@ function ChangesTab({ status, onRefresh }) {
|
|
|
54880
55429
|
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
55430
|
}
|
|
54882
55431
|
),
|
|
54883
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
54884
|
-
|
|
54885
|
-
|
|
54886
|
-
|
|
54887
|
-
|
|
54888
|
-
|
|
54889
|
-
|
|
54890
|
-
|
|
54891
|
-
|
|
55432
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
55433
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55434
|
+
"button",
|
|
55435
|
+
{
|
|
55436
|
+
onClick: commit,
|
|
55437
|
+
disabled: !message.trim() || !hasStaged,
|
|
55438
|
+
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",
|
|
55439
|
+
children: hasStaged ? t("Commit (:count)", { count: status.staged.length }) : t("Commit")
|
|
55440
|
+
}
|
|
55441
|
+
),
|
|
55442
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55443
|
+
"button",
|
|
55444
|
+
{
|
|
55445
|
+
onClick: stash,
|
|
55446
|
+
disabled: !isDirty,
|
|
55447
|
+
title: t("Park all uncommitted changes - restore them later from the Branches tab"),
|
|
55448
|
+
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",
|
|
55449
|
+
children: t("Stash")
|
|
55450
|
+
}
|
|
55451
|
+
)
|
|
55452
|
+
] })
|
|
54892
55453
|
] })
|
|
54893
55454
|
] });
|
|
54894
55455
|
}
|
|
@@ -54916,6 +55477,8 @@ function BranchesTab({ onRefresh }) {
|
|
|
54916
55477
|
const t = useT();
|
|
54917
55478
|
const [branches, setBranches] = reactExports.useState([]);
|
|
54918
55479
|
const [remotes, setRemotes] = reactExports.useState([]);
|
|
55480
|
+
const [stashes, setStashes] = reactExports.useState([]);
|
|
55481
|
+
const [info, setInfo] = reactExports.useState(null);
|
|
54919
55482
|
const [loading, setLoading] = reactExports.useState(true);
|
|
54920
55483
|
const [newBranch, setNewBranch] = reactExports.useState("");
|
|
54921
55484
|
const [creating, setCreating] = reactExports.useState(false);
|
|
@@ -54929,9 +55492,10 @@ function BranchesTab({ onRefresh }) {
|
|
|
54929
55492
|
const [filter2, setFilter] = reactExports.useState("");
|
|
54930
55493
|
const load2 = reactExports.useCallback(() => {
|
|
54931
55494
|
setLoadError(null);
|
|
54932
|
-
Promise.all([electron$4.gitBranches(), electron$4.gitRemotes()]).then(([b, r]) => {
|
|
55495
|
+
Promise.all([electron$4.gitBranches(), electron$4.gitRemotes(), electron$4.gitStashList()]).then(([b, r, s]) => {
|
|
54933
55496
|
setBranches(b);
|
|
54934
55497
|
setRemotes(r);
|
|
55498
|
+
setStashes(s);
|
|
54935
55499
|
}).catch((err) => {
|
|
54936
55500
|
console.warn("GitPanel: failed to load branches/remotes", err);
|
|
54937
55501
|
setLoadError(err instanceof Error ? err.message : String(err));
|
|
@@ -54940,13 +55504,34 @@ function BranchesTab({ onRefresh }) {
|
|
|
54940
55504
|
reactExports.useEffect(() => {
|
|
54941
55505
|
load2();
|
|
54942
55506
|
}, [load2]);
|
|
55507
|
+
function isDirtyTreeError(msg) {
|
|
55508
|
+
return /overwritten by (checkout|merge)|commit your changes or stash/i.test(msg);
|
|
55509
|
+
}
|
|
55510
|
+
async function checkoutOrStash(localName, create2) {
|
|
55511
|
+
try {
|
|
55512
|
+
await electron$4.gitCheckout(localName, create2);
|
|
55513
|
+
return true;
|
|
55514
|
+
} catch (e) {
|
|
55515
|
+
const msg = String(e);
|
|
55516
|
+
if (!isDirtyTreeError(msg)) throw e;
|
|
55517
|
+
if (!confirm(t('You have uncommitted changes that would be lost switching to ":name". Stash them and switch?', { name: localName }))) {
|
|
55518
|
+
return false;
|
|
55519
|
+
}
|
|
55520
|
+
await electron$4.gitStash(t("Auto-stash before switching to :name", { name: localName }));
|
|
55521
|
+
await electron$4.gitCheckout(localName, create2);
|
|
55522
|
+
setInfo(t("Your changes were stashed. Restore them from the Stashes list below when you return."));
|
|
55523
|
+
return true;
|
|
55524
|
+
}
|
|
55525
|
+
}
|
|
54943
55526
|
async function checkout(name, remote2) {
|
|
54944
55527
|
try {
|
|
54945
55528
|
setError(null);
|
|
55529
|
+
setInfo(null);
|
|
54946
55530
|
const localName = remote2 ? name.replace(/^origin\//, "") : name;
|
|
54947
|
-
await
|
|
54948
|
-
|
|
54949
|
-
|
|
55531
|
+
if (await checkoutOrStash(localName, false)) {
|
|
55532
|
+
load2();
|
|
55533
|
+
onRefresh();
|
|
55534
|
+
}
|
|
54950
55535
|
} catch (e) {
|
|
54951
55536
|
setError(String(e));
|
|
54952
55537
|
}
|
|
@@ -54955,15 +55540,39 @@ function BranchesTab({ onRefresh }) {
|
|
|
54955
55540
|
if (!newBranch.trim()) return;
|
|
54956
55541
|
try {
|
|
54957
55542
|
setError(null);
|
|
54958
|
-
|
|
54959
|
-
|
|
54960
|
-
|
|
55543
|
+
setInfo(null);
|
|
55544
|
+
if (await checkoutOrStash(newBranch.trim(), true)) {
|
|
55545
|
+
setNewBranch("");
|
|
55546
|
+
setCreating(false);
|
|
55547
|
+
load2();
|
|
55548
|
+
onRefresh();
|
|
55549
|
+
}
|
|
55550
|
+
} catch (e) {
|
|
55551
|
+
setError(String(e));
|
|
55552
|
+
}
|
|
55553
|
+
}
|
|
55554
|
+
async function popStash(ref) {
|
|
55555
|
+
try {
|
|
55556
|
+
setError(null);
|
|
55557
|
+
setInfo(null);
|
|
55558
|
+
await electron$4.gitStashPop(ref);
|
|
54961
55559
|
load2();
|
|
54962
55560
|
onRefresh();
|
|
54963
55561
|
} catch (e) {
|
|
54964
55562
|
setError(String(e));
|
|
54965
55563
|
}
|
|
54966
55564
|
}
|
|
55565
|
+
async function dropStash(ref) {
|
|
55566
|
+
if (!confirm(t("Discard stashed changes (:ref)? This cannot be undone.", { ref }))) return;
|
|
55567
|
+
try {
|
|
55568
|
+
setError(null);
|
|
55569
|
+
setInfo(null);
|
|
55570
|
+
await electron$4.gitStashDrop(ref);
|
|
55571
|
+
load2();
|
|
55572
|
+
} catch (e) {
|
|
55573
|
+
setError(String(e));
|
|
55574
|
+
}
|
|
55575
|
+
}
|
|
54967
55576
|
async function addRemote() {
|
|
54968
55577
|
if (!remoteName.trim() || !remoteUrl.trim()) return;
|
|
54969
55578
|
try {
|
|
@@ -55022,7 +55631,8 @@ function BranchesTab({ onRefresh }) {
|
|
|
55022
55631
|
const remote = branches.filter((b) => b.remote && (!q || b.name.toLowerCase().includes(q)));
|
|
55023
55632
|
if (loading) return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 px-3 py-4", children: t("Loading…") });
|
|
55024
55633
|
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 }),
|
|
55634
|
+
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-red-400 px-3 py-1 truncate", title: error2, children: error2 }),
|
|
55635
|
+
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
55636
|
loadError && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] text-amber-400 px-3 py-1 truncate", title: loadError, children: [
|
|
55027
55637
|
t("Couldn't load git state:"),
|
|
55028
55638
|
" ",
|
|
@@ -55114,6 +55724,37 @@ function BranchesTab({ onRefresh }) {
|
|
|
55114
55724
|
))
|
|
55115
55725
|
] }),
|
|
55116
55726
|
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 }) }),
|
|
55727
|
+
stashes.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "border-t border-surface-800 mt-1", children: [
|
|
55728
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "px-3 py-1.5 text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: t("Stashes") }),
|
|
55729
|
+
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: [
|
|
55730
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-[10px] text-surface-500 shrink-0", children: s.ref }),
|
|
55731
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "truncate flex-1", title: s.branch ? t("on :branch: :message", { branch: s.branch, message: s.message }) : s.message, children: [
|
|
55732
|
+
s.message,
|
|
55733
|
+
s.branch && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-600", children: [
|
|
55734
|
+
" ",
|
|
55735
|
+
t("(on :branch)", { branch: s.branch })
|
|
55736
|
+
] })
|
|
55737
|
+
] }),
|
|
55738
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55739
|
+
"button",
|
|
55740
|
+
{
|
|
55741
|
+
onClick: () => popStash(s.ref),
|
|
55742
|
+
className: "opacity-0 group-hover:opacity-100 text-[10px] text-blue-400 hover:text-blue-300 transition-all shrink-0",
|
|
55743
|
+
title: t("Restore these changes onto the current branch"),
|
|
55744
|
+
children: t("Pop")
|
|
55745
|
+
}
|
|
55746
|
+
),
|
|
55747
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55748
|
+
"button",
|
|
55749
|
+
{
|
|
55750
|
+
onClick: () => dropStash(s.ref),
|
|
55751
|
+
className: "opacity-0 group-hover:opacity-100 text-[10px] text-surface-500 hover:text-red-400 transition-all shrink-0",
|
|
55752
|
+
title: t("Discard this stash"),
|
|
55753
|
+
children: "✕"
|
|
55754
|
+
}
|
|
55755
|
+
)
|
|
55756
|
+
] }, s.ref))
|
|
55757
|
+
] }),
|
|
55117
55758
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "border-t border-surface-800 mt-1", children: [
|
|
55118
55759
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-1.5 flex items-center justify-between", children: [
|
|
55119
55760
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] uppercase tracking-widest text-surface-500 font-semibold", children: t("Remotes") }),
|
|
@@ -57912,6 +58553,43 @@ function App() {
|
|
|
57912
58553
|
});
|
|
57913
58554
|
return () => electron.offOpenFromGit();
|
|
57914
58555
|
}, [applyWorkspace]);
|
|
58556
|
+
reactExports.useEffect(() => {
|
|
58557
|
+
electron.onImportShare(async (token) => {
|
|
58558
|
+
try {
|
|
58559
|
+
const { type, name, payload } = await electron.cloudImportShare(token);
|
|
58560
|
+
let collection2;
|
|
58561
|
+
if (type === "request") {
|
|
58562
|
+
const r = payload;
|
|
58563
|
+
const reqId = r.id || crypto.randomUUID();
|
|
58564
|
+
const req = { ...r, id: reqId };
|
|
58565
|
+
collection2 = {
|
|
58566
|
+
version: "1.0",
|
|
58567
|
+
id: crypto.randomUUID(),
|
|
58568
|
+
name: name || req.name || "Shared request",
|
|
58569
|
+
rootFolder: { id: crypto.randomUUID(), name: "", folders: [], requestIds: [reqId] },
|
|
58570
|
+
requests: { [reqId]: req }
|
|
58571
|
+
};
|
|
58572
|
+
} else {
|
|
58573
|
+
collection2 = { ...payload, id: crypto.randomUUID() };
|
|
58574
|
+
}
|
|
58575
|
+
const store = useStore$1.getState();
|
|
58576
|
+
const id2 = store.addCollectionObject(collection2);
|
|
58577
|
+
try {
|
|
58578
|
+
const entry = useStore$1.getState().collections[id2];
|
|
58579
|
+
if (entry && useStore$1.getState().workspace) {
|
|
58580
|
+
await electron.saveCollection(entry.relPath, entry.data);
|
|
58581
|
+
await electron.saveWorkspace(useStore$1.getState().workspace);
|
|
58582
|
+
}
|
|
58583
|
+
} catch (persistErr) {
|
|
58584
|
+
console.error("Imported shared collection but could not save it yet:", persistErr);
|
|
58585
|
+
}
|
|
58586
|
+
setSidebarTab("collections");
|
|
58587
|
+
} catch (err) {
|
|
58588
|
+
console.error("Import from share link failed:", err);
|
|
58589
|
+
}
|
|
58590
|
+
});
|
|
58591
|
+
return () => electron.offImportShare();
|
|
58592
|
+
}, [setSidebarTab]);
|
|
57915
58593
|
reactExports.useEffect(() => {
|
|
57916
58594
|
electron.onMockHit(addMockHit);
|
|
57917
58595
|
return () => electron.offMockHit();
|
|
@@ -58080,7 +58758,7 @@ function App() {
|
|
|
58080
58758
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-accent)" }, children: "Spector" }),
|
|
58081
58759
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal", style: { color: "var(--text-muted)" }, children: [
|
|
58082
58760
|
"v",
|
|
58083
|
-
"0.9.
|
|
58761
|
+
"0.9.2"
|
|
58084
58762
|
] }),
|
|
58085
58763
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", "aria-hidden": "true", children: "·" }),
|
|
58086
58764
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|