mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-06-09 08:02:48 +02:00
Remove useNavigate everywhere, and make request a query param. And convert dialog to Jotai
This commit is contained in:
Generated
+33
-39
@@ -2634,9 +2634,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/history": {
|
"node_modules/@tanstack/history": {
|
||||||
"version": "1.90.0",
|
"version": "1.95.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.90.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/history/-/history-1.95.0.tgz",
|
||||||
"integrity": "sha512-riNhDGm+fAwxgZRJ0J/36IZis1UDHsDCNIxfEodbw6BgTWJr0ah+G20V4HT91uBXiCqYFvX3somlfTLhS5yHDA==",
|
"integrity": "sha512-w1/yWuIBqmG0Z0MPMf1OuOCce7FXyVH4L4dIA4rvpnjIUCH8qRUgloFAVg37nTMUbOmhMsY2NZDxCpKBv+CLJg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
@@ -2647,9 +2647,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/query-core": {
|
"node_modules/@tanstack/query-core": {
|
||||||
"version": "5.62.8",
|
"version": "5.62.16",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.8.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.62.16.tgz",
|
||||||
"integrity": "sha512-4fV31vDsUyvNGrKIOUNPrZztoyL187bThnoQOvAXEVlZbSiuPONpfx53634MKKdvsDir5NyOGm80ShFaoHS/mw==",
|
"integrity": "sha512-9Sgft7Qavcd+sN0V25xVyo0nfmcZXBuODy3FVG7BMWTg1HMLm8wwG5tNlLlmSic1u7l1v786oavn+STiFaPH2g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -2668,12 +2668,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/react-query": {
|
"node_modules/@tanstack/react-query": {
|
||||||
"version": "5.62.8",
|
"version": "5.62.16",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.8.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.62.16.tgz",
|
||||||
"integrity": "sha512-8TUstKxF/fysHonZsWg/hnlDVgasTdHx6Q+f1/s/oPKJBJbKUWPZEHwLTMOZgrZuroLMiqYKJ9w69Abm8mWP0Q==",
|
"integrity": "sha512-XJIZNj65d2IdvU8VBESmrPakfIm6FSdHDzrS1dPrAwmq3ZX+9riMh/ZfbNQHAWnhrgmq7KoXpgZSRyXnqMYT9A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/query-core": "5.62.8"
|
"@tanstack/query-core": "5.62.16"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -2702,13 +2702,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/react-router": {
|
"node_modules/@tanstack/react-router": {
|
||||||
"version": "1.91.3",
|
"version": "1.95.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.91.3.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-router/-/react-router-1.95.1.tgz",
|
||||||
"integrity": "sha512-T6k50ApwcWKYjJB4VSK2WhXu/p40luynNJg5QC3oIqk24p0tLlgXIblXoTJzy7lVvDmQ4lwHCP9dBTvLy5NhVA==",
|
"integrity": "sha512-P5x4yNhcdkYsCEoYeGZP8Q9Jlxf0WXJa4G/xvbmM905seZc9FqJqvCSRvX3dWTPOXRABhl4g+8DHqfft0c/AvQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/history": "1.90.0",
|
"@tanstack/history": "1.95.0",
|
||||||
"@tanstack/react-store": "^0.6.1",
|
"@tanstack/react-store": "^0.7.0",
|
||||||
"jsesc": "^3.0.2",
|
"jsesc": "^3.0.2",
|
||||||
"tiny-invariant": "^1.3.3",
|
"tiny-invariant": "^1.3.3",
|
||||||
"tiny-warning": "^1.0.3"
|
"tiny-warning": "^1.0.3"
|
||||||
@@ -2721,24 +2721,18 @@
|
|||||||
"url": "https://github.com/sponsors/tannerlinsley"
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@tanstack/router-generator": "^1.87.7",
|
|
||||||
"react": ">=18",
|
"react": ">=18",
|
||||||
"react-dom": ">=18"
|
"react-dom": ">=18"
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"@tanstack/router-generator": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/react-store": {
|
"node_modules/@tanstack/react-store": {
|
||||||
"version": "0.6.1",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.7.0.tgz",
|
||||||
"integrity": "sha512-6gOopOpPp1cAXkEyTEv6tMbAywwFunvIdCKN/SpEiButUayjXU+Q5Sp5Y3hREN3VMR4OA5+RI5SPhhJoqP9e4w==",
|
"integrity": "sha512-S/Rq17HaGOk+tQHV/yrePMnG1xbsKZIl/VsNWnNXt4XW+tTY8dTlvpJH2ZQ3GRALsusG5K6Q3unAGJ2pd9W/Ng==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/store": "0.6.0",
|
"@tanstack/store": "0.7.0",
|
||||||
"use-sync-external-store": "^1.2.2"
|
"use-sync-external-store": "^1.4.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -2793,7 +2787,7 @@
|
|||||||
"version": "1.87.7",
|
"version": "1.87.7",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.87.7.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/router-generator/-/router-generator-1.87.7.tgz",
|
||||||
"integrity": "sha512-w9Px1C6DM0YNVXvu1VjUuZ5el0ykOeofEmEZBW83VUTzvCXFpcjPCHncU9FO9uXup8NFIxNfGz+xpwf93GoFnQ==",
|
"integrity": "sha512-w9Px1C6DM0YNVXvu1VjUuZ5el0ykOeofEmEZBW83VUTzvCXFpcjPCHncU9FO9uXup8NFIxNfGz+xpwf93GoFnQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/virtual-file-routes": "^1.87.6",
|
"@tanstack/virtual-file-routes": "^1.87.6",
|
||||||
@@ -2860,9 +2854,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/store": {
|
"node_modules/@tanstack/store": {
|
||||||
"version": "0.6.0",
|
"version": "0.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.0.tgz",
|
||||||
"integrity": "sha512-+m2OBglsjXcLmmKOX6/9v8BDOCtyxhMmZLsRUDswOOSdIIR9mvv6i0XNKsmTh3AlYU8c1mRcodC8/Vyf+69VlQ==",
|
"integrity": "sha512-CNIhdoUsmD2NolYuaIs8VfWM467RK6oIBAW4nPEKZhg1smZ+/CwtCdpURgp7nxSqOaV9oKkzdWD80+bC66F/Jg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -2883,7 +2877,7 @@
|
|||||||
"version": "1.87.6",
|
"version": "1.87.6",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.87.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/virtual-file-routes/-/virtual-file-routes-1.87.6.tgz",
|
||||||
"integrity": "sha512-PTpeM8SHL7AJM0pJOacFvHribbUODS51qe9NsMqku4mogh6BWObY1EeVmeGnp9o3VngAEsf+rJMs2zqIVz3WFA==",
|
"integrity": "sha512-PTpeM8SHL7AJM0pJOacFvHribbUODS51qe9NsMqku4mogh6BWObY1EeVmeGnp9o3VngAEsf+rJMs2zqIVz3WFA==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
@@ -7386,7 +7380,7 @@
|
|||||||
"version": "4.8.1",
|
"version": "4.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz",
|
||||||
"integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==",
|
"integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"resolve-pkg-maps": "^1.0.0"
|
"resolve-pkg-maps": "^1.0.0"
|
||||||
@@ -11586,7 +11580,7 @@
|
|||||||
"version": "3.4.2",
|
"version": "3.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
|
||||||
"integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
|
"integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"prettier": "bin/prettier.cjs"
|
"prettier": "bin/prettier.cjs"
|
||||||
@@ -12562,7 +12556,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
|
||||||
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
|
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
|
||||||
@@ -14152,7 +14146,7 @@
|
|||||||
"version": "4.19.2",
|
"version": "4.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz",
|
||||||
"integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==",
|
"integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "~0.23.0",
|
"esbuild": "~0.23.0",
|
||||||
@@ -14563,7 +14557,7 @@
|
|||||||
"version": "0.23.1",
|
"version": "0.23.1",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz",
|
||||||
"integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==",
|
"integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
@@ -15788,7 +15782,7 @@
|
|||||||
"version": "3.24.1",
|
"version": "3.24.1",
|
||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
|
||||||
"integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
|
"integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
|
||||||
"devOptional": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
@@ -15937,8 +15931,8 @@
|
|||||||
"@lezer/lr": "^1.3.3",
|
"@lezer/lr": "^1.3.3",
|
||||||
"@react-hook/size": "^2.1.2",
|
"@react-hook/size": "^2.1.2",
|
||||||
"@tailwindcss/container-queries": "^0.1.1",
|
"@tailwindcss/container-queries": "^0.1.1",
|
||||||
"@tanstack/react-query": "^5.62.8",
|
"@tanstack/react-query": "^5.62.16",
|
||||||
"@tanstack/react-router": "^1.91.3",
|
"@tanstack/react-router": "^1.95.1",
|
||||||
"@tanstack/react-virtual": "^3.11.2",
|
"@tanstack/react-virtual": "^3.11.2",
|
||||||
"@tauri-apps/api": "^2.0.1",
|
"@tauri-apps/api": "^2.0.1",
|
||||||
"@tauri-apps/plugin-clipboard-manager": "^2.0.0",
|
"@tauri-apps/plugin-clipboard-manager": "^2.0.0",
|
||||||
|
|||||||
@@ -424,8 +424,6 @@ mod placeholder_tests {
|
|||||||
],
|
],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
println!("HELLO?: {result:?}");
|
|
||||||
|
|
||||||
assert_eq!(result.url, "example.com/aaa/bar");
|
assert_eq!(result.url, "example.com/aaa/bar");
|
||||||
assert_eq!(result.url_parameters.len(), 1);
|
assert_eq!(result.url_parameters.len(), 1);
|
||||||
assert_eq!(result.url_parameters[0].name, "b");
|
assert_eq!(result.url_parameters[0].name, "b");
|
||||||
|
|||||||
@@ -1,59 +1,250 @@
|
|||||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||||
|
|
||||||
export type AnyModel = CookieJar | Environment | Folder | GrpcConnection | GrpcEvent | GrpcRequest | HttpRequest | HttpResponse | Plugin | Settings | KeyValue | Workspace;
|
export type AnyModel =
|
||||||
|
| CookieJar
|
||||||
|
| Environment
|
||||||
|
| Folder
|
||||||
|
| GrpcConnection
|
||||||
|
| GrpcEvent
|
||||||
|
| GrpcRequest
|
||||||
|
| HttpRequest
|
||||||
|
| HttpResponse
|
||||||
|
| Plugin
|
||||||
|
| Settings
|
||||||
|
| KeyValue
|
||||||
|
| Workspace;
|
||||||
|
|
||||||
export type Cookie = { raw_cookie: string, domain: CookieDomain, expires: CookieExpires, path: [string, boolean], };
|
export type Cookie = {
|
||||||
|
raw_cookie: string;
|
||||||
|
domain: CookieDomain;
|
||||||
|
expires: CookieExpires;
|
||||||
|
path: [string, boolean];
|
||||||
|
};
|
||||||
|
|
||||||
export type CookieDomain = { "HostOnly": string } | { "Suffix": string } | "NotPresent" | "Empty";
|
export type CookieDomain = { HostOnly: string } | { Suffix: string } | 'NotPresent' | 'Empty';
|
||||||
|
|
||||||
export type CookieExpires = { "AtUtc": string } | "SessionEnd";
|
export type CookieExpires = { AtUtc: string } | 'SessionEnd';
|
||||||
|
|
||||||
export type CookieJar = { model: "cookie_jar", id: string, createdAt: string, updatedAt: string, workspaceId: string, cookies: Array<Cookie>, name: string, };
|
export type CookieJar = {
|
||||||
|
model: 'cookie_jar';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
workspaceId: string;
|
||||||
|
cookies: Array<Cookie>;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type Environment = { model: "environment", id: string, workspaceId: string, environmentId: string | null, createdAt: string, updatedAt: string, name: string, variables: Array<EnvironmentVariable>, };
|
export type Environment = {
|
||||||
|
model: 'environment';
|
||||||
|
id: string;
|
||||||
|
workspaceId: string;
|
||||||
|
environmentId: string | null;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
name: string;
|
||||||
|
variables: Array<EnvironmentVariable>;
|
||||||
|
};
|
||||||
|
|
||||||
export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, id: string, };
|
export type EnvironmentVariable = { enabled?: boolean; name: string; value: string; id: string };
|
||||||
|
|
||||||
export type Folder = { model: "folder", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, name: string, description: string, sortPriority: number, };
|
export type Folder = {
|
||||||
|
model: 'folder';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
workspaceId: string;
|
||||||
|
folderId: string | null;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
sortPriority: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type GrpcConnection = { model: "grpc_connection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, elapsed: number, error: string | null, method: string, service: string, status: number, state: GrpcConnectionState, trailers: { [key in string]?: string }, url: string, };
|
export type GrpcConnection = {
|
||||||
|
model: 'grpc_connection';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
workspaceId: string;
|
||||||
|
requestId: string;
|
||||||
|
elapsed: number;
|
||||||
|
error: string | null;
|
||||||
|
method: string;
|
||||||
|
service: string;
|
||||||
|
status: number;
|
||||||
|
state: GrpcConnectionState;
|
||||||
|
trailers: { [key in string]?: string };
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type GrpcConnectionState = "initialized" | "connected" | "closed";
|
export type GrpcConnectionState = 'initialized' | 'connected' | 'closed';
|
||||||
|
|
||||||
export type GrpcEvent = { model: "grpc_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, connectionId: string, content: string, error: string | null, eventType: GrpcEventType, metadata: { [key in string]?: string }, status: number | null, };
|
export type GrpcEvent = {
|
||||||
|
model: 'grpc_event';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
workspaceId: string;
|
||||||
|
requestId: string;
|
||||||
|
connectionId: string;
|
||||||
|
content: string;
|
||||||
|
error: string | null;
|
||||||
|
eventType: GrpcEventType;
|
||||||
|
metadata: { [key in string]?: string };
|
||||||
|
status: number | null;
|
||||||
|
};
|
||||||
|
|
||||||
export type GrpcEventType = "info" | "error" | "client_message" | "server_message" | "connection_start" | "connection_end";
|
export type GrpcEventType =
|
||||||
|
| 'info'
|
||||||
|
| 'error'
|
||||||
|
| 'client_message'
|
||||||
|
| 'server_message'
|
||||||
|
| 'connection_start'
|
||||||
|
| 'connection_end';
|
||||||
|
|
||||||
export type GrpcMetadataEntry = { enabled?: boolean, name: string, value: string, id: string, };
|
export type GrpcMetadataEntry = { enabled?: boolean; name: string; value: string; id: string };
|
||||||
|
|
||||||
export type GrpcRequest = { model: "grpc_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authenticationType: string | null, authentication: Record<string, any>, description: string, message: string, metadata: Array<GrpcMetadataEntry>, method: string | null, name: string, service: string | null, sortPriority: number, url: string, };
|
export type GrpcRequest = {
|
||||||
|
model: 'grpc_request';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
workspaceId: string;
|
||||||
|
folderId: string | null;
|
||||||
|
authenticationType: string | null;
|
||||||
|
authentication: Record<string, any>;
|
||||||
|
description: string;
|
||||||
|
message: string;
|
||||||
|
metadata: Array<GrpcMetadataEntry>;
|
||||||
|
method: string | null;
|
||||||
|
name: string;
|
||||||
|
service: string | null;
|
||||||
|
sortPriority: number;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type HttpRequest = { model: "http_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record<string, any>, authenticationType: string | null, body: Record<string, any>, bodyType: string | null, description: string, headers: Array<HttpRequestHeader>, method: string, name: string, sortPriority: number, url: string, urlParameters: Array<HttpUrlParameter>, };
|
export type HttpRequest = {
|
||||||
|
model: 'http_request';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
workspaceId: string;
|
||||||
|
folderId: string | null;
|
||||||
|
authentication: Record<string, any>;
|
||||||
|
authenticationType: string | null;
|
||||||
|
body: Record<string, any>;
|
||||||
|
bodyType: string | null;
|
||||||
|
description: string;
|
||||||
|
headers: Array<HttpRequestHeader>;
|
||||||
|
method: string;
|
||||||
|
name: string;
|
||||||
|
sortPriority: number;
|
||||||
|
url: string;
|
||||||
|
urlParameters: Array<HttpUrlParameter>;
|
||||||
|
};
|
||||||
|
|
||||||
export type HttpRequestHeader = { enabled?: boolean, name: string, value: string, id: string, };
|
export type HttpRequestHeader = { enabled?: boolean; name: string; value: string; id: string };
|
||||||
|
|
||||||
export type HttpResponse = { model: "http_response", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, bodyPath: string | null, contentLength: number | null, elapsed: number, elapsedHeaders: number, error: string | null, headers: Array<HttpResponseHeader>, remoteAddr: string | null, status: number, statusReason: string | null, state: HttpResponseState, url: string, version: string | null, };
|
export type HttpResponse = {
|
||||||
|
model: 'http_response';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
workspaceId: string;
|
||||||
|
requestId: string;
|
||||||
|
bodyPath: string | null;
|
||||||
|
contentLength: number | null;
|
||||||
|
elapsed: number;
|
||||||
|
elapsedHeaders: number;
|
||||||
|
error: string | null;
|
||||||
|
headers: Array<HttpResponseHeader>;
|
||||||
|
remoteAddr: string | null;
|
||||||
|
status: number;
|
||||||
|
statusReason: string | null;
|
||||||
|
state: HttpResponseState;
|
||||||
|
url: string;
|
||||||
|
version: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
export type HttpResponseHeader = { name: string, value: string, };
|
export type HttpResponseHeader = { name: string; value: string };
|
||||||
|
|
||||||
export type HttpResponseState = "initialized" | "connected" | "closed";
|
export type HttpResponseState = 'initialized' | 'connected' | 'closed';
|
||||||
|
|
||||||
export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, id: string, };
|
export type HttpUrlParameter = { enabled?: boolean; name: string; value: string; id: string };
|
||||||
|
|
||||||
export type KeyValue = { model: "key_value", createdAt: string, updatedAt: string, key: string, namespace: string, value: string, };
|
export type KeyValue = {
|
||||||
|
model: 'key_value';
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
key: string;
|
||||||
|
namespace: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type ModelPayload = { model: AnyModel, windowLabel: string, updateSource: UpdateSource, };
|
export type ModelPayload = { model: AnyModel; windowLabel: string; updateSource: UpdateSource };
|
||||||
|
|
||||||
export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt: string, checkedAt: string | null, directory: string, enabled: boolean, url: string | null, };
|
export type Plugin = {
|
||||||
|
model: 'plugin';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
checkedAt: string | null;
|
||||||
|
directory: string;
|
||||||
|
enabled: boolean;
|
||||||
|
url: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
export type ProxySetting = { "type": "enabled", http: string, https: string, auth: ProxySettingAuth | null, } | { "type": "disabled" };
|
export type ProxySetting =
|
||||||
|
| { type: 'enabled'; http: string; https: string; auth: ProxySettingAuth | null }
|
||||||
|
| {
|
||||||
|
type: 'disabled';
|
||||||
|
};
|
||||||
|
|
||||||
export type ProxySettingAuth = { user: string, password: string, };
|
export type ProxySettingAuth = { user: string; password: string };
|
||||||
|
|
||||||
export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, editorFontSize: number, editorSoftWrap: boolean, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, telemetry: boolean, theme: string, themeDark: string, themeLight: string, updateChannel: string, proxy: ProxySetting | null, };
|
export type Settings = {
|
||||||
|
model: 'settings';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
appearance: string;
|
||||||
|
editorFontSize: number;
|
||||||
|
editorSoftWrap: boolean;
|
||||||
|
interfaceFontSize: number;
|
||||||
|
interfaceScale: number;
|
||||||
|
openWorkspaceNewWindow: boolean | null;
|
||||||
|
telemetry: boolean;
|
||||||
|
theme: string;
|
||||||
|
themeDark: string;
|
||||||
|
themeLight: string;
|
||||||
|
updateChannel: string;
|
||||||
|
proxy: ProxySetting | null;
|
||||||
|
};
|
||||||
|
|
||||||
export type SyncState = { model: "sync_state", id: string, workspaceId: string, createdAt: string, updatedAt: string, flushedAt: string, modelId: string, checksum: string, relPath: string, syncDir: string, };
|
export type SyncState = {
|
||||||
|
model: 'sync_state';
|
||||||
|
id: string;
|
||||||
|
workspaceId: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
flushedAt: string;
|
||||||
|
modelId: string;
|
||||||
|
checksum: string;
|
||||||
|
relPath: string;
|
||||||
|
syncDir: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type UpdateSource = "sync" | "window" | "plugin" | "background";
|
export type UpdateSource = 'sync' | 'window' | 'plugin' | 'background';
|
||||||
|
|
||||||
export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, name: string, description: string, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, settingSyncDir: string | null, };
|
export type Workspace = {
|
||||||
|
model: 'workspace';
|
||||||
|
id: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
settingValidateCertificates: boolean;
|
||||||
|
settingFollowRedirects: boolean;
|
||||||
|
settingRequestTimeout: number;
|
||||||
|
settingSyncDir: string | null;
|
||||||
|
};
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export async function calculateSync(workspace: Workspace) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function applySync(workspace: Workspace, syncOps: SyncOp[]) {
|
export async function applySync(workspace: Workspace, syncOps: SyncOp[]) {
|
||||||
console.log('Applying sync', syncOps);
|
|
||||||
return invoke<void>('plugin:yaak-sync|apply', {
|
return invoke<void>('plugin:yaak-sync|apply', {
|
||||||
workspaceId: workspace.id,
|
workspaceId: workspace.id,
|
||||||
dir: workspace.settingSyncDir,
|
dir: workspace.settingSyncDir,
|
||||||
@@ -23,17 +22,14 @@ export async function applySync(workspace: Workspace, syncOps: SyncOp[]) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useWatchWorkspace(workspace: Workspace | null, cb: (e: WatchEvent) => void) {
|
export function useWatchWorkspace(workspace: Workspace | null, callback: (e: WatchEvent) => void) {
|
||||||
const workspaceId = workspace?.id ?? null;
|
const workspaceId = workspace?.id ?? null;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (workspaceId == null) return;
|
if (workspaceId == null) return;
|
||||||
|
|
||||||
console.log('Watching workspace', workspaceId);
|
|
||||||
const channel = new Channel<WatchEvent>();
|
const channel = new Channel<WatchEvent>();
|
||||||
channel.onmessage = (event) => {
|
channel.onmessage = callback;
|
||||||
cb(event);
|
|
||||||
};
|
|
||||||
const promise = invoke<WatchResult>('plugin:yaak-sync|watch', { workspaceId, channel });
|
const promise = invoke<WatchResult>('plugin:yaak-sync|watch', { workspaceId, channel });
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { fuzzyFilter } from 'fuzzbunny';
|
import { fuzzyFilter } from 'fuzzbunny';
|
||||||
import type { KeyboardEvent, ReactNode } from 'react';
|
import type { KeyboardEvent, ReactNode } from 'react';
|
||||||
@@ -13,7 +12,6 @@ import { useCreateHttpRequest } from '../hooks/useCreateHttpRequest';
|
|||||||
import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
||||||
import { useDebouncedState } from '../hooks/useDebouncedState';
|
import { useDebouncedState } from '../hooks/useDebouncedState';
|
||||||
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
||||||
import { useDialog } from '../hooks/useDialog';
|
|
||||||
import { useEnvironments } from '../hooks/useEnvironments';
|
import { useEnvironments } from '../hooks/useEnvironments';
|
||||||
import type { HotkeyAction } from '../hooks/useHotKey';
|
import type { HotkeyAction } from '../hooks/useHotKey';
|
||||||
import { useHotKey } from '../hooks/useHotKey';
|
import { useHotKey } from '../hooks/useHotKey';
|
||||||
@@ -29,7 +27,9 @@ import { useScrollIntoView } from '../hooks/useScrollIntoView';
|
|||||||
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
||||||
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
import { useSidebarHidden } from '../hooks/useSidebarHidden';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
|
import { showDialog, toggleDialog } from '../lib/dialog';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { CookieDialog } from './CookieDialog';
|
import { CookieDialog } from './CookieDialog';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { Heading } from './core/Heading';
|
import { Heading } from './core/Heading';
|
||||||
@@ -70,16 +70,14 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
|
|||||||
const openWorkspace = useOpenWorkspace();
|
const openWorkspace = useOpenWorkspace();
|
||||||
const createHttpRequest = useCreateHttpRequest();
|
const createHttpRequest = useCreateHttpRequest();
|
||||||
const { createFolder } = useCommands();
|
const { createFolder } = useCommands();
|
||||||
const [activeCookieJar] = useActiveCookieJar();
|
const activeCookieJar = useActiveCookieJar();
|
||||||
const createGrpcRequest = useCreateGrpcRequest();
|
const createGrpcRequest = useCreateGrpcRequest();
|
||||||
const createEnvironment = useCreateEnvironment();
|
const createEnvironment = useCreateEnvironment();
|
||||||
const dialog = useDialog();
|
|
||||||
const sendRequest = useSendAnyHttpRequest();
|
const sendRequest = useSendAnyHttpRequest();
|
||||||
const renameRequest = useRenameRequest(activeRequest?.id ?? null);
|
const renameRequest = useRenameRequest(activeRequest?.id ?? null);
|
||||||
const deleteRequest = useDeleteRequest(activeRequest?.id ?? null);
|
const deleteRequest = useDeleteRequest(activeRequest?.id ?? null);
|
||||||
const [, setSidebarHidden] = useSidebarHidden();
|
const [, setSidebarHidden] = useSidebarHidden();
|
||||||
const openSettings = useOpenSettings();
|
const openSettings = useOpenSettings();
|
||||||
const navigate = useNavigate();
|
|
||||||
const { baseEnvironment } = useEnvironments();
|
const { baseEnvironment } = useEnvironments();
|
||||||
|
|
||||||
const workspaceCommands = useMemo<CommandPaletteItem[]>(() => {
|
const workspaceCommands = useMemo<CommandPaletteItem[]>(() => {
|
||||||
@@ -109,7 +107,7 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
|
|||||||
key: 'cookies.show',
|
key: 'cookies.show',
|
||||||
label: 'Show Cookies',
|
label: 'Show Cookies',
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'cookies',
|
id: 'cookies',
|
||||||
title: 'Manage Cookies',
|
title: 'Manage Cookies',
|
||||||
size: 'full',
|
size: 'full',
|
||||||
@@ -127,7 +125,7 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
|
|||||||
label: 'Edit Environment',
|
label: 'Edit Environment',
|
||||||
action: 'environmentEditor.toggle',
|
action: 'environmentEditor.toggle',
|
||||||
onSelect: () => {
|
onSelect: () => {
|
||||||
dialog.toggle({
|
toggleDialog({
|
||||||
id: 'environment-editor',
|
id: 'environment-editor',
|
||||||
noPadding: true,
|
noPadding: true,
|
||||||
size: 'lg',
|
size: 'lg',
|
||||||
@@ -195,7 +193,6 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
|
|||||||
createHttpRequest,
|
createHttpRequest,
|
||||||
createWorkspace,
|
createWorkspace,
|
||||||
deleteRequest.mutate,
|
deleteRequest.mutate,
|
||||||
dialog,
|
|
||||||
httpRequestActions,
|
httpRequestActions,
|
||||||
openSettings.mutate,
|
openSettings.mutate,
|
||||||
renameRequest.mutate,
|
renameRequest.mutate,
|
||||||
@@ -284,13 +281,10 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
|
|||||||
</HStack>
|
</HStack>
|
||||||
),
|
),
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
await navigate({
|
await router.navigate({
|
||||||
to: '/workspaces/$workspaceId/requests/$requestId',
|
to: '/workspaces/$workspaceId',
|
||||||
params: {
|
params: { workspaceId: r.workspaceId },
|
||||||
workspaceId: r.workspaceId,
|
search: (prev) => ({ ...prev, request_id: r.id }),
|
||||||
requestId: r.id,
|
|
||||||
},
|
|
||||||
search: (prev) => ({ ...prev }),
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -331,7 +325,6 @@ export function CommandPaletteDialog({ onClose }: { onClose: () => void }) {
|
|||||||
}, [
|
}, [
|
||||||
workspaceCommands,
|
workspaceCommands,
|
||||||
sortedRequests,
|
sortedRequests,
|
||||||
navigate,
|
|
||||||
sortedEnvironments,
|
sortedEnvironments,
|
||||||
activeEnvironment?.id,
|
activeEnvironment?.id,
|
||||||
setActiveEnvironmentId,
|
setActiveEnvironmentId,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { memo, useCallback } from 'react';
|
import { memo, useMemo } from 'react';
|
||||||
import { useActiveCookieJar } from '../hooks/useActiveCookieJar';
|
import { setActiveCookieJar, useActiveCookieJar } from '../hooks/useActiveCookieJar';
|
||||||
import { cookieJarsAtom } from '../hooks/useCookieJars';
|
import { cookieJarsAtom } from '../hooks/useCookieJars';
|
||||||
import { useCreateCookieJar } from '../hooks/useCreateCookieJar';
|
import { useCreateCookieJar } from '../hooks/useCreateCookieJar';
|
||||||
import { useDeleteCookieJar } from '../hooks/useDeleteCookieJar';
|
import { useDeleteCookieJar } from '../hooks/useDeleteCookieJar';
|
||||||
import { useDialog } from '../hooks/useDialog';
|
|
||||||
import { usePrompt } from '../hooks/usePrompt';
|
import { usePrompt } from '../hooks/usePrompt';
|
||||||
import { useUpdateCookieJar } from '../hooks/useUpdateCookieJar';
|
import { useUpdateCookieJar } from '../hooks/useUpdateCookieJar';
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
import { CookieDialog } from './CookieDialog';
|
import { CookieDialog } from './CookieDialog';
|
||||||
import { Dropdown, type DropdownItem } from './core/Dropdown';
|
import { Dropdown, type DropdownItem } from './core/Dropdown';
|
||||||
@@ -14,21 +14,20 @@ import { IconButton } from './core/IconButton';
|
|||||||
import { InlineCode } from './core/InlineCode';
|
import { InlineCode } from './core/InlineCode';
|
||||||
|
|
||||||
export const CookieDropdown = memo(function CookieDropdown() {
|
export const CookieDropdown = memo(function CookieDropdown() {
|
||||||
const [activeCookieJar, setActiveCookieJarId] = useActiveCookieJar();
|
const activeCookieJar = useActiveCookieJar();
|
||||||
const updateCookieJar = useUpdateCookieJar(activeCookieJar?.id ?? null);
|
const updateCookieJar = useUpdateCookieJar(activeCookieJar?.id ?? null);
|
||||||
const deleteCookieJar = useDeleteCookieJar(activeCookieJar ?? null);
|
const deleteCookieJar = useDeleteCookieJar(activeCookieJar ?? null);
|
||||||
const createCookieJar = useCreateCookieJar();
|
const createCookieJar = useCreateCookieJar();
|
||||||
const dialog = useDialog();
|
|
||||||
const prompt = usePrompt();
|
const prompt = usePrompt();
|
||||||
|
|
||||||
const getItems = useCallback((): DropdownItem[] => {
|
const items = useMemo((): DropdownItem[] => {
|
||||||
const cookieJars = jotaiStore.get(cookieJarsAtom) ?? [];
|
const cookieJars = jotaiStore.get(cookieJarsAtom) ?? [];
|
||||||
return [
|
return [
|
||||||
...cookieJars.map((j) => ({
|
...cookieJars.map((j) => ({
|
||||||
key: j.id,
|
key: j.id,
|
||||||
label: j.name,
|
label: j.name,
|
||||||
leftSlot: <Icon icon={j.id === activeCookieJar?.id ? 'check' : 'empty'} />,
|
leftSlot: <Icon icon={j.id === activeCookieJar?.id ? 'check' : 'empty'} />,
|
||||||
onSelect: () => setActiveCookieJarId(j.id),
|
onSelect: () => setActiveCookieJar(j),
|
||||||
})),
|
})),
|
||||||
...((cookieJars.length > 0 && activeCookieJar != null
|
...((cookieJars.length > 0 && activeCookieJar != null
|
||||||
? [
|
? [
|
||||||
@@ -39,7 +38,7 @@ export const CookieDropdown = memo(function CookieDropdown() {
|
|||||||
leftSlot: <Icon icon="cookie" />,
|
leftSlot: <Icon icon="cookie" />,
|
||||||
onSelect: () => {
|
onSelect: () => {
|
||||||
if (activeCookieJar == null) return;
|
if (activeCookieJar == null) return;
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'cookies',
|
id: 'cookies',
|
||||||
title: 'Manage Cookies',
|
title: 'Manage Cookies',
|
||||||
size: 'full',
|
size: 'full',
|
||||||
@@ -90,18 +89,10 @@ export const CookieDropdown = memo(function CookieDropdown() {
|
|||||||
onSelect: () => createCookieJar.mutate(),
|
onSelect: () => createCookieJar.mutate(),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}, [
|
}, [activeCookieJar, createCookieJar, deleteCookieJar, prompt, updateCookieJar]);
|
||||||
activeCookieJar,
|
|
||||||
createCookieJar,
|
|
||||||
deleteCookieJar,
|
|
||||||
dialog,
|
|
||||||
prompt,
|
|
||||||
setActiveCookieJarId,
|
|
||||||
updateCookieJar,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown items={getItems}>
|
<Dropdown items={items}>
|
||||||
<IconButton size="sm" icon="cookie" title="Cookie Jar" />
|
<IconButton size="sm" icon="cookie" title="Cookie Jar" />
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
import { createContext } from 'react';
|
|
||||||
import type { DialogState } from './Dialogs';
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
export const DialogContext = createContext<DialogState>({} as DialogState);
|
|
||||||
@@ -1,74 +1,29 @@
|
|||||||
import React, { useContext, useMemo, useState } from 'react';
|
import { useAtomValue } from 'jotai';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import React from 'react';
|
||||||
|
import { dialogsAtom, hideDialog } from '../lib/dialog';
|
||||||
import { Dialog, type DialogProps } from './core/Dialog';
|
import { Dialog, type DialogProps } from './core/Dialog';
|
||||||
import { DialogContext } from './DialogContext';
|
|
||||||
|
|
||||||
type DialogEntry = {
|
export type DialogInstance = {
|
||||||
id: string;
|
id: string;
|
||||||
render: ({ hide }: { hide: () => void }) => React.ReactNode;
|
render: ({ hide }: { hide: () => void }) => React.ReactNode;
|
||||||
} & Omit<DialogProps, 'open' | 'children'>;
|
} & Omit<DialogProps, 'open' | 'children'>;
|
||||||
|
|
||||||
export interface DialogState {
|
|
||||||
dialogs: DialogEntry[];
|
|
||||||
actions: Actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Actions {
|
|
||||||
show: (d: DialogEntry) => void;
|
|
||||||
toggle: (d: DialogEntry) => void;
|
|
||||||
hide: (id: string) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const DialogProvider = ({ children }: { children: React.ReactNode }) => {
|
|
||||||
const [dialogs, setDialogs] = useState<DialogState['dialogs']>([]);
|
|
||||||
const actions = useMemo<Actions>(
|
|
||||||
() => ({
|
|
||||||
show({ id, ...props }: DialogEntry) {
|
|
||||||
trackEvent('dialog', 'show', { id });
|
|
||||||
setDialogs((a) => [...a.filter((d) => d.id !== id), { id, ...props }]);
|
|
||||||
},
|
|
||||||
toggle({ id, ...props }: DialogEntry) {
|
|
||||||
if (dialogs.some((d) => d.id === id)) this.hide(id);
|
|
||||||
else this.show({ id, ...props });
|
|
||||||
},
|
|
||||||
hide: (id: string) => {
|
|
||||||
setDialogs((a) => a.filter((d) => d.id !== id));
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[dialogs],
|
|
||||||
);
|
|
||||||
|
|
||||||
const state: DialogState = {
|
|
||||||
dialogs,
|
|
||||||
actions,
|
|
||||||
};
|
|
||||||
|
|
||||||
return <DialogContext.Provider value={state}>{children}</DialogContext.Provider>;
|
|
||||||
};
|
|
||||||
|
|
||||||
function DialogInstance({ id, render, onClose, ...props }: DialogEntry) {
|
|
||||||
const { actions } = useContext(DialogContext);
|
|
||||||
const children = render({ hide: () => actions.hide(id) });
|
|
||||||
return (
|
|
||||||
<Dialog
|
|
||||||
open
|
|
||||||
onClose={() => {
|
|
||||||
onClose?.();
|
|
||||||
actions.hide(id);
|
|
||||||
}}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Dialog>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Dialogs() {
|
export function Dialogs() {
|
||||||
const { dialogs } = useContext(DialogContext);
|
const dialogs = useAtomValue(dialogsAtom);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{dialogs.map((props: DialogEntry) => (
|
{dialogs.map(({ render, onClose, id, ...props }: DialogInstance) => (
|
||||||
<DialogInstance key={props.id} {...props} />
|
<Dialog
|
||||||
|
open
|
||||||
|
key={id}
|
||||||
|
onClose={() => {
|
||||||
|
onClose?.();
|
||||||
|
hideDialog(id);
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{render({ hide: () => hideDialog(id) })}
|
||||||
|
</Dialog>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ import classNames from 'classnames';
|
|||||||
import { memo, useCallback, useMemo } from 'react';
|
import { memo, useCallback, useMemo } from 'react';
|
||||||
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
import { useActiveEnvironment } from '../hooks/useActiveEnvironment';
|
||||||
import { useEnvironments } from '../hooks/useEnvironments';
|
import { useEnvironments } from '../hooks/useEnvironments';
|
||||||
|
import { toggleDialog } from '../lib/dialog';
|
||||||
import type { ButtonProps } from './core/Button';
|
import type { ButtonProps } from './core/Button';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import type { DropdownItem } from './core/Dropdown';
|
import type { DropdownItem } from './core/Dropdown';
|
||||||
import { Dropdown } from './core/Dropdown';
|
import { Dropdown } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
import { useDialog } from '../hooks/useDialog';
|
|
||||||
import { EnvironmentEditDialog } from './EnvironmentEditDialog';
|
import { EnvironmentEditDialog } from './EnvironmentEditDialog';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -20,17 +20,16 @@ export const EnvironmentActionsDropdown = memo(function EnvironmentActionsDropdo
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
const { subEnvironments, baseEnvironment } = useEnvironments();
|
const { subEnvironments, baseEnvironment } = useEnvironments();
|
||||||
const [activeEnvironment, setActiveEnvironmentId] = useActiveEnvironment();
|
const [activeEnvironment, setActiveEnvironmentId] = useActiveEnvironment();
|
||||||
const dialog = useDialog();
|
|
||||||
|
|
||||||
const showEnvironmentDialog = useCallback(() => {
|
const showEnvironmentDialog = useCallback(() => {
|
||||||
dialog.toggle({
|
toggleDialog({
|
||||||
id: 'environment-editor',
|
id: 'environment-editor',
|
||||||
noPadding: true,
|
noPadding: true,
|
||||||
size: 'lg',
|
size: 'lg',
|
||||||
className: 'h-[80vh]',
|
className: 'h-[80vh]',
|
||||||
render: () => <EnvironmentEditDialog initialEnvironment={activeEnvironment} />,
|
render: () => <EnvironmentEditDialog initialEnvironment={activeEnvironment} />,
|
||||||
});
|
});
|
||||||
}, [dialog, activeEnvironment]);
|
}, [activeEnvironment]);
|
||||||
|
|
||||||
const items: DropdownItem[] = useMemo(
|
const items: DropdownItem[] = useMemo(
|
||||||
() => [
|
() => [
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
useSubscribeActiveCookieJarId,
|
useSubscribeActiveCookieJarId,
|
||||||
} from '../hooks/useActiveCookieJar';
|
} from '../hooks/useActiveCookieJar';
|
||||||
import { useSubscribeActiveEnvironmentId } from '../hooks/useActiveEnvironment';
|
import { useSubscribeActiveEnvironmentId } from '../hooks/useActiveEnvironment';
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import { getActiveRequest, useActiveRequest } from '../hooks/useActiveRequest';
|
||||||
import { useSubscribeActiveRequestId } from '../hooks/useActiveRequestId';
|
import { useSubscribeActiveRequestId } from '../hooks/useActiveRequestId';
|
||||||
import { useActiveWorkspace, useSubscribeActiveWorkspaceId } from '../hooks/useActiveWorkspace';
|
import { useActiveWorkspace, useSubscribeActiveWorkspaceId } from '../hooks/useActiveWorkspace';
|
||||||
import { useActiveWorkspaceChangedToast } from '../hooks/useActiveWorkspaceChangedToast';
|
import { useActiveWorkspaceChangedToast } from '../hooks/useActiveWorkspaceChangedToast';
|
||||||
@@ -78,6 +78,7 @@ export function GlobalHooks() {
|
|||||||
navigateAfter: true,
|
navigateAfter: true,
|
||||||
});
|
});
|
||||||
useHotKey('http_request.duplicate', async () => {
|
useHotKey('http_request.duplicate', async () => {
|
||||||
|
const activeRequest = getActiveRequest();
|
||||||
if (activeRequest?.model === 'http_request') {
|
if (activeRequest?.model === 'http_request') {
|
||||||
await duplicateHttpRequest.mutateAsync();
|
await duplicateHttpRequest.mutateAsync();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import type { EditorView } from 'codemirror';
|
|||||||
import { formatSdl } from 'format-graphql';
|
import { formatSdl } from 'format-graphql';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useLocalStorage } from 'react-use';
|
import { useLocalStorage } from 'react-use';
|
||||||
import { useDialog } from '../hooks/useDialog';
|
|
||||||
import { useIntrospectGraphQL } from '../hooks/useIntrospectGraphQL';
|
import { useIntrospectGraphQL } from '../hooks/useIntrospectGraphQL';
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import { tryFormatJson } from '../lib/formatters';
|
import { tryFormatJson } from '../lib/formatters';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { Dropdown } from './core/Dropdown';
|
import { Dropdown } from './core/Dropdown';
|
||||||
@@ -62,8 +62,6 @@ export function GraphQLEditor({ request, onChange, baseRequest, ...extraEditorPr
|
|||||||
updateSchema(editorViewRef.current, schema ?? undefined);
|
updateSchema(editorViewRef.current, schema ?? undefined);
|
||||||
}, [schema]);
|
}, [schema]);
|
||||||
|
|
||||||
const dialog = useDialog();
|
|
||||||
|
|
||||||
const actions = useMemo<EditorProps['actions']>(
|
const actions = useMemo<EditorProps['actions']>(
|
||||||
() => [
|
() => [
|
||||||
<div key="introspection" className="!opacity-100">
|
<div key="introspection" className="!opacity-100">
|
||||||
@@ -122,7 +120,7 @@ export function GraphQLEditor({ request, onChange, baseRequest, ...extraEditorPr
|
|||||||
color="danger"
|
color="danger"
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
dialog.show({
|
showDialog({
|
||||||
title: 'Introspection Failed',
|
title: 'Introspection Failed',
|
||||||
size: 'dynamic',
|
size: 'dynamic',
|
||||||
id: 'introspection-failed',
|
id: 'introspection-failed',
|
||||||
@@ -161,7 +159,6 @@ export function GraphQLEditor({ request, onChange, baseRequest, ...extraEditorPr
|
|||||||
clear,
|
clear,
|
||||||
schema,
|
schema,
|
||||||
setAutoIntrospectDisabled,
|
setAutoIntrospectDisabled,
|
||||||
dialog,
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { jsonLanguage } from '@codemirror/lang-json';
|
import { jsonLanguage } from '@codemirror/lang-json';
|
||||||
import { linter } from '@codemirror/lint';
|
import { linter } from '@codemirror/lint';
|
||||||
|
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import type { EditorView } from 'codemirror';
|
import type { EditorView } from 'codemirror';
|
||||||
import {
|
import {
|
||||||
@@ -10,19 +11,18 @@ import {
|
|||||||
updateSchema,
|
updateSchema,
|
||||||
} from 'codemirror-json-schema';
|
} from 'codemirror-json-schema';
|
||||||
import { useEffect, useMemo, useRef } from 'react';
|
import { useEffect, useMemo, useRef } from 'react';
|
||||||
import { useAlert } from '../hooks/useAlert';
|
|
||||||
import type { ReflectResponseService } from '../hooks/useGrpc';
|
import type { ReflectResponseService } from '../hooks/useGrpc';
|
||||||
|
import { showAlert } from '../lib/alert';
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import { tryFormatJson } from '../lib/formatters';
|
import { tryFormatJson } from '../lib/formatters';
|
||||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
|
||||||
import { pluralizeCount } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
|
import type { EditorProps } from './core/Editor/Editor';
|
||||||
|
import { Editor } from './core/Editor/Editor';
|
||||||
import { FormattedError } from './core/FormattedError';
|
import { FormattedError } from './core/FormattedError';
|
||||||
import { InlineCode } from './core/InlineCode';
|
import { InlineCode } from './core/InlineCode';
|
||||||
import { VStack } from './core/Stacks';
|
import { VStack } from './core/Stacks';
|
||||||
import { useDialog } from '../hooks/useDialog';
|
|
||||||
import { GrpcProtoSelection } from './GrpcProtoSelection';
|
import { GrpcProtoSelection } from './GrpcProtoSelection';
|
||||||
import type { EditorProps} from './core/Editor/Editor';
|
|
||||||
import {Editor} from './core/Editor/Editor';
|
|
||||||
|
|
||||||
type Props = Pick<EditorProps, 'heightMode' | 'onChange' | 'className'> & {
|
type Props = Pick<EditorProps, 'heightMode' | 'onChange' | 'className'> & {
|
||||||
services: ReflectResponseService[] | null;
|
services: ReflectResponseService[] | null;
|
||||||
@@ -42,9 +42,6 @@ export function GrpcEditor({
|
|||||||
}: Props) {
|
}: Props) {
|
||||||
const editorViewRef = useRef<EditorView>(null);
|
const editorViewRef = useRef<EditorView>(null);
|
||||||
|
|
||||||
const alert = useAlert();
|
|
||||||
const dialog = useDialog();
|
|
||||||
|
|
||||||
// Find the schema for the selected service and method and update the editor
|
// Find the schema for the selected service and method and update the editor
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
@@ -59,7 +56,7 @@ export function GrpcEditor({
|
|||||||
const s = services.find((s) => s.name === request.service);
|
const s = services.find((s) => s.name === request.service);
|
||||||
if (s == null) {
|
if (s == null) {
|
||||||
console.log('Failed to find service', { service: request.service, services });
|
console.log('Failed to find service', { service: request.service, services });
|
||||||
alert({
|
showAlert({
|
||||||
id: 'grpc-find-service-error',
|
id: 'grpc-find-service-error',
|
||||||
title: "Couldn't Find Service",
|
title: "Couldn't Find Service",
|
||||||
body: (
|
body: (
|
||||||
@@ -74,7 +71,7 @@ export function GrpcEditor({
|
|||||||
const schema = s.methods.find((m) => m.name === request.method)?.schema;
|
const schema = s.methods.find((m) => m.name === request.method)?.schema;
|
||||||
if (request.method != null && schema == null) {
|
if (request.method != null && schema == null) {
|
||||||
console.log('Failed to find method', { method: request.method, methods: s?.methods });
|
console.log('Failed to find method', { method: request.method, methods: s?.methods });
|
||||||
alert({
|
showAlert({
|
||||||
id: 'grpc-find-schema-error',
|
id: 'grpc-find-schema-error',
|
||||||
title: "Couldn't Find Method",
|
title: "Couldn't Find Method",
|
||||||
body: (
|
body: (
|
||||||
@@ -94,7 +91,7 @@ export function GrpcEditor({
|
|||||||
try {
|
try {
|
||||||
updateSchema(editorViewRef.current, JSON.parse(schema));
|
updateSchema(editorViewRef.current, JSON.parse(schema));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert({
|
showAlert({
|
||||||
id: 'grpc-parse-schema-error',
|
id: 'grpc-parse-schema-error',
|
||||||
title: 'Failed to Parse Schema',
|
title: 'Failed to Parse Schema',
|
||||||
body: (
|
body: (
|
||||||
@@ -108,7 +105,7 @@ export function GrpcEditor({
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [alert, services, request.method, request.service]);
|
}, [services, request.method, request.service]);
|
||||||
|
|
||||||
const extraExtensions = useMemo(
|
const extraExtensions = useMemo(
|
||||||
() => [
|
() => [
|
||||||
@@ -143,7 +140,7 @@ export function GrpcEditor({
|
|||||||
}
|
}
|
||||||
isLoading={reflectionLoading}
|
isLoading={reflectionLoading}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
dialog.show({
|
showDialog({
|
||||||
title: 'Configure Schema',
|
title: 'Configure Schema',
|
||||||
size: 'md',
|
size: 'md',
|
||||||
id: 'reflection-failed',
|
id: 'reflection-failed',
|
||||||
@@ -172,7 +169,6 @@ export function GrpcEditor({
|
|||||||
</div>,
|
</div>,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
dialog,
|
|
||||||
protoFiles.length,
|
protoFiles.length,
|
||||||
reflectionError,
|
reflectionError,
|
||||||
reflectionLoading,
|
reflectionLoading,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
||||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import {showToast} from "../lib/toast";
|
import { router } from '../lib/router';
|
||||||
|
import { showToast } from '../lib/toast';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import { InlineCode } from './core/InlineCode';
|
import { InlineCode } from './core/InlineCode';
|
||||||
import { Select } from './core/Select';
|
import { Select } from './core/Select';
|
||||||
@@ -21,7 +21,6 @@ export function MoveToWorkspaceDialog({ onDone, request, activeWorkspaceId }: Pr
|
|||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
const updateHttpRequest = useUpdateAnyHttpRequest();
|
const updateHttpRequest = useUpdateAnyHttpRequest();
|
||||||
const updateGrpcRequest = useUpdateAnyGrpcRequest();
|
const updateGrpcRequest = useUpdateAnyGrpcRequest();
|
||||||
const navigate = useNavigate();
|
|
||||||
const [selectedWorkspaceId, setSelectedWorkspaceId] = useState<string>(activeWorkspaceId);
|
const [selectedWorkspaceId, setSelectedWorkspaceId] = useState<string>(activeWorkspaceId);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -69,7 +68,7 @@ export function MoveToWorkspaceDialog({ onDone, request, activeWorkspaceId }: Pr
|
|||||||
color="secondary"
|
color="secondary"
|
||||||
className="mr-auto min-w-[5rem]"
|
className="mr-auto min-w-[5rem]"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await navigate({
|
await router.navigate({
|
||||||
to: '/workspaces/$workspaceId',
|
to: '/workspaces/$workspaceId',
|
||||||
params: { workspaceId: selectedWorkspaceId },
|
params: { workspaceId: selectedWorkspaceId },
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useCallback, useMemo, useRef } from 'react';
|
import { useMemo, useRef } from 'react';
|
||||||
import { useKeyPressEvent } from 'react-use';
|
import { useKeyPressEvent } from 'react-use';
|
||||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||||
import { getActiveWorkspaceId } from '../hooks/useActiveWorkspace';
|
import { getActiveWorkspaceId } from '../hooks/useActiveWorkspace';
|
||||||
@@ -10,6 +9,7 @@ import { httpRequestsAtom } from '../hooks/useHttpRequests';
|
|||||||
import { useRecentRequests } from '../hooks/useRecentRequests';
|
import { useRecentRequests } from '../hooks/useRecentRequests';
|
||||||
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
import { fallbackRequestName } from '../lib/fallbackRequestName';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
import type { DropdownItem, DropdownRef } from './core/Dropdown';
|
import type { DropdownItem, DropdownRef } from './core/Dropdown';
|
||||||
import { Dropdown } from './core/Dropdown';
|
import { Dropdown } from './core/Dropdown';
|
||||||
@@ -24,7 +24,6 @@ export function RecentRequestsDropdown({ className }: Props) {
|
|||||||
const dropdownRef = useRef<DropdownRef>(null);
|
const dropdownRef = useRef<DropdownRef>(null);
|
||||||
const [allRecentRequestIds] = useRecentRequests();
|
const [allRecentRequestIds] = useRecentRequests();
|
||||||
const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]);
|
const recentRequestIds = useMemo(() => allRecentRequestIds.slice(1), [allRecentRequestIds]);
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
// Handle key-up
|
// Handle key-up
|
||||||
useKeyPressEvent('Control', undefined, () => {
|
useKeyPressEvent('Control', undefined, () => {
|
||||||
@@ -42,7 +41,7 @@ export function RecentRequestsDropdown({ className }: Props) {
|
|||||||
dropdownRef.current?.prev?.();
|
dropdownRef.current?.prev?.();
|
||||||
});
|
});
|
||||||
|
|
||||||
const getItems = useCallback(() => {
|
const items = useMemo(() => {
|
||||||
const activeWorkspaceId = getActiveWorkspaceId();
|
const activeWorkspaceId = getActiveWorkspaceId();
|
||||||
if (activeWorkspaceId === null) return [];
|
if (activeWorkspaceId === null) return [];
|
||||||
|
|
||||||
@@ -58,13 +57,10 @@ export function RecentRequestsDropdown({ className }: Props) {
|
|||||||
// leftSlot: <CountBadge className="!ml-0 px-0 w-5" count={recentRequestItems.length} />,
|
// leftSlot: <CountBadge className="!ml-0 px-0 w-5" count={recentRequestItems.length} />,
|
||||||
leftSlot: <HttpMethodTag className="text-right" shortNames request={request} />,
|
leftSlot: <HttpMethodTag className="text-right" shortNames request={request} />,
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
await navigate({
|
await router.navigate({
|
||||||
to: '/workspaces/$workspaceId/requests/$requestId',
|
to: '/workspaces/$workspaceId',
|
||||||
params: {
|
params: { workspaceId: activeWorkspaceId },
|
||||||
requestId: request.id,
|
search: (prev) => ({ ...prev, request_id: request.id }),
|
||||||
workspaceId: activeWorkspaceId,
|
|
||||||
},
|
|
||||||
search: (prev) => ({ ...prev }),
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -82,10 +78,10 @@ export function RecentRequestsDropdown({ className }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return recentRequestItems.slice(0, 20);
|
return recentRequestItems.slice(0, 20);
|
||||||
}, [navigate, recentRequestIds]);
|
}, [recentRequestIds]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown ref={dropdownRef} items={getItems}>
|
<Dropdown ref={dropdownRef} items={items}>
|
||||||
<Button
|
<Button
|
||||||
data-tauri-drag-region
|
data-tauri-drag-region
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { getRecentCookieJars } from '../hooks/useRecentCookieJars';
|
import { getRecentCookieJars } from '../hooks/useRecentCookieJars';
|
||||||
import { getRecentEnvironments } from '../hooks/useRecentEnvironments';
|
import { getRecentEnvironments } from '../hooks/useRecentEnvironments';
|
||||||
import { getRecentRequests } from '../hooks/useRecentRequests';
|
import { getRecentRequests } from '../hooks/useRecentRequests';
|
||||||
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
import { useRecentWorkspaces } from '../hooks/useRecentWorkspaces';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
|
import { router } from '../lib/router';
|
||||||
|
|
||||||
export function RedirectToLatestWorkspace() {
|
export function RedirectToLatestWorkspace() {
|
||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
const recentWorkspaces = useRecentWorkspaces();
|
const recentWorkspaces = useRecentWorkspaces();
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (workspaces.length === 0 || recentWorkspaces == null) {
|
if (workspaces.length === 0 || recentWorkspaces == null) {
|
||||||
@@ -22,23 +21,16 @@ export function RedirectToLatestWorkspace() {
|
|||||||
const environmentId = (await getRecentEnvironments(workspaceId))[0] ?? null;
|
const environmentId = (await getRecentEnvironments(workspaceId))[0] ?? null;
|
||||||
const cookieJarId = (await getRecentCookieJars(workspaceId))[0] ?? null;
|
const cookieJarId = (await getRecentCookieJars(workspaceId))[0] ?? null;
|
||||||
const requestId = (await getRecentRequests(workspaceId))[0] ?? null;
|
const requestId = (await getRecentRequests(workspaceId))[0] ?? null;
|
||||||
const search = { cookie_jar_id: cookieJarId, environment_id: environmentId };
|
const params = { workspaceId };
|
||||||
|
const search = {
|
||||||
|
cookie_jar_id: cookieJarId,
|
||||||
|
environment_id: environmentId,
|
||||||
|
requestId: requestId,
|
||||||
|
};
|
||||||
|
|
||||||
if (workspaceId != null && requestId != null) {
|
await router.navigate({ to: '/workspaces/$workspaceId', params, search });
|
||||||
await navigate({
|
|
||||||
to: '/workspaces/$workspaceId/requests/$requestId',
|
|
||||||
params: { workspaceId, requestId },
|
|
||||||
search,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await navigate({
|
|
||||||
to: '/workspaces/$workspaceId',
|
|
||||||
params: { workspaceId },
|
|
||||||
search,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
})();
|
||||||
}, [navigate, recentWorkspaces, workspaces, workspaces.length]);
|
}, [recentWorkspaces, workspaces, workspaces.length]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import { openUrl } from '@tauri-apps/plugin-opener';
|
|||||||
import { useRef } from 'react';
|
import { useRef } from 'react';
|
||||||
import { useAppInfo } from '../hooks/useAppInfo';
|
import { useAppInfo } from '../hooks/useAppInfo';
|
||||||
import { useCheckForUpdates } from '../hooks/useCheckForUpdates';
|
import { useCheckForUpdates } from '../hooks/useCheckForUpdates';
|
||||||
import { useDialog } from '../hooks/useDialog';
|
|
||||||
import { useExportData } from '../hooks/useExportData';
|
import { useExportData } from '../hooks/useExportData';
|
||||||
import { useImportData } from '../hooks/useImportData';
|
import { useImportData } from '../hooks/useImportData';
|
||||||
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
import { useListenToTauriEvent } from '../hooks/useListenToTauriEvent';
|
||||||
import { useOpenSettings } from '../hooks/useOpenSettings';
|
import { useOpenSettings } from '../hooks/useOpenSettings';
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import type { DropdownRef } from './core/Dropdown';
|
import type { DropdownRef } from './core/Dropdown';
|
||||||
import { Dropdown } from './core/Dropdown';
|
import { Dropdown } from './core/Dropdown';
|
||||||
import { Icon } from './core/Icon';
|
import { Icon } from './core/Icon';
|
||||||
@@ -18,7 +18,6 @@ export function SettingsDropdown() {
|
|||||||
const exportData = useExportData();
|
const exportData = useExportData();
|
||||||
const appInfo = useAppInfo();
|
const appInfo = useAppInfo();
|
||||||
const dropdownRef = useRef<DropdownRef>(null);
|
const dropdownRef = useRef<DropdownRef>(null);
|
||||||
const dialog = useDialog();
|
|
||||||
const checkForUpdates = useCheckForUpdates();
|
const checkForUpdates = useCheckForUpdates();
|
||||||
const openSettings = useOpenSettings();
|
const openSettings = useOpenSettings();
|
||||||
|
|
||||||
@@ -41,7 +40,7 @@ export function SettingsDropdown() {
|
|||||||
hotKeyAction: 'hotkeys.showHelp',
|
hotKeyAction: 'hotkeys.showHelp',
|
||||||
leftSlot: <Icon icon="keyboard" />,
|
leftSlot: <Icon icon="keyboard" />,
|
||||||
onSelect: () => {
|
onSelect: () => {
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'hotkey',
|
id: 'hotkey',
|
||||||
title: 'Keyboard Shortcuts',
|
title: 'Keyboard Shortcuts',
|
||||||
size: 'dynamic',
|
size: 'dynamic',
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
import type { Folder, GrpcRequest, HttpRequest, Workspace } from '@yaakapp-internal/models';
|
||||||
import type { AnyModel, Folder, GrpcRequest, HttpRequest } from '@yaakapp-internal/models';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useAtom, useAtomValue } from 'jotai';
|
import { useAtom, useAtomValue } from 'jotai';
|
||||||
import React, { useCallback, useRef, useState } from 'react';
|
import React, { useCallback, useRef, useState } from 'react';
|
||||||
@@ -15,6 +14,7 @@ import { getSidebarCollapsedMap } from '../hooks/useSidebarItemCollapsed';
|
|||||||
import { useUpdateAnyFolder } from '../hooks/useUpdateAnyFolder';
|
import { useUpdateAnyFolder } from '../hooks/useUpdateAnyFolder';
|
||||||
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
import { useUpdateAnyGrpcRequest } from '../hooks/useUpdateAnyGrpcRequest';
|
||||||
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
import { useUpdateAnyHttpRequest } from '../hooks/useUpdateAnyHttpRequest';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { ContextMenu } from './core/Dropdown';
|
import { ContextMenu } from './core/Dropdown';
|
||||||
import { sidebarSelectedIdAtom, sidebarTreeAtom } from './SidebarAtoms';
|
import { sidebarSelectedIdAtom, sidebarTreeAtom } from './SidebarAtoms';
|
||||||
import type { SidebarItemProps } from './SidebarItem';
|
import type { SidebarItemProps } from './SidebarItem';
|
||||||
@@ -24,10 +24,12 @@ interface Props {
|
|||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type SidebarModel = Folder | GrpcRequest | HttpRequest | Workspace;
|
||||||
|
|
||||||
export interface SidebarTreeNode {
|
export interface SidebarTreeNode {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
model: AnyModel['model'];
|
model: SidebarModel['model'];
|
||||||
sortPriority?: number;
|
sortPriority?: number;
|
||||||
workspaceId?: string;
|
workspaceId?: string;
|
||||||
folderId?: string | null;
|
folderId?: string | null;
|
||||||
@@ -35,8 +37,6 @@ export interface SidebarTreeNode {
|
|||||||
depth: number;
|
depth: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SidebarModel = Folder | GrpcRequest | HttpRequest;
|
|
||||||
|
|
||||||
export function Sidebar({ className }: Props) {
|
export function Sidebar({ className }: Props) {
|
||||||
const [hidden, setHidden] = useSidebarHidden();
|
const [hidden, setHidden] = useSidebarHidden();
|
||||||
const sidebarRef = useRef<HTMLElement>(null);
|
const sidebarRef = useRef<HTMLElement>(null);
|
||||||
@@ -52,7 +52,6 @@ export function Sidebar({ className }: Props) {
|
|||||||
const [draggingId, setDraggingId] = useState<string | null>(null);
|
const [draggingId, setDraggingId] = useState<string | null>(null);
|
||||||
const [hoveredTree, setHoveredTree] = useState<SidebarTreeNode | null>(null);
|
const [hoveredTree, setHoveredTree] = useState<SidebarTreeNode | null>(null);
|
||||||
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const { tree, treeParentMap, selectableRequests } = useAtomValue(sidebarTreeAtom);
|
const { tree, treeParentMap, selectableRequests } = useAtomValue(sidebarTreeAtom);
|
||||||
|
|
||||||
@@ -95,14 +94,13 @@ export function Sidebar({ className }: Props) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.model === 'http_request' || node.model === 'grpc_request') {
|
// NOTE: I'm not sure why, but TS thinks workspaceId is (string | undefined) here
|
||||||
await navigate({
|
if ((node.model === 'http_request' || node.model === 'grpc_request') && node.workspaceId) {
|
||||||
to: '/workspaces/$workspaceId/requests/$requestId',
|
const workspaceId = node.workspaceId;
|
||||||
params: {
|
await router.navigate({
|
||||||
requestId: id,
|
to: '/workspaces/$workspaceId',
|
||||||
workspaceId: node.workspaceId ?? 'n/a',
|
params: { workspaceId },
|
||||||
},
|
search: (prev) => ({ ...prev, request_id: node.id }),
|
||||||
search: (prev) => ({ ...prev }),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setHasFocus(true);
|
setHasFocus(true);
|
||||||
@@ -110,7 +108,7 @@ export function Sidebar({ className }: Props) {
|
|||||||
setSelectedTree(tree);
|
setSelectedTree(tree);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[treeParentMap, navigate, setSelectedId],
|
[treeParentMap, setSelectedId],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleClearSelected = useCallback(() => {
|
const handleClearSelected = useCallback(() => {
|
||||||
@@ -153,13 +151,10 @@ export function Sidebar({ className }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await navigate({
|
await router.navigate({
|
||||||
to: '/workspaces/$workspaceId/requests/$requestId',
|
to: '/workspaces/$workspaceId',
|
||||||
params: {
|
params: { workspaceId: activeWorkspace?.id ?? null },
|
||||||
requestId: selected.id,
|
search: (prev) => ({ ...prev, request_id: selected.id }),
|
||||||
workspaceId: activeWorkspace?.id ?? null,
|
|
||||||
},
|
|
||||||
search: (prev) => ({ ...prev }),
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useCreateDropdownItems } from '../hooks/useCreateDropdownItems';
|
import { useCreateDropdownItems } from '../hooks/useCreateDropdownItems';
|
||||||
import { useDeleteFolder } from '../hooks/useDeleteFolder';
|
import { useDeleteFolder } from '../hooks/useDeleteFolder';
|
||||||
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
||||||
import { useDialog } from '../hooks/useDialog';
|
|
||||||
import { useDuplicateFolder } from '../hooks/useDuplicateFolder';
|
import { useDuplicateFolder } from '../hooks/useDuplicateFolder';
|
||||||
import { useDuplicateGrpcRequest } from '../hooks/useDuplicateGrpcRequest';
|
import { useDuplicateGrpcRequest } from '../hooks/useDuplicateGrpcRequest';
|
||||||
import { useDuplicateHttpRequest } from '../hooks/useDuplicateHttpRequest';
|
import { useDuplicateHttpRequest } from '../hooks/useDuplicateHttpRequest';
|
||||||
@@ -12,6 +11,8 @@ import { useRenameRequest } from '../hooks/useRenameRequest';
|
|||||||
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
import { useSendAnyHttpRequest } from '../hooks/useSendAnyHttpRequest';
|
||||||
import { useSendManyRequests } from '../hooks/useSendManyRequests';
|
import { useSendManyRequests } from '../hooks/useSendManyRequests';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
|
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import { getHttpRequest } from '../lib/store';
|
import { getHttpRequest } from '../lib/store';
|
||||||
import type { DropdownItem } from './core/Dropdown';
|
import type { DropdownItem } from './core/Dropdown';
|
||||||
import { ContextMenu } from './core/Dropdown';
|
import { ContextMenu } from './core/Dropdown';
|
||||||
@@ -32,7 +33,6 @@ export function SidebarItemContextMenu({ child, show, close }: Props) {
|
|||||||
const httpRequestActions = useHttpRequestActions();
|
const httpRequestActions = useHttpRequestActions();
|
||||||
const sendRequest = useSendAnyHttpRequest();
|
const sendRequest = useSendAnyHttpRequest();
|
||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
const dialog = useDialog();
|
|
||||||
const deleteRequest = useDeleteRequest(child.id);
|
const deleteRequest = useDeleteRequest(child.id);
|
||||||
const renameRequest = useRenameRequest(child.id);
|
const renameRequest = useRenameRequest(child.id);
|
||||||
const duplicateHttpRequest = useDuplicateHttpRequest({ id: child.id, navigateAfter: true });
|
const duplicateHttpRequest = useDuplicateHttpRequest({ id: child.id, navigateAfter: true });
|
||||||
@@ -42,7 +42,7 @@ export function SidebarItemContextMenu({ child, show, close }: Props) {
|
|||||||
folderId: child.model === 'folder' ? child.id : null,
|
folderId: child.model === 'folder' ? child.id : null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const items = useCallback((): DropdownItem[] => {
|
const items = useMemo((): DropdownItem[] => {
|
||||||
if (child.model === 'folder') {
|
if (child.model === 'folder') {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -56,7 +56,7 @@ export function SidebarItemContextMenu({ child, show, close }: Props) {
|
|||||||
label: 'Settings',
|
label: 'Settings',
|
||||||
leftSlot: <Icon icon="settings" />,
|
leftSlot: <Icon icon="settings" />,
|
||||||
onSelect: () =>
|
onSelect: () =>
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'folder-settings',
|
id: 'folder-settings',
|
||||||
title: 'Folder Settings',
|
title: 'Folder Settings',
|
||||||
size: 'md',
|
size: 'md',
|
||||||
@@ -77,7 +77,7 @@ export function SidebarItemContextMenu({ child, show, close }: Props) {
|
|||||||
onSelect: () => deleteFolder.mutate(),
|
onSelect: () => deleteFolder.mutate(),
|
||||||
},
|
},
|
||||||
{ type: 'separator' },
|
{ type: 'separator' },
|
||||||
...createDropdownItems(),
|
...createDropdownItems,
|
||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
const requestItems: DropdownItem[] =
|
const requestItems: DropdownItem[] =
|
||||||
@@ -146,7 +146,6 @@ export function SidebarItemContextMenu({ child, show, close }: Props) {
|
|||||||
createDropdownItems,
|
createDropdownItems,
|
||||||
deleteFolder,
|
deleteFolder,
|
||||||
deleteRequest,
|
deleteRequest,
|
||||||
dialog,
|
|
||||||
duplicateFolder,
|
duplicateFolder,
|
||||||
duplicateGrpcRequest,
|
duplicateGrpcRequest,
|
||||||
duplicateHttpRequest,
|
duplicateHttpRequest,
|
||||||
|
|||||||
@@ -5,41 +5,30 @@ import { hideToast, toastsAtom } from '../lib/toast';
|
|||||||
import { Toast, type ToastProps } from './core/Toast';
|
import { Toast, type ToastProps } from './core/Toast';
|
||||||
import { Portal } from './Portal';
|
import { Portal } from './Portal';
|
||||||
|
|
||||||
export type ToastEntry = {
|
export type ToastInstance = {
|
||||||
id?: string;
|
id: string;
|
||||||
message: ReactNode;
|
message: ReactNode;
|
||||||
timeout?: 3000 | 5000 | 8000 | null;
|
timeout: 3000 | 5000 | 8000 | null;
|
||||||
onClose?: ToastProps['onClose'];
|
onClose?: ToastProps['onClose'];
|
||||||
} & Omit<ToastProps, 'onClose' | 'open' | 'children' | 'timeout'>;
|
} & Omit<ToastProps, 'onClose' | 'open' | 'children' | 'timeout'>;
|
||||||
|
|
||||||
export type PrivateToastEntry = ToastEntry & {
|
|
||||||
id: string;
|
|
||||||
timeout: number | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
function ToastInstance({ id, message, timeout, ...props }: PrivateToastEntry) {
|
|
||||||
return (
|
|
||||||
<Toast
|
|
||||||
open
|
|
||||||
timeout={timeout}
|
|
||||||
{...props}
|
|
||||||
// We call onClose inside actions.hide instead of passing to toast so that
|
|
||||||
// it gets called from external close calls as well
|
|
||||||
onClose={() => hideToast(id)}
|
|
||||||
>
|
|
||||||
{message}
|
|
||||||
</Toast>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Toasts = () => {
|
export const Toasts = () => {
|
||||||
const toasts = useAtomValue(toastsAtom);
|
const toasts = useAtomValue(toastsAtom);
|
||||||
return (
|
return (
|
||||||
<Portal name="toasts">
|
<Portal name="toasts">
|
||||||
<div className="absolute right-0 bottom-0 z-20">
|
<div className="absolute right-0 bottom-0 z-20">
|
||||||
<AnimatePresence>
|
<AnimatePresence>
|
||||||
{toasts.map((props: PrivateToastEntry) => (
|
{toasts.map(({ message, ...props }: ToastInstance) => (
|
||||||
<ToastInstance key={props.id} {...props} />
|
<Toast
|
||||||
|
key={props.id}
|
||||||
|
open
|
||||||
|
{...props}
|
||||||
|
// We call onClose inside actions.hide instead of passing to toast so that
|
||||||
|
// it gets called from external close calls as well
|
||||||
|
onClose={() => hideToast(props.id)}
|
||||||
|
>
|
||||||
|
{message}
|
||||||
|
</Toast>
|
||||||
))}
|
))}
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import { memo, useCallback, useMemo } from 'react';
|
|||||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||||
import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
import { useCreateWorkspace } from '../hooks/useCreateWorkspace';
|
||||||
import { useDeleteSendHistory } from '../hooks/useDeleteSendHistory';
|
import { useDeleteSendHistory } from '../hooks/useDeleteSendHistory';
|
||||||
import { useDialog } from '../hooks/useDialog';
|
|
||||||
import { useOpenWorkspace } from '../hooks/useOpenWorkspace';
|
import { useOpenWorkspace } from '../hooks/useOpenWorkspace';
|
||||||
import { useSettings } from '../hooks/useSettings';
|
import { useSettings } from '../hooks/useSettings';
|
||||||
import { useSyncWorkspace } from '../hooks/useSyncWorkspace';
|
import { useSyncWorkspace } from '../hooks/useSyncWorkspace';
|
||||||
import { useWorkspaces } from '../hooks/useWorkspaces';
|
import { useWorkspaces } from '../hooks/useWorkspaces';
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import { getWorkspace } from '../lib/store';
|
import { getWorkspace } from '../lib/store';
|
||||||
import type { ButtonProps } from './core/Button';
|
import type { ButtonProps } from './core/Button';
|
||||||
import { Button } from './core/Button';
|
import { Button } from './core/Button';
|
||||||
@@ -28,7 +28,6 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
|||||||
const activeWorkspace = useActiveWorkspace();
|
const activeWorkspace = useActiveWorkspace();
|
||||||
const createWorkspace = useCreateWorkspace();
|
const createWorkspace = useCreateWorkspace();
|
||||||
const { mutate: deleteSendHistory } = useDeleteSendHistory();
|
const { mutate: deleteSendHistory } = useDeleteSendHistory();
|
||||||
const dialog = useDialog();
|
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const openWorkspace = useOpenWorkspace();
|
const openWorkspace = useOpenWorkspace();
|
||||||
const openWorkspaceNewWindow = settings?.openWorkspaceNewWindow ?? null;
|
const openWorkspaceNewWindow = settings?.openWorkspaceNewWindow ?? null;
|
||||||
@@ -57,7 +56,7 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
|||||||
leftSlot: <Icon icon="settings" />,
|
leftSlot: <Icon icon="settings" />,
|
||||||
hotKeyAction: 'workspace_settings.show',
|
hotKeyAction: 'workspace_settings.show',
|
||||||
onSelect: async () => {
|
onSelect: async () => {
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'workspace-settings',
|
id: 'workspace-settings',
|
||||||
title: 'Workspace Settings',
|
title: 'Workspace Settings',
|
||||||
size: 'md',
|
size: 'md',
|
||||||
@@ -97,7 +96,6 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
|||||||
sync,
|
sync,
|
||||||
deleteSendHistory,
|
deleteSendHistory,
|
||||||
createWorkspace,
|
createWorkspace,
|
||||||
dialog,
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
@@ -112,14 +110,14 @@ export const WorkspaceActionsDropdown = memo(function WorkspaceActionsDropdown({
|
|||||||
const workspace = await getWorkspace(workspaceId);
|
const workspace = await getWorkspace(workspaceId);
|
||||||
if (workspace == null) return;
|
if (workspace == null) return;
|
||||||
|
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'open-workspace',
|
id: 'open-workspace',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
title: 'Open Workspace',
|
title: 'Open Workspace',
|
||||||
render: ({ hide }) => <OpenWorkspaceDialog workspace={workspace} hide={hide} />,
|
render: ({ hide }) => <OpenWorkspaceDialog workspace={workspace} hide={hide} />,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[dialog, openWorkspace, openWorkspaceNewWindow],
|
[openWorkspace, openWorkspaceNewWindow],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export type DropdownItem = DropdownItemDefault | DropdownItemSeparator;
|
|||||||
|
|
||||||
export interface DropdownProps {
|
export interface DropdownProps {
|
||||||
children: ReactElement<HTMLAttributes<HTMLButtonElement>>;
|
children: ReactElement<HTMLAttributes<HTMLButtonElement>>;
|
||||||
items: DropdownItem[] | (() => DropdownItem[]);
|
items: DropdownItem[];
|
||||||
onOpen?: () => void;
|
onOpen?: () => void;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
fullWidth?: boolean;
|
fullWidth?: boolean;
|
||||||
@@ -75,7 +75,7 @@ export interface DropdownRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown(
|
export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown(
|
||||||
{ children, items: itemsGetter, onOpen, onClose, hotKeyAction, fullWidth }: DropdownProps,
|
{ children, items, onOpen, onClose, hotKeyAction, fullWidth }: DropdownProps,
|
||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
const [isOpen, _setIsOpen] = useState<boolean>(false);
|
const [isOpen, _setIsOpen] = useState<boolean>(false);
|
||||||
@@ -83,8 +83,6 @@ export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown
|
|||||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||||
const menuRef = useRef<Omit<DropdownRef, 'open'>>(null);
|
const menuRef = useRef<Omit<DropdownRef, 'open'>>(null);
|
||||||
|
|
||||||
const [items, setItems] = useState<DropdownItem[]>([]);
|
|
||||||
|
|
||||||
const setIsOpen = useCallback(
|
const setIsOpen = useCallback(
|
||||||
(o: SetStateAction<boolean>) => {
|
(o: SetStateAction<boolean>) => {
|
||||||
_setIsOpen(o);
|
_setIsOpen(o);
|
||||||
@@ -103,8 +101,7 @@ export const Dropdown = forwardRef<DropdownRef, DropdownProps>(function Dropdown
|
|||||||
|
|
||||||
const openDropdown = useCallback(() => {
|
const openDropdown = useCallback(() => {
|
||||||
setIsOpen((o) => !o);
|
setIsOpen((o) => !o);
|
||||||
setItems(typeof itemsGetter === 'function' ? itemsGetter() : itemsGetter);
|
}, [setIsOpen]);
|
||||||
}, [itemsGetter, setIsOpen]);
|
|
||||||
|
|
||||||
useImperativeHandle(
|
useImperativeHandle(
|
||||||
ref,
|
ref,
|
||||||
@@ -205,7 +202,7 @@ export const ContextMenu = forwardRef<DropdownRef, ContextMenuProps>(function Co
|
|||||||
isOpen={true} // Always open because we return null if not
|
isOpen={true} // Always open because we return null if not
|
||||||
className={className}
|
className={className}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
items={typeof items === 'function' ? items() : items}
|
items={items}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
triggerShape={triggerShape}
|
triggerShape={triggerShape}
|
||||||
/>
|
/>
|
||||||
@@ -417,11 +414,9 @@ const Menu = forwardRef<Omit<DropdownRef, 'open' | 'isOpen' | 'toggle' | 'items'
|
|||||||
[filteredItems, setSelectedIndex],
|
[filteredItems, setSelectedIndex],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (items.length === 0) return null;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{filteredItems.map(
|
{items.map(
|
||||||
(item) =>
|
(item) =>
|
||||||
item.type !== 'separator' &&
|
item.type !== 'separator' &&
|
||||||
!item.hotKeyLabelOnly && (
|
!item.hotKeyLabelOnly && (
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useActiveEnvironmentVariables } from '../../../hooks/useActiveEnvironmentVariables';
|
import { useActiveEnvironmentVariables } from '../../../hooks/useActiveEnvironmentVariables';
|
||||||
import { useDialog } from '../../../hooks/useDialog';
|
|
||||||
import { parseTemplate } from '../../../hooks/useParseTemplate';
|
import { parseTemplate } from '../../../hooks/useParseTemplate';
|
||||||
import { useRequestEditor } from '../../../hooks/useRequestEditor';
|
import { useRequestEditor } from '../../../hooks/useRequestEditor';
|
||||||
import { useSettings } from '../../../hooks/useSettings';
|
import { useSettings } from '../../../hooks/useSettings';
|
||||||
@@ -28,6 +27,7 @@ import {
|
|||||||
useTemplateFunctions,
|
useTemplateFunctions,
|
||||||
useTwigCompletionOptions,
|
useTwigCompletionOptions,
|
||||||
} from '../../../hooks/useTemplateFunctions';
|
} from '../../../hooks/useTemplateFunctions';
|
||||||
|
import { showDialog } from '../../../lib/dialog';
|
||||||
import { TemplateFunctionDialog } from '../../TemplateFunctionDialog';
|
import { TemplateFunctionDialog } from '../../TemplateFunctionDialog';
|
||||||
import { TemplateVariableDialog } from '../../TemplateVariableDialog';
|
import { TemplateVariableDialog } from '../../TemplateVariableDialog';
|
||||||
import { IconButton } from '../IconButton';
|
import { IconButton } from '../IconButton';
|
||||||
@@ -195,11 +195,10 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
|||||||
[wrapLines],
|
[wrapLines],
|
||||||
);
|
);
|
||||||
|
|
||||||
const dialog = useDialog();
|
|
||||||
const onClickFunction = useCallback(
|
const onClickFunction = useCallback(
|
||||||
async (fn: TemplateFunction, tagValue: string, startPos: number) => {
|
async (fn: TemplateFunction, tagValue: string, startPos: number) => {
|
||||||
const initialTokens = await parseTemplate(tagValue);
|
const initialTokens = await parseTemplate(tagValue);
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'template-function',
|
id: 'template-function',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
title: 'Configure Function',
|
title: 'Configure Function',
|
||||||
@@ -218,13 +217,13 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[dialog],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onClickVariable = useCallback(
|
const onClickVariable = useCallback(
|
||||||
async (_v: EnvironmentVariable, tagValue: string, startPos: number) => {
|
async (_v: EnvironmentVariable, tagValue: string, startPos: number) => {
|
||||||
const initialTokens = await parseTemplate(tagValue);
|
const initialTokens = await parseTemplate(tagValue);
|
||||||
dialog.show({
|
showDialog({
|
||||||
size: 'dynamic',
|
size: 'dynamic',
|
||||||
id: 'template-variable',
|
id: 'template-variable',
|
||||||
title: 'Change Variable',
|
title: 'Change Variable',
|
||||||
@@ -241,13 +240,13 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[dialog],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const onClickMissingVariable = useCallback(
|
const onClickMissingVariable = useCallback(
|
||||||
async (_name: string, tagValue: string, startPos: number) => {
|
async (_name: string, tagValue: string, startPos: number) => {
|
||||||
const initialTokens = await parseTemplate(tagValue);
|
const initialTokens = await parseTemplate(tagValue);
|
||||||
dialog.show({
|
showDialog({
|
||||||
size: 'dynamic',
|
size: 'dynamic',
|
||||||
id: 'template-variable',
|
id: 'template-variable',
|
||||||
title: 'Configure Variable',
|
title: 'Configure Variable',
|
||||||
@@ -264,7 +263,7 @@ export const Editor = forwardRef<EditorView | undefined, EditorProps>(function E
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[dialog],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const [, { focusParamValue }] = useRequestEditor();
|
const [, { focusParamValue }] = useRequestEditor();
|
||||||
|
|||||||
@@ -338,7 +338,7 @@ function PairEditorRow({
|
|||||||
const handleFocus = useCallback(() => onFocus?.(pair), [onFocus, pair]);
|
const handleFocus = useCallback(() => onFocus?.(pair), [onFocus, pair]);
|
||||||
const handleDelete = useCallback(() => onDelete?.(pair, false), [onDelete, pair]);
|
const handleDelete = useCallback(() => onDelete?.(pair, false), [onDelete, pair]);
|
||||||
|
|
||||||
const getDeleteItems = useCallback(
|
const deleteItems = useMemo(
|
||||||
(): DropdownItem[] => [
|
(): DropdownItem[] => [
|
||||||
{
|
{
|
||||||
key: 'delete',
|
key: 'delete',
|
||||||
@@ -525,7 +525,7 @@ function PairEditorRow({
|
|||||||
onDelete={handleDelete}
|
onDelete={handleDelete}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Dropdown items={getDeleteItems}>
|
<Dropdown items={deleteItems}>
|
||||||
<IconButton
|
<IconButton
|
||||||
iconSize="sm"
|
iconSize="sm"
|
||||||
size="xs"
|
size="xs"
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { useNavigate, useSearch } from '@tanstack/react-router';
|
import { useSearch } from '@tanstack/react-router';
|
||||||
import type { CookieJar } from '@yaakapp-internal/models';
|
import type { CookieJar } from '@yaakapp-internal/models';
|
||||||
import { atom, useAtomValue } from 'jotai/index';
|
import { atom, useAtomValue } from 'jotai/index';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { cookieJarsAtom, useCookieJars } from './useCookieJars';
|
import { cookieJarsAtom, useCookieJars } from './useCookieJars';
|
||||||
|
|
||||||
export const QUERY_COOKIE_JAR_ID = 'cookie_jar_id';
|
export const QUERY_COOKIE_JAR_ID = 'cookie_jar_id';
|
||||||
@@ -14,33 +15,15 @@ export const activeCookieJarAtom = atom<CookieJar | null>((get) => {
|
|||||||
return get(cookieJarsAtom)?.find((e) => e.id === activeId) ?? null;
|
return get(cookieJarsAtom)?.find((e) => e.id === activeId) ?? null;
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useActiveCookieJar() {
|
export function setActiveCookieJar(cookieJar: CookieJar) {
|
||||||
const navigate = useNavigate({ from: '/workspaces/$workspaceId' });
|
router.navigate({
|
||||||
const setId = useCallback(
|
from: '/workspaces/$workspaceId',
|
||||||
(id: string) =>
|
search: (prev) => ({ ...prev, cookie_jar_id: cookieJar.id }),
|
||||||
navigate({
|
});
|
||||||
search: (prev) => ({ ...prev, cookie_jar_id: id }),
|
|
||||||
}),
|
|
||||||
[navigate],
|
|
||||||
);
|
|
||||||
const cookieJar = useAtomValue(activeCookieJarAtom);
|
|
||||||
return [cookieJar, setId] as const;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function useActiveCookieJarId() {
|
export function useActiveCookieJar() {
|
||||||
// NOTE: This query param is accessed from Rust side, so do not change
|
return useAtomValue(activeCookieJarAtom);
|
||||||
const { cookie_jar_id: id } = useSearch({ strict: false });
|
|
||||||
const navigate = useNavigate({ from: '/workspaces/$workspaceId' });
|
|
||||||
|
|
||||||
const setId = useCallback(
|
|
||||||
(id: string) =>
|
|
||||||
navigate({
|
|
||||||
search: (prev) => ({ ...prev, cookie_jar_id: id }),
|
|
||||||
}),
|
|
||||||
[navigate],
|
|
||||||
);
|
|
||||||
|
|
||||||
return [id, setId] as const;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useSubscribeActiveCookieJarId() {
|
export function useSubscribeActiveCookieJarId() {
|
||||||
@@ -56,12 +39,12 @@ export function getActiveCookieJar() {
|
|||||||
|
|
||||||
export function useEnsureActiveCookieJar() {
|
export function useEnsureActiveCookieJar() {
|
||||||
const cookieJars = useCookieJars();
|
const cookieJars = useCookieJars();
|
||||||
const [activeCookieJarId, setActiveCookieJarId] = useActiveCookieJarId();
|
const activeCookieJar = useActiveCookieJar();
|
||||||
|
|
||||||
// Set the active cookie jar to the first one, if none set
|
// Set the active cookie jar to the first one, if none set
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cookieJars == null) return; // Hasn't loaded yet
|
if (cookieJars == null) return; // Hasn't loaded yet
|
||||||
if (cookieJars.find((j) => j.id === activeCookieJarId)) {
|
if (cookieJars.find((j) => j.id === activeCookieJar?.id)) {
|
||||||
return; // There's an active jar
|
return; // There's an active jar
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +56,6 @@ export function useEnsureActiveCookieJar() {
|
|||||||
|
|
||||||
// There's no active jar, so set it to the first one
|
// There's no active jar, so set it to the first one
|
||||||
console.log('Setting active cookie jar to', firstJar.id);
|
console.log('Setting active cookie jar to', firstJar.id);
|
||||||
setActiveCookieJarId(firstJar.id).catch(console.error);
|
setActiveCookieJar(firstJar);
|
||||||
}, [activeCookieJarId, cookieJars, setActiveCookieJarId]);
|
}, [activeCookieJar?.id, cookieJars]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { useNavigate, useSearch } from '@tanstack/react-router';
|
import { useSearch } from '@tanstack/react-router';
|
||||||
import type { Environment } from '@yaakapp-internal/models';
|
import type { Environment } from '@yaakapp-internal/models';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
import { atom } from 'jotai/index';
|
import { atom } from 'jotai/index';
|
||||||
import { useCallback, useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { environmentsAtom } from './useEnvironments';
|
import { environmentsAtom } from './useEnvironments';
|
||||||
|
|
||||||
export const QUERY_ENVIRONMENT_ID = 'environment_id';
|
export const QUERY_ENVIRONMENT_ID = 'environment_id';
|
||||||
@@ -16,13 +17,13 @@ export const activeEnvironmentAtom = atom<Environment | null>((get) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function useActiveEnvironment() {
|
export function useActiveEnvironment() {
|
||||||
const navigate = useNavigate({ from: '/workspaces/$workspaceId' });
|
|
||||||
const setId = useCallback(
|
const setId = useCallback(
|
||||||
(id: string | null) =>
|
(id: string | null) =>
|
||||||
navigate({
|
router.navigate({
|
||||||
|
from: '/workspaces/$workspaceId',
|
||||||
search: (prev) => ({ ...prev, environment_id: id }),
|
search: (prev) => ({ ...prev, environment_id: id }),
|
||||||
}),
|
}),
|
||||||
[navigate],
|
[],
|
||||||
);
|
);
|
||||||
const environment = useAtomValue(activeEnvironmentAtom);
|
const environment = useAtomValue(activeEnvironmentAtom);
|
||||||
return [environment, setId] as const;
|
return [environment, setId] as const;
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { useParams } from '@tanstack/react-router';
|
import { useSearch } from '@tanstack/react-router';
|
||||||
import { atom, useAtomValue } from 'jotai';
|
import { atom, useAtomValue } from 'jotai';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
|
|
||||||
export const activeRequestIdAtom = atom<string>();
|
export const activeRequestIdAtom = atom<string | null>(null);
|
||||||
|
|
||||||
export function useActiveRequestId(): string | null {
|
export function useActiveRequestId(): string | null {
|
||||||
return useAtomValue(activeRequestIdAtom) ?? null;
|
return useAtomValue(activeRequestIdAtom);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useSubscribeActiveRequestId() {
|
export function useSubscribeActiveRequestId() {
|
||||||
const { requestId } = useParams({ strict: false });
|
const { request_id } = useSearch({ strict: false });
|
||||||
useEffect(() => jotaiStore.set(activeRequestIdAtom, requestId), [requestId]);
|
useEffect(() => jotaiStore.set(activeRequestIdAtom, request_id ?? null), [request_id]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
import { useCallback } from 'react';
|
|
||||||
import type { DialogProps } from '../components/core/Dialog';
|
|
||||||
import type { AlertProps } from './Alert';
|
|
||||||
import { Alert } from './Alert';
|
|
||||||
import {useDialog} from "./useDialog";
|
|
||||||
|
|
||||||
interface AlertArg {
|
|
||||||
id: string;
|
|
||||||
title: DialogProps['title'];
|
|
||||||
body: AlertProps['body'];
|
|
||||||
size?: DialogProps['size'];
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useAlert() {
|
|
||||||
const dialog = useDialog();
|
|
||||||
return useCallback<(a: AlertArg) => void>(
|
|
||||||
({ id, title, body, size = 'sm' }: AlertArg) =>
|
|
||||||
dialog.show({
|
|
||||||
id,
|
|
||||||
title,
|
|
||||||
hideX: true,
|
|
||||||
size,
|
|
||||||
render: ({ hide }) => Alert({ onHide: hide, body }),
|
|
||||||
}),
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
|
import { showAlert } from '../lib/alert';
|
||||||
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
import { minPromiseMillis } from '../lib/minPromiseMillis';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useAlert } from './useAlert';
|
|
||||||
import { useAppInfo } from './useAppInfo';
|
import { useAppInfo } from './useAppInfo';
|
||||||
|
|
||||||
export function useCheckForUpdates() {
|
export function useCheckForUpdates() {
|
||||||
const alert = useAlert();
|
|
||||||
const appInfo = useAppInfo();
|
const appInfo = useAppInfo();
|
||||||
|
|
||||||
return useMutation({
|
return useMutation({
|
||||||
@@ -14,7 +13,7 @@ export function useCheckForUpdates() {
|
|||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const hasUpdate: boolean = await minPromiseMillis(invokeCmd('cmd_check_for_updates'), 500);
|
const hasUpdate: boolean = await minPromiseMillis(invokeCmd('cmd_check_for_updates'), 500);
|
||||||
if (!hasUpdate) {
|
if (!hasUpdate) {
|
||||||
alert({
|
showAlert({
|
||||||
id: 'no-updates',
|
id: 'no-updates',
|
||||||
title: 'No Update Available',
|
title: 'No Update Available',
|
||||||
body: (
|
body: (
|
||||||
|
|||||||
@@ -1,25 +1,19 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import type { Folder, Workspace } from '@yaakapp-internal/models';
|
import type { Folder, Workspace } from '@yaakapp-internal/models';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||||
import { createFastMutation } from './useFastMutation';
|
import { createFastMutation } from './useFastMutation';
|
||||||
import { usePrompt } from './usePrompt';
|
import { usePrompt } from './usePrompt';
|
||||||
|
|
||||||
function makeCommands({
|
function makeCommands({ prompt }: { prompt: ReturnType<typeof usePrompt> }) {
|
||||||
navigate,
|
|
||||||
prompt,
|
|
||||||
}: {
|
|
||||||
navigate: ReturnType<typeof useNavigate>;
|
|
||||||
prompt: ReturnType<typeof usePrompt>;
|
|
||||||
}) {
|
|
||||||
return {
|
return {
|
||||||
createWorkspace: createFastMutation<Workspace, void, Partial<Workspace>>({
|
createWorkspace: createFastMutation<Workspace, void, Partial<Workspace>>({
|
||||||
mutationKey: ['create_workspace'],
|
mutationKey: ['create_workspace'],
|
||||||
mutationFn: (patch) => invokeCmd<Workspace>('cmd_update_workspace', { workspace: patch }),
|
mutationFn: (patch) => invokeCmd<Workspace>('cmd_update_workspace', { workspace: patch }),
|
||||||
onSuccess: async (workspace) => {
|
onSuccess: async (workspace) => {
|
||||||
await navigate({
|
await router.navigate({
|
||||||
to: '/workspaces/$workspaceId',
|
to: '/workspaces/$workspaceId',
|
||||||
params: { workspaceId: workspace.id },
|
params: { workspaceId: workspace.id },
|
||||||
});
|
});
|
||||||
@@ -62,7 +56,6 @@ function makeCommands({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useCommands() {
|
export function useCommands() {
|
||||||
const navigate = useNavigate();
|
|
||||||
const prompt = usePrompt();
|
const prompt = usePrompt();
|
||||||
return useMemo(() => makeCommands({ navigate, prompt }), [navigate, prompt]);
|
return useMemo(() => makeCommands({ prompt }), [prompt]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import type { DialogProps } from '../components/core/Dialog';
|
import type { DialogProps } from '../components/core/Dialog';
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import type { ConfirmProps } from './Confirm';
|
import type { ConfirmProps } from './Confirm';
|
||||||
import { Confirm } from './Confirm';
|
import { Confirm } from './Confirm';
|
||||||
import { useDialog } from './useDialog';
|
|
||||||
|
|
||||||
export function useConfirm() {
|
export function useConfirm() {
|
||||||
const dialog = useDialog();
|
|
||||||
return useCallback(
|
return useCallback(
|
||||||
({
|
({
|
||||||
id,
|
id,
|
||||||
@@ -21,7 +20,7 @@ export function useConfirm() {
|
|||||||
confirmText?: ConfirmProps['confirmText'];
|
confirmText?: ConfirmProps['confirmText'];
|
||||||
}) =>
|
}) =>
|
||||||
new Promise((onResult: ConfirmProps['onResult']) => {
|
new Promise((onResult: ConfirmProps['onResult']) => {
|
||||||
dialog.show({
|
showDialog({
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
@@ -30,6 +29,6 @@ export function useConfirm() {
|
|||||||
render: ({ hide }) => Confirm({ onHide: hide, variant, onResult, confirmText }),
|
render: ({ hide }) => Confirm({ onHide: hide, variant, onResult, confirmText }),
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
[dialog],
|
[],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useCallback } from 'react';
|
import { useMemo } from 'react';
|
||||||
import type { DropdownItem } from '../components/core/Dropdown';
|
import type { DropdownItem } from '../components/core/Dropdown';
|
||||||
import { Icon } from '../components/core/Icon';
|
import { Icon } from '../components/core/Icon';
|
||||||
import { generateId } from '../lib/generateId';
|
import { generateId } from '../lib/generateId';
|
||||||
import { BODY_TYPE_GRAPHQL } from '../lib/model_util';
|
import { BODY_TYPE_GRAPHQL } from '../lib/model_util';
|
||||||
import { getActiveRequest } from './useActiveRequest';
|
import { getActiveRequest } from './useActiveRequest';
|
||||||
import {useCommands} from "./useCommands";
|
import { useCommands } from './useCommands';
|
||||||
import { useCreateGrpcRequest } from './useCreateGrpcRequest';
|
import { useCreateGrpcRequest } from './useCreateGrpcRequest';
|
||||||
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
import { useCreateHttpRequest } from './useCreateHttpRequest';
|
||||||
|
|
||||||
@@ -16,12 +16,12 @@ export function useCreateDropdownItems({
|
|||||||
hideFolder?: boolean;
|
hideFolder?: boolean;
|
||||||
hideIcons?: boolean;
|
hideIcons?: boolean;
|
||||||
folderId?: string | null | 'active-folder';
|
folderId?: string | null | 'active-folder';
|
||||||
} = {}): () => DropdownItem[] {
|
} = {}): DropdownItem[] {
|
||||||
const { mutate: createHttpRequest } = useCreateHttpRequest();
|
const { mutate: createHttpRequest } = useCreateHttpRequest();
|
||||||
const { mutate: createGrpcRequest } = useCreateGrpcRequest();
|
const { mutate: createGrpcRequest } = useCreateGrpcRequest();
|
||||||
const { createFolder } = useCommands();
|
const { createFolder } = useCommands();
|
||||||
|
|
||||||
return useCallback((): DropdownItem[] => {
|
return useMemo((): DropdownItem[] => {
|
||||||
const folderId =
|
const folderId =
|
||||||
folderIdOption === 'active-folder' ? getActiveRequest()?.folderId : folderIdOption;
|
folderIdOption === 'active-folder' ? getActiveRequest()?.folderId : folderIdOption;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
@@ -6,10 +5,9 @@ import { invokeCmd } from '../lib/tauri';
|
|||||||
import { getActiveRequest } from './useActiveRequest';
|
import { getActiveRequest } from './useActiveRequest';
|
||||||
import { activeWorkspaceAtom } from './useActiveWorkspace';
|
import { activeWorkspaceAtom } from './useActiveWorkspace';
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
|
import { router } from '../lib/router';
|
||||||
|
|
||||||
export function useCreateGrpcRequest() {
|
export function useCreateGrpcRequest() {
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
return useFastMutation<
|
return useFastMutation<
|
||||||
GrpcRequest,
|
GrpcRequest,
|
||||||
unknown,
|
unknown,
|
||||||
@@ -40,13 +38,10 @@ export function useCreateGrpcRequest() {
|
|||||||
},
|
},
|
||||||
onSettled: () => trackEvent('grpc_request', 'create'),
|
onSettled: () => trackEvent('grpc_request', 'create'),
|
||||||
onSuccess: async (request) => {
|
onSuccess: async (request) => {
|
||||||
await navigate({
|
await router.navigate({
|
||||||
to: '/workspaces/$workspaceId/requests/$requestId',
|
to: '/workspaces/$workspaceId',
|
||||||
params: {
|
params: { workspaceId: request.workspaceId },
|
||||||
workspaceId: request.workspaceId,
|
search: (prev) => ({ ...prev, request_id: request.id }),
|
||||||
requestId: request.id,
|
|
||||||
},
|
|
||||||
search: (prev) => ({ ...prev }),
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveRequest } from './useActiveRequest';
|
import { getActiveRequest } from './useActiveRequest';
|
||||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
|
|
||||||
export function useCreateHttpRequest() {
|
export function useCreateHttpRequest() {
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
return useFastMutation<HttpRequest, unknown, Partial<HttpRequest>>({
|
return useFastMutation<HttpRequest, unknown, Partial<HttpRequest>>({
|
||||||
mutationKey: ['create_http_request'],
|
mutationKey: ['create_http_request'],
|
||||||
mutationFn: async (patch = {}) => {
|
mutationFn: async (patch = {}) => {
|
||||||
@@ -34,10 +32,10 @@ export function useCreateHttpRequest() {
|
|||||||
},
|
},
|
||||||
onSettled: () => trackEvent('http_request', 'create'),
|
onSettled: () => trackEvent('http_request', 'create'),
|
||||||
onSuccess: async (request) => {
|
onSuccess: async (request) => {
|
||||||
await navigate({
|
await router.navigate({
|
||||||
to: '/workspaces/$workspaceId/requests/$requestId',
|
to: '/workspaces/$workspaceId',
|
||||||
params: { workspaceId: request.workspaceId, requestId: request.id },
|
params: { workspaceId: request.workspaceId },
|
||||||
search: (prev) => ({ ...prev }),
|
search: (prev) => ({ ...prev, request_id: request.id }),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { CreateWorkspaceDialog } from '../components/CreateWorkspaceDialog';
|
import { CreateWorkspaceDialog } from '../components/CreateWorkspaceDialog';
|
||||||
import { useDialog } from './useDialog';
|
import { showDialog } from '../lib/dialog';
|
||||||
|
|
||||||
export function useCreateWorkspace() {
|
export function useCreateWorkspace() {
|
||||||
const dialog = useDialog();
|
|
||||||
|
|
||||||
return useCallback(() => {
|
return useCallback(() => {
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'create-workspace',
|
id: 'create-workspace',
|
||||||
title: 'Create Workspace',
|
title: 'Create Workspace',
|
||||||
size: 'md',
|
size: 'md',
|
||||||
render: ({ hide }) => <CreateWorkspaceDialog hide={hide} />,
|
render: ({ hide }) => <CreateWorkspaceDialog hide={hide} />,
|
||||||
});
|
});
|
||||||
}, [dialog]);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import type { Workspace } from '@yaakapp-internal/models';
|
import type { Workspace } from '@yaakapp-internal/models';
|
||||||
import { InlineCode } from '../components/core/InlineCode';
|
import { InlineCode } from '../components/core/InlineCode';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveWorkspace } from './useActiveWorkspace';
|
import { getActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useConfirm } from './useConfirm';
|
import { useConfirm } from './useConfirm';
|
||||||
@@ -9,7 +9,6 @@ import { useFastMutation } from './useFastMutation';
|
|||||||
|
|
||||||
export function useDeleteActiveWorkspace() {
|
export function useDeleteActiveWorkspace() {
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
return useFastMutation<Workspace | null, string>({
|
return useFastMutation<Workspace | null, string>({
|
||||||
mutationKey: ['delete_workspace'],
|
mutationKey: ['delete_workspace'],
|
||||||
@@ -31,7 +30,7 @@ export function useDeleteActiveWorkspace() {
|
|||||||
onSettled: () => trackEvent('workspace', 'delete'),
|
onSettled: () => trackEvent('workspace', 'delete'),
|
||||||
onSuccess: async (workspace) => {
|
onSuccess: async (workspace) => {
|
||||||
if (workspace === null) return;
|
if (workspace === null) return;
|
||||||
await navigate({ to: '/workspaces' });
|
await router.navigate({ to: '/workspaces' });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useSetAtom } from 'jotai/index';
|
import { useSetAtom } from 'jotai/index';
|
||||||
|
import { showAlert } from '../lib/alert';
|
||||||
import { pluralizeCount } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||||
import { useAlert } from './useAlert';
|
|
||||||
import { useConfirm } from './useConfirm';
|
import { useConfirm } from './useConfirm';
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { useGrpcConnections } from './useGrpcConnections';
|
import { useGrpcConnections } from './useGrpcConnections';
|
||||||
@@ -10,7 +10,6 @@ import { httpResponsesAtom, useHttpResponses } from './useHttpResponses';
|
|||||||
|
|
||||||
export function useDeleteSendHistory() {
|
export function useDeleteSendHistory() {
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
const alert = useAlert();
|
|
||||||
const setHttpResponses = useSetAtom(httpResponsesAtom);
|
const setHttpResponses = useSetAtom(httpResponsesAtom);
|
||||||
const httpResponses = useHttpResponses();
|
const httpResponses = useHttpResponses();
|
||||||
const grpcConnections = useGrpcConnections();
|
const grpcConnections = useGrpcConnections();
|
||||||
@@ -23,7 +22,7 @@ export function useDeleteSendHistory() {
|
|||||||
mutationKey: ['delete_send_history'],
|
mutationKey: ['delete_send_history'],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
if (labels.length === 0) {
|
if (labels.length === 0) {
|
||||||
alert({
|
showAlert({
|
||||||
id: 'no-responses',
|
id: 'no-responses',
|
||||||
title: 'Nothing to Delete',
|
title: 'Nothing to Delete',
|
||||||
body: 'There are no Http Response or Grpc Connections to delete',
|
body: 'There are no Http Response or Grpc Connections to delete',
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import { useContext } from 'react';
|
|
||||||
import { DialogContext } from '../components/DialogContext';
|
|
||||||
|
|
||||||
export function useDialog() {
|
|
||||||
return useContext(DialogContext).actions;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import type { GrpcRequest } from '@yaakapp-internal/models';
|
import type { GrpcRequest } from '@yaakapp-internal/models';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { getGrpcProtoFiles, setGrpcProtoFiles } from './useGrpcProtoFiles';
|
import { getGrpcProtoFiles, setGrpcProtoFiles } from './useGrpcProtoFiles';
|
||||||
@@ -12,7 +12,6 @@ export function useDuplicateGrpcRequest({
|
|||||||
id: string | null;
|
id: string | null;
|
||||||
navigateAfter: boolean;
|
navigateAfter: boolean;
|
||||||
}) {
|
}) {
|
||||||
const navigate = useNavigate();
|
|
||||||
return useFastMutation<GrpcRequest, string>({
|
return useFastMutation<GrpcRequest, string>({
|
||||||
mutationKey: ['duplicate_grpc_request', id],
|
mutationKey: ['duplicate_grpc_request', id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
@@ -28,10 +27,10 @@ export function useDuplicateGrpcRequest({
|
|||||||
await setGrpcProtoFiles(request.id, protoFiles);
|
await setGrpcProtoFiles(request.id, protoFiles);
|
||||||
|
|
||||||
if (navigateAfter) {
|
if (navigateAfter) {
|
||||||
await navigate({
|
await router.navigate({
|
||||||
to: '/workspaces/$workspaceId/requests/$requestId',
|
to: '/workspaces/$workspaceId',
|
||||||
params: { workspaceId: request.workspaceId, requestId: request.id },
|
params: { workspaceId: request.workspaceId },
|
||||||
search: (prev) => ({ ...prev }),
|
search: (prev) => ({ ...prev, request_id: request.id }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import type { HttpRequest } from '@yaakapp-internal/models';
|
import type { HttpRequest } from '@yaakapp-internal/models';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
|
|
||||||
@@ -11,7 +11,6 @@ export function useDuplicateHttpRequest({
|
|||||||
id: string | null;
|
id: string | null;
|
||||||
navigateAfter: boolean;
|
navigateAfter: boolean;
|
||||||
}) {
|
}) {
|
||||||
const navigate = useNavigate();
|
|
||||||
return useFastMutation<HttpRequest, string>({
|
return useFastMutation<HttpRequest, string>({
|
||||||
mutationKey: ['duplicate_http_request', id],
|
mutationKey: ['duplicate_http_request', id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
@@ -21,13 +20,10 @@ export function useDuplicateHttpRequest({
|
|||||||
onSettled: () => trackEvent('http_request', 'duplicate'),
|
onSettled: () => trackEvent('http_request', 'duplicate'),
|
||||||
onSuccess: async (request) => {
|
onSuccess: async (request) => {
|
||||||
if (navigateAfter) {
|
if (navigateAfter) {
|
||||||
await navigate({
|
await router.navigate({
|
||||||
to: '/workspaces/$workspaceId/requests/$requestId',
|
to: '/workspaces/$workspaceId',
|
||||||
params: {
|
params: { workspaceId: request.workspaceId },
|
||||||
workspaceId: request.workspaceId,
|
search: (prev) => ({ ...prev, request_id: request.id }),
|
||||||
requestId: request.id,
|
|
||||||
},
|
|
||||||
search: (prev) => ({ ...prev }),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
import { ExportDataDialog } from '../components/ExportDataDialog';
|
import { ExportDataDialog } from '../components/ExportDataDialog';
|
||||||
|
import { showAlert } from '../lib/alert';
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import { jotaiStore } from '../lib/jotai';
|
import { jotaiStore } from '../lib/jotai';
|
||||||
import { getActiveWorkspace } from './useActiveWorkspace';
|
|
||||||
import { useAlert } from './useAlert';
|
|
||||||
import { useDialog } from './useDialog';
|
|
||||||
import { useFastMutation } from './useFastMutation';
|
|
||||||
import { showToast } from '../lib/toast';
|
import { showToast } from '../lib/toast';
|
||||||
|
import { getActiveWorkspace } from './useActiveWorkspace';
|
||||||
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { workspacesAtom } from './useWorkspaces';
|
import { workspacesAtom } from './useWorkspaces';
|
||||||
|
|
||||||
export function useExportData() {
|
export function useExportData() {
|
||||||
const alert = useAlert();
|
|
||||||
const dialog = useDialog();
|
|
||||||
|
|
||||||
return useFastMutation({
|
return useFastMutation({
|
||||||
mutationKey: ['export_data'],
|
mutationKey: ['export_data'],
|
||||||
onError: (err: string) => {
|
onError: (err: string) => {
|
||||||
alert({ id: 'export-failed', title: 'Export Failed', body: err });
|
showAlert({ id: 'export-failed', title: 'Export Failed', body: err });
|
||||||
},
|
},
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const activeWorkspace = getActiveWorkspace();
|
const activeWorkspace = getActiveWorkspace();
|
||||||
@@ -22,7 +19,7 @@ export function useExportData() {
|
|||||||
|
|
||||||
if (activeWorkspace == null || workspaces.length === 0) return;
|
if (activeWorkspace == null || workspaces.length === 0) return;
|
||||||
|
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'export-data',
|
id: 'export-data',
|
||||||
title: 'Export App Data',
|
title: 'Export App Data',
|
||||||
size: 'md',
|
size: 'md',
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useNavigate } from '@tanstack/react-router';
|
|
||||||
import type {
|
import type {
|
||||||
Environment,
|
Environment,
|
||||||
Folder,
|
Folder,
|
||||||
@@ -10,18 +9,15 @@ import { Button } from '../components/core/Button';
|
|||||||
import { FormattedError } from '../components/core/FormattedError';
|
import { FormattedError } from '../components/core/FormattedError';
|
||||||
import { VStack } from '../components/core/Stacks';
|
import { VStack } from '../components/core/Stacks';
|
||||||
import { ImportDataDialog } from '../components/ImportDataDialog';
|
import { ImportDataDialog } from '../components/ImportDataDialog';
|
||||||
|
import { showAlert } from '../lib/alert';
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import { pluralizeCount } from '../lib/pluralize';
|
import { pluralizeCount } from '../lib/pluralize';
|
||||||
|
import { router } from '../lib/router';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveWorkspace } from './useActiveWorkspace';
|
import { getActiveWorkspace } from './useActiveWorkspace';
|
||||||
import { useAlert } from './useAlert';
|
|
||||||
import { useDialog } from './useDialog';
|
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
|
|
||||||
export function useImportData() {
|
export function useImportData() {
|
||||||
const dialog = useDialog();
|
|
||||||
const alert = useAlert();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
const importData = async (filePath: string): Promise<boolean> => {
|
const importData = async (filePath: string): Promise<boolean> => {
|
||||||
const activeWorkspace = getActiveWorkspace();
|
const activeWorkspace = getActiveWorkspace();
|
||||||
const imported: {
|
const imported: {
|
||||||
@@ -37,7 +33,7 @@ export function useImportData() {
|
|||||||
|
|
||||||
const importedWorkspace = imported.workspaces[0];
|
const importedWorkspace = imported.workspaces[0];
|
||||||
|
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'import-complete',
|
id: 'import-complete',
|
||||||
title: 'Import Complete',
|
title: 'Import Complete',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
@@ -65,7 +61,7 @@ export function useImportData() {
|
|||||||
|
|
||||||
if (importedWorkspace != null) {
|
if (importedWorkspace != null) {
|
||||||
const environmentId = imported.environments[0]?.id ?? null;
|
const environmentId = imported.environments[0]?.id ?? null;
|
||||||
await navigate({
|
await router.navigate({
|
||||||
to: '/workspaces/$workspaceId',
|
to: '/workspaces/$workspaceId',
|
||||||
params: { workspaceId: importedWorkspace.id },
|
params: { workspaceId: importedWorkspace.id },
|
||||||
search: { environment_id: environmentId },
|
search: { environment_id: environmentId },
|
||||||
@@ -78,7 +74,7 @@ export function useImportData() {
|
|||||||
return useFastMutation({
|
return useFastMutation({
|
||||||
mutationKey: ['import_data'],
|
mutationKey: ['import_data'],
|
||||||
onError: (err: string) => {
|
onError: (err: string) => {
|
||||||
alert({
|
showAlert({
|
||||||
id: 'import-failed',
|
id: 'import-failed',
|
||||||
title: 'Import Failed',
|
title: 'Import Failed',
|
||||||
size: 'md',
|
size: 'md',
|
||||||
@@ -87,7 +83,7 @@ export function useImportData() {
|
|||||||
},
|
},
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
dialog.show({
|
showDialog({
|
||||||
id: 'import',
|
id: 'import',
|
||||||
title: 'Import Data',
|
title: 'Import Data',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog';
|
import { MoveToWorkspaceDialog } from '../components/MoveToWorkspaceDialog';
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
import { getActiveWorkspaceId } from './useActiveWorkspace';
|
||||||
import { useDialog } from './useDialog';
|
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { useRequests } from './useRequests';
|
import { getRequests } from './useRequests';
|
||||||
|
|
||||||
export function useMoveToWorkspace(id: string) {
|
export function useMoveToWorkspace(id: string) {
|
||||||
const dialog = useDialog();
|
|
||||||
const requests = useRequests();
|
|
||||||
const request = requests.find((r) => r.id === id);
|
|
||||||
|
|
||||||
return useFastMutation<void, unknown>({
|
return useFastMutation<void, unknown>({
|
||||||
mutationKey: ['move_workspace', id],
|
mutationKey: ['move_workspace', id],
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const activeWorkspaceId = getActiveWorkspaceId();
|
const activeWorkspaceId = getActiveWorkspaceId();
|
||||||
if (request == null || activeWorkspaceId == null) return;
|
if (activeWorkspaceId == null) return;
|
||||||
|
|
||||||
dialog.show({
|
const request = getRequests().find((r) => r.id === id);
|
||||||
|
if (request == null) return;
|
||||||
|
|
||||||
|
showDialog({
|
||||||
id: 'change-workspace',
|
id: 'change-workspace',
|
||||||
title: 'Move Workspace',
|
title: 'Move Workspace',
|
||||||
size: 'sm',
|
size: 'sm',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useNavigate, useRouter } from '@tanstack/react-router';
|
import { router } from '../lib/router';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
import { getRecentCookieJars } from './useRecentCookieJars';
|
import { getRecentCookieJars } from './useRecentCookieJars';
|
||||||
@@ -6,9 +6,6 @@ import { getRecentEnvironments } from './useRecentEnvironments';
|
|||||||
import { getRecentRequests } from './useRecentRequests';
|
import { getRecentRequests } from './useRecentRequests';
|
||||||
|
|
||||||
export function useOpenWorkspace() {
|
export function useOpenWorkspace() {
|
||||||
const router = useRouter();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
return useFastMutation({
|
return useFastMutation({
|
||||||
mutationKey: ['open_workspace'],
|
mutationKey: ['open_workspace'],
|
||||||
mutationFn: async ({
|
mutationFn: async ({
|
||||||
@@ -21,7 +18,11 @@ export function useOpenWorkspace() {
|
|||||||
const environmentId = (await getRecentEnvironments(workspaceId))[0] ?? undefined;
|
const environmentId = (await getRecentEnvironments(workspaceId))[0] ?? undefined;
|
||||||
const requestId = (await getRecentRequests(workspaceId))[0] ?? undefined;
|
const requestId = (await getRecentRequests(workspaceId))[0] ?? undefined;
|
||||||
const cookieJarId = (await getRecentCookieJars(workspaceId))[0] ?? undefined;
|
const cookieJarId = (await getRecentCookieJars(workspaceId))[0] ?? undefined;
|
||||||
const search = { environment_id: environmentId, cookie_jar_id: cookieJarId };
|
const search = {
|
||||||
|
environment_id: environmentId,
|
||||||
|
cookie_jar_id: cookieJarId,
|
||||||
|
request_id: requestId,
|
||||||
|
};
|
||||||
|
|
||||||
if (inNewWindow) {
|
if (inNewWindow) {
|
||||||
const location = router.buildLocation({
|
const location = router.buildLocation({
|
||||||
@@ -33,15 +34,11 @@ export function useOpenWorkspace() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestId != null) {
|
await router.navigate({
|
||||||
await navigate({
|
to: '/workspaces/$workspaceId',
|
||||||
to: '/workspaces/$workspaceId/requests/$requestId',
|
params: { workspaceId },
|
||||||
params: { workspaceId, requestId },
|
search,
|
||||||
search,
|
});
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await navigate({ to: '/workspaces/$workspaceId', params: { workspaceId }, search });
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import type { DialogProps } from '../components/core/Dialog';
|
import type { DialogProps } from '../components/core/Dialog';
|
||||||
|
import { showDialog } from '../lib/dialog';
|
||||||
import type { PromptProps } from './Prompt';
|
import type { PromptProps } from './Prompt';
|
||||||
import { Prompt } from './Prompt';
|
import { Prompt } from './Prompt';
|
||||||
import {useDialog} from "./useDialog";
|
|
||||||
|
|
||||||
type Props = Pick<DialogProps, 'title' | 'description'> &
|
type Props = Pick<DialogProps, 'title' | 'description'> &
|
||||||
Omit<PromptProps, 'onClose' | 'onCancel' | 'onResult'> & { id: string };
|
Omit<PromptProps, 'onClose' | 'onCancel' | 'onResult'> & { id: string };
|
||||||
|
|
||||||
export function usePrompt() {
|
export function usePrompt() {
|
||||||
const dialog = useDialog();
|
|
||||||
return ({ id, title, description, ...props }: Props) =>
|
return ({ id, title, description, ...props }: Props) =>
|
||||||
new Promise((resolve: PromptProps['onResult']) => {
|
new Promise((resolve: PromptProps['onResult']) => {
|
||||||
dialog.show({
|
showDialog({
|
||||||
id,
|
id,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import { useMemo } from 'react';
|
import { atom, useAtomValue } from 'jotai';
|
||||||
import { useGrpcRequests } from './useGrpcRequests';
|
import {jotaiStore} from "../lib/jotai";
|
||||||
import { useHttpRequests } from './useHttpRequests';
|
import { grpcRequestsAtom } from './useGrpcRequests';
|
||||||
|
import { httpRequestsAtom } from './useHttpRequests';
|
||||||
|
|
||||||
|
const requestsAtom = atom((get) => [...get(httpRequestsAtom), ...get(grpcRequestsAtom)]);
|
||||||
|
|
||||||
export function useRequests() {
|
export function useRequests() {
|
||||||
const httpRequests = useHttpRequests();
|
return useAtomValue(requestsAtom);
|
||||||
const grpcRequests = useGrpcRequests();
|
}
|
||||||
return useMemo(() => [...httpRequests, ...grpcRequests], [httpRequests, grpcRequests]);
|
|
||||||
|
export function getRequests() {
|
||||||
|
return jotaiStore.get(requestsAtom);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
import type { HttpResponse } from '@yaakapp-internal/models';
|
import type { HttpResponse } from '@yaakapp-internal/models';
|
||||||
|
import { showAlert } from '../lib/alert';
|
||||||
import { trackEvent } from '../lib/analytics';
|
import { trackEvent } from '../lib/analytics';
|
||||||
import { getHttpRequest } from '../lib/store';
|
import { getHttpRequest } from '../lib/store';
|
||||||
import { invokeCmd } from '../lib/tauri';
|
import { invokeCmd } from '../lib/tauri';
|
||||||
import { getActiveCookieJar } from './useActiveCookieJar';
|
import { getActiveCookieJar } from './useActiveCookieJar';
|
||||||
import { getActiveEnvironment } from './useActiveEnvironment';
|
import { getActiveEnvironment } from './useActiveEnvironment';
|
||||||
import { useAlert } from './useAlert';
|
|
||||||
import { useFastMutation } from './useFastMutation';
|
import { useFastMutation } from './useFastMutation';
|
||||||
|
|
||||||
export function useSendAnyHttpRequest() {
|
export function useSendAnyHttpRequest() {
|
||||||
const alert = useAlert();
|
|
||||||
return useFastMutation<HttpResponse | null, string, string | null>({
|
return useFastMutation<HttpResponse | null, string, string | null>({
|
||||||
mutationKey: ['send_any_request'],
|
mutationKey: ['send_any_request'],
|
||||||
mutationFn: async (id) => {
|
mutationFn: async (id) => {
|
||||||
@@ -24,6 +23,6 @@ export function useSendAnyHttpRequest() {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
onSettled: () => trackEvent('http_request', 'send'),
|
onSettled: () => trackEvent('http_request', 'send'),
|
||||||
onError: (err) => alert({ id: 'send-failed', title: 'Send Failed', body: err }),
|
onError: (err) => showAlert({ id: 'send-failed', title: 'Send Failed', body: err }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { CommandPaletteDialog } from '../components/CommandPaletteDialog';
|
import { CommandPaletteDialog } from '../components/CommandPaletteDialog';
|
||||||
import { useDialog } from './useDialog';
|
import { toggleDialog } from '../lib/dialog';
|
||||||
|
|
||||||
export function useToggleCommandPalette() {
|
export function useToggleCommandPalette() {
|
||||||
const dialog = useDialog();
|
|
||||||
const togglePalette = useCallback(() => {
|
const togglePalette = useCallback(() => {
|
||||||
dialog.toggle({
|
toggleDialog({
|
||||||
id: 'command_palette',
|
id: 'command_palette',
|
||||||
size: 'dynamic',
|
size: 'dynamic',
|
||||||
hideX: true,
|
hideX: true,
|
||||||
@@ -15,7 +14,7 @@ export function useToggleCommandPalette() {
|
|||||||
noScroll: true,
|
noScroll: true,
|
||||||
render: ({ hide }) => <CommandPaletteDialog onClose={hide} />,
|
render: ({ hide }) => <CommandPaletteDialog onClose={hide} />,
|
||||||
});
|
});
|
||||||
}, [dialog]);
|
}, []);
|
||||||
|
|
||||||
return togglePalette;
|
return togglePalette;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import type { DialogProps } from '../components/core/Dialog';
|
||||||
|
import type { AlertProps } from '../hooks/Alert';
|
||||||
|
import { Alert } from '../hooks/Alert';
|
||||||
|
import { showDialog } from './dialog';
|
||||||
|
|
||||||
|
interface AlertArgs {
|
||||||
|
id: string;
|
||||||
|
title: DialogProps['title'];
|
||||||
|
body: AlertProps['body'];
|
||||||
|
size?: DialogProps['size'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function showAlert({ id, title, body, size = 'sm' }: AlertArgs) {
|
||||||
|
showDialog({
|
||||||
|
id,
|
||||||
|
title,
|
||||||
|
hideX: true,
|
||||||
|
size,
|
||||||
|
render: ({ hide }) => Alert({ onHide: hide, body }),
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { atom } from 'jotai/index';
|
||||||
|
import type { DialogInstance } from '../components/Dialogs';
|
||||||
|
import { trackEvent } from './analytics';
|
||||||
|
import { jotaiStore } from './jotai';
|
||||||
|
|
||||||
|
export const dialogsAtom = atom<DialogInstance[]>([]);
|
||||||
|
|
||||||
|
export function showDialog({ id, ...props }: DialogInstance) {
|
||||||
|
trackEvent('dialog', 'show', { id });
|
||||||
|
jotaiStore.set(dialogsAtom, (a) => [...a.filter((d) => d.id !== id), { id, ...props }]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function toggleDialog({ id, ...props }: DialogInstance) {
|
||||||
|
const dialogs = jotaiStore.get(dialogsAtom);
|
||||||
|
if (dialogs.some((d) => d.id === id)) hideDialog(id);
|
||||||
|
else showDialog({ id, ...props });
|
||||||
|
}
|
||||||
|
|
||||||
|
export function hideDialog(id: string) {
|
||||||
|
jotaiStore.set(dialogsAtom, (a) => a.filter((d) => d.id !== id));
|
||||||
|
}
|
||||||
+10
-3
@@ -1,11 +1,18 @@
|
|||||||
import { atom } from 'jotai/index';
|
import { atom } from 'jotai/index';
|
||||||
import type { PrivateToastEntry, ToastEntry } from '../components/Toasts';
|
import type { ToastInstance } from '../components/Toasts';
|
||||||
import { generateId } from './generateId';
|
import { generateId } from './generateId';
|
||||||
import { jotaiStore } from './jotai';
|
import { jotaiStore } from './jotai';
|
||||||
|
|
||||||
export const toastsAtom = atom<PrivateToastEntry[]>([]);
|
export const toastsAtom = atom<ToastInstance[]>([]);
|
||||||
|
|
||||||
export function showToast({ id, timeout = 5000, ...props }: ToastEntry) {
|
export function showToast({
|
||||||
|
id,
|
||||||
|
timeout = 5000,
|
||||||
|
...props
|
||||||
|
}: Omit<ToastInstance, 'id' | 'timeout'> & {
|
||||||
|
id?: ToastInstance['id'];
|
||||||
|
timeout?: ToastInstance['timeout'];
|
||||||
|
}) {
|
||||||
id = id ?? generateId();
|
id = id ?? generateId();
|
||||||
if (timeout != null) {
|
if (timeout != null) {
|
||||||
setTimeout(() => hideToast(id), timeout);
|
setTimeout(() => hideToast(id), timeout);
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
"@lezer/lr": "^1.3.3",
|
"@lezer/lr": "^1.3.3",
|
||||||
"@react-hook/size": "^2.1.2",
|
"@react-hook/size": "^2.1.2",
|
||||||
"@tailwindcss/container-queries": "^0.1.1",
|
"@tailwindcss/container-queries": "^0.1.1",
|
||||||
"@tanstack/react-query": "^5.62.8",
|
"@tanstack/react-query": "^5.62.16",
|
||||||
"@tanstack/react-router": "^1.91.3",
|
"@tanstack/react-router": "^1.95.1",
|
||||||
"@tanstack/react-virtual": "^3.11.2",
|
"@tanstack/react-virtual": "^3.11.2",
|
||||||
"@tauri-apps/api": "^2.0.1",
|
"@tauri-apps/api": "^2.0.1",
|
||||||
"@tauri-apps/plugin-clipboard-manager": "^2.0.0",
|
"@tauri-apps/plugin-clipboard-manager": "^2.0.0",
|
||||||
|
|||||||
+12
-14
@@ -7,7 +7,7 @@ import React, { Suspense } from 'react';
|
|||||||
import { DndProvider } from 'react-dnd';
|
import { DndProvider } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
import { HelmetProvider } from 'react-helmet-async';
|
import { HelmetProvider } from 'react-helmet-async';
|
||||||
import { DialogProvider, Dialogs } from '../components/Dialogs';
|
import { Dialogs } from '../components/Dialogs';
|
||||||
import { GlobalHooks } from '../components/GlobalHooks';
|
import { GlobalHooks } from '../components/GlobalHooks';
|
||||||
import RouteError from '../components/RouteError';
|
import RouteError from '../components/RouteError';
|
||||||
import { Toasts } from '../components/Toasts';
|
import { Toasts } from '../components/Toasts';
|
||||||
@@ -65,19 +65,17 @@ function RouteComponent() {
|
|||||||
<HelmetProvider>
|
<HelmetProvider>
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<DialogProvider>
|
<GlobalHooks />
|
||||||
<GlobalHooks />
|
<Toasts />
|
||||||
<Toasts />
|
<Dialogs />
|
||||||
<Dialogs />
|
<div
|
||||||
<div
|
className={classNames(
|
||||||
className={classNames(
|
'w-full h-full',
|
||||||
'w-full h-full',
|
osInfo?.osType === 'linux' && 'border border-border-subtle',
|
||||||
osInfo?.osType === 'linux' && 'border border-border-subtle',
|
)}
|
||||||
)}
|
>
|
||||||
>
|
<Outlet />
|
||||||
<Outlet />
|
</div>
|
||||||
</div>
|
|
||||||
</DialogProvider>
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
</HelmetProvider>
|
</HelmetProvider>
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router';
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
import { Workspace } from '../../../components/Workspace';
|
import { Workspace } from '../../../components/Workspace'
|
||||||
|
|
||||||
interface WorkspaceSearchSchema {
|
interface WorkspaceSearchSchema {
|
||||||
cookie_jar_id?: string | null;
|
request_id?: string | null
|
||||||
environment_id?: string | null;
|
environment_id?: string | null
|
||||||
|
cookie_jar_id?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Route = createFileRoute('/workspaces/$workspaceId/')({
|
export const Route = createFileRoute('/workspaces/$workspaceId/')({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
validateSearch: (search: Record<string, unknown>): WorkspaceSearchSchema => ({
|
validateSearch: (search: Record<string, unknown>): WorkspaceSearchSchema => ({
|
||||||
|
request_id: search.request_id as string,
|
||||||
environment_id: search.environment_id as string,
|
environment_id: search.environment_id as string,
|
||||||
cookie_jar_id: search.cookie_jar_id as string,
|
cookie_jar_id: search.cookie_jar_id as string,
|
||||||
}),
|
}),
|
||||||
});
|
})
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
return <Workspace />;
|
return <Workspace />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,25 @@
|
|||||||
import { createFileRoute } from '@tanstack/react-router';
|
import { createFileRoute, Navigate, useParams } from '@tanstack/react-router'
|
||||||
import { Workspace } from '../../../../components/Workspace';
|
|
||||||
|
|
||||||
export const Route = createFileRoute('/workspaces/$workspaceId/requests/$requestId')({
|
// -----------------------------------------------------------------------------------
|
||||||
|
// IMPORTANT: This is a deprecated route. Since the active request is optional, it was
|
||||||
|
// moved from a path param to a query parameter. This route does a redirect to the
|
||||||
|
// parent, while preserving the active request.
|
||||||
|
|
||||||
|
export const Route = createFileRoute(
|
||||||
|
'/workspaces/$workspaceId/requests/$requestId',
|
||||||
|
)({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
});
|
})
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
return <Workspace />;
|
const { workspaceId, requestId } = useParams({
|
||||||
|
from: '/workspaces/$workspaceId/requests/$requestId',
|
||||||
|
})
|
||||||
|
return (
|
||||||
|
<Navigate
|
||||||
|
to="/workspaces/$workspaceId"
|
||||||
|
params={{ workspaceId }}
|
||||||
|
search={(prev) => ({ ...prev, requestId })}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user