From 60caf0bcf4783da692d90bca57463b276fbc6a00 Mon Sep 17 00:00:00 2001 From: John Obelenus Date: Tue, 7 Jan 2025 17:18:52 -0500 Subject: [PATCH] Improved: breaking out this onSuccess call into three pieces, optimistic, WsEvent, fail, linked via requestUlid --- app/web/src/store/components.store.ts | 78 +++++++++++-------- app/web/src/store/realtime/realtime_events.ts | 6 ++ lib/dal/src/schema/variant.rs | 25 ++++++ lib/dal/src/ws_event.rs | 3 +- .../v2/management/generate_template.rs | 12 +++ lib/vue-lib/src/pinia/pinia_api_tools.ts | 4 +- 6 files changed, 91 insertions(+), 37 deletions(-) diff --git a/app/web/src/store/components.store.ts b/app/web/src/store/components.store.ts index 7cf4550a2e..a522f8ca79 100644 --- a/app/web/src/store/components.store.ts +++ b/app/web/src/store/components.store.ts @@ -1179,22 +1179,6 @@ export const useComponentsStore = (forceChangeSetId?: ChangeSetId) => { category, } = templateData; - // TODO: @zack should we move this into a WsEvent?? because the changeset in the closure below will be HEAD (if thats where we started) and navigation will fail - const toastID = toast( - { - component: CreatingTemplate, - props: { - updating: true, - }, - }, - { - timeout: false, - closeOnClick: false, - position: POSITION.TOP_CENTER, - toastClassName: "si-toast-no-defaults", - }, - ); - const req = new ApiRequest<{ schemaVariantId: string; funcId: string; @@ -1208,28 +1192,25 @@ export const useComponentsStore = (forceChangeSetId?: ChangeSetId) => { category, color, }, - onSuccess: (response) => { - toast.update(toastID, { - content: { + optimistic: (requestUlid) => { + toast( + { + id: requestUlid, + component: CreatingTemplate, props: { - updating: false, - templateName: assetName, - schemaVariantId: response.schemaVariantId, - funcId: response.funcId, - router: (s: string) => { - routerStore.push(changeSetId, { - name: "workspace-lab-assets", - query: { s }, - }); - }, + updating: true, }, - component: CreatingTemplate, }, - options: { timeout: false, closeOnClick: true }, - }); + { + timeout: false, + closeOnClick: false, + position: POSITION.TOP_CENTER, + toastClassName: "si-toast-no-defaults", + }, + ); }, - onFail: (_response) => { - toast.dismiss(toastID); + onFail: (_response, requestUlid) => { + toast.dismiss(requestUlid); }, }); @@ -1414,6 +1395,35 @@ export const useComponentsStore = (forceChangeSetId?: ChangeSetId) => { this.refreshingStatus[data.component.id] = false; }, }, + { + eventType: "TemplateGenerated", + callback: (data, metadata) => { + if (metadata.change_set_id !== changeSetId) return; + + const didIFireThisRequest = + realtimeStore.inflightRequests.get(metadata.requestUlid); + if (!didIFireThisRequest) return; + + toast.update(metadata.requestUlid, { + content: { + props: { + updating: false, + templateName: data.assetName, + schemaVariantId: data.schemaVariantId, + funcId: data.funcId, + router: (s: string) => { + routerStore.push(metadata.change_set_id, { + name: "workspace-lab-assets", + query: { s }, + }); + }, + }, + component: CreatingTemplate, + }, + options: { timeout: false, closeOnClick: true }, + }); + }, + }, /* { TODO PUT BACK eventType: "DeprecatedActionRunnerReturn", callback: (update) => { diff --git a/app/web/src/store/realtime/realtime_events.ts b/app/web/src/store/realtime/realtime_events.ts index f178c7019e..fef61ec578 100644 --- a/app/web/src/store/realtime/realtime_events.ts +++ b/app/web/src/store/realtime/realtime_events.ts @@ -288,6 +288,12 @@ export type WsEventPayloadMap = { secretId: SecretId; changeSetId: ChangeSetId; }; + TemplateGenerated: { + schemaVariantId: SchemaVariantId; + schemaId: SchemaId; + assetName: string; + funcId: FuncId; + }; SchemaVariantDeleted: { schemaVariantId: SchemaVariantId; schemaId: SchemaId; diff --git a/lib/dal/src/schema/variant.rs b/lib/dal/src/schema/variant.rs index 2af9a3192a..cf257b4e6d 100644 --- a/lib/dal/src/schema/variant.rs +++ b/lib/dal/src/schema/variant.rs @@ -309,7 +309,32 @@ pub struct SchemaVariantReplacedPayload { change_set_id: ChangeSetId, } +#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct TemplateGeneratedPayload { + schema_id: SchemaId, + schema_variant_id: SchemaVariantId, + func_id: FuncId, + asset_name: String, +} + impl WsEvent { + pub async fn template_generated( + ctx: &DalContext, + schema_id: SchemaId, + schema_variant_id: SchemaVariantId, + func_id: FuncId, + asset_name: String, + ) -> WsEventResult { + let payload = TemplateGeneratedPayload { + schema_id, + schema_variant_id, + func_id, + asset_name, + }; + WsEvent::new(ctx, WsPayload::TemplateGenerated(payload)).await + } + pub async fn schema_variant_created( ctx: &DalContext, schema_id: SchemaId, diff --git a/lib/dal/src/ws_event.rs b/lib/dal/src/ws_event.rs index 7a198b8562..f5998b5881 100644 --- a/lib/dal/src/ws_event.rs +++ b/lib/dal/src/ws_event.rs @@ -36,7 +36,7 @@ use crate::prompt_override::PromptUpdatedPayload; use crate::qualification::QualificationCheckPayload; use crate::schema::variant::{ SchemaVariantClonedPayload, SchemaVariantDeletedPayload, SchemaVariantReplacedPayload, - SchemaVariantSavedPayload, SchemaVariantUpdatedPayload, + SchemaVariantSavedPayload, SchemaVariantUpdatedPayload, TemplateGeneratedPayload, }; use crate::secret::SecretDeletedPayload; use crate::status::StatusUpdate; @@ -133,6 +133,7 @@ pub enum WsPayload { SecretUpdated(SecretUpdatedPayload), SetComponentPosition(ComponentSetPositionPayload), StatusUpdate(StatusUpdate), + TemplateGenerated(TemplateGeneratedPayload), ViewComponentsUpdate(ViewComponentsUpdatePayload), ViewCreated(ViewWsPayload), ViewDeleted(ViewDeletedPayload), diff --git a/lib/sdf-server/src/service/v2/management/generate_template.rs b/lib/sdf-server/src/service/v2/management/generate_template.rs index ba7f28d9ce..419dc0e46c 100644 --- a/lib/sdf-server/src/service/v2/management/generate_template.rs +++ b/lib/sdf-server/src/service/v2/management/generate_template.rs @@ -107,11 +107,23 @@ pub async fn generate_template( .set_managed_schemas(&ctx, Some(managed_schemas)) .await?; + let schema_variant_id = new_variant.id(); WsEvent::schema_variant_created(&ctx, schema_id, new_variant.clone()) .await? .publish_on_commit(&ctx) .await?; + WsEvent::template_generated( + &ctx, + schema_id, + schema_variant_id, + func.id, + request.asset_name.clone(), + ) + .await? + .publish_on_commit(&ctx) + .await?; + track( &posthog_client, &ctx, diff --git a/lib/vue-lib/src/pinia/pinia_api_tools.ts b/lib/vue-lib/src/pinia/pinia_api_tools.ts index 3387818223..31862b179a 100644 --- a/lib/vue-lib/src/pinia/pinia_api_tools.ts +++ b/lib/vue-lib/src/pinia/pinia_api_tools.ts @@ -209,7 +209,7 @@ export type ApiRequestDescription< /** function to call if request is successfull (2xx) - usually contains changes to the store */ onSuccess?(response: Response): Promise | void; /** function to call if request fails (>=400) - not common */ - onFail?(response: any): any | void; + onFail?(response: any, requestUlid: RequestUlid): any | void; /** additional headers to pass with request */ headers?: Record; /** additional axios options */ @@ -477,7 +477,7 @@ export const initPiniaApiToolkitPlugin = (config: { api: AxiosInstance }) => { // call explicit failure handler if one is defined (usually rare) if (typeof onFail === "function") { - const convertedData = onFail(err); + const convertedData = onFail(err, requestUlid); if (convertedData) { err.response = {