Skip to content

Commit

Permalink
feat: add data plane and the switch button
Browse files Browse the repository at this point in the history
  • Loading branch information
Meng-20 committed Aug 5, 2024
1 parent ddca749 commit 5dc3a06
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 10 deletions.
79 changes: 71 additions & 8 deletions webui/src/components/Dashboard/Dashboard.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
<!-- Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates -->
<template>
<v-container style="width: 100%; height: 80vh">
<h2 style="text-align: center; margin-bottom: 20px">
CFM Ethernet Connections
<v-container
style="
width: 100%;
height: 80vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
"
>
<h2 style="margin-bottom: 20px">
{{ currentTitle }}
</h2>

<v-btn @click="toggleGraph" style="margin-bottom: 40px" variant="tonal">
{{ buttonLabel }}
</v-btn>

<div style="position: relative; width: 25%">
<v-text-field
v-if="showSearch"
Expand All @@ -23,8 +36,8 @@
</div>

<VueFlow
:nodes="controlNodes"
:edges="controlEdges"
:nodes="nodes"
:edges="edges"
class="basic-flow"
:default-viewport="{ zoom: 1 }"
:min-zoom="0.2"
Expand All @@ -41,12 +54,14 @@
</template>

<script>
import { ref, onMounted } from "vue";
import { ref, onMounted, computed } from "vue";
import { useControlData } from "./initial-control-elements";
import { useData } from "./initial-data-elements";
import { useApplianceStore } from "../Stores/ApplianceStore";
import { useHostStore } from "../Stores/HostStore";
import { useBladeStore } from "../Stores/BladeStore";
import { useServiceStore } from "../Stores/ServiceStore";
import { useBladePortStore } from "../Stores/BladePortStore";
import { VueFlow } from "@vue-flow/core";
import { useRouter } from "vue-router";
import { ControlButton, Controls } from "@vue-flow/controls";
Expand All @@ -59,13 +74,18 @@ export default {
const hostStore = useHostStore();
const bladeStore = useBladeStore();
const serviceStore = useServiceStore();
const bladePortStore = useBladePortStore();

const router = useRouter();
const { controlNodes, controlEdges } = useControlData();
const { dataNodes, dataEdges } = useData();

const searchTerm = ref("");
const showSearch = ref(false);

// Set Data Plane as the default one
const currentGraph = ref("dataPlane");

const handleSearch = () => {
const term = searchTerm.value.toLowerCase();
const elements = document.querySelectorAll(".basic-flow *");
Expand Down Expand Up @@ -97,6 +117,7 @@ export default {
showSearch.value = !showSearch.value;
};

// Jump to the target page by changing the url
const handleNodeClick = async (event) => {
const node = event.node || event;

Expand All @@ -121,21 +142,63 @@ export default {
}
};

// Toggle graphs by changing the current graph value
const toggleGraph = () => {
currentGraph.value =
currentGraph.value === "controlPlane" ? "dataPlane" : "controlPlane";
};

// Change the nodes and edges by the current graph value
const nodes = computed(() =>
currentGraph.value === "controlPlane"
? controlNodes.value
: dataNodes.value
);
const edges = computed(() =>
currentGraph.value === "controlPlane"
? controlEdges.value
: dataEdges.value
);

// Make the title of this conponent dynamic
const currentTitle = computed(() =>
currentGraph.value === "controlPlane"
? "CFM Ethernet Connections"
: "CFM CXL Connections"
);

// Make the switch button label of this conponent dynamic
const buttonLabel = computed(() =>
currentGraph.value === "controlPlane"
? "Switch to Data Plane"
: "Switch to Control Plane"
);

// Fetch appliances/blades/hosts when component is mounted
onMounted(async () => {
await serviceStore.getServiceVersion();
await applianceStore.fetchAppliances();
await hostStore.fetchHosts();
// Ensure blade ports are fetched after appliances, this action will create the edges for dataPlane
for (const appliance of applianceStore.applianceIds) {
for (const bladeId of appliance.bladeIds) {
await bladePortStore.fetchBladePorts(appliance.id, bladeId);
}
}
});

return {
controlNodes,
controlEdges,
nodes,
edges,
currentGraph,
handleNodeClick,
searchTerm,
handleSearch,
showSearch,
toggleSearch,
toggleGraph,
currentTitle,
buttonLabel,
};
},
};
Expand Down
81 changes: 81 additions & 0 deletions webui/src/components/Dashboard/initial-data-elements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright (c) 2024 Seagate Technology LLC and/or its Affiliates
import { computed } from "vue";
import { useApplianceStore } from "../Stores/ApplianceStore";
import { useHostStore } from "../Stores/HostStore";
import { useBladePortStore } from "../Stores/BladePortStore";

export const useData = () => {
const applianceStore = useApplianceStore();
const hostStore = useHostStore();
const bladePortStore = useBladePortStore();

const applianceNodeType = "appliance";
const hostNodeType = "host";
const bladeNodeType = "blade";

const dataNodes = computed(() => {
let currentYPosition = 0;
const applianceNodes = applianceStore.applianceIds.flatMap(
(appliance, index) => {
const bladeCount = appliance.bladeIds.length;
const applianceHeight = 50 + bladeCount * 50; // Adjust height based on number of blades
const applianceWidth = 270; // Width of the appliance node
const bladeWidth = 250; // Width of the blade node
const bladeXPosition = (applianceWidth - bladeWidth) / 2; // Center the blade nodes

const applianceNode = {
id: `appliance-${appliance.id}`,
data: { label: appliance.id, url: `/appliances/${appliance.id}` },
position: { x: 100, y: currentYPosition },
style: { backgroundColor: "rgba(242, 174, 114, 0.5)", color: "#000", height: `${applianceHeight}px`, width: `${applianceWidth}px` },
type: applianceNodeType,
sourcePosition: 'right',
targetPosition: 'left',
};

const bladeNodes = appliance.bladeIds.map((bladeId, bladeIndex) => ({
id: `blade-${bladeId}`,
data: { label: bladeId, url: `/appliances/${appliance.id}/blades/${bladeId}`, associatedAppliance: appliance.id },
position: { x: bladeXPosition, y: 50 + bladeIndex * 50 }, // Center blades within the appliance node
style: { backgroundColor: "#f2e394", color: "#000", width: `${bladeWidth}px` },
type: bladeNodeType,
parentNode: `appliance-${appliance.id}`,
extent: 'parent',
expandParent: true,
sourcePosition: 'right',
targetPosition: 'left',
}));

currentYPosition += applianceHeight + 20; // Add some space between nodes

return [applianceNode, ...bladeNodes];
}
);

const hostNodes = hostStore.hostIds.map((host, index) => ({
id: `host-${host}`,
data: { label: host, url: `/hosts/${host}` },
position: { x: 500, y: index * 200 },
style: { backgroundColor: "#d9ecd0", color: "#000" },
type: hostNodeType,
sourcePosition: 'right',
targetPosition: 'left',
}));

return [...applianceNodes, ...hostNodes];
});

const dataEdges = computed(() => {
const edges = bladePortStore.bladeIds.flatMap((blade) => [
...blade.connectedHostIds.map((hostId) => ({
id: `appliance-blade-${blade.id}-${hostId}`,
source: `blade-${blade.id}`,
target: `host-${hostId}`,
animated: true,
}))
]);
return edges;
});

return { dataNodes, dataEdges };
};
5 changes: 5 additions & 0 deletions webui/src/components/Stores/BladePortStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const API_BASE_PATH = process.env.BASE_PATH || BASE_PATH;
export const useBladePortStore = defineStore('bladePort', {
state: () => ({
bladePorts: [] as PortInformation[],
// Use bladeIds to store the relationship between blade and host, the relationship is used to determine the dataEdges in the dashboard
bladeIds: [] as { id: string, connectedHostIds: string[] }[],
}),

actions: {
Expand All @@ -22,6 +24,7 @@ export const useBladePortStore = defineStore('bladePort', {
bladeId
);

const hostIds = [];
const portsCount = response.data.memberCount;
for (let i = 0; i < portsCount; i++) {
// Extract the id for each port
Expand All @@ -42,6 +45,7 @@ export const useBladePortStore = defineStore('bladePort', {
const hostId = JSON.stringify(linkedPortUri).split("/")[4];
const hostPort: string = JSON.stringify(linkedPortUri).split("/").pop()?.slice(0, -1) as string;
detailsResponse.data.linkedPortUri = hostId + "/" + hostPort;
hostIds.push(hostId);
} else {
detailsResponse.data.linkedPortUri = "NOT_FOUND";
}
Expand All @@ -50,6 +54,7 @@ export const useBladePortStore = defineStore('bladePort', {
this.bladePorts.push(detailsResponse.data);
}
}
this.bladeIds.push({ id: bladeId, connectedHostIds: hostIds });
} catch (error) {
console.error("Error fetching ports:", error);
}
Expand Down
4 changes: 2 additions & 2 deletions webui/src/components/Stores/HostPortStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ export const useHostPortStore = defineStore('hostPort', {
detailsResponse.data.linkedPortUri
).split("/");
const applianceId = uri[4];
const hostId = uri[6];
detailsResponse.data.linkedPortUri = applianceId + "/" + hostId;
const bladeId = uri[6];
detailsResponse.data.linkedPortUri = applianceId + "/" + bladeId;
}
this.hostPorts.push(detailsResponse.data);
}
Expand Down

0 comments on commit 5dc3a06

Please sign in to comment.