Skip to content

Commit

Permalink
merge: #4034
Browse files Browse the repository at this point in the history
4034: Clone or New Asset: provide an initial schema name in a modal r=vbustamante a=jobelenus

This is in anticipation of making the schema name immutable after creation.

Co-authored-by: John Obelenus <[email protected]>
Co-authored-by: Victor Bustamante <[email protected]>
  • Loading branch information
3 people authored Jun 24, 2024
2 parents d74aa45 + 0e512ba commit 025c47a
Show file tree
Hide file tree
Showing 18 changed files with 146 additions and 51 deletions.
15 changes: 12 additions & 3 deletions app/web/src/components/AssetDetailsPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@
tone="neutral"
icon="clipboard-copy"
size="md"
@click="cloneAsset"
@click="() => cloneAssetModalRef?.modal?.open()"
/>
</div>
<AssetNameModal
ref="cloneAssetModalRef"
title="Asset Name"
buttonLabel="Clone Asset"
@submit="cloneAsset"
/>

<ErrorMessage
v-for="(warning, index) in assetStore.detachmentWarnings"
Expand Down Expand Up @@ -165,6 +171,7 @@ import { FuncId } from "@/store/func/funcs.store";
import { ComponentType } from "@/api/sdf/dal/diagram";
import ColorPicker from "./ColorPicker.vue";
import AssetFuncAttachModal from "./AssetFuncAttachModal.vue";
import AssetNameModal from "./AssetNameModal.vue";
const props = defineProps<{
assetId?: string;
Expand All @@ -176,6 +183,7 @@ const loadAssetReqStatus = assetStore.getRequestStatus(
props.assetId,
);
const executeAssetModalRef = ref();
const cloneAssetModalRef = ref<InstanceType<typeof AssetNameModal>>();
const openAttachModal = (warning: { kind?: FuncKind; funcId?: FuncId }) => {
if (!warning.kind) return;
Expand Down Expand Up @@ -232,10 +240,11 @@ const closeHandler = () => {
assetStore.executeAssetTaskId = undefined;
};
const cloneAsset = async () => {
const cloneAsset = async (name: string) => {
if (editingAsset.value?.id) {
const result = await assetStore.CLONE_ASSET(editingAsset.value.id);
const result = await assetStore.CLONE_ASSET(editingAsset.value.id, name);
if (result.result.success) {
cloneAssetModalRef.value?.modal?.close();
await assetStore.setAssetSelection(result.result.data.id);
}
}
Expand Down
21 changes: 18 additions & 3 deletions app/web/src/components/AssetListPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
tooltip="New Asset"
tooltipPlacement="top"
loadingTooltip="Creating Asset..."
@click="newAsset"
@click="() => newAssetModalRef?.modal?.open()"
/>
<IconButton
v-if="canContribute || true"
Expand All @@ -47,6 +47,12 @@
tooltipPlacement="top"
/>
</div>
<AssetNameModal
ref="newAssetModalRef"
title="New Asset"
buttonLabel="Create Asset"
@submit="(name) => newAsset(name)"
/>
</SidebarSubpanelTitle>
<SiSearch
ref="searchRef"
Expand Down Expand Up @@ -122,6 +128,7 @@ import {
import SiSearch, { Filter } from "@/components/SiSearch.vue";
import { AssetListEntry, useAssetStore } from "@/store/asset.store";
import { getAssetIcon } from "@/store/components.store";
import AssetNameModal from "./AssetNameModal.vue";
import AssetListItem from "./AssetListItem.vue";
import ModuleExportModal from "./modules/ModuleExportModal.vue";
import SidebarSubpanelTitle from "./SidebarSubpanelTitle.vue";
Expand All @@ -133,6 +140,7 @@ const loadAssetsReqStatus = assetStore.getRequestStatus("LOAD_ASSET_LIST");
const createAssetReqStatus = assetStore.getRequestStatus("CREATE_ASSET");
const contributeAssetModalRef = ref<InstanceType<typeof ModuleExportModal>>();
const exportSuccessModalRef = ref<InstanceType<typeof Modal>>();
const newAssetModalRef = ref<InstanceType<typeof AssetNameModal>>();
const contributeLoadingTexts = [
"Engaging Photon Torpedos...",
Expand Down Expand Up @@ -219,10 +227,17 @@ const categoryColor = (category: string) => {
return "#000";
};
const newAsset = async () => {
const result = await assetStore.CREATE_ASSET(assetStore.createNewAsset());
const newAsset = async (newAssetName: string) => {
const result = await assetStore.CREATE_ASSET(
assetStore.createNewAsset(newAssetName),
);
if (result.result.success) {
assetStore.setAssetSelection(result.result.data.id);
newAssetModalRef.value?.modal?.close();
} else if (result.result.statusCode === 409) {
if (newAssetModalRef.value) {
newAssetModalRef.value.setError("That name is already in use");
}
}
};
Expand Down
44 changes: 44 additions & 0 deletions app/web/src/components/AssetNameModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<template>
<Modal ref="modal" size="sm" :title="props.title">
<VormInput
ref="assetNameVorm"
v-model="assetName"
type="text"
label="Asset Name"
required
@enterPressed="submit"
/>
<VButton class="mt-md" @click="submit">{{ props.buttonLabel }}</VButton>
</Modal>
</template>

<script lang="ts" setup>
import { ref } from "vue";
import { Modal, VormInput, VButton } from "@si/vue-lib/design-system";
const props = defineProps<{
title: string;
buttonLabel: string;
}>();
const modal = ref<InstanceType<typeof Modal>>();
const assetName = ref("");
const assetNameVorm = ref<InstanceType<typeof VormInput>>();
const submit = () => {
emit("submit", assetName.value);
};
const setError = (msg: string) => {
if (assetNameVorm.value) {
assetNameVorm.value.validationState.isError = true;
assetNameVorm.value.validationState.errorMessage = msg;
}
};
defineExpose({
modal,
setError,
});
const emit = defineEmits(["submit"]);
</script>
11 changes: 7 additions & 4 deletions app/web/src/store/asset.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export type AssetCreateRequest = Omit<
AssetSaveRequest,
"id" | "definition" | "variantExists"
>;
export type AssetCloneRequest = Visibility & { id: AssetId };
export type AssetCloneRequest = Visibility & { id: AssetId; name: string };

export const assetDisplayName = (asset: Asset | AssetListEntry) =>
(asset.displayName ?? "").length === 0 ? asset.name : asset.displayName;
Expand Down Expand Up @@ -298,11 +298,13 @@ export const useAssetStore = () => {
])}`;
},

createNewAsset(): Asset {
createNewAsset(name?: string): Asset {
name = name || `new asset ${Math.floor(Math.random() * 10000)}`;
return {
id: nilId(),
defaultSchemaVariantId: "",
name: `new asset ${Math.floor(Math.random() * 10000)}`,
name,
displayName: name,
code: "",
color: this.generateMockColor(),
description: "",
Expand Down Expand Up @@ -339,7 +341,7 @@ export const useAssetStore = () => {
});
},

async CLONE_ASSET(assetId: AssetId) {
async CLONE_ASSET(assetId: AssetId, name: string) {
if (changeSetsStore.creatingChangeSet)
throw new Error("race, wait until the change set is created");
if (changeSetsStore.headSelected)
Expand All @@ -355,6 +357,7 @@ export const useAssetStore = () => {
params: {
...visibility,
id: assetId,
name,
},
});
},
Expand Down
4 changes: 4 additions & 0 deletions lib/dal/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,4 +473,8 @@ impl Schema {
let funcs = Func::list_from_ids(ctx, func_ids.as_slice()).await?;
Ok(funcs)
}

pub async fn is_name_taken(ctx: &DalContext, name: &String) -> SchemaResult<bool> {
Ok(Self::list(ctx).await?.iter().any(|s| s.name.eq(name)))
}
}
36 changes: 17 additions & 19 deletions lib/dal/src/schema/variant/authoring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ use crate::pkg::import::import_only_new_funcs;
use crate::pkg::{import_pkg_from_pkg, PkgError};
use crate::schema::variant::{SchemaVariantJson, SchemaVariantMetadataJson};
use crate::{
generate_unique_id, pkg, ComponentType, DalContext, Func, FuncBackendKind,
FuncBackendResponseType, FuncError, FuncId, Schema, SchemaError, SchemaVariant,
SchemaVariantError, SchemaVariantId,
pkg, ComponentType, DalContext, Func, FuncBackendKind, FuncBackendResponseType, FuncError,
FuncId, Schema, SchemaError, SchemaVariant, SchemaVariantError, SchemaVariantId,
};

#[allow(missing_docs)]
Expand Down Expand Up @@ -82,7 +81,7 @@ impl VariantAuthoringClient {
/// Creates a [`SchemaVariant`] and returns the [result](SchemaVariant).
#[instrument(name = "variant.authoring.create_variant", level = "info", skip_all)]
#[allow(clippy::too_many_arguments)]
pub async fn create_variant(
pub async fn create_schema_and_variant(
ctx: &DalContext,
name: impl Into<String>,
display_name: Option<String>,
Expand Down Expand Up @@ -112,7 +111,7 @@ impl VariantAuthoringClient {
let definition = execute_asset_func(ctx, &asset_func).await?;

let metadata = SchemaVariantMetadataJson {
name,
schema_name: name,
menu_name: display_name.clone(),
category: category.into(),
color: color.into(),
Expand Down Expand Up @@ -159,23 +158,22 @@ impl VariantAuthoringClient {
pub async fn clone_variant(
ctx: &DalContext,
schema_variant_id: SchemaVariantId,
name: String,
) -> VariantAuthoringResult<(SchemaVariant, Schema)> {
println!("clone variant");
let variant = SchemaVariant::get_by_id(ctx, schema_variant_id).await?;
let schema = variant.schema(ctx).await?;

let new_name = format!("{} Clone {}", schema.name(), generate_unique_id(4));
let menu_name = variant.display_name().map(|mn| format!("{mn} Clone"));
let display_name = variant.display_name().map(|dn| format!("{dn} Clone"));

if let Some(asset_func_id) = variant.asset_func_id() {
let old_func = Func::get_by_id_or_error(ctx, asset_func_id).await?;

let cloned_func = old_func.duplicate(ctx, new_name.clone()).await?;
let cloned_func = old_func.duplicate(ctx, name.clone()).await?;
let cloned_func_spec = build_asset_func_spec(&cloned_func)?;
let definition = execute_asset_func(ctx, &cloned_func).await?;
let metadata = SchemaVariantMetadataJson {
name: new_name.clone(),
menu_name: menu_name.clone(),
schema_name: name,
menu_name: display_name.clone(),
category: variant.category().to_string(),
color: variant.get_color(ctx).await?,
component_type: variant.component_type(),
Expand Down Expand Up @@ -331,7 +329,7 @@ impl VariantAuthoringClient {
let asset_func_spec = build_asset_func_spec(&asset_func)?;
let definition = execute_asset_func(ctx, &asset_func).await?;
let metadata = SchemaVariantMetadataJson {
name: name.clone(),
schema_name: name.clone(),
menu_name: menu_name.clone(),
category: category.clone(),
color: color.clone(),
Expand All @@ -350,10 +348,10 @@ impl VariantAuthoringClient {
)
.await?;

let schema_spec = metadata.to_spec(new_variant_spec)?;
let schema_spec = metadata.to_schema_spec(new_variant_spec)?;
//TODO @stack72 - figure out how we get the current user in this!
let pkg_spec = PkgSpec::builder()
.name(&metadata.name)
.name(&metadata.schema_name)
.created_by("[email protected]")
.funcs(variant_funcs.clone())
.func(asset_func_spec)
Expand Down Expand Up @@ -475,7 +473,7 @@ impl VariantAuthoringClient {
let definition = execute_asset_func(ctx, &new_asset_func).await?;

let metadata = SchemaVariantMetadataJson {
name: name.clone(),
schema_name: name.clone(),
menu_name: menu_name.clone(),
category: category.into(),
color: color.into(),
Expand All @@ -494,11 +492,11 @@ impl VariantAuthoringClient {
)
.await?;

let schema_spec = metadata.to_spec(new_variant_spec)?;
let schema_spec = metadata.to_schema_spec(new_variant_spec)?;

//TODO @stack72 - figure out how we get the current user in this!
let pkg_spec = PkgSpec::builder()
.name(&metadata.name)
.name(&metadata.schema_name)
.created_by("[email protected]")
.funcs(variant_funcs.clone())
.func(asset_func_spec)
Expand Down Expand Up @@ -746,9 +744,9 @@ fn build_pkg_spec_for_variant(
&identity_func_spec.unique_id,
&asset_func_spec.unique_id,
)?;
let schema_spec = metadata.to_spec(variant_spec)?;
let schema_spec = metadata.to_schema_spec(variant_spec)?;
Ok(PkgSpec::builder()
.name(metadata.clone().name)
.name(metadata.clone().schema_name)
.created_by(user_email)
.func(identity_func_spec)
.func(asset_func_spec.clone())
Expand Down
10 changes: 5 additions & 5 deletions lib/dal/src/schema/variant/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{ComponentType, PropKind, SchemaVariantError, SocketArity};
pub struct SchemaVariantMetadataJson {
/// Name for this variant. Actually, this is the name for this [`Schema`](crate::Schema), we're
/// punting on the issue of multiple variants for the moment.
pub name: String,
pub schema_name: String,
/// Override for the UI name for this schema
#[serde(alias = "menu_name")]
pub menu_name: Option<String>,
Expand All @@ -31,11 +31,11 @@ pub struct SchemaVariantMetadataJson {
}

impl SchemaVariantMetadataJson {
pub fn to_spec(&self, variant: SchemaVariantSpec) -> SchemaVariantResult<SchemaSpec> {
pub fn to_schema_spec(&self, variant: SchemaVariantSpec) -> SchemaVariantResult<SchemaSpec> {
let mut builder = SchemaSpec::builder();
builder.name(&self.name);
builder.name(&self.schema_name);
let mut data_builder = SchemaSpecData::builder();
data_builder.name(&self.name);
data_builder.name(&self.schema_name);
data_builder.category(&self.category);
if let Some(menu_name) = &self.menu_name {
data_builder.category_name(menu_name.as_str());
Expand Down Expand Up @@ -168,7 +168,7 @@ impl SchemaVariantJson {
});

let metadata = SchemaVariantMetadataJson {
name: schema_spec.name,
schema_name: schema_spec.name,
menu_name: schema_data.category_name,
category: schema_data.category,
color: variant_spec_data
Expand Down
2 changes: 1 addition & 1 deletion lib/dal/tests/integration_test/component/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ async fn upgrade_component(ctx: &mut DalContext) {
let link = None;
let category = "Integration Tests".to_string();
let color = "#00b0b0".to_string();
let variant_zero = VariantAuthoringClient::create_variant(
let variant_zero = VariantAuthoringClient::create_schema_and_variant(
ctx,
asset_name.clone(),
display_name.clone(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ async fn create_qualification_and_code_gen_with_existing_component(ctx: &mut Dal
let link = None;
let category = "Integration Tests".to_string();
let color = "#00b0b0".to_string();
let variant_zero = VariantAuthoringClient::create_variant(
let variant_zero = VariantAuthoringClient::create_schema_and_variant(
ctx,
asset_name.clone(),
display_name.clone(),
Expand Down
2 changes: 1 addition & 1 deletion lib/dal/tests/integration_test/pkg/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ async fn import_pkg_from_pkg_set_latest_default(ctx: &mut DalContext) {
let link = None;
let category = "Integration Tests".to_string();
let color = "#00b0b0".to_string();
let variant = VariantAuthoringClient::create_variant(
let variant = VariantAuthoringClient::create_schema_and_variant(
ctx,
asset_name.clone(),
display_name.clone(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ async fn clone_variant(ctx: &mut DalContext) {
let (new_schema_variant, _) = VariantAuthoringClient::clone_variant(
ctx,
default_schema_variant.expect("unable to get the schema variant id from the option"),
existing_schema.name().to_string(),
)
.await
.expect("unable to clone the schema variant");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async fn create_variant(ctx: &mut DalContext) {
let link = None;
let category = "Integration Tests".to_string();
let color = "#00b0b0".to_string();
let variant = VariantAuthoringClient::create_variant(
let variant = VariantAuthoringClient::create_schema_and_variant(
ctx,
asset_name.clone(),
display_name.clone(),
Expand Down
Loading

0 comments on commit 025c47a

Please sign in to comment.