diff --git a/apps/yaak-client/lib/restoreRequestVersion.test.ts b/apps/yaak-client/lib/restoreRequestVersion.test.ts new file mode 100644 index 000000000..62973e4a2 --- /dev/null +++ b/apps/yaak-client/lib/restoreRequestVersion.test.ts @@ -0,0 +1,54 @@ +import type { ModelVersion } from "@yaakapp-internal/models"; +import { beforeEach, describe, expect, test, vi } from "vite-plus/test"; + +const mocks = vi.hoisted(() => ({ + calls: [] as string[], + flushAllModelWrites: vi.fn(), + mergeModelsInStore: vi.fn(), + wasUpdatedExternally: vi.fn(), + rpc: vi.fn(), +})); + +vi.mock("@yaakapp-internal/models", () => ({ + flushAllModelWrites: mocks.flushAllModelWrites, + mergeModelsInStore: mocks.mergeModelsInStore, +})); +vi.mock("../hooks/useRequestUpdateKey", () => ({ + wasUpdatedExternally: mocks.wasUpdatedExternally, +})); +vi.mock("./rpc", () => ({ rpc: mocks.rpc })); +vi.mock("./toast", () => ({ showToast: vi.fn() })); + +const restored = { model: "http_request", id: "rq_1", url: "https://example.com/one" }; +const version = { id: "mv_1", modelId: "rq_1" } as ModelVersion; + +describe("applyRequestVersion", () => { + beforeEach(() => { + mocks.calls = []; + mocks.flushAllModelWrites.mockImplementation(async () => mocks.calls.push("flush")); + mocks.rpc.mockImplementation(async (cmd: string) => { + mocks.calls.push(cmd); + return restored; + }); + mocks.mergeModelsInStore.mockImplementation(() => mocks.calls.push("store")); + mocks.wasUpdatedExternally.mockImplementation(() => mocks.calls.push("editors")); + }); + + test("puts the restored request in the store before editors re-read it", async () => { + const { applyRequestVersion } = await import("./restoreRequestVersion"); + await applyRequestVersion(version); + + expect(mocks.calls).toEqual(["flush", "models_restore_request_version", "store", "editors"]); + expect(mocks.mergeModelsInStore).toHaveBeenCalledWith("http_request", [restored]); + expect(mocks.wasUpdatedExternally).toHaveBeenCalledWith("rq_1"); + }); + + test("a failed restore leaves the store and editors alone", async () => { + mocks.rpc.mockRejectedValue(new Error("no such version")); + const { applyRequestVersion } = await import("./restoreRequestVersion"); + + await expect(applyRequestVersion(version)).rejects.toThrow("no such version"); + expect(mocks.mergeModelsInStore).not.toHaveBeenCalled(); + expect(mocks.wasUpdatedExternally).not.toHaveBeenCalled(); + }); +}); diff --git a/apps/yaak-client/lib/restoreRequestVersion.ts b/apps/yaak-client/lib/restoreRequestVersion.ts index 2daff40cb..171f6d502 100644 --- a/apps/yaak-client/lib/restoreRequestVersion.ts +++ b/apps/yaak-client/lib/restoreRequestVersion.ts @@ -1,5 +1,5 @@ -import { flushAllModelWrites } from "@yaakapp-internal/models"; -import type { ModelVersion } from "@yaakapp-internal/models"; +import { flushAllModelWrites, mergeModelsInStore } from "@yaakapp-internal/models"; +import type { AnyModel, ModelVersion } from "@yaakapp-internal/models"; import { wasUpdatedExternally } from "../hooks/useRequestUpdateKey"; import { fireAndForget } from "./fireAndForget"; import { rpc } from "./rpc"; @@ -16,15 +16,7 @@ import { showToast } from "./toast"; export function restoreRequestVersion(version: ModelVersion) { fireAndForget( (async () => { - // The backend restores from the database, so anything still sitting in a - // debounce has to land first — otherwise it would overwrite the restore - await flushAllModelWrites(); - const requestId = await rpc("models_restore_request_version", { - versionId: version.id, - }); - // The write came from this window, so the store's echo suppression would - // otherwise leave open editors showing what was there before - wasUpdatedExternally(requestId); + await applyRequestVersion(version); showToast({ id: "request-version-restored", color: "success", @@ -33,3 +25,20 @@ export function restoreRequestVersion(version: ModelVersion) { })(), ); } + +/** The restore itself, in the order the editors need it. */ +export async function applyRequestVersion(version: ModelVersion): Promise { + // The backend restores from the database, so anything still sitting in a + // debounce has to land first — otherwise it would overwrite the restore + await flushAllModelWrites(); + const restored = await rpc("models_restore_request_version", { + versionId: version.id, + }); + // Editors re-read from the store when told to, and the change event can + // arrive after this resolves, so put the restored request there first. The + // event re-applying it later changes nothing. + mergeModelsInStore(restored.model, [restored]); + // The write came from this window, so the store's echo suppression would + // otherwise leave open editors showing what was there before + wasUpdatedExternally(restored.id); +} diff --git a/crates-tauri/yaak-app-client/src/rpc_ext.rs b/crates-tauri/yaak-app-client/src/rpc_ext.rs index ed8c5ac56..c85b9d366 100644 --- a/crates-tauri/yaak-app-client/src/rpc_ext.rs +++ b/crates-tauri/yaak-app-client/src/rpc_ext.rs @@ -36,7 +36,7 @@ use yaak_grpc::ServiceDefinition; use yaak_grpc::manager::GrpcHandle; use yaak_models::blob_manager::BlobManager; use yaak_models::models::{ - GraphQlIntrospection, GrpcEvent, HttpRequest, HttpRequestHeader, HttpResponse, + AnyModel, GraphQlIntrospection, GrpcEvent, HttpRequest, HttpRequestHeader, HttpResponse, HttpResponseEvent, ImportSource, ModelVersion, Plugin, RequestVersionComparison, Settings, WebsocketConnection, WebsocketEvent, WorkspaceMeta, }; @@ -888,7 +888,7 @@ async fn models_request_version( async fn models_restore_request_version( ctx: ClientCtx, req: ModelsRestoreRequestVersionReq, -) -> Result { +) -> Result { Ok(yaak_commands::models::models_restore_request_version(ctx, req).await?) } diff --git a/crates/common/yaak-rpc-schema/bindings/gen_rpc.ts b/crates/common/yaak-rpc-schema/bindings/gen_rpc.ts index 0c83aa596..59d71d265 100644 --- a/crates/common/yaak-rpc-schema/bindings/gen_rpc.ts +++ b/crates/common/yaak-rpc-schema/bindings/gen_rpc.ts @@ -275,6 +275,6 @@ export type ModelsWebsocketEventsReq = { connectionId: string, }; export type ModelsWorkspaceModelsReq = { workspaceId: string | null, }; -export type RpcSchema = { cmd_metadata: [CmdMetadataReq, AppMetaData], cmd_agent_setup_status: [CmdAgentSetupStatusReq, AgentSetupStatus], cmd_template_tokens_to_string: [CmdTemplateTokensToStringReq, string], cmd_render_template: [CmdRenderTemplateReq, string], cmd_send_feedback: [CmdSendFeedbackReq, null], cmd_dismiss_notification: [CmdDismissNotificationReq, null], cmd_grpc_reflect: [CmdGrpcReflectReq, Array], cmd_grpc_go: [CmdGrpcGoReq, string], cmd_restart: [CmdRestartReq, null], cmd_send_ephemeral_request: [CmdSendEphemeralRequestReq, EphemeralHttpResponse], cmd_format_json: [CmdFormatJsonReq, string], cmd_format_graphql: [CmdFormatGraphqlReq, string], cmd_http_response_body: [CmdHttpResponseBodyReq, FilterResponse], cmd_http_response_body_path: [CmdHttpResponseBodyPathReq, string | null], cmd_http_request_body: [CmdHttpRequestBodyReq, Array | null], cmd_get_sse_events: [CmdGetSseEventsReq, Array], cmd_get_http_response_events: [CmdGetHttpResponseEventsReq, Array], cmd_import_data: [CmdImportDataReq, ImportPlan], cmd_commit_import: [CmdCommitImportReq, BatchUpsertResult], cmd_list_import_sources: [CmdListImportSourcesReq, Array], cmd_import_sources_for_origin: [CmdImportSourcesForOriginReq, Array], cmd_detect_import_source: [CmdDetectImportSourceReq, string], cmd_http_request_actions: [CmdHttpRequestActionsReq, Array], cmd_websocket_request_actions: [CmdWebsocketRequestActionsReq, Array], cmd_call_websocket_request_action: [CmdCallWebsocketRequestActionReq, null], cmd_workspace_actions: [CmdWorkspaceActionsReq, Array], cmd_call_workspace_action: [CmdCallWorkspaceActionReq, null], cmd_folder_actions: [CmdFolderActionsReq, Array], cmd_call_folder_action: [CmdCallFolderActionReq, null], cmd_grpc_request_actions: [CmdGrpcRequestActionsReq, Array], cmd_template_function_summaries: [CmdTemplateFunctionSummariesReq, Array], cmd_template_function_config: [CmdTemplateFunctionConfigReq, GetTemplateFunctionConfigResponse], cmd_get_http_authentication_summaries: [CmdGetHttpAuthenticationSummariesReq, Array], cmd_get_http_authentication_config: [CmdGetHttpAuthenticationConfigReq, GetHttpAuthenticationConfigResponse], cmd_call_http_request_action: [CmdCallHttpRequestActionReq, null], cmd_call_grpc_request_action: [CmdCallGrpcRequestActionReq, null], cmd_call_http_authentication_action: [CmdCallHttpAuthenticationActionReq, null], cmd_curl_to_request: [CmdCurlToRequestReq, HttpRequest], cmd_export_data: [CmdExportDataReq, string], cmd_create_example_workspace: [CmdCreateExampleWorkspaceReq, BatchUpsertResult], cmd_save_base64_to_binary: [CmdSaveBase64ToBinaryReq, null], cmd_save_response: [CmdSaveResponseReq, null], cmd_send_http_request: [CmdSendHttpRequestReq, HttpResponse], cmd_reload_plugins: [CmdReloadPluginsReq, Array<[string, string]>], cmd_plugin_info: [CmdPluginInfoReq, PluginMetadata], cmd_delete_all_grpc_connections: [CmdDeleteAllGrpcConnectionsReq, null], cmd_delete_send_history: [CmdDeleteSendHistoryReq, null], cmd_delete_all_http_responses: [CmdDeleteAllHttpResponsesReq, null], cmd_get_workspace_meta: [CmdGetWorkspaceMetaReq, WorkspaceMeta], cmd_new_child_window: [CmdNewChildWindowReq, null], cmd_new_main_window: [CmdNewMainWindowReq, null], cmd_check_for_updates: [CmdCheckForUpdatesReq, boolean], cmd_decrypt_template: [CmdDecryptTemplateReq, string], cmd_secure_template: [CmdSecureTemplateReq, string], cmd_get_themes: [CmdGetThemesReq, Array], cmd_enable_encryption: [CmdEnableEncryptionReq, null], cmd_reveal_workspace_key: [CmdRevealWorkspaceKeyReq, string], cmd_set_workspace_key: [CmdSetWorkspaceKeyReq, null], cmd_disable_encryption: [CmdDisableEncryptionReq, null], cmd_default_headers: [CmdDefaultHeadersReq, Array], models_upsert: [ModelsUpsertReq, string], models_delete: [ModelsDeleteReq, string], models_duplicate: [ModelsDuplicateReq, string], models_snapshot_request: [ModelsSnapshotRequestReq, ModelVersion], models_request_version: [ModelsRequestVersionReq, RequestVersionComparison], models_restore_request_version: [ModelsRestoreRequestVersionReq, string], models_websocket_events: [ModelsWebsocketEventsReq, Array], models_grpc_events: [ModelsGrpcEventsReq, Array], models_get_settings: [ModelsGetSettingsReq, Settings], models_get_graphql_introspection: [ModelsGetGraphqlIntrospectionReq, GraphQlIntrospection | null], models_upsert_graphql_introspection: [ModelsUpsertGraphqlIntrospectionReq, GraphQlIntrospection], models_workspace_models: [ModelsWorkspaceModelsReq, string], cmd_git_checkout: [CmdGitCheckoutReq, string], cmd_git_branch: [CmdGitBranchReq, null], cmd_git_delete_branch: [CmdGitDeleteBranchReq, BranchDeleteResult], cmd_git_delete_remote_branch: [CmdGitDeleteRemoteBranchReq, null], cmd_git_merge_branch: [CmdGitMergeBranchReq, null], cmd_git_rename_branch: [CmdGitRenameBranchReq, null], cmd_git_status: [CmdGitStatusReq, GitStatusSummary], cmd_git_branch_info: [CmdGitBranchInfoReq, GitBranchInfo], cmd_git_worktree_status: [CmdGitWorktreeStatusReq, GitWorktreeStatus], cmd_git_log: [CmdGitLogReq, Array], cmd_git_log_for_file: [CmdGitLogForFileReq, Array], cmd_git_file_diff_for_commit: [CmdGitFileDiffForCommitReq, GitFileDiff], cmd_git_initialize: [CmdGitInitializeReq, null], cmd_git_clone: [CmdGitCloneReq, CloneResult], cmd_git_commit: [CmdGitCommitReq, null], cmd_git_fetch_all: [CmdGitFetchAllReq, null], cmd_git_push: [CmdGitPushReq, PushResult], cmd_git_pull: [CmdGitPullReq, PullResult], cmd_git_pull_force_reset: [CmdGitPullForceResetReq, PullResult], cmd_git_pull_merge: [CmdGitPullMergeReq, PullResult], cmd_git_add: [CmdGitAddReq, null], cmd_git_unstage: [CmdGitUnstageReq, null], cmd_git_reset_changes: [CmdGitResetChangesReq, null], cmd_git_restore_files: [CmdGitRestoreFilesReq, null], cmd_git_restore_file_from_commit: [CmdGitRestoreFileFromCommitReq, null], cmd_git_add_credential: [CmdGitAddCredentialReq, null], cmd_git_remotes: [CmdGitRemotesReq, Array], cmd_git_add_remote: [CmdGitAddRemoteReq, GitRemote], cmd_git_rm_remote: [CmdGitRmRemoteReq, null], cmd_sync_calculate: [CmdSyncCalculateReq, Array], cmd_sync_calculate_fs: [CmdSyncCalculateFsReq, Array], cmd_sync_apply: [CmdSyncApplyReq, boolean], cmd_ws_delete_connections: [CmdWsDeleteConnectionsReq, null], cmd_ws_send: [CmdWsSendReq, WebsocketConnection], cmd_ws_close: [CmdWsCloseReq, WebsocketConnection], cmd_ws_connect: [CmdWsConnectReq, WebsocketConnection], cmd_plugins_search: [CmdPluginsSearchReq, PluginSearchResponse], cmd_plugins_install: [CmdPluginsInstallReq, null], cmd_plugins_install_from_directory: [CmdPluginsInstallFromDirectoryReq, Plugin], cmd_plugins_uninstall: [CmdPluginsUninstallReq, Plugin], cmd_plugin_init_errors: [CmdPluginInitErrorsReq, Array<[string, string]>], cmd_plugins_updates: [CmdPluginsUpdatesReq, PluginUpdatesResponse], cmd_plugins_update_all: [CmdPluginsUpdateAllReq, Array], cmd_git_watch_worktree_status: [CmdGitWatchWorktreeStatusReq, GitWatchResult], cmd_sync_watch: [CmdSyncWatchReq, WatchResult], }; +export type RpcSchema = { cmd_metadata: [CmdMetadataReq, AppMetaData], cmd_agent_setup_status: [CmdAgentSetupStatusReq, AgentSetupStatus], cmd_template_tokens_to_string: [CmdTemplateTokensToStringReq, string], cmd_render_template: [CmdRenderTemplateReq, string], cmd_send_feedback: [CmdSendFeedbackReq, null], cmd_dismiss_notification: [CmdDismissNotificationReq, null], cmd_grpc_reflect: [CmdGrpcReflectReq, Array], cmd_grpc_go: [CmdGrpcGoReq, string], cmd_restart: [CmdRestartReq, null], cmd_send_ephemeral_request: [CmdSendEphemeralRequestReq, EphemeralHttpResponse], cmd_format_json: [CmdFormatJsonReq, string], cmd_format_graphql: [CmdFormatGraphqlReq, string], cmd_http_response_body: [CmdHttpResponseBodyReq, FilterResponse], cmd_http_response_body_path: [CmdHttpResponseBodyPathReq, string | null], cmd_http_request_body: [CmdHttpRequestBodyReq, Array | null], cmd_get_sse_events: [CmdGetSseEventsReq, Array], cmd_get_http_response_events: [CmdGetHttpResponseEventsReq, Array], cmd_import_data: [CmdImportDataReq, ImportPlan], cmd_commit_import: [CmdCommitImportReq, BatchUpsertResult], cmd_list_import_sources: [CmdListImportSourcesReq, Array], cmd_import_sources_for_origin: [CmdImportSourcesForOriginReq, Array], cmd_detect_import_source: [CmdDetectImportSourceReq, string], cmd_http_request_actions: [CmdHttpRequestActionsReq, Array], cmd_websocket_request_actions: [CmdWebsocketRequestActionsReq, Array], cmd_call_websocket_request_action: [CmdCallWebsocketRequestActionReq, null], cmd_workspace_actions: [CmdWorkspaceActionsReq, Array], cmd_call_workspace_action: [CmdCallWorkspaceActionReq, null], cmd_folder_actions: [CmdFolderActionsReq, Array], cmd_call_folder_action: [CmdCallFolderActionReq, null], cmd_grpc_request_actions: [CmdGrpcRequestActionsReq, Array], cmd_template_function_summaries: [CmdTemplateFunctionSummariesReq, Array], cmd_template_function_config: [CmdTemplateFunctionConfigReq, GetTemplateFunctionConfigResponse], cmd_get_http_authentication_summaries: [CmdGetHttpAuthenticationSummariesReq, Array], cmd_get_http_authentication_config: [CmdGetHttpAuthenticationConfigReq, GetHttpAuthenticationConfigResponse], cmd_call_http_request_action: [CmdCallHttpRequestActionReq, null], cmd_call_grpc_request_action: [CmdCallGrpcRequestActionReq, null], cmd_call_http_authentication_action: [CmdCallHttpAuthenticationActionReq, null], cmd_curl_to_request: [CmdCurlToRequestReq, HttpRequest], cmd_export_data: [CmdExportDataReq, string], cmd_create_example_workspace: [CmdCreateExampleWorkspaceReq, BatchUpsertResult], cmd_save_base64_to_binary: [CmdSaveBase64ToBinaryReq, null], cmd_save_response: [CmdSaveResponseReq, null], cmd_send_http_request: [CmdSendHttpRequestReq, HttpResponse], cmd_reload_plugins: [CmdReloadPluginsReq, Array<[string, string]>], cmd_plugin_info: [CmdPluginInfoReq, PluginMetadata], cmd_delete_all_grpc_connections: [CmdDeleteAllGrpcConnectionsReq, null], cmd_delete_send_history: [CmdDeleteSendHistoryReq, null], cmd_delete_all_http_responses: [CmdDeleteAllHttpResponsesReq, null], cmd_get_workspace_meta: [CmdGetWorkspaceMetaReq, WorkspaceMeta], cmd_new_child_window: [CmdNewChildWindowReq, null], cmd_new_main_window: [CmdNewMainWindowReq, null], cmd_check_for_updates: [CmdCheckForUpdatesReq, boolean], cmd_decrypt_template: [CmdDecryptTemplateReq, string], cmd_secure_template: [CmdSecureTemplateReq, string], cmd_get_themes: [CmdGetThemesReq, Array], cmd_enable_encryption: [CmdEnableEncryptionReq, null], cmd_reveal_workspace_key: [CmdRevealWorkspaceKeyReq, string], cmd_set_workspace_key: [CmdSetWorkspaceKeyReq, null], cmd_disable_encryption: [CmdDisableEncryptionReq, null], cmd_default_headers: [CmdDefaultHeadersReq, Array], models_upsert: [ModelsUpsertReq, string], models_delete: [ModelsDeleteReq, string], models_duplicate: [ModelsDuplicateReq, string], models_snapshot_request: [ModelsSnapshotRequestReq, ModelVersion], models_request_version: [ModelsRequestVersionReq, RequestVersionComparison], models_restore_request_version: [ModelsRestoreRequestVersionReq, AnyModel], models_websocket_events: [ModelsWebsocketEventsReq, Array], models_grpc_events: [ModelsGrpcEventsReq, Array], models_get_settings: [ModelsGetSettingsReq, Settings], models_get_graphql_introspection: [ModelsGetGraphqlIntrospectionReq, GraphQlIntrospection | null], models_upsert_graphql_introspection: [ModelsUpsertGraphqlIntrospectionReq, GraphQlIntrospection], models_workspace_models: [ModelsWorkspaceModelsReq, string], cmd_git_checkout: [CmdGitCheckoutReq, string], cmd_git_branch: [CmdGitBranchReq, null], cmd_git_delete_branch: [CmdGitDeleteBranchReq, BranchDeleteResult], cmd_git_delete_remote_branch: [CmdGitDeleteRemoteBranchReq, null], cmd_git_merge_branch: [CmdGitMergeBranchReq, null], cmd_git_rename_branch: [CmdGitRenameBranchReq, null], cmd_git_status: [CmdGitStatusReq, GitStatusSummary], cmd_git_branch_info: [CmdGitBranchInfoReq, GitBranchInfo], cmd_git_worktree_status: [CmdGitWorktreeStatusReq, GitWorktreeStatus], cmd_git_log: [CmdGitLogReq, Array], cmd_git_log_for_file: [CmdGitLogForFileReq, Array], cmd_git_file_diff_for_commit: [CmdGitFileDiffForCommitReq, GitFileDiff], cmd_git_initialize: [CmdGitInitializeReq, null], cmd_git_clone: [CmdGitCloneReq, CloneResult], cmd_git_commit: [CmdGitCommitReq, null], cmd_git_fetch_all: [CmdGitFetchAllReq, null], cmd_git_push: [CmdGitPushReq, PushResult], cmd_git_pull: [CmdGitPullReq, PullResult], cmd_git_pull_force_reset: [CmdGitPullForceResetReq, PullResult], cmd_git_pull_merge: [CmdGitPullMergeReq, PullResult], cmd_git_add: [CmdGitAddReq, null], cmd_git_unstage: [CmdGitUnstageReq, null], cmd_git_reset_changes: [CmdGitResetChangesReq, null], cmd_git_restore_files: [CmdGitRestoreFilesReq, null], cmd_git_restore_file_from_commit: [CmdGitRestoreFileFromCommitReq, null], cmd_git_add_credential: [CmdGitAddCredentialReq, null], cmd_git_remotes: [CmdGitRemotesReq, Array], cmd_git_add_remote: [CmdGitAddRemoteReq, GitRemote], cmd_git_rm_remote: [CmdGitRmRemoteReq, null], cmd_sync_calculate: [CmdSyncCalculateReq, Array], cmd_sync_calculate_fs: [CmdSyncCalculateFsReq, Array], cmd_sync_apply: [CmdSyncApplyReq, boolean], cmd_ws_delete_connections: [CmdWsDeleteConnectionsReq, null], cmd_ws_send: [CmdWsSendReq, WebsocketConnection], cmd_ws_close: [CmdWsCloseReq, WebsocketConnection], cmd_ws_connect: [CmdWsConnectReq, WebsocketConnection], cmd_plugins_search: [CmdPluginsSearchReq, PluginSearchResponse], cmd_plugins_install: [CmdPluginsInstallReq, null], cmd_plugins_install_from_directory: [CmdPluginsInstallFromDirectoryReq, Plugin], cmd_plugins_uninstall: [CmdPluginsUninstallReq, Plugin], cmd_plugin_init_errors: [CmdPluginInitErrorsReq, Array<[string, string]>], cmd_plugins_updates: [CmdPluginsUpdatesReq, PluginUpdatesResponse], cmd_plugins_update_all: [CmdPluginsUpdateAllReq, Array], cmd_git_watch_worktree_status: [CmdGitWatchWorktreeStatusReq, GitWatchResult], cmd_sync_watch: [CmdSyncWatchReq, WatchResult], }; export type WatchResult = { unlistenEvent: string, }; diff --git a/crates/common/yaak-rpc-schema/src/lib.rs b/crates/common/yaak-rpc-schema/src/lib.rs index 7c1a4c795..aa44d47cd 100644 --- a/crates/common/yaak-rpc-schema/src/lib.rs +++ b/crates/common/yaak-rpc-schema/src/lib.rs @@ -1043,7 +1043,7 @@ macro_rules! with_commands { models_duplicate(ModelsDuplicateReq) -> String, models_snapshot_request(ModelsSnapshotRequestReq) -> ModelVersion, models_request_version(ModelsRequestVersionReq) -> RequestVersionComparison, - models_restore_request_version(ModelsRestoreRequestVersionReq) -> String, + models_restore_request_version(ModelsRestoreRequestVersionReq) -> AnyModel, models_websocket_events(ModelsWebsocketEventsReq) -> Vec, models_grpc_events(ModelsGrpcEventsReq) -> Vec, models_get_settings(ModelsGetSettingsReq) -> Settings, diff --git a/crates/yaak-commands/src/models.rs b/crates/yaak-commands/src/models.rs index 279d1ea94..43710e977 100644 --- a/crates/yaak-commands/src/models.rs +++ b/crates/yaak-commands/src/models.rs @@ -73,15 +73,16 @@ pub async fn models_request_version( Ok(RequestVersionComparison { version, current_document, differs }) } -/// Returns the id of the request that was restored. +/// Returns the restored request, so the frontend can put it in its store +/// without waiting for the change event to come back around. pub async fn models_restore_request_version( host: H, req: ModelsRestoreRequestVersionReq, -) -> Result { +) -> Result { let source = host.update_source(); let restored = host.query_manager().with_tx(|tx| tx.restore_request_version(&req.version_id, &source))?; - Ok(restored.id().to_string()) + Ok(restored.into()) } pub async fn models_websocket_events( diff --git a/crates/yaak-models/src/queries/any_request.rs b/crates/yaak-models/src/queries/any_request.rs index aed33f2d2..c40848cf6 100644 --- a/crates/yaak-models/src/queries/any_request.rs +++ b/crates/yaak-models/src/queries/any_request.rs @@ -1,6 +1,6 @@ use crate::client_db::ClientDb; use crate::error::Result; -use crate::models::{GrpcRequest, HttpRequest, WebsocketRequest}; +use crate::models::{AnyModel, GrpcRequest, HttpRequest, WebsocketRequest}; use serde_json::Value; pub enum AnyRequest { @@ -39,6 +39,12 @@ impl AnyRequest { } } +impl From for AnyModel { + fn from(request: AnyRequest) -> Self { + with_request!(request, |request| request.into()) + } +} + impl<'a> ClientDb<'a> { pub fn get_any_request(&self, id: &str) -> Result { if let Ok(http_request) = self.get_http_request(id) { diff --git a/crates/yaak-wasm/src/lib.rs b/crates/yaak-wasm/src/lib.rs index 5c5d21ebd..abd67eea9 100644 --- a/crates/yaak-wasm/src/lib.rs +++ b/crates/yaak-wasm/src/lib.rs @@ -379,7 +379,7 @@ fn dispatch( .queries .with_tx(|tx| tx.restore_request_version(&req.version_id, source)) .map_err(js_error)?; - to_json(restored.id().to_string()) + to_json(AnyModel::from(restored)) } "models_get_settings" => to_json(host.queries.connect().get_settings()),