mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-02-19 22:27:51 +01:00
Compare commits
8 Commits
v2024.4.0-
...
v2024.4.0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cf45ba97f | ||
|
|
6749fa9348 | ||
|
|
0f739834c8 | ||
|
|
2d69b83765 | ||
|
|
fa1765f356 | ||
|
|
d1a0265ea5 | ||
|
|
bc191fec95 | ||
|
|
43d042ae68 |
154
package-lock.json
generated
154
package-lock.json
generated
@@ -19,10 +19,7 @@
|
||||
"@lezer/lr": "^1.3.3",
|
||||
"@react-hook/resize-observer": "^1.2.6",
|
||||
"@tailwindcss/container-queries": "^0.1.0",
|
||||
"@tanstack/query-sync-storage-persister": "^4.27.1",
|
||||
"@tanstack/react-query": "^4.28.0",
|
||||
"@tanstack/react-query-devtools": "^4.28.0",
|
||||
"@tanstack/react-query-persist-client": "^4.28.0",
|
||||
"@tanstack/react-query": "^5.35.5",
|
||||
"@tauri-apps/api": ">=2.0.0-beta.0",
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.1.0-beta.1",
|
||||
"@tauri-apps/plugin-dialog": ">=2.0.0-beta.0",
|
||||
@@ -56,6 +53,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
|
||||
"@tanstack/react-query-devtools": "^5.35.5",
|
||||
"@tauri-apps/cli": ">=2.0.0-beta.0",
|
||||
"@types/node": "^18.7.10",
|
||||
"@types/papaparse": "^5.3.7",
|
||||
@@ -2245,112 +2243,55 @@
|
||||
"postcss": "^8.2.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/match-sorter-utils": {
|
||||
"version": "8.15.1",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/match-sorter-utils/-/match-sorter-utils-8.15.1.tgz",
|
||||
"integrity": "sha512-PnVV3d2poenUM31ZbZi/yXkBu3J7kd5k2u51CGwwNojag451AjTH9N6n41yjXz2fpLeewleyLBmNS6+HcGDlXw==",
|
||||
"dependencies": {
|
||||
"remove-accents": "0.5.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-core": {
|
||||
"version": "4.36.1",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.36.1.tgz",
|
||||
"integrity": "sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-persist-client-core": {
|
||||
"version": "4.36.1",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-4.36.1.tgz",
|
||||
"integrity": "sha512-eocgCeI7D7TRv1IUUBMfVwOI0wdSmMkBIbkKhqEdTrnUHUQEeOaYac8oeZk2cumAWJdycu6P/wB+WqGynTnzXg==",
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "4.36.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/query-sync-storage-persister": {
|
||||
"version": "4.36.1",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-sync-storage-persister/-/query-sync-storage-persister-4.36.1.tgz",
|
||||
"integrity": "sha512-yMEt5hWe2+1eclf1agMtXHnPIkxEida0lYWkfdhR8U6KXk/lO4Vca6piJmhKI85t0NHlx3l/z6zX+t/Fn5O9NA==",
|
||||
"dependencies": {
|
||||
"@tanstack/query-persist-client-core": "4.36.1"
|
||||
},
|
||||
"node_modules/@tanstack/query-devtools": {
|
||||
"version": "5.32.1",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.32.1.tgz",
|
||||
"integrity": "sha512-7Xq57Ctopiy/4atpb0uNY5VRuCqRS/1fi/WBCKKX6jHMa6cCgDuV/AQuiwRXcKARbq2OkVAOrW2v4xK9nTbcCA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query": {
|
||||
"version": "4.36.1",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.36.1.tgz",
|
||||
"integrity": "sha512-y7ySVHFyyQblPl3J3eQBWpXZkliroki3ARnBKsdJchlgt7yJLRDUcf4B8soufgiYt3pEQIkBWBx1N9/ZPIeUWw==",
|
||||
"version": "5.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.35.5.tgz",
|
||||
"integrity": "sha512-sppX7L+PVn5GBV3In6zzj0zcKfnZRKhXbX1MfIfKo1OjIq2GMaopvAFOP0x1bRYTUk2ikrdYcQYOozX7PWkb8A==",
|
||||
"dependencies": {
|
||||
"@tanstack/query-core": "4.36.1",
|
||||
"use-sync-external-store": "^1.2.0"
|
||||
"@tanstack/query-core": "5.35.5"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-native": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
},
|
||||
"react-native": {
|
||||
"optional": true
|
||||
}
|
||||
"react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query-devtools": {
|
||||
"version": "4.36.1",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-4.36.1.tgz",
|
||||
"integrity": "sha512-WYku83CKP3OevnYSG8Y/QO9g0rT75v1om5IvcWUwiUZJ4LanYGLVCZ8TdFG5jfsq4Ej/lu2wwDAULEUnRIMBSw==",
|
||||
"version": "5.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.35.5.tgz",
|
||||
"integrity": "sha512-4Xll14B9uhgEJ+uqZZ5tqZ7G1LDR7wGYgb+NOZHGn11TTABnlV8GWon7zDMqdaHeR5mjjuY1UFo9pbz39kuZKQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@tanstack/match-sorter-utils": "^8.7.0",
|
||||
"superjson": "^1.10.0",
|
||||
"use-sync-external-store": "^1.2.0"
|
||||
"@tanstack/query-devtools": "5.32.1"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tanstack/react-query": "^4.36.1",
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
"@tanstack/react-query": "^5.35.5",
|
||||
"react": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@tanstack/react-query-persist-client": {
|
||||
"version": "4.36.1",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-persist-client/-/react-query-persist-client-4.36.1.tgz",
|
||||
"integrity": "sha512-32I5b9aAu4NCiXZ7Te/KEQLfHbYeTNriVPrKYcvEThnZ9tlW01vLcSoxpUIsMYRsembvJUUAkzYBAiZHLOd6pQ==",
|
||||
"dependencies": {
|
||||
"@tanstack/query-persist-client-core": "4.36.1"
|
||||
},
|
||||
"node_modules/@tanstack/react-query/node_modules/@tanstack/query-core": {
|
||||
"version": "5.35.5",
|
||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.35.5.tgz",
|
||||
"integrity": "sha512-OMWvlEqG01RfGj+XZb/piDzPp0eZkkHWSDHt2LvE/fd1zWburP/xwm0ghk6Iv8cuPlP+ACFkZviKXK0OVt6lhg==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/tannerlinsley"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tanstack/react-query": "^4.36.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@tauri-apps/api": {
|
||||
@@ -4248,20 +4189,6 @@
|
||||
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/copy-anything": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
|
||||
"integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
|
||||
"dependencies": {
|
||||
"is-what": "^4.1.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.13"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mesqueeb"
|
||||
}
|
||||
},
|
||||
"node_modules/copy-to-clipboard": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
|
||||
@@ -7068,17 +6995,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-what": {
|
||||
"version": "4.1.16",
|
||||
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
|
||||
"integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
|
||||
"engines": {
|
||||
"node": ">=12.13"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mesqueeb"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
|
||||
@@ -9376,11 +9292,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/remove-accents": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz",
|
||||
"integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A=="
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
@@ -10392,17 +10303,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/superjson": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/superjson/-/superjson-1.13.3.tgz",
|
||||
"integrity": "sha512-mJiVjfd2vokfDxsQPOwJ/PtanO87LhpYY88ubI5dUB1Ab58Txbyje3+jpm+/83R/fevaq/107NNhtYBLuoTrFg==",
|
||||
"dependencies": {
|
||||
"copy-anything": "^3.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
@@ -11047,14 +10947,6 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/use-sync-external-store": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz",
|
||||
"integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
|
||||
@@ -39,10 +39,7 @@
|
||||
"@lezer/lr": "^1.3.3",
|
||||
"@react-hook/resize-observer": "^1.2.6",
|
||||
"@tailwindcss/container-queries": "^0.1.0",
|
||||
"@tanstack/query-sync-storage-persister": "^4.27.1",
|
||||
"@tanstack/react-query": "^4.28.0",
|
||||
"@tanstack/react-query-devtools": "^4.28.0",
|
||||
"@tanstack/react-query-persist-client": "^4.28.0",
|
||||
"@tanstack/react-query": "^5.35.5",
|
||||
"@tauri-apps/api": ">=2.0.0-beta.0",
|
||||
"@tauri-apps/plugin-clipboard-manager": "^2.1.0-beta.1",
|
||||
"@tauri-apps/plugin-dialog": ">=2.0.0-beta.0",
|
||||
@@ -76,6 +73,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
|
||||
"@tanstack/react-query-devtools": "^5.35.5",
|
||||
"@tauri-apps/cli": ">=2.0.0-beta.0",
|
||||
"@types/node": "^18.7.10",
|
||||
"@types/papaparse": "^5.3.7",
|
||||
|
||||
16
plugins/importer-insomnia/package-lock.json
generated
16
plugins/importer-insomnia/package-lock.json
generated
@@ -6,7 +6,21 @@
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "importer-insomnia",
|
||||
"version": "0.0.1"
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"yaml": "^2.4.2"
|
||||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz",
|
||||
"integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"name": "importer-insomnia",
|
||||
"version": "0.0.1"
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"yaml": "^2.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
HttpRequest,
|
||||
Workspace,
|
||||
} from '../../../src-web/lib/models';
|
||||
import { parse as parseYaml } from 'yaml';
|
||||
|
||||
type AtLeast<T, K extends keyof T> = Partial<T> & Pick<T, K>;
|
||||
|
||||
@@ -17,12 +18,15 @@ export interface ExportResources {
|
||||
}
|
||||
|
||||
export function pluginHookImport(contents: string) {
|
||||
let parsed;
|
||||
let parsed: any;
|
||||
|
||||
try {
|
||||
parsed = JSON.parse(contents);
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
try {
|
||||
parsed = parseYaml(contents);
|
||||
} catch (e) {}
|
||||
|
||||
if (!isJSObject(parsed)) return;
|
||||
if (!Array.isArray(parsed.resources)) return;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"os:allow-os-type",
|
||||
"event:allow-emit",
|
||||
"clipboard-manager:allow-write-text",
|
||||
"clipboard-manager:allow-read-text",
|
||||
"dialog:allow-open",
|
||||
"dialog:allow-save",
|
||||
"event:allow-listen",
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"main":{"identifier":"main","description":"Main permissions","local":true,"windows":["*"],"permissions":["os:allow-os-type","event:allow-emit","clipboard-manager:allow-write-text","dialog:allow-open","dialog:allow-save","event:allow-listen","event:allow-unlisten","fs:allow-read-file","fs:allow-read-text-file",{"identifier":"fs:scope","allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]},"shell:allow-open",{"identifier":"shell:allow-execute","allow":[{"args":true,"name":"protoc","sidecar":true}]},"window:allow-close","window:allow-is-fullscreen","window:allow-maximize","window:allow-minimize","window:allow-set-decorations","window:allow-set-title","window:allow-start-dragging","window:allow-unmaximize","clipboard-manager:default"]}}
|
||||
{"main":{"identifier":"main","description":"Main permissions","local":true,"windows":["*"],"permissions":["os:allow-os-type","event:allow-emit","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","dialog:allow-open","dialog:allow-save","event:allow-listen","event:allow-unlisten","fs:allow-read-file","fs:allow-read-text-file",{"identifier":"fs:scope","allow":[{"path":"$APPDATA"},{"path":"$APPDATA/**"}]},"shell:allow-open",{"identifier":"shell:allow-execute","allow":[{"args":true,"name":"protoc","sidecar":true}]},"window:allow-close","window:allow-is-fullscreen","window:allow-maximize","window:allow-minimize","window:allow-set-decorations","window:allow-set-title","window:allow-start-dragging","window:allow-unmaximize","clipboard-manager:default"]}}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -91,16 +91,19 @@ struct AppMetaData {
|
||||
version: String,
|
||||
name: String,
|
||||
app_data_dir: String,
|
||||
app_log_dir: String,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn cmd_metadata(app_handle: AppHandle) -> Result<AppMetaData, ()> {
|
||||
let app_data_dir = app_handle.path().app_data_dir().unwrap();
|
||||
let app_log_dir = app_handle.path().app_log_dir().unwrap();
|
||||
return Ok(AppMetaData {
|
||||
is_dev: is_dev(),
|
||||
version: app_handle.package_info().version.to_string(),
|
||||
name: app_handle.package_info().name.to_string(),
|
||||
app_data_dir: app_data_dir.to_string_lossy().to_string(),
|
||||
app_log_dir: app_log_dir.to_string_lossy().to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"frontendDist": "../dist"
|
||||
},
|
||||
"productName": "Yaak",
|
||||
"version": "2024.4.0-beta.1",
|
||||
"version": "2024.4.0-beta.2",
|
||||
"identifier": "app.yaak.desktop",
|
||||
"app": {
|
||||
"withGlobalTauri": false,
|
||||
|
||||
@@ -7,7 +7,6 @@ import { HelmetProvider } from 'react-helmet-async';
|
||||
import { AppRouter } from './AppRouter';
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
logger: undefined,
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
retry: false,
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { Outlet } from 'react-router-dom';
|
||||
import { DialogProvider } from './DialogContext';
|
||||
import { GlobalHooks } from './GlobalHooks';
|
||||
import { ToastProvider } from './ToastContext';
|
||||
|
||||
export function DefaultLayout() {
|
||||
return (
|
||||
<DialogProvider>
|
||||
<Outlet />
|
||||
<GlobalHooks />
|
||||
<ToastProvider>
|
||||
<Outlet />
|
||||
<GlobalHooks />
|
||||
</ToastProvider>
|
||||
</DialogProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ export function GrpcConnectionLayout({ style }: Props) {
|
||||
/>
|
||||
)}
|
||||
secondSlot={({ style }) =>
|
||||
!grpc.go.isLoading && (
|
||||
!grpc.go.isPending && (
|
||||
<div
|
||||
style={style}
|
||||
className={classNames(
|
||||
|
||||
@@ -71,7 +71,7 @@ export function GrpcProtoSelection({ requestId }: Props) {
|
||||
{!serverReflection && services != null && services.length > 0 && (
|
||||
<Banner className="flex flex-col gap-2">
|
||||
<p>
|
||||
Found services
|
||||
Found services{' '}
|
||||
{services?.slice(0, 5).map((s, i) => {
|
||||
return (
|
||||
<span key={i}>
|
||||
@@ -124,7 +124,6 @@ export function GrpcProtoSelection({ requestId }: Props) {
|
||||
className="ml-auto opacity-30 transition-opacity group-hover:opacity-100"
|
||||
onClick={async () => {
|
||||
await protoFilesKv.set(protoFiles.filter((p) => p !== f));
|
||||
grpc.reflect.remove();
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
|
||||
42
src-web/components/ImportDataDialog.tsx
Normal file
42
src-web/components/ImportDataDialog.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { VStack } from './core/Stacks';
|
||||
import { Button } from './core/Button';
|
||||
import React, { useState } from 'react';
|
||||
import { Banner } from './core/Banner';
|
||||
import { Icon } from './core/Icon';
|
||||
|
||||
interface Props {
|
||||
importData: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function ImportDataDialog({ importData }: Props) {
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
return (
|
||||
<VStack space={5} className="pb-4">
|
||||
<VStack space={1}>
|
||||
<ul className="list-disc pl-5">
|
||||
<li>Postman Collection v2+</li>
|
||||
<li>Insomnia v4+</li>
|
||||
<li>Curl commands</li>
|
||||
</ul>
|
||||
<Banner className="mt-3 flex items-center gap-2">
|
||||
<Icon icon="magicWand" />
|
||||
Paste any Curl command into URL bar
|
||||
</Banner>
|
||||
</VStack>
|
||||
<Button
|
||||
color="primary"
|
||||
isLoading={isLoading}
|
||||
onClick={async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await importData();
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isLoading ? 'Importing' : 'Select File'}
|
||||
</Button>
|
||||
</VStack>
|
||||
);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import classNames from 'classnames';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { memo, useCallback, useMemo, useState } from 'react';
|
||||
import React, { memo, useCallback, useMemo, useState } from 'react';
|
||||
import { createGlobalState } from 'react-use';
|
||||
import { useCancelHttpResponse } from '../hooks/useCancelHttpResponse';
|
||||
import { useIsResponseLoading } from '../hooks/useIsResponseLoading';
|
||||
@@ -39,7 +39,8 @@ import { HeadersEditor } from './HeadersEditor';
|
||||
import { UrlBar } from './UrlBar';
|
||||
import { UrlParametersEditor } from './UrlParameterEditor';
|
||||
import { useCurlToRequest } from '../hooks/useCurlToRequest';
|
||||
import { useConfirm } from '../hooks/useConfirm';
|
||||
import { useToast } from './ToastContext';
|
||||
import { Icon } from './core/Icon';
|
||||
|
||||
interface Props {
|
||||
style: CSSProperties;
|
||||
@@ -230,7 +231,7 @@ export const RequestPane = memo(function RequestPane({
|
||||
);
|
||||
|
||||
const importCurl = useCurlToRequest();
|
||||
const confirm = useConfirm();
|
||||
const toast = useToast();
|
||||
|
||||
const isLoading = useIsResponseLoading(activeRequestId ?? null);
|
||||
const { updateKey } = useRequestUpdateKey(activeRequestId ?? null);
|
||||
@@ -250,17 +251,15 @@ export const RequestPane = memo(function RequestPane({
|
||||
if (!command.startsWith('curl ')) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
await confirm({
|
||||
id: 'paste-curl',
|
||||
title: 'Import from Curl?',
|
||||
description:
|
||||
'Do you want to overwrite the current request with the Curl command?',
|
||||
confirmText: 'Overwrite',
|
||||
})
|
||||
) {
|
||||
importCurl.mutate({ requestId: activeRequestId, command });
|
||||
}
|
||||
importCurl.mutate({ requestId: activeRequestId, command });
|
||||
toast.show({
|
||||
render: () => [
|
||||
<>
|
||||
<Icon icon="info" />
|
||||
<span>Curl command imported</span>
|
||||
</>,
|
||||
],
|
||||
});
|
||||
}}
|
||||
onSend={handleSend}
|
||||
onCancel={handleCancel}
|
||||
|
||||
@@ -81,7 +81,7 @@ export const SettingsDialog = () => {
|
||||
size="sm"
|
||||
title="Check for updates"
|
||||
icon="refresh"
|
||||
spin={checkForUpdates.isLoading}
|
||||
spin={checkForUpdates.isPending}
|
||||
onClick={() => checkForUpdates.mutateAsync()}
|
||||
/>
|
||||
</div>
|
||||
@@ -135,6 +135,7 @@ export const SettingsDialog = () => {
|
||||
<KeyValueRows>
|
||||
<KeyValueRow label="Version" value={appInfo.data?.version} />
|
||||
<KeyValueRow label="Data Directory" value={appInfo.data?.appDataDir} />
|
||||
<KeyValueRow label="Logs Directory" value={appInfo.data?.appLogDir} />
|
||||
</KeyValueRows>
|
||||
</VStack>
|
||||
);
|
||||
|
||||
@@ -9,7 +9,6 @@ import { useActiveEnvironmentId } from '../hooks/useActiveEnvironmentId';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
import { useAppRoutes } from '../hooks/useAppRoutes';
|
||||
import { useCopyAsCurl } from '../hooks/useCopyAsCurl';
|
||||
import { useCreateDropdownItems } from '../hooks/useCreateDropdownItems';
|
||||
import { useDeleteFolder } from '../hooks/useDeleteFolder';
|
||||
import { useDeleteRequest } from '../hooks/useDeleteRequest';
|
||||
@@ -41,6 +40,7 @@ import { InlineCode } from './core/InlineCode';
|
||||
import { VStack } from './core/Stacks';
|
||||
import { StatusTag } from './core/StatusTag';
|
||||
import { DropMarker } from './DropMarker';
|
||||
import { useCopyAsCurl } from '../hooks/useCopyAsCurl';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
@@ -608,7 +608,7 @@ const SidebarItem = forwardRef(function SidebarItem(
|
||||
const deleteRequest = useDeleteRequest(activeRequest ?? null);
|
||||
const duplicateHttpRequest = useDuplicateHttpRequest({ id: itemId, navigateAfter: true });
|
||||
const duplicateGrpcRequest = useDuplicateGrpcRequest({ id: itemId, navigateAfter: true });
|
||||
const [isCopied, copyAsCurl] = useCopyAsCurl(itemId);
|
||||
const [copyAsCurl] = useCopyAsCurl(itemId);
|
||||
const sendRequest = useSendRequest(itemId);
|
||||
const sendManyRequests = useSendManyRequests();
|
||||
const latestHttpResponse = useLatestHttpResponse(itemId);
|
||||
@@ -739,12 +739,7 @@ const SidebarItem = forwardRef(function SidebarItem(
|
||||
{
|
||||
key: 'copyCurl',
|
||||
label: 'Copy as Curl',
|
||||
leftSlot: (
|
||||
<Icon
|
||||
className={isCopied ? 'text-green-500' : undefined}
|
||||
icon={isCopied ? 'check' : 'copy'}
|
||||
/>
|
||||
),
|
||||
leftSlot: <Icon icon="copy" />,
|
||||
onSelect: copyAsCurl,
|
||||
},
|
||||
{ type: 'separator' },
|
||||
|
||||
79
src-web/components/ToastContext.tsx
Normal file
79
src-web/components/ToastContext.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import React, { createContext, useContext, useMemo, useRef, useState } from 'react';
|
||||
import type { ToastProps } from './core/Toast';
|
||||
import { Toast } from './core/Toast';
|
||||
import { generateId } from '../lib/generateId';
|
||||
import { Portal } from './Portal';
|
||||
import { AnimatePresence } from 'framer-motion';
|
||||
|
||||
type ToastEntry = {
|
||||
render: ({ hide }: { hide: () => void }) => React.ReactNode;
|
||||
timeout?: number;
|
||||
} & Omit<ToastProps, 'onClose' | 'open' | 'children' | 'timeout'>;
|
||||
|
||||
type PrivateToastEntry = ToastEntry & {
|
||||
id: string;
|
||||
timeout: number;
|
||||
};
|
||||
|
||||
interface State {
|
||||
toasts: PrivateToastEntry[];
|
||||
actions: Actions;
|
||||
}
|
||||
|
||||
interface Actions {
|
||||
show: (d: ToastEntry) => void;
|
||||
hide: (id: string) => void;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const ToastContext = createContext<State>({} as State);
|
||||
|
||||
export const ToastProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const [toasts, setToasts] = useState<State['toasts']>([]);
|
||||
const timeoutRef = useRef<NodeJS.Timeout>();
|
||||
const actions = useMemo<Actions>(
|
||||
() => ({
|
||||
show({ timeout = 4000, ...props }: ToastEntry) {
|
||||
const id = generateId();
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
this.hide(id);
|
||||
}, timeout);
|
||||
setToasts((a) => [...a.filter((d) => d.id !== id), { id, timeout, ...props }]);
|
||||
return id;
|
||||
},
|
||||
hide: (id: string) => {
|
||||
setToasts((a) => a.filter((d) => d.id !== id));
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
const state: State = { toasts, actions };
|
||||
|
||||
return (
|
||||
<ToastContext.Provider value={state}>
|
||||
{children}
|
||||
<Portal name="toasts">
|
||||
<div className="absolute right-0 bottom-0">
|
||||
<AnimatePresence>
|
||||
{toasts.map((props: PrivateToastEntry) => (
|
||||
<ToastInstance key={props.id} {...props} />
|
||||
))}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</Portal>
|
||||
</ToastContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
function ToastInstance({ id, render, timeout, ...props }: PrivateToastEntry) {
|
||||
const { actions } = useContext(ToastContext);
|
||||
const children = render({ hide: () => actions.hide(id) });
|
||||
return (
|
||||
<Toast open timeout={timeout} onClose={() => actions.hide(id)} {...props}>
|
||||
{children}
|
||||
</Toast>
|
||||
);
|
||||
}
|
||||
|
||||
export const useToast = () => useContext(ToastContext).actions;
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
MouseEvent as ReactMouseEvent,
|
||||
ReactNode,
|
||||
} from 'react';
|
||||
import { useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useWindowSize } from 'react-use';
|
||||
import { useActiveRequest } from '../hooks/useActiveRequest';
|
||||
import { useActiveWorkspace } from '../hooks/useActiveWorkspace';
|
||||
@@ -33,6 +33,8 @@ import { ResizeHandle } from './ResizeHandle';
|
||||
import { Sidebar } from './Sidebar';
|
||||
import { SidebarActions } from './SidebarActions';
|
||||
import { WorkspaceHeader } from './WorkspaceHeader';
|
||||
import { useClipboardText } from '../hooks/useClipboardText';
|
||||
import { useToast } from './ToastContext';
|
||||
|
||||
const side = { gridArea: 'side' };
|
||||
const head = { gridArea: 'head' };
|
||||
@@ -54,6 +56,24 @@ export default function Workspace() {
|
||||
const moveState = useRef<{ move: (e: MouseEvent) => void; up: (e: MouseEvent) => void } | null>(
|
||||
null,
|
||||
);
|
||||
const clipboardText = useClipboardText();
|
||||
const toast = useToast();
|
||||
|
||||
useEffect(() => {
|
||||
const isCurlInClipboard = clipboardText?.startsWith('curl ');
|
||||
if (!isCurlInClipboard) {
|
||||
return;
|
||||
}
|
||||
|
||||
toast.show({
|
||||
render: () => (
|
||||
<div>
|
||||
<p>Curl command detected?</p>
|
||||
<Button color="primary">Import</Button>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
}, [clipboardText, toast]);
|
||||
|
||||
const unsub = () => {
|
||||
if (moveState.current !== null) {
|
||||
|
||||
@@ -60,9 +60,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
|
||||
size === 'sm' && 'h-sm px-2.5 text-sm',
|
||||
size === 'xs' && 'h-xs px-2 text-sm',
|
||||
// Solids
|
||||
variant === 'solid' &&
|
||||
color === 'custom' &&
|
||||
'ring-blue-400 enabled:hocus:bg-highlightSecondary',
|
||||
variant === 'solid' && color === 'custom' && 'ring-blue-400',
|
||||
variant === 'solid' &&
|
||||
color === 'default' &&
|
||||
'text-gray-700 enabled:hocus:bg-gray-700/10 enabled:hocus:text-gray-800 ring-blue-400',
|
||||
@@ -118,13 +116,13 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
|
||||
ref={buttonRef}
|
||||
type={type}
|
||||
className={classes}
|
||||
disabled={disabled}
|
||||
disabled={disabled || isLoading}
|
||||
onClick={onClick}
|
||||
title={fullTitle}
|
||||
{...props}
|
||||
>
|
||||
{isLoading ? (
|
||||
<Icon icon="update" size={size} className="animate-spin mr-1" />
|
||||
<Icon icon="refresh" size={size} className="animate-spin mr-1" />
|
||||
) : leftSlot ? (
|
||||
<div className="mr-1">{leftSlot}</div>
|
||||
) : null}
|
||||
|
||||
@@ -329,10 +329,18 @@ function getExtensions({
|
||||
return [
|
||||
// NOTE: These *must* be anonymous functions so the references update properly
|
||||
EditorView.domEventHandlers({
|
||||
focus: () => onFocus.current?.(),
|
||||
blur: () => onBlur.current?.(),
|
||||
keydown: (e) => onKeyDown.current?.(e),
|
||||
paste: (e) => onPaste.current?.(e.clipboardData?.getData('text/plain') ?? ''),
|
||||
focus: () => {
|
||||
onFocus.current?.();
|
||||
},
|
||||
blur: () => {
|
||||
onBlur.current?.();
|
||||
},
|
||||
keydown: (e) => {
|
||||
onKeyDown.current?.(e);
|
||||
},
|
||||
paste: (e) => {
|
||||
onPaste.current?.(e.clipboardData?.getData('text/plain') ?? '');
|
||||
},
|
||||
}),
|
||||
tooltips({ parent }),
|
||||
keymap.of(singleLine ? defaultKeymap.filter((k) => k.key !== 'Enter') : defaultKeymap),
|
||||
|
||||
@@ -17,7 +17,6 @@ const icons = {
|
||||
arrowUpFromDot: lucide.ArrowUpFromDotIcon,
|
||||
box: lucide.BoxIcon,
|
||||
cake: lucide.CakeIcon,
|
||||
minus: lucide.MinusIcon,
|
||||
chat: lucide.MessageSquare,
|
||||
check: lucide.CheckIcon,
|
||||
chevronDown: lucide.ChevronDownIcon,
|
||||
@@ -25,6 +24,7 @@ const icons = {
|
||||
code: lucide.CodeIcon,
|
||||
cookie: lucide.CookieIcon,
|
||||
copy: lucide.CopyIcon,
|
||||
copyCheck: lucide.CopyCheck,
|
||||
download: lucide.DownloadIcon,
|
||||
externalLink: lucide.ExternalLinkIcon,
|
||||
eye: lucide.EyeIcon,
|
||||
@@ -39,6 +39,7 @@ const icons = {
|
||||
leftPanelHidden: lucide.PanelLeftOpenIcon,
|
||||
leftPanelVisible: lucide.PanelLeftCloseIcon,
|
||||
magicWand: lucide.Wand2Icon,
|
||||
minus: lucide.MinusIcon,
|
||||
moreVertical: lucide.MoreVerticalIcon,
|
||||
pencil: lucide.PencilIcon,
|
||||
plug: lucide.Plug,
|
||||
|
||||
76
src-web/components/core/Toast.tsx
Normal file
76
src-web/components/core/Toast.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import classNames from 'classnames';
|
||||
import { motion } from 'framer-motion';
|
||||
import type { ReactNode } from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { useKey } from 'react-use';
|
||||
import { Heading } from './Heading';
|
||||
import { IconButton } from './IconButton';
|
||||
|
||||
export interface ToastProps {
|
||||
children: ReactNode;
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
title?: ReactNode;
|
||||
className?: string;
|
||||
timeout: number;
|
||||
}
|
||||
|
||||
export function Toast({ children, className, open, onClose, title, timeout }: ToastProps) {
|
||||
const titleId = useMemo(() => Math.random().toString(36).slice(2), []);
|
||||
|
||||
useKey(
|
||||
'Escape',
|
||||
() => {
|
||||
if (!open) return;
|
||||
onClose();
|
||||
},
|
||||
{},
|
||||
[open],
|
||||
);
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, right: '-10%' }}
|
||||
animate={{ opacity: 100, right: 0 }}
|
||||
exit={{ opacity: 0, right: '-100%' }}
|
||||
transition={{ duration: 0.2 }}
|
||||
className={classNames(
|
||||
className,
|
||||
'pointer-events-auto',
|
||||
'relative bg-gray-50 dark:bg-gray-100 pointer-events-auto',
|
||||
'rounded-lg',
|
||||
'border border-highlightSecondary dark:border-highlight shadow-xl',
|
||||
'max-w-[calc(100vw-5rem)] max-h-[calc(100vh-6rem)]',
|
||||
'w-[22rem] max-h-[80vh]',
|
||||
'm-2 grid grid-cols-[1fr_auto]',
|
||||
'text-gray-700',
|
||||
)}
|
||||
>
|
||||
<div className="px-3 py-2">
|
||||
{title && (
|
||||
<Heading size={3} id={titleId}>
|
||||
{title}
|
||||
</Heading>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-2">{children}</div>
|
||||
</div>
|
||||
|
||||
<IconButton
|
||||
color="custom"
|
||||
className="opacity-50"
|
||||
title="Dismiss"
|
||||
icon="x"
|
||||
onClick={onClose}
|
||||
/>
|
||||
<div className="w-full absolute bottom-0 left-0 right-0">
|
||||
<motion.div
|
||||
className="bg-highlight h-0.5"
|
||||
initial={{ width: '100%' }}
|
||||
animate={{ width: '0%', opacity: 0.2 }}
|
||||
transition={{ duration: timeout / 1000, ease: 'linear' }}
|
||||
/>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +1,20 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
|
||||
export interface AppInfo {
|
||||
isDev: boolean;
|
||||
version: string;
|
||||
name: string;
|
||||
appDataDir: string;
|
||||
appLogDir: string;
|
||||
}
|
||||
|
||||
export function useAppInfo() {
|
||||
return useQuery(['appInfo'], async () => {
|
||||
return (await invoke('cmd_metadata')) as {
|
||||
isDev: boolean;
|
||||
version: string;
|
||||
name: string;
|
||||
appDataDir: string;
|
||||
};
|
||||
return useQuery({
|
||||
queryKey: ['appInfo'],
|
||||
queryFn: async () => {
|
||||
const metadata = await invoke('cmd_metadata');
|
||||
return metadata as AppInfo;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
9
src-web/hooks/useClipboardText.ts
Normal file
9
src-web/hooks/useClipboardText.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { readText } from '@tauri-apps/plugin-clipboard-manager';
|
||||
|
||||
export function useClipboardText() {
|
||||
return useQuery({
|
||||
queryKey: [],
|
||||
queryFn: () => readText(),
|
||||
}).data;
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { writeText } from '@tauri-apps/plugin-clipboard-manager';
|
||||
import { useState } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { useToast } from '../components/ToastContext';
|
||||
import { Icon } from '../components/core/Icon';
|
||||
|
||||
export function useCopyAsCurl(requestId: string) {
|
||||
const [checked, setChecked] = useState<boolean>(false);
|
||||
const toast = useToast();
|
||||
return [
|
||||
checked,
|
||||
async () => {
|
||||
@@ -11,6 +14,14 @@ export function useCopyAsCurl(requestId: string) {
|
||||
await writeText(cmd);
|
||||
setChecked(true);
|
||||
setTimeout(() => setChecked(false), 800);
|
||||
toast.show({
|
||||
render: () => [
|
||||
<>
|
||||
<Icon icon="copyCheck" />
|
||||
<span>Command copied to clipboard</span>
|
||||
</>,
|
||||
],
|
||||
});
|
||||
return cmd;
|
||||
},
|
||||
] as const;
|
||||
@@ -35,7 +35,9 @@ export function useCreateFolder() {
|
||||
},
|
||||
onSettled: () => trackEvent('folder', 'create'),
|
||||
onSuccess: async (request) => {
|
||||
await queryClient.invalidateQueries(foldersQueryKey({ workspaceId: request.workspaceId }));
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: foldersQueryKey({ workspaceId: request.workspaceId }),
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,8 +36,8 @@ export function useDeleteFolder(id: string | null) {
|
||||
const { workspaceId } = folder;
|
||||
|
||||
// Nesting makes it hard to clean things up, so just clear everything that could have been deleted
|
||||
await queryClient.invalidateQueries(httpRequestsQueryKey({ workspaceId }));
|
||||
await queryClient.invalidateQueries(foldersQueryKey({ workspaceId }));
|
||||
await queryClient.invalidateQueries({ queryKey: httpRequestsQueryKey({ workspaceId }) });
|
||||
await queryClient.invalidateQueries({ queryKey: foldersQueryKey({ workspaceId }) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export function useDeleteWorkspace(workspace: Workspace | null) {
|
||||
|
||||
// Also clean up other things that may have been deleted
|
||||
queryClient.setQueryData(httpRequestsQueryKey({ workspaceId }), []);
|
||||
await queryClient.invalidateQueries(httpRequestsQueryKey({ workspaceId }));
|
||||
await queryClient.invalidateQueries({ queryKey: httpRequestsQueryKey({ workspaceId }) });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export function useGrpc(
|
||||
const debouncedUrl = useDebouncedValue<string>(req?.url ?? 'n/a', 500);
|
||||
const reflect = useQuery<ReflectResponseService[], string>({
|
||||
enabled: req != null,
|
||||
queryKey: ['grpc_reflect', req?.id ?? 'n/a', debouncedUrl],
|
||||
queryKey: ['grpc_reflect', req?.id ?? 'n/a', debouncedUrl, protoFiles],
|
||||
refetchOnWindowFocus: false,
|
||||
queryFn: async () => {
|
||||
return (await minPromiseMillis(
|
||||
|
||||
@@ -9,6 +9,7 @@ import { count } from '../lib/pluralize';
|
||||
import { useActiveWorkspaceId } from './useActiveWorkspaceId';
|
||||
import { useAlert } from './useAlert';
|
||||
import { useAppRoutes } from './useAppRoutes';
|
||||
import { ImportDataDialog } from '../components/ImportDataDialog';
|
||||
|
||||
export function useImportData() {
|
||||
const routes = useAppRoutes();
|
||||
@@ -16,13 +17,13 @@ export function useImportData() {
|
||||
const alert = useAlert();
|
||||
const activeWorkspaceId = useActiveWorkspaceId();
|
||||
|
||||
const importData = async () => {
|
||||
const importData = async (): Promise<boolean> => {
|
||||
const selected = await open({
|
||||
filters: [{ name: 'Export File', extensions: ['json', 'yaml', 'sh', 'txt'] }],
|
||||
multiple: false,
|
||||
});
|
||||
if (selected == null) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
const imported: {
|
||||
@@ -35,6 +36,7 @@ export function useImportData() {
|
||||
filePath: selected.path,
|
||||
workspaceId: activeWorkspaceId,
|
||||
});
|
||||
|
||||
const importedWorkspace = imported.workspaces[0];
|
||||
|
||||
dialog.show({
|
||||
@@ -69,6 +71,8 @@ export function useImportData() {
|
||||
environmentId: imported.environments[0]?.id,
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
return useMutation({
|
||||
@@ -82,32 +86,20 @@ export function useImportData() {
|
||||
title: 'Import Data',
|
||||
size: 'sm',
|
||||
render: ({ hide }) => {
|
||||
return (
|
||||
<VStack space={5} className="pb-4">
|
||||
<VStack space={1}>
|
||||
<p>Supported Formats:</p>
|
||||
<ul className="list-disc pl-5">
|
||||
<li>Postman Collection v2/v2.1</li>
|
||||
<li>Insomnia</li>
|
||||
</ul>
|
||||
</VStack>
|
||||
<Button
|
||||
size="sm"
|
||||
color="primary"
|
||||
onClick={async () => {
|
||||
try {
|
||||
await importData();
|
||||
resolve();
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
}
|
||||
hide();
|
||||
}}
|
||||
>
|
||||
Select File
|
||||
</Button>
|
||||
</VStack>
|
||||
);
|
||||
const importAndHide = async () => {
|
||||
try {
|
||||
const didImport = await importData();
|
||||
if (!didImport) {
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
} catch (err) {
|
||||
reject(err);
|
||||
} finally {
|
||||
hide();
|
||||
}
|
||||
};
|
||||
return <ImportDataDialog importData={importAndHide} />;
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,8 +9,12 @@ export function workspacesQueryKey(_?: {}) {
|
||||
|
||||
export function useWorkspaces() {
|
||||
return (
|
||||
useQuery(workspacesQueryKey(), async () => {
|
||||
return (await invoke('cmd_list_workspaces')) as Workspace[];
|
||||
useQuery({
|
||||
queryKey: workspacesQueryKey(),
|
||||
queryFn: async () => {
|
||||
const workspaces = await invoke('cmd_list_workspaces');
|
||||
return workspaces as Workspace[];
|
||||
},
|
||||
}).data ?? []
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ export type TrackResource =
|
||||
| 'key_value'
|
||||
| 'setting'
|
||||
| 'sidebar'
|
||||
| 'toast'
|
||||
| 'workspace';
|
||||
|
||||
export type TrackAction =
|
||||
|
||||
@@ -4,7 +4,7 @@ import { internalIpV4 } from 'internal-ip';
|
||||
import svgr from 'vite-plugin-svgr';
|
||||
import topLevelAwait from 'vite-plugin-top-level-await';
|
||||
|
||||
const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM);
|
||||
const mobile = !!/android|ios/.exec(process.env.TAURI_ENV_PLATFORM ?? '');
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(async () => ({
|
||||
|
||||
Reference in New Issue
Block a user