diff --git a/plugins/importer-yaak/src/index.js b/plugins/importer-yaak/src/index.js index cafebd78..2fe39739 100644 --- a/plugins/importer-yaak/src/index.js +++ b/plugins/importer-yaak/src/index.js @@ -10,9 +10,21 @@ export function pluginHookImport(contents) { return undefined; } - if (parsed.yaakSchema !== 1) return undefined; + if (!('yaakSchema' in parsed)) { + return; + } - return { resources: parsed.resources }; // Should already be in the correct format + // Migrate v1 to v2 -- changes requests to httpRequests + if (parsed.yaakSchema === 1) { + parsed.resources.httpRequests = parsed.resources.requests; + parsed.yaakSchema = 2; + } + + if (parsed.yaakSchema === 2) { + return { resources: parsed.resources }; // Should already be in the correct format + } + + return undefined; } export function isJSObject(obj) { diff --git a/src-tauri/.sqlx/query-14930955e8a914e292dfbebfce2ea43cc41c1d517386ed816c16d436bf626bf3.json b/src-tauri/.sqlx/query-14930955e8a914e292dfbebfce2ea43cc41c1d517386ed816c16d436bf626bf3.json new file mode 100644 index 00000000..3258060d --- /dev/null +++ b/src-tauri/.sqlx/query-14930955e8a914e292dfbebfce2ea43cc41c1d517386ed816c16d436bf626bf3.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "\n INSERT INTO grpc_events (\n id, workspace_id, request_id, connection_id, content, event_type, metadata,\n status, error\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n content = excluded.content,\n event_type = excluded.event_type,\n metadata = excluded.metadata,\n status = excluded.status,\n error = excluded.error\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 9 + }, + "nullable": [] + }, + "hash": "14930955e8a914e292dfbebfce2ea43cc41c1d517386ed816c16d436bf626bf3" +} diff --git a/src-tauri/.sqlx/query-df70bef8eac244eeedd03f5e42573b4c9dbd19cd764e97817c7de30209d21af9.json b/src-tauri/.sqlx/query-df70bef8eac244eeedd03f5e42573b4c9dbd19cd764e97817c7de30209d21af9.json deleted file mode 100644 index 58dd7b11..00000000 --- a/src-tauri/.sqlx/query-df70bef8eac244eeedd03f5e42573b4c9dbd19cd764e97817c7de30209d21af9.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "\n INSERT INTO grpc_events (\n id, workspace_id, request_id, connection_id, content, event_type, metadata, \n status, error\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT (id) DO UPDATE SET\n updated_at = CURRENT_TIMESTAMP,\n content = excluded.content,\n event_type = excluded.event_type,\n metadata = excluded.metadata,\n status = excluded.status,\n error = excluded.error\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 9 - }, - "nullable": [] - }, - "hash": "df70bef8eac244eeedd03f5e42573b4c9dbd19cd764e97817c7de30209d21af9" -} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 892875ca..6ba58c38 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -42,22 +42,8 @@ use window_ext::TrafficLightWindowExt; use crate::analytics::{AnalyticsAction, AnalyticsResource}; use crate::grpc::metadata_to_map; use crate::http::send_http_request; -use crate::models::{ - cancel_pending_grpc_connections, cancel_pending_responses, create_http_response, - delete_all_grpc_connections, delete_all_http_responses, delete_cookie_jar, delete_environment, - delete_folder, delete_grpc_connection, delete_grpc_request, delete_http_request, - delete_http_response, delete_workspace, duplicate_grpc_request, duplicate_http_request, - get_cookie_jar, get_environment, get_folder, get_grpc_connection, get_grpc_request, - get_http_request, get_http_response, get_key_value_raw, get_or_create_settings, get_workspace, - get_workspace_export_resources, list_cookie_jars, list_environments, list_folders, - list_grpc_connections, list_grpc_events, list_grpc_requests, list_requests, list_responses, - list_workspaces, set_key_value_raw, update_response_if_id, update_settings, upsert_cookie_jar, - upsert_environment, upsert_folder, upsert_grpc_connection, upsert_grpc_event, - upsert_grpc_request, upsert_http_request, upsert_workspace, CookieJar, Environment, - EnvironmentVariable, Folder, GrpcConnection, GrpcEvent, GrpcEventType, GrpcRequest, - HttpRequest, HttpResponse, KeyValue, Settings, Workspace, -}; -use crate::plugin::{ImportResources, ImportResult}; +use crate::models::{cancel_pending_grpc_connections, cancel_pending_responses, create_http_response, delete_all_grpc_connections, delete_all_http_responses, delete_cookie_jar, delete_environment, delete_folder, delete_grpc_connection, delete_grpc_request, delete_http_request, delete_http_response, delete_workspace, duplicate_grpc_request, duplicate_http_request, get_cookie_jar, get_environment, get_folder, get_grpc_connection, get_grpc_request, get_http_request, get_http_response, get_key_value_raw, get_or_create_settings, get_workspace, get_workspace_export_resources, list_cookie_jars, list_environments, list_folders, list_grpc_connections, list_grpc_events, list_grpc_requests, list_requests, list_responses, list_workspaces, set_key_value_raw, update_response_if_id, update_settings, upsert_cookie_jar, upsert_environment, upsert_folder, upsert_grpc_connection, upsert_grpc_event, upsert_grpc_request, upsert_http_request, upsert_workspace, CookieJar, Environment, EnvironmentVariable, Folder, GrpcConnection, GrpcEvent, GrpcEventType, GrpcRequest, HttpRequest, HttpResponse, KeyValue, Settings, Workspace, WorkspaceExportResources}; +use crate::plugin::{ImportResult}; use crate::updates::{update_mode_from_str, UpdateMode, YaakUpdater}; mod analytics; @@ -691,7 +677,7 @@ async fn cmd_filter_response(w: Window, response_id: &str, filter: &str) -> Resu } #[tauri::command] -async fn cmd_import_data(w: Window, file_paths: Vec<&str>) -> Result { +async fn cmd_import_data(w: Window, file_paths: Vec<&str>) -> Result { let mut result: Option = None; let plugins = vec!["importer-yaak", "importer-insomnia", "importer-postman"]; for plugin_name in plugins { @@ -714,7 +700,7 @@ async fn cmd_import_data(w: Window, file_paths: Vec<&str>) -> Result Err("No importers found for the chosen file".to_string()), Some(r) => { - let mut imported_resources = ImportResources::default(); + let mut imported_resources = WorkspaceExportResources::default(); info!("Importing resources"); for v in r.resources.workspaces { @@ -739,11 +725,19 @@ async fn cmd_import_data(w: Window, file_paths: Vec<&str>) -> Result, - id: &str, -) -> Result { +pub async fn get_grpc_event(mgr: &impl Manager, id: &str) -> Result { let db = get_db(mgr).await; sqlx::query_as!( GrpcEvent, @@ -760,8 +757,8 @@ pub async fn get_grpc_event( "#, id, ) - .fetch_one(&db) - .await + .fetch_one(&db) + .await } pub async fn list_grpc_events( @@ -781,8 +778,8 @@ pub async fn list_grpc_events( "#, connection_id, ) - .fetch_all(&db) - .await + .fetch_all(&db) + .await } pub async fn upsert_cookie_jar( @@ -1532,19 +1529,20 @@ pub fn generate_id(prefix: Option<&str>) -> String { #[derive(Default, Debug, Deserialize, Serialize)] #[serde(default, rename_all = "camelCase")] pub struct WorkspaceExport { - yaak_version: String, - yaak_schema: i64, - timestamp: NaiveDateTime, - resources: WorkspaceExportResources, + pub yaak_version: String, + pub yaak_schema: i64, + pub timestamp: NaiveDateTime, + pub resources: WorkspaceExportResources, } #[derive(Default, Debug, Deserialize, Serialize)] #[serde(default, rename_all = "camelCase")] pub struct WorkspaceExportResources { - workspaces: Vec, - environments: Vec, - folders: Vec, - requests: Vec, + pub workspaces: Vec, + pub environments: Vec, + pub folders: Vec, + pub http_requests: Vec, + pub grpc_requests: Vec, } pub async fn get_workspace_export_resources( @@ -1556,7 +1554,7 @@ pub async fn get_workspace_export_resources( .expect("Failed to get workspace"); return WorkspaceExport { yaak_version: app_handle.package_info().version.clone().to_string(), - yaak_schema: 1, + yaak_schema: 2, timestamp: chrono::Utc::now().naive_utc(), resources: WorkspaceExportResources { workspaces: vec![workspace], @@ -1566,9 +1564,12 @@ pub async fn get_workspace_export_resources( folders: list_folders(app_handle, workspace_id) .await .expect("Failed to get folders"), - requests: list_requests(app_handle, workspace_id) + http_requests: list_requests(app_handle, workspace_id) .await .expect("Failed to get requests"), + grpc_requests: list_grpc_requests(app_handle, workspace_id) + .await + .expect("Failed to get grpc requests"), }, }; } diff --git a/src-tauri/src/plugin.rs b/src-tauri/src/plugin.rs index 28548b1d..302613d2 100644 --- a/src-tauri/src/plugin.rs +++ b/src-tauri/src/plugin.rs @@ -1,18 +1,18 @@ use std::fs; +use boa_engine::{ + Context, js_string, JsNativeError, JsValue, Module, module::SimpleModuleLoader, + property::Attribute, Source, +}; use boa_engine::builtins::promise::PromiseState; use boa_engine::module::ModuleLoader; -use boa_engine::{ - js_string, module::SimpleModuleLoader, property::Attribute, Context, JsNativeError, JsValue, - Module, Source, -}; use boa_runtime::Console; use log::{debug, error}; use serde::{Deserialize, Serialize}; use serde_json::json; use tauri::AppHandle; -use crate::models::{Environment, Folder, HttpRequest, Workspace}; +use crate::models::{Environment, Folder, HttpRequest, Workspace, WorkspaceExportResources}; #[derive(Default, Debug, Deserialize, Serialize)] pub struct FilterResult { @@ -21,15 +21,7 @@ pub struct FilterResult { #[derive(Default, Debug, Deserialize, Serialize)] pub struct ImportResult { - pub resources: ImportResources, -} - -#[derive(Default, Debug, Deserialize, Serialize)] -pub struct ImportResources { - pub workspaces: Vec, - pub environments: Vec, - pub folders: Vec, - pub requests: Vec, + pub resources: WorkspaceExportResources, } pub async fn run_plugin_filter( diff --git a/src-web/components/GrpcConnectionMessagesPane.tsx b/src-web/components/GrpcConnectionMessagesPane.tsx index ef4f554e..b3b13609 100644 --- a/src-web/components/GrpcConnectionMessagesPane.tsx +++ b/src-web/components/GrpcConnectionMessagesPane.tsx @@ -1,6 +1,6 @@ import classNames from 'classnames'; import { format } from 'date-fns'; -import type { CSSProperties, ReactNode } from 'react'; +import type { CSSProperties } from 'react'; import React, { useEffect, useMemo, useState } from 'react'; import { useGrpcConnections } from '../hooks/useGrpcConnections'; import { useGrpcEvents } from '../hooks/useGrpcEvents'; diff --git a/src-web/components/SettingsDropdown.tsx b/src-web/components/SettingsDropdown.tsx index b2c7ec0a..f86fbd17 100644 --- a/src-web/components/SettingsDropdown.tsx +++ b/src-web/components/SettingsDropdown.tsx @@ -65,30 +65,7 @@ export function SettingsDropdown() { key: 'import-data', label: 'Import Data', leftSlot: , - onSelect: () => { - dialog.show({ - id: 'import', - title: 'Import Data', - size: 'sm', - render: ({ hide }) => { - return ( - -

Insomnia or Postman Collection v2/v2.1 formats are supported

- -
- ); - }, - }); - }, + onSelect: () => importData.mutate(), }, { key: 'export-data', diff --git a/src-web/components/Workspace.tsx b/src-web/components/Workspace.tsx index 88069d5e..fb1337b6 100644 --- a/src-web/components/Workspace.tsx +++ b/src-web/components/Workspace.tsx @@ -9,6 +9,7 @@ import type { import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useWindowSize } from 'react-use'; import { useActiveRequest } from '../hooks/useActiveRequest'; +import { useImportData } from '../hooks/useImportData'; import { useIsFullscreen } from '../hooks/useIsFullscreen'; import { useOsInfo } from '../hooks/useOsInfo'; import { useSidebarHidden } from '../hooks/useSidebarHidden'; @@ -36,6 +37,7 @@ export default function Workspace() { const { hide, show, hidden } = useSidebarHidden(); const activeRequest = useActiveRequest(); const windowSize = useWindowSize(); + const importData = useImportData(); const [floating, setFloating] = useState(false); const [isResizing, setIsResizing] = useState(false); const moveState = useRef<{ move: (e: MouseEvent) => void; up: (e: MouseEvent) => void } | null>( @@ -165,7 +167,7 @@ export default function Workspace() { hotkeys={['http_request.create', 'sidebar.toggle', 'settings.show']} bottomSlot={ - + + + ); + }, + }); + + if (importedWorkspace != null) { + routes.navigate('workspace', { + workspaceId: importedWorkspace.id, + environmentId: imported.environments[0]?.id, + }); + } + }; + return useMutation({ onError: (err: string) => { alert({ id: 'import-failed', title: 'Import Failed', body: err }); }, mutationFn: async () => { - const selected = await open(openArgs); - if (selected == null || selected.length === 0) { - return; - } - - const imported: { - workspaces: Workspace[]; - environments: Environment[]; - folders: Folder[]; - requests: HttpRequest[]; - } = await invoke('cmd_import_data', { - filePaths: Array.isArray(selected) ? selected : [selected], - }); - const importedWorkspace = imported.workspaces[0]; - dialog.show({ - id: 'import-complete', - title: 'Import Complete', + id: 'import', + title: 'Import Data', size: 'sm', - hideX: true, render: ({ hide }) => { - const { workspaces, environments, folders, requests } = imported; return ( -
    -
  • {count('Workspace', workspaces.length)}
  • -
  • {count('Environment', environments.length)}
  • -
  • {count('Folder', folders.length)}
  • -
  • {count('Request', requests.length)}
  • -
-
- -
+

Insomnia or Postman Collection v2/v2.1 formats are supported

+
); }, }); - - if (importedWorkspace != null) { - routes.navigate('workspace', { - workspaceId: importedWorkspace.id, - environmentId: imported.environments[0]?.id, - }); - } }, }); }