diff --git a/app/web/src/components/ManagementRunPrototype.vue b/app/web/src/components/ManagementRunPrototype.vue
index c7552f491d..a781340205 100644
--- a/app/web/src/components/ManagementRunPrototype.vue
+++ b/app/web/src/components/ManagementRunPrototype.vue
@@ -7,7 +7,18 @@
)
"
>
-
+
+
+
+
+
+
+
{{
`Run ${props.prototype.label}`
}}
@@ -31,6 +42,8 @@ import { ref, computed, onMounted, watch } from "vue";
import clsx from "clsx";
import { useToast } from "vue-toastification";
import {
+ DropdownMenu,
+ DropdownMenuItem,
IconButton,
themeClasses,
TruncateWithTooltip,
@@ -44,6 +57,8 @@ import {
import { useComponentsStore } from "@/store/components.store";
import { FuncRunId } from "@/store/func_runs.store";
import { useManagementRunsStore } from "@/store/management_runs.store";
+import { useViewsStore } from "@/store/views.store";
+import { ViewId } from "@/api/sdf/dal/views";
import {
DiagramGroupData,
DiagramNodeData,
@@ -56,6 +71,9 @@ const componentsStore = useComponentsStore();
const router = useRouter();
const toast = useToast();
const managementRunsStore = useManagementRunsStore();
+const viewsStore = useViewsStore();
+
+const viewSelectorMenuRef = ref>();
const lastExecution = ref(undefined);
@@ -89,16 +107,25 @@ const latestRunId = computed(() =>
),
);
+const componentViews = computed(() =>
+ Object.keys(viewsStore.viewsById).filter(
+ (viewId) =>
+ !!viewsStore.viewsById[viewId]?.components[props.component.def.id] ||
+ !!viewsStore.viewsById[viewId]?.groups[props.component.def.id],
+ ),
+);
+
watch(latestRunId, (latest) => {
if (latest) {
emit("runUpdated", latest);
}
});
-const runPrototype = async () => {
+const runPrototype = async (viewId: ViewId) => {
const result = await funcStore.RUN_MGMT_PROTOTYPE(
props.prototype.managementPrototypeId,
props.component.def.id,
+ viewId,
);
if (result.result.success) {
@@ -123,6 +150,16 @@ const runPrototype = async () => {
}
};
+const runClick = async (e?: MouseEvent) => {
+ if (componentViews.value.length === 1 && componentViews.value[0]) {
+ await runPrototype(componentViews.value[0]);
+ } else if (componentViews.value.length > 1) {
+ viewSelectorMenuRef.value?.open(e, false);
+ } else if (viewsStore.selectedViewId) {
+ await runPrototype(viewsStore.selectedViewId);
+ }
+};
+
function onClickView() {
router.push({
name: "workspace-lab-assets",
diff --git a/app/web/src/components/ModelingView/ModelingRightClickMenu.vue b/app/web/src/components/ModelingView/ModelingRightClickMenu.vue
index 53f4df395d..ab59e8abc2 100644
--- a/app/web/src/components/ModelingView/ModelingRightClickMenu.vue
+++ b/app/web/src/components/ModelingView/ModelingRightClickMenu.vue
@@ -433,10 +433,12 @@ const rightClickMenuItems = computed(() => {
const runManagementFunc = async (prototype: MgmtPrototype) => {
if (!selectedComponent.value) return;
+ if (!viewStore.selectedViewId) return;
const result = await funcStore.RUN_MGMT_PROTOTYPE(
prototype.managementPrototypeId,
selectedComponent.value.def.id,
+ viewStore.selectedViewId,
);
if (result.result.success && result.result.data.message) {
diff --git a/app/web/src/store/func/funcs.store.ts b/app/web/src/store/func/funcs.store.ts
index 59fed9bc37..26d6f8e128 100644
--- a/app/web/src/store/func/funcs.store.ts
+++ b/app/web/src/store/func/funcs.store.ts
@@ -31,6 +31,7 @@ import { useAssetStore } from "@/store/asset.store";
import { SchemaVariant, SchemaVariantId } from "@/api/sdf/dal/schema";
import { DefaultMap } from "@/utils/defaultmap";
import { ComponentId } from "@/api/sdf/dal/component";
+import { ViewId } from "@/api/sdf/dal/views";
import { useChangeSetsStore } from "../change_sets.store";
import { useRealtimeStore } from "../realtime/realtime.store";
import { useComponentsStore } from "../components.store";
@@ -287,6 +288,7 @@ export const useFuncStore = () => {
async RUN_MGMT_PROTOTYPE(
prototypeId: ManagementPrototypeId,
componentId: ComponentId,
+ viewId: ViewId,
) {
return new ApiRequest({
method: "post",
@@ -296,6 +298,7 @@ export const useFuncStore = () => {
"prototype",
{ prototypeId },
{ componentId },
+ { viewId },
]),
});
},
diff --git a/bin/lang-js/src/component.ts b/bin/lang-js/src/component.ts
index 88eefcab47..c1e59c2a44 100644
--- a/bin/lang-js/src/component.ts
+++ b/bin/lang-js/src/component.ts
@@ -4,13 +4,13 @@ export interface Component {
}
export interface Geometry {
- x: number;
- y: number;
+ x?: number;
+ y?: number;
width?: number;
height?: number;
}
export interface ComponentWithGeometry {
properties: Record;
- geometry: Geometry;
+ geometry: { [key: string]: Geometry };
}
diff --git a/bin/lang-js/src/function_kinds/management.ts b/bin/lang-js/src/function_kinds/management.ts
index fad0774210..1fe94e78db 100644
--- a/bin/lang-js/src/function_kinds/management.ts
+++ b/bin/lang-js/src/function_kinds/management.ts
@@ -13,6 +13,7 @@ import { RequestCtx } from "../request";
const debug = Debug("langJs:management");
export interface ManagementFunc extends Func {
+ currentView: string;
thisComponent: ComponentWithGeometry;
components: {
[key: string]: ComponentWithGeometry;
@@ -20,8 +21,8 @@ export interface ManagementFunc extends Func {
}
export type ManagementFuncResult =
- | ManagementFuncResultSuccess
- | ManagementFuncResultFailure;
+ | ManagementFuncResultSuccess
+ | ManagementFuncResultFailure;
export interface ManagmentConnect {
from: string,
@@ -32,22 +33,26 @@ export interface ManagmentConnect {
}
export interface ManagementOperations {
- create?: { [key: string]: {
- kind: string;
- properties?: object;
- geometry?: Geometry;
- parent?: string;
- connect?: ManagmentConnect[],
- } };
- update?: { [key: string]: {
- properties?: object;
- geometry?: Geometry;
- parent?: string;
- connect: {
- add?: ManagmentConnect[],
- remove?: ManagmentConnect[],
+ create?: {
+ [key: string]: {
+ kind: string;
+ properties?: object;
+ geometry?: Geometry;
+ parent?: string;
+ connect?: ManagmentConnect[],
}
- } };
+ };
+ update?: {
+ [key: string]: {
+ properties?: object;
+ geometry?: { [key: string]: Geometry };
+ parent?: string;
+ connect: {
+ add?: ManagmentConnect[],
+ remove?: ManagmentConnect[],
+ }
+ }
+ };
actions?: {
[key: string]: {
add?: string[],
@@ -66,14 +71,14 @@ export interface ManagementFuncResultFailure extends ResultFailure { }
async function execute(
vm: NodeVM,
{ executionId }: RequestCtx,
- { thisComponent, components }: ManagementFunc,
+ { thisComponent, components, currentView }: ManagementFunc,
code: string,
): Promise {
let managementResult: Record | undefined | null;
try {
const runner = vm.run(code);
managementResult = await new Promise((resolve) => {
- runner({ thisComponent, components }, (resolution: Record) => resolve(resolution));
+ runner({ thisComponent, components, currentView }, (resolution: Record) => resolve(resolution));
});
} catch (err) {
return failureExecution(err as Error, executionId);
diff --git a/lib/cyclone-client/src/client.rs b/lib/cyclone-client/src/client.rs
index f675a60584..c362b304c8 100644
--- a/lib/cyclone-client/src/client.rs
+++ b/lib/cyclone-client/src/client.rs
@@ -1325,6 +1325,7 @@ mod tests {
let req = ManagementRequest {
execution_id: "1234".to_string(),
handler: "manage".to_string(),
+ current_view: "DEFAULT".to_string(),
this_component: ComponentViewWithGeometry {
kind: None,
properties: serde_json::json!({"it": "is", "a": "principle", "of": "music", "to": "repeat the theme"}),
@@ -1409,6 +1410,7 @@ mod tests {
let req = ManagementRequest {
execution_id: "1234".to_string(),
handler: "manage".to_string(),
+ current_view: "DEFAULT".to_string(),
this_component: ComponentViewWithGeometry {
kind: None,
properties: serde_json::json!({"it": "is", "a": "principle", "of": "music", "to": "repeat the theme"}),
diff --git a/lib/cyclone-core/src/management.rs b/lib/cyclone-core/src/management.rs
index 358875ba68..0b7d7bc593 100644
--- a/lib/cyclone-core/src/management.rs
+++ b/lib/cyclone-core/src/management.rs
@@ -12,6 +12,7 @@ pub struct ManagementRequest {
pub execution_id: String,
pub handler: String,
pub code_base64: String,
+ pub current_view: String,
pub this_component: ComponentViewWithGeometry,
pub components: HashMap,
pub before: Vec,
diff --git a/lib/dal-test/src/expected.rs b/lib/dal-test/src/expected.rs
index 260658ba6b..a8be0e89cc 100644
--- a/lib/dal-test/src/expected.rs
+++ b/lib/dal-test/src/expected.rs
@@ -880,4 +880,8 @@ impl ExpectView {
let name = generate_fake_name();
View::new(ctx, name).await.expect("create view")
}
+
+ pub async fn create_with_name(ctx: &DalContext, name: &str) -> View {
+ View::new(ctx, name).await.expect("create view")
+ }
}
diff --git a/lib/dal-test/src/test_exclusive_schemas/legos/small.rs b/lib/dal-test/src/test_exclusive_schemas/legos/small.rs
index 7ca2bb8a6a..5dcafa9cfd 100644
--- a/lib/dal-test/src/test_exclusive_schemas/legos/small.rs
+++ b/lib/dal-test/src/test_exclusive_schemas/legos/small.rs
@@ -149,6 +149,44 @@ pub(crate) async fn migrate_test_exclusive_schema_small_odd_lego(
let update_mgmt_func_name = "test:updateManagedComponent";
let update_mgmt_func = build_management_func(update_managed_func_code, update_mgmt_func_name)?;
+ let update_managed_func_in_view_code = r#"
+ async function main({ thisComponent, components, currentView }: Input): Promise