Skip to main content
Glama
Connection.vue6.38 kB
<template> <div> <div v-if="isDevMode" class="pb-xs text-3xs italic opacity-30 break-all hidden" > ID = {{ connection.id }} </div> <ConnectionEndCard v-if="isSocketConnection(connection)" :changeStatus="connection.changeStatus" :componentName="componentNames.from" :subjectLabel="connection.fromSocket.def.label" type="input-socket" /> <ConnectionEndCard v-else :changeStatus="connection.changeStatus" :componentName="componentNames.from" :subjectLabel="connection.fromAttributePath" type="prop" /> <div :class="clsx('_connection-label border-l-2', statusColors)"> <div class="flex flex-row items-center"> <DetailsPanelTimestamps :changeStatus="connection.changeStatus" :created="connection.createdInfo" :deleted="connection.deletedInfo" noMargin /> <template v-if="showMenu"> <DetailsPanelMenuIcon @click="openMenu" /> <DropdownMenu ref="menuRef" :items="menuItems" variant="editor" /> </template> </div> </div> <ConnectionEndCard v-if="isSocketConnection(connection)" :changeStatus="connection.changeStatus" :componentName="componentNames.to" :subjectLabel="connection.toSocket.def.label" type="input-socket" /> <ConnectionEndCard v-else :changeStatus="connection.changeStatus" :componentName="componentNames.to" :subjectLabel="connection.toAttributePath" type="prop" /> </div> </template> <script lang="ts" setup> import * as _ from "lodash-es"; import { computed, PropType, ref } from "vue"; import clsx from "clsx"; import { DropdownMenu, DropdownMenuItemObjectDef, themeClasses, } from "@si/vue-lib/design-system"; import { tw } from "@si/vue-lib"; import { isDevMode } from "@/utils/debug"; import { ChangeStatus } from "@/api/sdf/dal/change_set"; import { ActorAndTimestamp, AttributePath, ComponentId, } from "@/api/sdf/dal/component"; import { useComponentsStore } from "@/store/components.store"; import { useViewsStore } from "@/store/views.store"; import { DiagramSocketData } from "./ModelingDiagram/diagram_types"; import ConnectionEndCard from "./ConnectionEndCard.vue"; import DetailsPanelTimestamps from "./DetailsPanelTimestamps.vue"; import DetailsPanelMenuIcon from "./DetailsPanelMenuIcon.vue"; interface BaseConnection { id: string; changeStatus?: ChangeStatus; createdInfo?: ActorAndTimestamp; deletedInfo?: ActorAndTimestamp; } export interface SocketConnection extends BaseConnection { isManagement?: boolean; fromSocket: DiagramSocketData; toSocket: DiagramSocketData; } function isSocketConnection( connection: Connection, ): connection is SocketConnection { return "fromSocket" in connection; } export interface SubscriptionConnection extends BaseConnection { fromComponentId: ComponentId; fromAttributePath: AttributePath; toComponentId: ComponentId; toAttributePath: AttributePath; } function isSubscriptionConnection( connection: Connection, ): connection is SubscriptionConnection { return "fromAttributePath" in connection; } export type Connection = SocketConnection | SubscriptionConnection; const props = defineProps({ connection: { type: Object as PropType<Connection>, required: true }, showMenu: { type: Boolean }, }); const menuRef = ref<InstanceType<typeof DropdownMenu>>(); const componentsStore = useComponentsStore(); const viewsStore = useViewsStore(); const modelingEventBus = componentsStore.eventBus; const componentNames = computed(() => { if (isSubscriptionConnection(props.connection)) { const toComponent = componentsStore.allComponentsById[props.connection.toComponentId]; const fromComponent = componentsStore.allComponentsById[props.connection.fromComponentId]; return { to: toComponent?.def.displayName ?? "?", from: fromComponent?.def.displayName ?? "?", }; } else { // Is socket connection return { to: props.connection.toSocket.parent.def.displayName ?? "?", from: props.connection.fromSocket.parent.def.displayName ?? "?", }; } }); const openMenu = (e: MouseEvent) => { menuRef.value?.open(e); }; const menuItems = computed(() => { const items: DropdownMenuItemObjectDef[] = []; const disabled = false; // single selected edge items.push({ label: "CONNECTION", header: true, }); if (props.connection.changeStatus === "deleted") { items.push({ label: "Restore", icon: "trash-restore", onSelect: triggerRestore, disabled, }); } else { items.push({ label: "Delete", shortcut: "⌫", icon: "trash", onSelect: triggerDelete, disabled, }); } return items; }); const triggerRestore = () => { viewsStore.setSelectedEdgeId(props.connection.id, viewsStore.selectedEdgeId); modelingEventBus.emit("restoreSelection"); }; const triggerDelete = () => { viewsStore.setSelectedEdgeId(props.connection.id, viewsStore.selectedEdgeId); modelingEventBus.emit("deleteSelection"); }; const statusColors = computed(() => { const unmodified = themeClasses( tw`border-shade-100 before:bg-shade-100 after:bg-shade-100`, tw`border-shade-0 before:bg-shade-0 after:bg-shade-0`, ); if (!props.connection.changeStatus) return unmodified; const colors = { added: themeClasses( tw`border-success-500 before:bg-success-500 after:bg-success-500`, tw`border-success-400 before:bg-success-400 after:bg-success-400`, ), deleted: tw`border-destructive-500 before:bg-destructive-500 after:bg-destructive-500`, modified: tw`border-warning-400 before:bg-warning-400 after:bg-warning-400`, unmodified, }; return colors[props.connection.changeStatus]; }); </script> <style lang="less"> @socket-size: 10px; ._connection-label { padding: 8px; position: relative; z-index: 1; margin-left: 20px; &:before, &:after { content: ""; width: @socket-size; height: @socket-size; border-radius: 100%; display: block; position: absolute; margin-left: (-@socket-size / 2 - 1); left: 0; } &::before { top: 0; margin-top: -(@socket-size / 2); } &::after { margin-bottom: -(@socket-size / 2); bottom: 0; } } </style>

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server