diff --git a/app/web/src/components/ModelingDiagram/DiagramGroup.vue b/app/web/src/components/ModelingDiagram/DiagramGroup.vue index 3f8426c345..2eb464715d 100644 --- a/app/web/src/components/ModelingDiagram/DiagramGroup.vue +++ b/app/web/src/components/ModelingDiagram/DiagramGroup.vue @@ -439,7 +439,9 @@ import { GROUP_RESIZE_HANDLE_SIZE, GROUP_TITLE_FONT_SIZE, SELECTION_COLOR, - MIN_NODE_DIMENSION, + NODE_SUBTITLE_TEXT_HEIGHT, + SOCKET_MARGIN_TOP, + NODE_PADDING_BOTTOM, } from "@/components/ModelingDiagram/diagram_constants"; import { QualificationStatus, @@ -514,11 +516,18 @@ const irect = computed(() => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const r = viewStore.groups[props.group.def.id]!; + const minimum = + NODE_SUBTITLE_TEXT_HEIGHT + + SOCKET_MARGIN_TOP + + NODE_PADDING_BOTTOM + + 30 + + NODE_HEADER_HEIGHT; + return { x: r.x, y: r.y, - width: Math.max(r.width, MIN_NODE_DIMENSION), - height: Math.max(r.height, MIN_NODE_DIMENSION), + width: Math.max(r.width, minimum), + height: Math.max(r.height, minimum), }; }); diff --git a/app/web/src/components/ModelingDiagram/DiagramView.vue b/app/web/src/components/ModelingDiagram/DiagramView.vue index e2c8abd17a..a6613ed6a5 100644 --- a/app/web/src/components/ModelingDiagram/DiagramView.vue +++ b/app/web/src/components/ModelingDiagram/DiagramView.vue @@ -92,7 +92,7 @@ import DiagramIcon from "./DiagramIcon.vue"; const { theme } = useTheme(); -const viewStore = useViewsStore(); +const viewsStore = useViewsStore(); const props = defineProps<{ view: DiagramViewDef; @@ -148,7 +148,7 @@ interface ViewStats { const statusIcons = computed(() => { const icons: ViewStats[] = []; - const stats = viewStore.viewStats[props.view.id]; + const stats = viewsStore.viewStats[props.view.id]; if (!stats) return icons; if (stats.components > 0) @@ -246,17 +246,17 @@ const config = computed(() => { function onMouseOver(evt: KonvaEventObject, type?: string) { evt.cancelBubble = true; - viewStore.setHoveredComponentId( + viewsStore.setHoveredComponentId( props.view.id, type ? ({ type } as ElementHoverMeta) : undefined, ); } function onMouseOut() { - viewStore.setHoveredComponentId(null); + viewsStore.setHoveredComponentId(null); } const goto = () => { - viewStore.selectView(props.view.id); + viewsStore.selectView(props.view.id); }; diff --git a/app/web/src/components/ViewCard.vue b/app/web/src/components/ViewCard.vue index 355a85a4d3..b713b8ec99 100644 --- a/app/web/src/components/ViewCard.vue +++ b/app/web/src/components/ViewCard.vue @@ -12,7 +12,10 @@ ) " > -
+
@@ -23,21 +26,21 @@
-
{{ viewStore.viewStats[view.id]?.components }}
+
{{ viewsStore.viewStats[view.id]?.components }}
-
{{ viewStore.viewStats[view.id]?.resources }}
+
{{ viewsStore.viewStats[view.id]?.resources }}
-
{{ viewStore.viewStats[view.id]?.failed }}
+
{{ viewsStore.viewStats[view.id]?.failed }}
@@ -55,12 +58,13 @@ /> @@ -69,7 +73,7 @@ icon="eye" :onSelect=" () => { - viewStore.selectView(view.id); + viewsStore.selectView(view.id); } " /> @@ -78,7 +82,7 @@ icon="bullet-list-indented" :onSelect=" () => { - viewStore.setOutlinerView(view.id); + viewsStore.setOutlinerView(view.id); } " /> @@ -154,7 +158,7 @@ import NodeSkeleton from "@/components/NodeSkeleton.vue"; import DetailsPanelMenuIcon from "./DetailsPanelMenuIcon.vue"; const toast = useToast(); -const viewStore = useViewsStore(); +const viewsStore = useViewsStore(); const props = defineProps<{ selected?: boolean; @@ -175,8 +179,8 @@ const updateMouseNode = (e: MouseEvent) => { const onMouseDown = (e: MouseEvent) => { updateMouseNode(e); - if (viewStore.addComponentId) { - viewStore.cancelAdd(); + if (viewsStore.addComponentId) { + viewsStore.cancelAdd(); } }; @@ -195,19 +199,19 @@ onBeforeUnmount(() => { }); const addingView = computed(() => { - if (viewStore.addViewId) - return viewStore.viewList.find((v) => v.id === viewStore.addViewId); + if (viewsStore.addViewId) + return viewsStore.viewList.find((v) => v.id === viewsStore.addViewId); return undefined; }); function onAdd(id: string, e: MouseEvent) { // cannot dupe views - if (Object.keys(viewStore.viewNodes).includes(id)) return; + if (Object.keys(viewsStore.viewNodes).includes(id)) return; - if (viewStore.addViewId === id) { - viewStore.cancelAdd(); + if (viewsStore.addViewId === id) { + viewsStore.cancelAdd(); } else { - viewStore.addViewId = id; + viewsStore.addViewId = id; if (e) { nextTick(() => { updateMouseNode(e); @@ -227,14 +231,14 @@ const updateName = (e?: Event) => { if (!viewName.value) { labelRef.value?.setError("Name is required"); } else { - viewStore.UPDATE_VIEW_NAME(props.view.id, viewName.value); + viewsStore.UPDATE_VIEW_NAME(props.view.id, viewName.value); modalRef.value?.close(); viewName.value = ""; } }; const deleteView = async (view: ViewDescription) => { - const resp = await viewStore.DELETE_VIEW(view.id); + const resp = await viewsStore.DELETE_VIEW(view.id); if (!resp.result.success) { if (resp.result.statusCode === 409) { /* We cannot easily pass JSON data as an error, punting for now with a generic message diff --git a/app/web/src/components/layout/navbar/Collaborators.vue b/app/web/src/components/layout/navbar/Collaborators.vue index 3d79537257..55b99bba17 100644 --- a/app/web/src/components/layout/navbar/Collaborators.vue +++ b/app/web/src/components/layout/navbar/Collaborators.vue @@ -102,6 +102,7 @@ import { useRoute, useRouter } from "vue-router"; import Popover from "@/components/Popover.vue"; import { usePresenceStore } from "@/store/presence.store"; import { useChangeSetsStore } from "@/store/change_sets.store"; +import { useViewsStore } from "@/store/views.store"; import UserIcon from "./UserIcon.vue"; import UserCard from "./UserCard.vue"; @@ -283,15 +284,20 @@ function goToUserChangeSet(user: UserInfo) { if (!user || !user.changeSet) return; if (user.view) { - router.push({ - name: "workspace-compose-view", - params: { - ...route.params, - changeSetId: user.changeSet, - viewId: user.view, - }, - query: route.query, - }); + if (user.changeSet === changeSetsStore.selectedChangeSetId) { + const viewsStore = useViewsStore(); // have to access the store here to prevent ending up with the none change set views store + viewsStore.selectView(user.view); + } else { + router.push({ + name: "workspace-compose-view", + params: { + ...route.params, + changeSetId: user.changeSet, + viewId: user.view, + }, + query: route.query, + }); + } return; } diff --git a/app/web/src/store/views.store.ts b/app/web/src/store/views.store.ts index 84034478b2..663dc75e56 100644 --- a/app/web/src/store/views.store.ts +++ b/app/web/src/store/views.store.ts @@ -3,7 +3,6 @@ import * as _ from "lodash-es"; import { addStoreHooks, ApiRequest, URLPattern } from "@si/vue-lib/pinia"; import { IRect, Vector2d } from "konva/lib/types"; import { useToast } from "vue-toastification"; -import { watch } from "vue"; import { IconNames } from "@si/vue-lib/design-system"; import { ChangeSetId } from "@/api/sdf/dal/change_set"; import { @@ -592,17 +591,19 @@ export const useViewsStore = (forceChangeSetId?: ChangeSetId) => { this.selectedComponentIds = valid; this.syncSelectionIntoUrl(); }, - selectView(id: ViewId) { + async selectView(id: ViewId) { const view = this.viewsById[id]; if (view) { const route = router.currentRoute; + const params = { + ...route.value.params, + viewId: id, + }; router.push({ name: "workspace-compose-view", - params: { - ...route.value.params, - viewId: id, - }, + params, }); + // move the currently selected view to the top of the if (this.selectedViewId) { this.pushRecentView(this.selectedViewId); @@ -628,7 +629,10 @@ export const useViewsStore = (forceChangeSetId?: ChangeSetId) => { // to begin, and then adjust it via delta when things move this.sockets = view.sockets; } else { - throw new Error(`${id} does not exist`); + const res = await this.FETCH_VIEW(id); + if (!res.result.success) { + throw new Error(`${id} does not exist`); + } } }, closeRecentView(id: ViewId) { @@ -1575,25 +1579,6 @@ export const useViewsStore = (forceChangeSetId?: ChangeSetId) => { } this.LIST_VIEWS(); - // TODO: prob want to take loading state into consideration as this will set it before its loaded - const stopWatchingUrl = watch( - router.currentRoute, - () => { - if ( - router.currentRoute.value.name === "workspace-compose" || - router.currentRoute.value.name === "workspace-compose-view" - ) - this.syncUrlIntoSelection(); - const viewId = router.currentRoute.value.params.viewId; - if (viewId && this.selectedViewId !== viewId) { - this.selectView(viewId as string); - } - }, - { - immediate: true, - }, - ); - if (router.currentRoute.value.name === "workspace-compose") { const key = `${changeSetId}_selected_component`; const lastId = window.localStorage.getItem(key); @@ -1984,7 +1969,6 @@ export const useViewsStore = (forceChangeSetId?: ChangeSetId) => { this.selectedComponentIds = []; this.selectedEdgeId = null; actionUnsub(); - stopWatchingUrl(); realtimeStore.unsubscribe(`${this.$id}-changeset`); realtimeStore.unsubscribe(`${this.$id}-workspace`); };