diff --git a/.env.example b/.env.example deleted file mode 100644 index 92bdf84..0000000 --- a/.env.example +++ /dev/null @@ -1 +0,0 @@ -NATS_URL= \ No newline at end of file diff --git a/.github/workflows/build-docker-images.yml b/.github/workflows/build-docker-images.yml new file mode 100644 index 0000000..c019b64 --- /dev/null +++ b/.github/workflows/build-docker-images.yml @@ -0,0 +1,38 @@ +name: Build front- and back-end docker images + +on: + push: + branches: + - main + - feature/docker-deployment + +jobs: + docker-back-end: + name: Build and push back-end docker image + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Docker build + working-directory: ./backend + run: docker build -t ghcr.io/simcorp/nats-topology-visualiser-backend . + - name: Docker login + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + - name: Docker push + run: docker push ghcr.io/simcorp/nats-topology-visualiser-backend + + docker-front-end: + name: Build and push front-end docker image + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Docker build + working-directory: ./ + run: docker build -t ghcr.io/simcorp/nats-topology-visualiser-frontend . + - name: Docker login + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin + - name: Docker push + run: docker push ghcr.io/simcorp/nats-topology-visualiser-frontend \ No newline at end of file diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index b5b93fa..48a4708 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -20,5 +20,4 @@ jobs: with: node-version: ${{ matrix.node-version }} - run: npm ci - - run: npm run build --if-present - run: npm test \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9905f9f..4692d4a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,7 +25,9 @@ pnpm-debug.log* *.sln *.sw? .vs +backend.sln.DotSettings.user # .NET build files bin obj +publish \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..03ff2e1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:lts-alpine as build-stage +WORKDIR /app +COPY package*.json ./ +RUN npm ci +COPY . . +RUN npm run build; exit 0 + +# production stage +FROM nginx:stable-alpine as production-stage +COPY --from=build-stage /app/dist /usr/share/nginx/html +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/appsettings.json b/appsettings.json index 831af5d..d9768e6 100644 --- a/appsettings.json +++ b/appsettings.json @@ -1,5 +1,10 @@ { "CORS": { - "AllowedHosts": [ "http://localhost:8080" ] + "AllowedHosts": [ + "http://localhost:8080", + "https://localhost:8080", + "http://localhost:80", + "https://localhost:80" + ] } } \ No newline at end of file diff --git a/backend/Controller.cs b/backend/Controller.cs index efa0040..8f95bc1 100644 --- a/backend/Controller.cs +++ b/backend/Controller.cs @@ -16,13 +16,28 @@ public class Controller : ControllerBase private readonly DataStorage _dataStorage; - private static String timeOfRequest; - public Controller(DataStorage dataStorage) { _dataStorage = dataStorage; } + [HttpGet("/updateEverything")] + [ProducesResponseType(Status200OK)] + public ActionResult GetData() + { + Program.UpdateData(); + return new DataTransfer { + processedServers = _dataStorage.processedServers, + links = _dataStorage.links, + processedClusters = _dataStorage.processedClusters, + gatewayLinks = _dataStorage.gatewayLinks, + leafLinks = _dataStorage.leafLinks, + varz = _dataStorage.servers, + treeNodes = _dataStorage.treeNodes, + timeOfRequest = Program.dateOfNatsRequest + }; + } + [HttpGet("/nodes")] [ProducesResponseType(Status200OK)] public ActionResult> GetNodes() @@ -46,10 +61,9 @@ public ActionResult> GetClusters() [HttpGet("/timeOfRequest")] [ProducesResponseType(Status200OK)] - public ActionResult GetTimeOfRequest() + public ActionResult GetTimeOfRequest() { - timeOfRequest = Program.dateOfNatsRequest.ToString("hh:mm tt - dd MMMM yyyy"); - return timeOfRequest; + return Program.dateOfNatsRequest; } [HttpGet("/iptoserverid")] @@ -70,22 +84,7 @@ public ActionResult> GetLeafLinks() [ProducesResponseType(Status200OK)] public ActionResult> GetGatewayLinks() { - var gatewayLinks = new List(); - foreach (var cluster in _dataStorage.clusterConnectionErrors) - { - var split = cluster.Key.Split(" NAMESPLIT "); - var source = split[0]; - var target = split[1]; - var link = new GatewayLink (source, target, cluster.Value.Count > 0); - link.errors = cluster.Value; - foreach (var err in cluster.Value) - { - link.errorsAsString += "\n" + err; - } - gatewayLinks.Add(link); - } - - return gatewayLinks; + return _dataStorage.gatewayLinks; } [HttpGet("/varz")] @@ -140,5 +139,12 @@ public ActionResult> GetLeafz() { return _dataStorage.leafs; } + + [HttpGet("/TreeViewData")] + [ProducesResponseType(Status200OK)] + public ActionResult> GetTreeViewData() + { + return _dataStorage.treeNodes; + } } } diff --git a/backend/DataStorage.cs b/backend/DataStorage.cs index 0798ccc..f65b19c 100644 --- a/backend/DataStorage.cs +++ b/backend/DataStorage.cs @@ -27,6 +27,8 @@ public class DataStorage public Dictionary ipToServerId; public List leafLinks; public HashSet leafConnections; + public List gatewayLinks; + public List treeNodes; public DataStorage() { @@ -43,7 +45,7 @@ public DataStorage() { serverToMissingServer = new Dictionary>(); ipToServerId = new Dictionary(); leafLinks = new List(); - + gatewayLinks = new List(); missingServerIds = new HashSet(); foundServers = new HashSet(); @@ -51,6 +53,8 @@ public DataStorage() { clusterConnectionErrors = new Dictionary>(); errorClusters = new List(); leafConnections = new HashSet(); + + treeNodes = new List(); } } } diff --git a/backend/DataTransfer.cs b/backend/DataTransfer.cs new file mode 100644 index 0000000..95e991a --- /dev/null +++ b/backend/DataTransfer.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using backend.drawables; +using backend.models; + +namespace backend +{ + public class DataTransfer + { + public ConcurrentBag processedServers {get; set;} + public List links {get; set;} + public ConcurrentBag processedClusters {get; set;} + public List gatewayLinks {get; set;} + public List leafLinks {get; set;} + public List varz {get; set;} + public List treeNodes { get; set; } + public DateTime timeOfRequest {get; set;} + } +} diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..a9b4151 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,10 @@ +FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build +WORKDIR /src/ +COPY . . +RUN dotnet publish -o /app/ + +FROM mcr.microsoft.com/dotnet/aspnet:5.0 AS runtime +WORKDIR /app/ +EXPOSE 443 +ENTRYPOINT ["dotnet", "backend.dll"] +COPY --from=build /app/ . \ No newline at end of file diff --git a/backend/DrawablesProcessor.cs b/backend/DrawablesProcessor.cs index c842699..2c7802e 100644 --- a/backend/DrawablesProcessor.cs +++ b/backend/DrawablesProcessor.cs @@ -11,7 +11,8 @@ public class DrawablesProcessor { private DataStorage _dataStorage; - public DrawablesProcessor(DataStorage dataStorage){ + public DrawablesProcessor(DataStorage dataStorage) + { _dataStorage = dataStorage; ProcessData(); @@ -23,27 +24,30 @@ public DrawablesProcessor(DataStorage dataStorage, string test) _dataStorage = dataStorage; } - public void ProcessData() + public void ProcessData() { - + ProcessServers(); ProcessClusters(); ProcessLinks(); ProcessLeafs(); + ProcessTreeNode(); // Patch for a missing node from varz // TODO dynamically handle these types of errors - foreach(var entry in _dataStorage.serverToMissingServer) + foreach (var entry in _dataStorage.serverToMissingServer) { var source = entry.Key; foreach (var target in entry.Value) { - var node = new ServerNode { + var node = new ServerNode + { server_id = target, server_name = "Unknown name", ntv_error = true }; - var cluster = _dataStorage.processedClusters.Where(c => c.ContainsServer(source)).Select(c => c).FirstOrDefault(); + var cluster = _dataStorage.processedClusters.Where(c => c.ContainsServer(source)).Select(c => c) + .FirstOrDefault(); if (cluster is null) continue; if (cluster.ContainsServer(target)) continue; _dataStorage.processedServers.Add(node); @@ -51,7 +55,8 @@ public void ProcessData() } } - foreach(var cluster in _dataStorage.processedClusters) { + foreach (var cluster in _dataStorage.processedClusters) + { foreach (var server in cluster.servers) { server.ntv_cluster = cluster.name; @@ -83,6 +88,7 @@ public void ProcessLeafs() } } } + ConstructSingleLeafConnections(); } @@ -99,12 +105,12 @@ public void ConstructSingleLeafConnections() var targetId = _dataStorage.ipToServerId[leaf.ip]; var oppositeLink = _dataStorage.leafLinks.Where(l => - l.source == targetId && + l.source == targetId && l.target == server.server_id ).Select(l => l).FirstOrDefault(); var identicalLink = _dataStorage.leafLinks.Where(l => - l.target == targetId && + l.target == targetId && l.source == server.server_id ).Select(l => l).FirstOrDefault(); @@ -114,7 +120,7 @@ public void ConstructSingleLeafConnections() } else if (oppositeLink is null) { - var link = new LeafLink ( + var link = new LeafLink( server.server_id, targetId ); @@ -125,7 +131,7 @@ public void ConstructSingleLeafConnections() { oppositeLink.connections.Add(leaf); } - + } } } @@ -139,13 +145,15 @@ public void ProcessClusters() { if (markedServers.Contains(server.server_id)) continue; // Probably only once for each cluster - var cluster = new ClusterNode { + var cluster = new ClusterNode + { name = "cluster nr:" + id, servers = new ConcurrentBag() }; id++; - ServerNode processedServer = _dataStorage.processedServers.Where(p => p.server_id == server.server_id).Select(p => p).FirstOrDefault(); + ServerNode processedServer = _dataStorage.processedServers.Where(p => p.server_id == server.server_id) + .Select(p => p).FirstOrDefault(); if (processedServer is null) continue; cluster.servers.Add(processedServer); markedServers.Add(server.server_id); @@ -155,18 +163,27 @@ public void ProcessClusters() if (markedServers.Contains(route.remote_id)) continue; markedServers.Add(route.remote_id); - processedServer = _dataStorage.processedServers.Where(p => p.server_id == route.remote_id).Select(p => p).FirstOrDefault(); + processedServer = _dataStorage.processedServers.Where(p => p.server_id == route.remote_id) + .Select(p => p).FirstOrDefault(); if (processedServer is null) continue; cluster.servers.Add(processedServer); markedServers.Add(server.server_id); - }; + } + + ; _dataStorage.processedClusters.Add(cluster); } constructClustersOfBrokenGateways(); - + detectGatewaysToCrashedServers(); + + constructSingleGatewayLinks(); + } + + public void constructSingleGatewayLinks() + { foreach (var connection in _dataStorage.clusterConnectionErrors) { var tuple = stringToTuple(connection.Key); @@ -177,13 +194,32 @@ public void ProcessClusters() if (gateway.name != source && gateway.name != target) continue; if (source == target) continue; if (gateway.name == target) continue; - if (!gateway.outbound_gateways.ContainsKey(target) /*|| !gateway.outbound_gateways.ContainsKey(source)*/) - { // TODO tjek hvilken cluster det er til og fra - connection.Value.Add("Missing gateway from cluster " + gateway.name + " to cluster " + target + " for server " + gateway.server_id); + if (!gateway.outbound_gateways + .ContainsKey(target) /*|| !gateway.outbound_gateways.ContainsKey(source)*/) + { + // TODO tjek hvilken cluster det er til og fra + connection.Value.Add("Missing gateway from cluster " + gateway.name + " to cluster " + target + + " for server " + gateway.server_id); } } } + + foreach (var cluster in _dataStorage.clusterConnectionErrors) + { + var split = cluster.Key.Split(" NAMESPLIT "); + var source = split[0]; + var target = split[1]; + var link = new GatewayLink(source, target, cluster.Value.Count > 0); + link.errors = cluster.Value; + foreach (var err in cluster.Value) + { + link.errorsAsString += "\n" + err; + } + + _dataStorage.gatewayLinks.Add(link); + } } + public void ProcessLinks() { // Information about routes are also on server, no request to routez necessary @@ -198,7 +234,7 @@ public void ProcessLinks() } } - foreach (var link in _dataStorage.links) + foreach (var link in _dataStorage.links) { if (!_dataStorage.idToServer.ContainsKey(link.target)) { @@ -220,96 +256,116 @@ public void ProcessLinks() public void ProcessServers() { // Add serverNodes to processedServers - foreach (var server in _dataStorage.servers) { + foreach (var server in _dataStorage.servers) + { _dataStorage.foundServers.Add(server.server_id); - _dataStorage.processedServers.Add(new ServerNode { - server_id = server.server_id, - server_name = server.server_name, + _dataStorage.processedServers.Add(new ServerNode + { + server_id = server.server_id, + server_name = server.server_name, ntv_error = false, clients = new ConcurrentBag() }); } // Add connections to servers - Parallel.ForEach(_dataStorage.connections, server => { - Parallel.ForEach(server.connections, connection => { - var processedServer = _dataStorage.processedServers.Where(p => p.server_id == server.server_id).Select(p => p).FirstOrDefault(); - if (processedServer != null) + Parallel.ForEach(_dataStorage.connections, server => + { + Parallel.ForEach(server.connections, connection => + { + var processedServer = _dataStorage.processedServers.Where(p => p.server_id == server.server_id) + .Select(p => p).FirstOrDefault(); + if (processedServer != null) { - processedServer.clients.Add(new ConnectionNode{ip = connection.ip, port = connection.port}); + processedServer.clients.Add(new ConnectionNode {ip = connection.ip, port = connection.port}); } }); }); } - + public string tupleString(string id1, string id2) { return id1 + " NAMESPLIT " + id2; } - public (string, string) stringToTuple (string input) + public (string, string) stringToTuple(string input) { var split = input.Split(" NAMESPLIT "); return (split[0], split[1]); } - public void detectGatewaysToCrashedServers() { + public void detectGatewaysToCrashedServers() + { foreach (var gateway in _dataStorage.gateways) { if (gateway.name is null) continue; foreach (var outbound in gateway.outbound_gateways) { - if (!_dataStorage.clusterConnectionErrors.ContainsKey(tupleString(gateway.name, outbound.Key)) && !_dataStorage.clusterConnectionErrors.ContainsKey(tupleString(outbound.Key, gateway.name))) + if (!_dataStorage.clusterConnectionErrors.ContainsKey(tupleString(gateway.name, outbound.Key)) && + !_dataStorage.clusterConnectionErrors.ContainsKey(tupleString(outbound.Key, gateway.name))) { - _dataStorage.clusterConnectionErrors.Add(tupleString(gateway.name, outbound.Key), new List()); + _dataStorage.clusterConnectionErrors.Add(tupleString(gateway.name, outbound.Key), + new List()); } + if (!_dataStorage.idToServer.ContainsKey(outbound.Value.connection.name)) { - _dataStorage.clusterConnectionErrors[tupleString(gateway.name, outbound.Key)].Add("Outbound gateway to crashed server. From " + gateway.server_id + " to " + outbound.Value.connection.name); + _dataStorage.clusterConnectionErrors[tupleString(gateway.name, outbound.Key)].Add( + "Outbound gateway to crashed server. From " + gateway.server_id + " to " + + outbound.Value.connection.name); } } + foreach (var inbound in gateway.inbound_gateways) { - if (!_dataStorage.clusterConnectionErrors.ContainsKey(tupleString(gateway.name, inbound.Key)) && !_dataStorage.clusterConnectionErrors.ContainsKey(tupleString(inbound.Key, gateway.name))) + if (!_dataStorage.clusterConnectionErrors.ContainsKey(tupleString(gateway.name, inbound.Key)) && + !_dataStorage.clusterConnectionErrors.ContainsKey(tupleString(inbound.Key, gateway.name))) { - _dataStorage.clusterConnectionErrors.Add(tupleString(gateway.name, inbound.Key), new List()); + _dataStorage.clusterConnectionErrors.Add(tupleString(gateway.name, inbound.Key), + new List()); } + foreach (var inboundEntry in inbound.Value) { if (!_dataStorage.idToServer.ContainsKey(inboundEntry.connection.name)) { - _dataStorage.clusterConnectionErrors[tupleString(gateway.name, inbound.Key)].Add("Inbound gateway to crashed server. To " + gateway.server_id + " from " + inboundEntry.connection.name); + _dataStorage.clusterConnectionErrors[tupleString(gateway.name, inbound.Key)] + .Add("Inbound gateway to crashed server. To " + gateway.server_id + " from " + + inboundEntry.connection.name); } - + } } } } - public void detectLeafConnections () + public void detectLeafConnections() { foreach (var leafLink in _dataStorage.leafLinks) { - if (! _dataStorage.leafConnections.Contains(tupleString(leafLink.source, leafLink.target))) + if (!_dataStorage.leafConnections.Contains(tupleString(leafLink.source, leafLink.target))) { - if (! _dataStorage.leafConnections.Contains(tupleString(leafLink.target, leafLink.source))) + if (!_dataStorage.leafConnections.Contains(tupleString(leafLink.target, leafLink.source))) { - _dataStorage.leafConnections.Add(tupleString(leafLink.source, leafLink.target)); //<-- only one leaf connection is shown + _dataStorage.leafConnections.Add(tupleString(leafLink.source, + leafLink.target)); //<-- only one leaf connection is shown continue; } } - if (! _dataStorage.leafConnections.Contains(tupleString(leafLink.target, leafLink.source))) + if (!_dataStorage.leafConnections.Contains(tupleString(leafLink.target, leafLink.source))) { - if (! _dataStorage.leafConnections.Contains(tupleString(leafLink.source, leafLink.target))) + if (!_dataStorage.leafConnections.Contains(tupleString(leafLink.source, leafLink.target))) { - _dataStorage.leafConnections.Add(tupleString(leafLink.target, leafLink.source)); //<-- only one leaf connection is shown - + _dataStorage.leafConnections.Add(tupleString(leafLink.target, + leafLink.source)); //<-- only one leaf connection is shown + continue; } } } - } + } + public void constructClustersOfBrokenGateways() { foreach (var gateway in _dataStorage.gateways) @@ -321,10 +377,12 @@ public void constructClustersOfBrokenGateways() { if (!_dataStorage.foundServers.Contains(server.connection.name)) { - var clusterToAddTo = _dataStorage.errorClusters.Where(c => c.name == clusterName).Select(c => c).FirstOrDefault(); - + var clusterToAddTo = _dataStorage.errorClusters.Where(c => c.name == clusterName) + .Select(c => c).FirstOrDefault(); - var node = new ServerNode { + + var node = new ServerNode + { server_id = server.connection.name, server_name = "Unknown name", ntv_error = true, @@ -333,14 +391,15 @@ public void constructClustersOfBrokenGateways() if (clusterToAddTo is null) { - var newCluster = new ClusterNode { + var newCluster = new ClusterNode + { name = clusterName, servers = new ConcurrentBag() }; newCluster.servers.Add(node); _dataStorage.errorClusters.Add(newCluster); } - else + else { clusterToAddTo.servers.Add(node); } @@ -356,30 +415,34 @@ public void constructClustersOfBrokenGateways() var clusterName = outbound.Key; if (!_dataStorage.foundServers.Contains(outbound.Value.connection.name)) { - var clusterToAddTo = _dataStorage.errorClusters.Where(c => c.name == clusterName).Select(c => c).FirstOrDefault(); - - var node = new ServerNode { - server_id = outbound.Value.connection.name, - server_name = "Unknown name", - ntv_error = true, - clients = new ConcurrentBag() - }; + var clusterToAddTo = _dataStorage.errorClusters.Where(c => c.name == clusterName).Select(c => c) + .FirstOrDefault(); - if (clusterToAddTo is null) - { - var newCluster = new ClusterNode { - name = clusterName, - servers = new ConcurrentBag() - }; - newCluster.servers.Add(node); - _dataStorage.errorClusters.Add(newCluster); - } - else + var node = new ServerNode + { + server_id = outbound.Value.connection.name, + server_name = "Unknown name", + ntv_error = true, + clients = new ConcurrentBag() + }; + + if (clusterToAddTo is null) + { + var newCluster = new ClusterNode { - clusterToAddTo.servers.Add(node); - } - _dataStorage.processedServers.Add(node); - _dataStorage.foundServers.Add(outbound.Value.connection.name); + name = clusterName, + servers = new ConcurrentBag() + }; + newCluster.servers.Add(node); + _dataStorage.errorClusters.Add(newCluster); + } + else + { + clusterToAddTo.servers.Add(node); + } + + _dataStorage.processedServers.Add(node); + _dataStorage.foundServers.Add(outbound.Value.connection.name); } } @@ -390,10 +453,227 @@ public void constructClustersOfBrokenGateways() cluster.name = gateway.name; } } + foreach (var cluster in _dataStorage.errorClusters) { _dataStorage.processedClusters.Add(cluster); } } + + public void ProcessTreeNode() + { + HashSet used_servers = new HashSet(); + + List test = new List(); + + Dictionary cluster_toId = new Dictionary(); + + UF uf = new UF(_dataStorage.processedClusters.Count); + + var count = 0; + foreach (var cluster in _dataStorage.processedClusters) + { + Console.WriteLine(cluster.name); + cluster_toId.Add(cluster.name, count++); + } + + foreach (var item in _dataStorage.gatewayLinks) + { + var p = cluster_toId[item.source]; + var q = cluster_toId[item.target]; + + uf.union(p, q); + } + + Dictionary> idTo_supercluster = new Dictionary>(); + + var i = 0; + foreach (var item in _dataStorage.processedClusters) + { + if (!idTo_supercluster.ContainsKey(uf.id[i])) + { + idTo_supercluster.Add(uf.id[i], new HashSet()); + } + + var set = idTo_supercluster[uf.id[i]]; + set.Add(item); + + idTo_supercluster.Remove(uf.id[i]); + + idTo_supercluster.Add(uf.id[i], set); + i++; + } + +var counter = 1; + foreach (var Supercluster in idTo_supercluster.Values) + { + + if (Supercluster.Count == 1) { + var ClusterCounter = counter+1; + foreach (var cluster in Supercluster) + { + var clusterTreeNode = new TreeNode + { + name = cluster.name, + id = ClusterCounter++, + pid = 0, + dragDisabled = true, + addTreeNodeDisabled = true, + addLeafNodeDisabled = true, + editNodeDisabled = true, + delNodeDisabled = true, + children = new List(), + }; + + var nodeServerCounter = ClusterCounter+1; + foreach (var server in cluster.servers) + { + used_servers.Add(server.server_id); + var serverTreeNode = new TreeNode + { + name = server.server_name , + id = nodeServerCounter++, + server_id = server.server_id, + pid = ClusterCounter, + dragDisabled = true, + addTreeNodeDisabled = true, + addLeafNodeDisabled = true, + editNodeDisabled = true, + delNodeDisabled = true, + isLeaf = true, + }; + + clusterTreeNode.children.Add(serverTreeNode); + } + test.Add(clusterTreeNode); + } + } + else { + + + var SuperClusterTreeNode = new TreeNode + { + name = "supercluster " + counter, + id = counter++, + pid = 0, + dragDisabled = true, + addTreeNodeDisabled = true, + addLeafNodeDisabled = true, + editNodeDisabled = true, + delNodeDisabled = true, + children = new List(), + }; + test.Add(SuperClusterTreeNode); + + var ClusterCounter = counter+1; + foreach (var cluster in Supercluster) + { + var clusterTreeNode = new TreeNode + { + name = cluster.name, + id = ClusterCounter++, + pid = counter, + dragDisabled = true, + addTreeNodeDisabled = true, + addLeafNodeDisabled = true, + editNodeDisabled = true, + delNodeDisabled = true, + children = new List(), + }; + SuperClusterTreeNode.children.Add(clusterTreeNode); + + var nodeServerCounter = ClusterCounter+1; + foreach (var server in cluster.servers) + { + used_servers.Add(server.server_id); + var serverTreeNode = new TreeNode + { + name = server.server_name , + id = nodeServerCounter++, + server_id = server.server_id, + pid = ClusterCounter, + dragDisabled = true, + addTreeNodeDisabled = true, + addLeafNodeDisabled = true, + editNodeDisabled = true, + delNodeDisabled = true, + isLeaf = true, + }; + + clusterTreeNode.children.Add(serverTreeNode); + } + } + } + } + + //Process servers not in any clusters + foreach (var server in _dataStorage.servers) + { + if(!used_servers.Contains(server.server_id)) { + var soloServerTreeNode = new TreeNode + { + name = server.server_name, + id = counter++, + server_id = server.server_id, + pid = 0, + dragDisabled = true, + addTreeNodeDisabled = true, + addLeafNodeDisabled = true, + editNodeDisabled = true, + delNodeDisabled = true, + isLeaf = true, + }; + used_servers.Add(server.server_id); + test.Add(soloServerTreeNode); + } + } + _dataStorage.treeNodes = test; + } + } + + class UF + { + public int[] id; + private int size; + + + public UF(int n) + { + this.size = n; + id = new int[n]; + for (int i = 0; i < n; i++) + { + id[i] = i; + } + } + + public int find(int p) + { + return id[p]; + } + + public bool connected(int p, int q) + { + return id[p] == id[q]; + } + + public void union(int p, int q) + { + int pID = id[p]; + int qID = id[q]; + + if (pID == qID) + { + return; + } + + for (int i = 0; i < this.size; i++) + { + if (id[i] == pID) + { + id[i] = qID; + } + } + } + } } -} \ No newline at end of file diff --git a/backend/EventParser.cs b/backend/EventParser.cs index 7a0b28b..5be33da 100644 --- a/backend/EventParser.cs +++ b/backend/EventParser.cs @@ -8,7 +8,7 @@ using Env = System.Environment; namespace backend { - class EventParser + public class EventParser { public DataStorage dataStorage; diff --git a/backend/Program.cs b/backend/Program.cs index b953040..2a0879e 100644 --- a/backend/Program.cs +++ b/backend/Program.cs @@ -6,12 +6,21 @@ namespace backend { - class Program + public class Program { public static DateTime dateOfNatsRequest; public static EventParser eventParser; public static DrawablesProcessor drawablesProcessor; private static void Main(string[] args) + { + UpdateData(); + var host = CreateHostBuilder(args).Build(); + + CreateHostBuilder(args).Build().Run(); + host.Run(); + } + + public static void UpdateData() { eventParser = new EventParser(new DataStorage()); eventParser.Parse(); @@ -19,11 +28,6 @@ private static void Main(string[] args) dateOfNatsRequest = DateTime.Now; drawablesProcessor = new DrawablesProcessor(eventParser.dataStorage); - - var host = CreateHostBuilder(args).Build(); - - CreateHostBuilder(args).Build().Run(); - host.Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => diff --git a/backend/Startup.cs b/backend/Startup.cs index 7de9561..5899665 100644 --- a/backend/Startup.cs +++ b/backend/Startup.cs @@ -31,17 +31,24 @@ public void ConfigureServices(IServiceCollection services) c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" }); }); - var AllowedHosts = Configuration.GetSection("CORS:AllowedHosts").Get(); + // var AllowedHosts = Configuration.GetSection("CORS:AllowedHosts").Get(); + var AllowedHosts = new string[] { + "http://localhost:8080", + "https://localhost:8080", + "http://localhost:80", + "https://localhost:80" + }; services.AddCors(options => - { - options.AddPolicy(name: MyAllowSpecificOrigins, - builder => - { - builder.WithOrigins(AllowedHosts); - }); - }); - } + { + options.AddPolicy( + name: MyAllowSpecificOrigins, + builder => { + builder.WithOrigins(AllowedHosts); + } + ); + }); + } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) @@ -50,12 +57,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseDeveloperExceptionPage(); } - else - { - app.UseHsts(); - } - - app.UseHttpsRedirection(); + + app.UsePathBase("/api"); app.UseRouting(); @@ -71,7 +74,8 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseSwagger(); app.UseSwaggerUI(c => { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); + + c.SwaggerEndpoint("/api/swagger/v1/swagger.json", "My API V1"); c.RoutePrefix = string.Empty; }); } diff --git a/backend/dockerCommands.sh b/backend/dockerCommands.sh new file mode 100755 index 0000000..aa08119 --- /dev/null +++ b/backend/dockerCommands.sh @@ -0,0 +1,9 @@ +#dotnet commands + +dotnet publish -o ./publish + +# docker commands build +docker build -t testapp . #include the . # <> is the projectname + +docker run -p 80:80 frontend +docker run -p 81:80 -e NATS_URL=nats://:@:4222/ backend \ No newline at end of file diff --git a/backend/drawables/TreeNode.cs b/backend/drawables/TreeNode.cs new file mode 100644 index 0000000..49b972f --- /dev/null +++ b/backend/drawables/TreeNode.cs @@ -0,0 +1,20 @@ +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace backend.drawables +{ + public class TreeNode + { + public string name { get; set; } + public int id { get; set; } + public string server_id { get; set; } + public int pid { get; set; } + public bool dragDisabled { get; set; } + public bool addTreeNodeDisabled { get; set; } + public bool addLeafNodeDisabled { get; set; } + public bool editNodeDisabled { get; set; } + public bool delNodeDisabled { get; set; } + public bool isLeaf { get; set; } + public List children { get; set; } + } +} \ No newline at end of file diff --git a/backend/helpers/DotEnv.cs b/backend/helpers/DotEnv.cs index 37644bd..5086489 100644 --- a/backend/helpers/DotEnv.cs +++ b/backend/helpers/DotEnv.cs @@ -7,19 +7,19 @@ public static class DotEnv { public static void Load(string filePath) { - if (!File.Exists(filePath)) - throw new Exception(filePath + " file not found"); - - foreach (var line in File.ReadAllLines(filePath)) + if (File.Exists(filePath)) { - var parts = line.Split( - '=', - StringSplitOptions.RemoveEmptyEntries); + foreach (var line in File.ReadAllLines(filePath)) + { + var parts = line.Split( + '=', + StringSplitOptions.RemoveEmptyEntries); - if (parts.Length != 2) - continue; + if (parts.Length != 2) + continue; - Environment.SetEnvironmentVariable(parts[0], parts[1]); + Environment.SetEnvironmentVariable(parts[0], parts[1]); + } } } } diff --git a/package-lock.json b/package-lock.json index 496fb5c..686486c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "node-notifier": ">=8.0.1", "vue": "^2.6.12", "vue-class-component": "^7.2.3", + "vue-json-component": "^0.4.1", "vue-panzoom": "^1.1.6", "vue-property-decorator": "^9.1.2", "vue-router": "^3.2.0", @@ -2101,7 +2102,8 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "dev": true, + "optional": true }, "node_modules/@types/q": { "version": "1.5.4", @@ -2484,211 +2486,15 @@ "@vue/cli-shared-utils": "^4.5.11", "cache-loader": "^4.1.0", "fork-ts-checker-webpack-plugin": "^3.1.1", - "fork-ts-checker-webpack-plugin-v5": "npm:fork-ts-checker-webpack-plugin@^5.0.11", "globby": "^9.2.0", "thread-loader": "^2.1.3", "ts-loader": "^6.2.2", "tslint": "^5.20.1", "webpack": "^4.0.0", "yorkie": "^2.0.0" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/cosmiconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", - "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.7.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/fork-ts-checker-webpack-plugin-v5": { - "name": "fork-ts-checker-webpack-plugin", - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz", - "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - }, - "engines": { - "node": ">=10", - "yarn": ">=1.0.0" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - }, - "engines": { - "node": ">= 8.9.0" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@vue/cli-plugin-typescript/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "dev": true, - "engines": { - "node": ">= 10.0.0" + "optionalDependencies": { + "fork-ts-checker-webpack-plugin-v5": "npm:fork-ts-checker-webpack-plugin@^5.0.11" } }, "node_modules/@vue/cli-plugin-unit-jest": { @@ -2775,7 +2581,6 @@ "thread-loader": "^2.1.3", "url-loader": "^2.2.0", "vue-loader": "^15.9.2", - "vue-loader-v16": "npm:vue-loader@^16.1.0", "vue-style-loader": "^4.1.2", "webpack": "^4.0.0", "webpack-bundle-analyzer": "^3.8.0", @@ -2788,6 +2593,9 @@ }, "engines": { "node": ">=8" + }, + "optionalDependencies": { + "vue-loader-v16": "npm:vue-loader@^16.1.0" } }, "node_modules/@vue/cli-service/node_modules/ansi-styles": { @@ -2795,6 +2603,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "optional": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2807,6 +2616,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "dev": true, + "optional": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2820,6 +2630,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "optional": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2831,13 +2642,15 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "optional": true }, "node_modules/@vue/cli-service/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "optional": true, "engines": { "node": ">=8" } @@ -2847,6 +2660,7 @@ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", "dev": true, + "optional": true, "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -2874,6 +2688,7 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "optional": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -2887,6 +2702,7 @@ "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.2.0.tgz", "integrity": "sha512-TitGhqSQ61RJljMmhIGvfWzJ2zk9m1Qug049Ugml6QP3t0e95o0XJjk29roNEiPKJQBEi8Ord5hFuSuELzSp8Q==", "dev": true, + "optional": true, "dependencies": { "chalk": "^4.1.0", "hash-sum": "^2.0.0", @@ -3623,6 +3439,7 @@ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, + "optional": true, "engines": { "node": ">= 4.0.0" } @@ -7714,78 +7531,292 @@ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "dependencies": { - "find-up": "^4.0.0" + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz", + "integrity": "sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ==", + "dev": true, + "dependencies": { + "babel-code-frame": "^6.22.0", + "chalk": "^2.4.1", + "chokidar": "^3.3.0", + "micromatch": "^3.1.10", + "minimatch": "^3.0.4", + "semver": "^5.6.0", + "tapable": "^1.0.0", + "worker-rpc": "^0.1.0" + }, + "engines": { + "node": ">=6.11.5", + "yarn": ">=1.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin-v5": { + "name": "fork-ts-checker-webpack-plugin", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.1.tgz", + "integrity": "sha512-SVi+ZAQOGbtAsUWrZvGzz38ga2YqjWvca1pXQFUArIVXqli0lLoDQ8uS0wg0kSpcwpZmaW5jVCZXQebkyUQSsw==", + "dev": true, + "optional": true, + "dependencies": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=10", + "yarn": ">=1.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "optional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "optional": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "optional": true + }, + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "dev": true, + "optional": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "optional": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "optional": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "optional": true, + "dependencies": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "optional": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { "node": ">=8" } }, - "node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, + "optional": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "node_modules/follow-redirects": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", - "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==", + "optional": true, "engines": { - "node": ">=4.0" + "node": ">=4" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", "dev": true, + "optional": true, + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 8.9.0" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "optional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/fork-ts-checker-webpack-plugin": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz", - "integrity": "sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ==", + "node_modules/fork-ts-checker-webpack-plugin-v5/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true, - "dependencies": { - "babel-code-frame": "^6.22.0", - "chalk": "^2.4.1", - "chokidar": "^3.3.0", - "micromatch": "^3.1.10", - "minimatch": "^3.0.4", - "semver": "^5.6.0", - "tapable": "^1.0.0", - "worker-rpc": "^0.1.0" - }, + "optional": true, "engines": { - "node": ">=6.11.5", - "yarn": ">=1.0.0" + "node": ">= 10.0.0" } }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/semver": { @@ -7890,7 +7921,8 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", - "dev": true + "dev": true, + "optional": true }, "node_modules/fs-write-stream-atomic": { "version": "1.0.10", @@ -9796,7 +9828,6 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, - "hasInstallScript": true, "optional": true, "os": [ "darwin" @@ -10897,6 +10928,7 @@ "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.2.2.tgz", "integrity": "sha512-RE0CwmIM3CEvpcdK3rZ19BC4E6hv9kADkMN5rPduRak58cNArWLi/9jFLsa4rhsjfVxMP3v0jO7FHXq7SvFY5Q==", "dev": true, + "optional": true, "dependencies": { "fs-monkey": "1.0.3" }, @@ -12159,6 +12191,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "optional": true, "dependencies": { "callsites": "^3.0.0" }, @@ -12171,6 +12204,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "optional": true, "engines": { "node": ">=6" } @@ -14707,9 +14741,6 @@ "dev": true, "dependencies": { "figgy-pudding": "^3.5.1" - }, - "engines": { - "node": ">= 8" } }, "node_modules/stable": { @@ -15135,6 +15166,7 @@ "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", "dev": true, + "optional": true, "engines": { "node": ">=6" } @@ -16304,6 +16336,11 @@ "vue-template-es2015-compiler": "^1.6.0" } }, + "node_modules/vue-json-component": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/vue-json-component/-/vue-json-component-0.4.1.tgz", + "integrity": "sha512-8Tw4C5LJOT09BRKjQx8F5itheP7UIeZtUUJvWnSltb0UFQZSrXw/4B32z3pelWo38MtoglaSmFTYpyxFIWWNRg==" + }, "node_modules/vue-loader": { "version": "15.9.6", "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.9.6.tgz", @@ -16570,7 +16607,6 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, - "hasInstallScript": true, "optional": true, "os": [ "darwin" @@ -16995,7 +17031,6 @@ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", "dev": true, - "hasInstallScript": true, "optional": true, "os": [ "darwin" @@ -17694,6 +17729,7 @@ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, + "optional": true, "engines": { "node": ">= 6" } @@ -20367,63 +20403,6 @@ "webpack-merge": "^4.2.2" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "optional": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "optional": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "optional": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "optional": true - }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "optional": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, "ssri": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.0.tgz", @@ -20433,28 +20412,6 @@ "figgy-pudding": "^3.5.1", "minipass": "^3.1.1" } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "optional": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "vue-loader-v16": { - "version": "npm:vue-loader@16.2.0", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.2.0.tgz", - "integrity": "sha512-TitGhqSQ61RJljMmhIGvfWzJ2zk9m1Qug049Ugml6QP3t0e95o0XJjk29roNEiPKJQBEi8Ord5hFuSuELzSp8Q==", - "dev": true, - "optional": true, - "requires": { - "chalk": "^4.1.0", - "hash-sum": "^2.0.0", - "loader-utils": "^2.0.0" - } } } }, @@ -32035,6 +31992,87 @@ } } }, + "vue-loader-v16": { + "version": "npm:vue-loader@16.2.0", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.2.0.tgz", + "integrity": "sha512-TitGhqSQ61RJljMmhIGvfWzJ2zk9m1Qug049Ugml6QP3t0e95o0XJjk29roNEiPKJQBEi8Ord5hFuSuELzSp8Q==", + "dev": true, + "optional": true, + "requires": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "loader-utils": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "optional": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "optional": true + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "optional": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "vue-numeric": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/vue-numeric/-/vue-numeric-2.4.1.tgz", @@ -32100,6 +32138,11 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "vue-tree-list": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/vue-tree-list/-/vue-tree-list-1.5.0.tgz", + "integrity": "sha512-qHRJtPMmjCYA9I9kpHgIT6F1H7leR1ZxcNETrP2r97otSHYdHdK42qt12t4glf2mNvI+wBpY2fLClUGcaQJnpg==" + }, "vue-zoomer": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/vue-zoomer/-/vue-zoomer-0.3.9.tgz", diff --git a/package.json b/package.json index 3112035..0df75d8 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "serve": "vue-cli-service serve", "test:unit": "vue-cli-service test:unit", "lint": "vue-cli-service lint", - "backend": "dotnet build && dotnet run --project backend/backend.csproj" + "backend": "dotnet build && dotnet run --project backend/backend.csproj", + "build": "vue-cli-service build" }, "repository": { "type": "git", @@ -37,6 +38,7 @@ "vue-panzoom": "^1.1.6", "vue-property-decorator": "^9.1.2", "vue-router": "^3.2.0", + "vue-tree-list": "^1.5.0", "vue-zoomer": "^0.3.9", "yargs-parser": ">=13.1.2" }, diff --git a/src/App.vue b/src/App.vue index d02f3cc..63b5a7d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,27 +1,33 @@ diff --git a/src/components/Refresh.vue b/src/components/Refresh.vue new file mode 100644 index 0000000..0d110bd --- /dev/null +++ b/src/components/Refresh.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/src/components/Searchbar.vue b/src/components/Searchbar.vue index 5ae13bc..9c1ab6b 100644 --- a/src/components/Searchbar.vue +++ b/src/components/Searchbar.vue @@ -26,7 +26,11 @@ export default { onReset () { this.text = '' this.$emit('button-click') + }, + changeText(text){ + this.text = text } + } } @@ -34,6 +38,6 @@ export default { diff --git a/src/components/Statusbar.vue b/src/components/Statusbar.vue index b57ff0a..a54ddb8 100644 --- a/src/components/Statusbar.vue +++ b/src/components/Statusbar.vue @@ -1,27 +1,16 @@  - + + diff --git a/src/main.ts b/src/main.ts index 52c704c..a6b0041 100644 --- a/src/main.ts +++ b/src/main.ts @@ -15,6 +15,10 @@ import JSONView from 'vue-json-component' import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' +import VueTreeList from 'vue-tree-list' + +Vue.use(VueTreeList) + Vue.config.productionTip = false Vue.use(BootstrapVue) diff --git a/tests/backend.Tests/ControllerTest.cs b/tests/backend.Tests/ControllerTest.cs new file mode 100644 index 0000000..2c79761 --- /dev/null +++ b/tests/backend.Tests/ControllerTest.cs @@ -0,0 +1,262 @@ +using System; +using System.Collections.Generic; +using System.Collections.Concurrent; +using System.IO; +using System.Linq; +using Xunit; +using Moq; +using backend; +using backend.drawables; +using backend.models; + +namespace backend.Tests +{ + public class ControllerTest + { + + [Fact] + public void GetNodesTest() + { + + ServerNode testNode = new ServerNode(); + + var mockStorage = new DataStorage() + { + processedServers = { testNode } + }; + + Controller testController = new Controller(mockStorage); + + Assert.Contains(testNode, testController.GetNodes().Value); + } + + [Fact] + public void GetGatewayErrorsTest() + { + var testList = new List(); + + var mockStorage = new DataStorage() + { + clusterConnectionErrors = {{"test", testList}} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetGatewayErrors().Value; + + Assert.Equal(testList, result["test"]); + } + + [Fact] + public void GetClustersTest() + { + var testCluster = new ClusterNode() + { + name = "test", + servers = new ConcurrentBag() + }; + + var mockStorage = new DataStorage() + { + processedClusters = {testCluster} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetClusters().Value; + + Assert.Contains(testCluster, result); + } + + [Fact] + public void GetIpToServerIdTest() + { + var mockStorage = new DataStorage() + { + ipToServerId = {{"test", "1337"}} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetIpToServerId().Value; + + Assert.Equal("1337", result["test"]); + } + + [Fact] + public void GetLeafLinksTest() + { + var leafLink = new LeafLink("origin", "target"); + + var mockStorage = new DataStorage() + { + leafLinks = {leafLink} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetLeafLinks().Value; + + Assert.Contains(leafLink, result); + } + + [Fact] + public void GetGatewayLinksTest() + { + var testGatewayLink = new GatewayLink("test", "test", false); + var mockStorage = new DataStorage() + { + gatewayLinks = {testGatewayLink} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetGatewayLinks().Value; + + Assert.Contains(testGatewayLink, result); + } + + [Fact] + public void GetVarzTest() + { + var testVar = new Server(); + + var mockStorage = new DataStorage() + { + servers = {testVar} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetVarz().Value; + + Assert.Contains(testVar, result); + } + + [Fact] + public void GetVarzSpecificTest() + { + var testVar = new Server() + { + server_id = "1337" + }; + + var mockStorage = new DataStorage() + { + servers = {testVar} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetVarz("1337").Value; + + Assert.Equal(testVar, result); + } + + [Fact] + public void GetVarzSpecificFailsTest() + { + var testVar = new Server() + { + server_id = "1337" + }; + + var mockStorage = new DataStorage() + { + servers = {testVar} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetVarz("1336").Value; + + Assert.Null(result); + } + + [Fact] + public void GetConnzTest() + { + var testConn = new Connection(); + + var mockStorage = new DataStorage() + { + connections = {testConn} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetConnz().Value; + + Assert.Contains(testConn, result); + } + + [Fact] + public void GetLinksTest() + { + var expected = new Link("test", "test", false); + + var mockStorage = new DataStorage() + { + links = {expected} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetLinks().Value; + + Assert.Contains(expected, result); + } + + [Fact] + public void GetRoutezTest() + { + var expected = new Route(); + + var mockStorage = new DataStorage() + { + routes = {expected} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetRoutez().Value; + + Assert.Contains(expected, result); + } + + [Fact] + public void GetGatewayzTest() + { + var expected = new Gateway(); + + var mockStorage = new DataStorage() + { + gateways = {expected} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetGatewayz().Value; + + Assert.Contains(expected, result); + } + + [Fact] + public void GetLeafzTest() + { + var expected = new Leaf(); + + var mockStorage = new DataStorage() + { + leafs = {expected} + }; + + Controller testController = new Controller(mockStorage); + + var result = testController.GetLeafz().Value; + + Assert.Contains(expected, result); + } + + } +} \ No newline at end of file diff --git a/tests/backend.Tests/DrawablesProcessorTests.cs b/tests/backend.Tests/DrawablesProcessorTests.cs index da697ce..33f6f95 100644 --- a/tests/backend.Tests/DrawablesProcessorTests.cs +++ b/tests/backend.Tests/DrawablesProcessorTests.cs @@ -231,7 +231,11 @@ public void ProcessClustersTest() data.foundServers.Add("ijkl"); - var dp = new DrawablesProcessor(data); + var dp = new DrawablesProcessor(data, ""); + dp.ProcessServers(); + dp.ProcessClusters(); + dp.ProcessLinks(); + dp.ProcessLeafs(); Assert.Equal(3, data.clusterConnectionErrors.Count); Assert.Equal(2, data.errorClusters.Count); } diff --git a/tests/backend.Tests/HelperTests.cs b/tests/backend.Tests/HelperTests.cs index 06f0aed..c5a4042 100644 --- a/tests/backend.Tests/HelperTests.cs +++ b/tests/backend.Tests/HelperTests.cs @@ -7,11 +7,6 @@ namespace backend.Tests { public class HelperTests { - [Fact] - public void EnvTest() - { - Assert.Throws(() => DotEnv.Load("")); - } [Fact] public void EnvTestWorks() diff --git a/tests/unit/graph.spec.ts b/tests/unit/graph.spec.ts index ca1dc6f..d1e7309 100644 --- a/tests/unit/graph.spec.ts +++ b/tests/unit/graph.spec.ts @@ -6,8 +6,17 @@ import Methods from '@/components/Graph/Graph.vue' describe('Graph', () => { // Methods set to any because typescript can't figure it out... // Maybe a fix https://github.com/vuejs/vue/issues/8721#issuecomment-545671348 - const graph = mount>>(Graph, {}) - + const graph = mount>>(Graph, { + propsData: { + servers: [], + routes: [], + clusters: [], + gateways: [], + leafs: [], + varz: [], + dataLoaded: true, + } + }) it('Graph contains an svg', () => { expect(graph.find('div#visualizer').exists()).toBe(true)