Skip to content
This repository was archived by the owner on Feb 6, 2026. It is now read-only.

Commit fb79236

Browse files
merge: #2392
2392: feat(web,dal,sdf-server): ENG-1682 make existing assets editable r=zacharyhamm a=zacharyhamm If an asset has no components on the graph, and is not connected to any attribute functions and validations, there's nothing preventing us from allowing users to update the structure of it through the asset function. This enables that. Also closes ENG-1686 and ENG-1683. NOTE: we're not deleting the props/attribute values/providers/prototypes for orphaned schema variants here. This should be fixed in a follow up. Co-authored-by: Zachary Hamm <zack@systeminit.com>
2 parents db2a7c4 + 5351900 commit fb79236

11 files changed

Lines changed: 363 additions & 132 deletions

File tree

app/web/src/components/AssetDetailsPanel.vue

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@
1313
<VButton
1414
:requestStatus="executeAssetReqStatus"
1515
loadingText="Creating Asset..."
16-
label="Create Asset"
16+
:label="
17+
assetStore.selectedAsset.schemaVariantId
18+
? 'Update Asset'
19+
: 'Create Asset'
20+
"
1721
:disabled="disabled"
1822
tone="action"
1923
icon="bolt"
@@ -30,6 +34,9 @@
3034
</div>
3135

3236
<Stack>
37+
<ErrorMessage v-if="disabled" icon="alert-triangle" tone="warning"
38+
>{{ disabledWarning }}
39+
</ErrorMessage>
3340
<ErrorMessage
3441
v-if="executeAssetReqStatus.isError"
3542
:requestStatus="executeAssetReqStatus"
@@ -134,6 +141,7 @@ import {
134141
import { useAssetStore } from "@/store/asset.store";
135142
import { useFuncStore } from "@/store/func/funcs.store";
136143
import { useChangeSetsStore } from "@/store/change_sets.store";
144+
import { nilId } from "@/utils/nilId";
137145
import ColorPicker from "./ColorPicker.vue";
138146
139147
defineProps<{
@@ -160,23 +168,45 @@ const updateAsset = () => {
160168
};
161169
162170
const disabled = computed(
163-
() => !!(assetStore.selectedAsset?.defaultVariantId ?? false),
171+
() =>
172+
!!(
173+
(assetStore.selectedAsset?.hasComponents ||
174+
assetStore.selectedAsset?.hasAttrFuncs) ??
175+
false
176+
),
164177
);
165178
179+
const disabledWarning = computed(() => {
180+
let byComponents = "";
181+
if (assetStore.selectedAsset?.hasComponents) {
182+
byComponents = "by components";
183+
}
184+
let byFuncs = "";
185+
if (assetStore.selectedAsset?.hasAttrFuncs) {
186+
byFuncs = "by attribute functions or custom validations";
187+
}
188+
const and =
189+
assetStore.selectedAsset?.hasComponents &&
190+
assetStore.selectedAsset?.hasAttrFuncs
191+
? " and "
192+
: "";
193+
194+
return `This asset cannot be edited because it is in use ${byComponents}${and}${byFuncs}.`;
195+
});
196+
166197
const executeAsset = async () => {
167198
if (assetStore.selectedAssetId) {
168199
const result = await assetStore.EXEC_ASSET(assetStore.selectedAssetId);
169200
if (result.result.success) {
170201
executeAssetModalRef.value.open();
171-
for (const ipa of result.result.data.installedPkgAssets) {
172-
if (ipa.assetKind === "schemaVariant") {
173-
// there should only be one sv for an exec'd asset
174-
assetStore.setSchemaVariantIdForAsset(
175-
assetStore.selectedAssetId,
176-
ipa.assetId,
177-
);
178-
await funcStore.FETCH_INPUT_SOURCE_LIST(ipa.assetId); // a new asset means new input sources
179-
}
202+
const { schemaVariantId } = result.result.data;
203+
if (schemaVariantId !== nilId()) {
204+
assetStore.setSchemaVariantIdForAsset(
205+
assetStore.selectedAssetId,
206+
schemaVariantId,
207+
);
208+
await assetStore.LOAD_ASSET(schemaVariantId);
209+
await funcStore.FETCH_INPUT_SOURCE_LIST(schemaVariantId); // a new asset means new input sources
180210
}
181211
}
182212
}

app/web/src/components/AssetEditor.vue

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,13 @@
2020
</div>
2121
<!-- TODO: Populate the created by from SDF actorHistory-->
2222
<div><span class="font-bold">Created By: </span>System Initiative</div>
23-
<SiChip
24-
v-if="selectedAsset.defaultVariantId"
25-
variant="warning"
26-
text="read-only"
27-
/>
23+
<SiChip v-if="isReadOnly" variant="warning" text="read-only" />
2824
</div>
2925
<div class="flex-grow relative overflow-auto">
3026
<CodeEditor
3127
v-model="editingAsset"
3228
:typescript="selectedAsset?.types"
33-
:disabled="
34-
!!selectedAsset.defaultVariantId || changeSetsStore.headSelected
35-
"
29+
:disabled="isReadOnly || changeSetsStore.headSelected"
3630
@change="onChange"
3731
/>
3832
</div>
@@ -62,6 +56,11 @@ const selectedAsset = computed(() =>
6256
props.assetId ? assetStore.assetsById[props.assetId] : undefined,
6357
);
6458
59+
const isReadOnly = computed(
60+
() =>
61+
!!(selectedAsset.value?.hasComponents || selectedAsset.value?.hasAttrFuncs),
62+
);
63+
6564
const editingAsset = ref<string>(selectedAsset.value?.code ?? "");
6665
6766
const loadAssetReqStatus = assetStore.getRequestStatus(

app/web/src/components/AssetFuncListPanel.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
v-if="assetStore.selectedAssetId && !changeSetsStore.headSelected"
1515
:disabled="
1616
!assetStore.assetsById[assetStore.selectedAssetId]
17-
?.defaultVariantId
17+
?.schemaVariantId
1818
"
1919
label="Attach Function"
2020
@selected-attach-type="openAttachFuncModal"
@@ -107,7 +107,7 @@ const loadAssetReqStatus = assetStore.getRequestStatus(
107107
const attachModalRef = ref<InstanceType<typeof AssetFuncAttachModal>>();
108108
const assetSchemaVariantId = computed(() =>
109109
props.assetId
110-
? assetStore.assetsById[props.assetId]?.defaultVariantId
110+
? assetStore.assetsById[props.assetId]?.schemaVariantId
111111
: undefined,
112112
);
113113

app/web/src/components/Workspace/WorkspaceCustomizeAssets.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
<FuncDetails
4444
v-else-if="assetId && funcId"
4545
:funcId="funcId"
46-
:schemaVariantId="assetStore.assetsById[assetId]?.defaultVariantId"
46+
:schemaVariantId="assetStore.assetsById[assetId]?.schemaVariantId"
4747
singleModelScreen
4848
@detached="onDetach"
4949
/>
@@ -53,7 +53,7 @@
5353
<FuncDetails
5454
v-else-if="assetId && funcId"
5555
:funcId="funcId"
56-
:schemaVariantId="assetStore.assetsById[assetId]?.defaultVariantId"
56+
:schemaVariantId="assetStore.assetsById[assetId]?.schemaVariantId"
5757
@detached="onDetach"
5858
/>
5959
</template>

app/web/src/store/asset.store.ts

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,27 @@ export interface ListedVariantDef {
4242

4343
export interface VariantDef extends ListedVariantDef {
4444
link?: string;
45-
defaultVariantId?: string;
45+
schemaVariantId?: string;
4646
code: string;
4747
handler: string;
4848
types?: string;
49+
hasComponents: boolean;
50+
hasAttrFuncs: boolean;
4951
}
5052

5153
const funcStore = useFuncStore();
5254

5355
export type Asset = VariantDef;
5456
export type AssetListEntry = ListedVariantDef;
5557
export type AssetSaveRequest = Visibility &
56-
Omit<Asset, "createdAt" | "updatedAt" | "variantExists">;
58+
Omit<
59+
Asset,
60+
| "createdAt"
61+
| "updatedAt"
62+
| "variantExists"
63+
| "hasComponents"
64+
| "hasAttrFuncs"
65+
>;
5766
export type AssetCreateRequest = Omit<
5867
AssetSaveRequest,
5968
"id" | "definition" | "variantExists"
@@ -105,7 +114,7 @@ export const useAssetStore = () => {
105114
setSchemaVariantIdForAsset(assetId: AssetId, schemaVariantId: string) {
106115
const asset = this.assetsById[assetId];
107116
if (asset) {
108-
asset.defaultVariantId = schemaVariantId;
117+
asset.schemaVariantId = schemaVariantId;
109118
this.assetsById[assetId] = asset;
110119
}
111120
},
@@ -185,11 +194,7 @@ export const useAssetStore = () => {
185194
createNewAsset(): Asset {
186195
return {
187196
id: nilId(),
188-
name: `new asset ${Math.floor(Math.random() * 10000)}${
189-
Math.floor(Math.random() * 20) === 0
190-
? " omg has such a long name the name is so long you can't even believe how long it is!"
191-
: ""
192-
}`,
197+
name: `new asset ${Math.floor(Math.random() * 10000)}`,
193198
code: "",
194199
handler: "",
195200
color: this.generateMockColor(),
@@ -200,7 +205,9 @@ export const useAssetStore = () => {
200205
funcs: [],
201206
createdAt: new Date().toISOString(),
202207
updatedAt: new Date().toISOString(),
203-
defaultVariantId: undefined,
208+
schemaVariantId: undefined,
209+
hasComponents: false,
210+
hasAttrFuncs: false,
204211
};
205212
},
206213

@@ -215,7 +222,9 @@ export const useAssetStore = () => {
215222
...visibility,
216223
..._.omit(asset, [
217224
"id",
218-
"defaultVariantId",
225+
"schemaVariantId",
226+
"hasComponents",
227+
"hasAttrFuncs",
219228
"createdAt",
220229
"updatedAt",
221230
]),
@@ -246,7 +255,13 @@ export const useAssetStore = () => {
246255
url: "/variant_def/save_variant_def",
247256
params: {
248257
...visibility,
249-
..._.omit(asset, ["defaultVariantId", "createdAt", "updatedAt"]),
258+
..._.omit(asset, [
259+
"schemaVariantId",
260+
"hasComponents",
261+
"hasAttrFuncs",
262+
"createdAt",
263+
"updatedAt",
264+
]),
250265
},
251266
});
252267
},
@@ -274,7 +289,7 @@ export const useAssetStore = () => {
274289

275290
async EXEC_ASSET(assetId: AssetId) {
276291
return new ApiRequest<
277-
{ success: true; installedPkgAssets: InstalledPkgAssetView[] },
292+
{ success: true; schemaVariantId: string },
278293
Visibility & { id: AssetId }
279294
>({
280295
method: "post",
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
DROP INDEX schema_names;
2+
DROP INDEX unique_schema_ui_menus;

0 commit comments

Comments
 (0)