From 07662257c11ab875ae13ee72262d1f1a8569ea63 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Fri, 6 Nov 2026 09:57:34 -0700 Subject: [PATCH] Put the restored request in the store before refreshing editors Restore told open editors to re-read the request before its change event had reached the store, so header and parameter rows could keep showing the old content. The restore RPC now returns the restored request, and the frontend puts it in the store before calling wasUpdatedExternally, the same way deleteModel applies its change locally once the RPC resolves. Co-Authored-By: Claude Opus 5.5 --- .../lib/restoreRequestVersion.test.ts | 54 +++++++++++++++++++ apps/yaak-client/lib/restoreRequestVersion.ts | 31 +++++++---- crates-tauri/yaak-app-client/src/rpc_ext.rs | 4 +- .../yaak-rpc-schema/bindings/gen_rpc.ts | 2 +- crates/common/yaak-rpc-schema/src/lib.rs | 2 +- crates/yaak-commands/src/models.rs | 7 +-- crates/yaak-models/src/queries/any_request.rs | 8 ++- crates/yaak-wasm/src/lib.rs | 2 +- 8 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 apps/yaak-client/lib/restoreRequestVersion.test.ts 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()),