diff --git a/app/web/src/components/AssetCard.vue b/app/web/src/components/AssetCard.vue index 6e8ae230c7..f9380bbd9b 100644 --- a/app/web/src/components/AssetCard.vue +++ b/app/web/src/components/AssetCard.vue @@ -49,6 +49,16 @@ @click="updateAsset" /> + +
+ ( undefined, ); +const hasEditingVersion = computed( + () => + assetStore.unlockedVariantIdForId[asset.value?.schemaVariantId ?? ""] !== + undefined, +); + const asset = computed( (): SchemaVariant | undefined => assetStore.variantFromListById[props.assetId], @@ -174,4 +195,22 @@ const unlock = async () => { } } }; + +const deleteUnlockedVariantReqStatus = assetStore.getRequestStatus( + "DELETE_UNLOCKED_VARIANT", + asset.value?.schemaVariantId, +); +const deleteUnlockedVariant = async () => { + if (asset.value) { + const resp = await assetStore.DELETE_UNLOCKED_VARIANT( + asset.value.schemaVariantId, + ); + if (resp.result.success) { + assetStore.setSchemaVariantSelection(""); + router.replace({ + name: "workspace-lab-assets", + }); + } + } +}; diff --git a/app/web/src/store/asset.store.ts b/app/web/src/store/asset.store.ts index 7750be7a6b..44487f65cd 100644 --- a/app/web/src/store/asset.store.ts +++ b/app/web/src/store/asset.store.ts @@ -488,11 +488,34 @@ export const useAssetStore = () => { const savedAssetIdx = this.variantList.findIndex( (a) => a.schemaVariantId === variant.schemaVariantId, ); + if (savedAssetIdx === -1) this.variantList.push(variant); else this.variantList.splice(savedAssetIdx, 1, variant); }, }); }, + async DELETE_UNLOCKED_VARIANT(id: SchemaVariantId) { + if (changeSetsStore.creatingChangeSet) + throw new Error("race, wait until the change set is created"); + if (changeSetsStore.headSelected) + changeSetsStore.creatingChangeSet = true; + + return new ApiRequest({ + method: "post", + url: `v2/workspaces/${workspaceId}/change-sets/${changeSetId}/schema-variants/${id}/delete_unlocked_variant`, + keyRequestStatusBy: id, + params: { + // ...visibility, + }, + onSuccess: (variant) => { + const deletedVariantIdx = this.variantList.findIndex( + (a) => a.schemaVariantId === variant.schemaVariantId, + ); + if (deletedVariantIdx !== -1) + this.variantList.splice(deletedVariantIdx, 1, variant); + }, + }); + }, }, async onActivated() { await Promise.all([ @@ -531,8 +554,8 @@ export const useAssetStore = () => { }, { eventType: "SchemaVariantDeleted", - callback: (data, metadata) => { - if (metadata.change_set_id !== changeSetId) return; + callback: (data) => { + if (data.changeSetId !== changeSetId) return; const savedAssetIdx = this.variantList.findIndex( (a) => a.schemaVariantId === data.schemaVariantId, ); diff --git a/app/web/src/store/realtime/realtime_events.ts b/app/web/src/store/realtime/realtime_events.ts index 5ff78ab019..24214dcc5e 100644 --- a/app/web/src/store/realtime/realtime_events.ts +++ b/app/web/src/store/realtime/realtime_events.ts @@ -261,6 +261,7 @@ export type WsEventPayloadMap = { SchemaVariantDeleted: { schemaVariantId: SchemaVariantId; schemaId: SchemaId; + changeSetId: ChangeSetId; }; SchemaVariantCreated: SchemaVariant; SchemaVariantUpdated: SchemaVariant; diff --git a/lib/dal/src/schema/variant.rs b/lib/dal/src/schema/variant.rs index ca5b3602bd..58cbc73a6b 100644 --- a/lib/dal/src/schema/variant.rs +++ b/lib/dal/src/schema/variant.rs @@ -303,6 +303,7 @@ pub struct SchemaVariantSavedPayload { pub struct SchemaVariantDeletedPayload { schema_variant_id: SchemaVariantId, schema_id: SchemaId, + change_set_id: ChangeSetId, } impl WsEvent { @@ -333,6 +334,7 @@ impl WsEvent { WsPayload::SchemaVariantDeleted(SchemaVariantDeletedPayload { schema_variant_id, schema_id, + change_set_id: ctx.change_set_id(), }), ) .await @@ -553,12 +555,27 @@ impl SchemaVariant { return Err(SchemaVariantError::SchemaVariantLocked(schema_variant_id)); } + let schema = variant.schema(ctx).await?; + dbg!(&schema); + // Firstly we want to delete the asset func let asset_func = variant.get_asset_func(ctx).await?; Func::delete_by_id(ctx, asset_func.id).await?; - // now we want to delete the schema variant let workspace_snapshot = ctx.workspace_snapshot()?; + + if let Some(default_schema_variant_id) = schema.get_default_schema_variant_id(ctx).await? { + dbg!(&default_schema_variant_id); + if variant.id == default_schema_variant_id { + dbg!("Deletion of the schema"); + dbg!(&schema); + workspace_snapshot + .remove_node_by_id(ctx.vector_clock_id()?, schema.id()) + .await?; + } + } + + // now we want to delete the schema variant workspace_snapshot .remove_node_by_id(ctx.vector_clock_id()?, variant.id) .await?; diff --git a/lib/sdf-server/src/server/service/v2/variant.rs b/lib/sdf-server/src/server/service/v2/variant.rs index d6847416ba..115d549efa 100644 --- a/lib/sdf-server/src/server/service/v2/variant.rs +++ b/lib/sdf-server/src/server/service/v2/variant.rs @@ -4,7 +4,7 @@ use axum::{ routing::{get, post}, Router, }; -use dal::{ChangeSetError, SchemaVariantId}; +use dal::{ChangeSetError, SchemaVariantId, WsEventError}; use telemetry::prelude::*; use thiserror::Error; @@ -19,6 +19,8 @@ mod list_variants; pub enum SchemaVariantsAPIError { #[error("cannot delete locked schema variant: {0}")] CannotDeleteLockedSchemaVariant(SchemaVariantId), + #[error("cannot delete a schema variant that has attached components")] + CannotDeleteVariantWithComponents, #[error("change set error: {0}")] ChangeSet(#[from] ChangeSetError), #[error("hyper error: {0}")] @@ -29,6 +31,8 @@ pub enum SchemaVariantsAPIError { Serde(#[from] serde_json::Error), #[error("transactions error: {0}")] Transactions(#[from] dal::TransactionsError), + #[error("ws event error: {0}")] + WsEvent(#[from] WsEventError), } pub type SchemaVariantsAPIResult = std::result::Result; @@ -57,7 +61,7 @@ pub fn v2_routes() -> Router { .route("/", get(list_variants::list_variants)) .route("/:schema_variant_id", get(get_variant::get_variant)) .route( - "/:schema_variant_id/delete_unlocked_copy", + "/:schema_variant_id/delete_unlocked_variant", post(delete_unlocked_variant::delete_unlocked_variant), ) } diff --git a/lib/sdf-server/src/server/service/v2/variant/delete_unlocked_variant.rs b/lib/sdf-server/src/server/service/v2/variant/delete_unlocked_variant.rs index c4f2b498a1..a1c1e0e7e2 100644 --- a/lib/sdf-server/src/server/service/v2/variant/delete_unlocked_variant.rs +++ b/lib/sdf-server/src/server/service/v2/variant/delete_unlocked_variant.rs @@ -2,14 +2,14 @@ use axum::{ extract::{OriginalUri, Path}, response::IntoResponse, }; -use dal::{ChangeSet, ChangeSetId, SchemaVariant, SchemaVariantId, WorkspacePk}; +use dal::{ChangeSet, ChangeSetId, SchemaVariant, SchemaVariantId, WorkspacePk, WsEvent}; use crate::server::{ extract::{AccessBuilder, HandlerContext, PosthogClient}, tracking::track, }; -use super::SchemaVariantsAPIResult; +use super::{SchemaVariantsAPIError, SchemaVariantsAPIResult}; pub async fn delete_unlocked_variant( HandlerContext(builder): HandlerContext, @@ -27,9 +27,20 @@ pub async fn delete_unlocked_variant( .await?; let force_change_set_id = ChangeSet::force_new(&mut ctx).await?; let schema_variant = SchemaVariant::get_by_id_or_error(&ctx, schema_variant_id).await?; + let schema = schema_variant.schema(&ctx).await?; + + let connected_components = SchemaVariant::list_component_ids(&ctx, schema_variant_id).await?; + if !connected_components.is_empty() { + return Err(SchemaVariantsAPIError::CannotDeleteVariantWithComponents); + } SchemaVariant::cleanup_unlocked_variant(&ctx, schema_variant_id).await?; + WsEvent::schema_variant_deleted(&ctx, schema.id(), schema_variant_id) + .await? + .publish_on_commit(&ctx) + .await?; + track( &posthog_client, &ctx,