diff --git a/frontend/dash/src/App.vue b/frontend/dash/src/App.vue
index 877f871..e9e1da6 100644
--- a/frontend/dash/src/App.vue
+++ b/frontend/dash/src/App.vue
@@ -80,34 +80,35 @@
-
-
Loading visualization data...
-
-
-
@@ -131,6 +132,7 @@ export default {
menuVisible: false,
currentPage: 1,
pageSize: 10,
+ clusterMapGenerationCount: 0,
expandedNamespaces: {},
selectedNamespace: '',
allNamespaces: [],
@@ -138,6 +140,7 @@ export default {
namespaceVisualizationData: {},
isLoadingVisualization: false,
isShowClusterMap: false,
+ isClusterMapLoading: false,
clusterVisualizationData: [],
};
},
@@ -204,6 +207,15 @@ export default {
}
return 0;
},
+ loadingMessage() {
+ if (this.isClusterMapLoading) {
+ return 'Loading cluster visualization data...';
+ }
+ if (this.isLoadingVisualization) {
+ return 'Loading visualization data...';
+ }
+ return '';
+ }
},
methods: {
toggleMenu() {
@@ -319,8 +331,13 @@ export default {
return;
}
+ this.isShowClusterMap = false;
+ this.namespaceVisualizationData = {};
+ this.clusterVisualizationData = [];
this.lastScanType = 'namespace';
this.scanInitiated = true;
+ this.isLoadingVisualization = true;
+
try {
const scanResponse = await axios.get(`http://localhost:8080/scan?namespace=${namespace}`);
this.scanResults = scanResponse.data;
@@ -329,7 +346,7 @@ export default {
this.netfetchScore = scanResponse.data.Score || null;
} else {
this.unprotectedPods = [];
- this.netfetchScore = 42; // Default score for no missing policies
+ this.netfetchScore = 42;
}
this.updateExpandedNamespaces();
@@ -338,6 +355,8 @@ export default {
} catch (error) {
console.error('Error scanning namespace:', namespace, error);
this.message = { type: 'error', text: `Failed to scan namespace: ${namespace}. Error: ${error.message}` };
+ } finally {
+ this.isLoadingVisualization = false;
}
},
// Fetch and update visualization data for multiple namespaces
@@ -362,6 +381,22 @@ export default {
}
this.isLoadingVisualization = false;
},
+ async generateClusterNetworkMap() {
+ this.isShowClusterMap = true;
+ this.isLoadingVisualization = true;
+ this.namespaceVisualizationData = {};
+ this.clusterMapGenerationCount++;
+
+ try {
+ const response = await axios.get('http://localhost:8080/visualization/cluster');
+ this.clusterVisualizationData = response.data;
+ } catch (error) {
+ console.error('Error fetching cluster visualization data:', error);
+ } finally {
+ this.isLoadingVisualization = false;
+ }
+ },
+
// Viz
async fetchVisualizationData(namespace) {
if (!namespace) return;
@@ -376,17 +411,6 @@ export default {
console.error('Error fetching visualization data:', error);
}
},
- async generateClusterNetworkMap() {
- this.isShowClusterMap = true;
- this.isLoadingVisualization = true;
- try {
- const response = await axios.get('http://localhost:8080/visualization/cluster');
- this.clusterVisualizationData = response.data;
- } catch (error) {
- console.error('Error fetching cluster visualization data:', error);
- }
- this.isLoadingVisualization = false;
- }
},
mounted() {
this.updateExpandedNamespaces();
diff --git a/frontend/dash/src/Viz.vue b/frontend/dash/src/Viz.vue
index d28bc29..f5b8e7d 100644
--- a/frontend/dash/src/Viz.vue
+++ b/frontend/dash/src/Viz.vue
@@ -9,22 +9,48 @@
name: 'NetworkPolicyVisualization',
props: {
policies: Array,
+ clusterData: {
+ type: Array,
+ default: () => [],
+ },
+ visualizationType: {
+ type: String,
+ default: 'namespace' // Possible values: 'namespace', 'cluster'
+ },
},
mounted() {
this.createNetworkMap();
},
methods: {
createNetworkMap() {
- console.log("Policies data:", this.policies)
+ let data;
+ if (this.visualizationType === 'cluster') {
+ // Flatten the policies array from the nested structure
+ data = this.clusterVisualizationData.reduce((acc, item) => {
+ if (item.policies && Array.isArray(item.policies)) {
+ return [...acc, ...item.policies];
+ }
+ return acc;
+ }, []);
+ } else {
+ data = this.policies;
+ }
+
+ console.log("Visualization data:", data);
const container = d3.select(this.$refs.vizContainer);
const width = 800;
const height = 600;
- // Transform policies into nodes and links
const nodes = [];
const links = [];
- this.policies.forEach(policy => {
+ // Iterate over flattened policies
+ data.forEach(policy => {
+ if (!policy.targetPods || !Array.isArray(policy.targetPods)) {
+ console.warn(`Skipping policy ${policy.name} as it has no targetPods or targetPods is not an array`);
+ return;
+ }
+
const policyNode = { id: policy.name, type: 'policy' };
nodes.push(policyNode);