|
@@ -1,7 +1,7 @@
|
|
|
<div class="standardContainer">
|
|
|
<button onclick="exitToGanList();" class="ui large circular black icon button"><i class="angle left icon"></i></button>
|
|
|
<div style="max-width: 300px; margin-top: 1em;">
|
|
|
- <button onclick='$("#gannetDetailEdit").toggle();' class="ui mini basic right floated circular icon button" style="display: inline-block; margin-top: 2.5em;"><i class="ui edit icon"></i></button>
|
|
|
+ <button onclick='$("#gannetDetailEdit").slideToggle("fast");' class="ui mini basic right floated circular icon button" style="display: inline-block; margin-top: 2.5em;"><i class="ui edit icon"></i></button>
|
|
|
<h1 class="ui header">
|
|
|
<span class="ganetID"></span>
|
|
|
<div class="sub header ganetName"></div>
|
|
@@ -21,28 +21,152 @@
|
|
|
<label>Network Description</label>
|
|
|
<textarea id="gaNetDescInput" style="resize: none;"></textarea>
|
|
|
<button onclick="saveNameAndDesc(this);" class="ui basic right floated button" style="margin-top: 0.6em;"><i class="ui save icon"></i> Save</button>
|
|
|
+ <button onclick='$("#gannetDetailEdit").slideUp("fast");' class="ui basic right floated button" style="margin-top: 0.6em;"><i class="ui red remove icon"></i> Cancel</button>
|
|
|
</div>
|
|
|
- <div class="field">
|
|
|
- <table class="ui very basic collapsing celled table">
|
|
|
- <tbody>
|
|
|
- <tr>
|
|
|
- <td>
|
|
|
-
|
|
|
- </td>
|
|
|
- <td>
|
|
|
-
|
|
|
- </td>
|
|
|
- </tr>
|
|
|
- </tbody>
|
|
|
- </table>
|
|
|
+ </div>
|
|
|
+ <div class="ui divider"></div>
|
|
|
+ <h2>Settings</h2>
|
|
|
+ <div class="" style="overflow-x: auto;">
|
|
|
+ <table class="ui basic celled unstackable table" style="min-width: 560px;">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th colspan="4">IPv4 Auto-Assign</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody id="ganetRangeTable">
|
|
|
+
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ <div class="ui basic segment form">
|
|
|
+ <div class="unstackable fields">
|
|
|
+ <div class="ten wide field">
|
|
|
+ <label>Multicast Recipient Limit</label>
|
|
|
+ <input type="number" id="" placeholder="32" value="32">
|
|
|
+ </div>
|
|
|
+ <div class="six wide field">
|
|
|
+ <div class="ui toggle checkbox" style="margin-top: 2.3em; padding-left: 0.6em;">
|
|
|
+ <label>Enable Multicast</label>
|
|
|
+ <input type="checkbox" tabindex="0" class="hidden">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+
|
|
|
<div class="ui divider"></div>
|
|
|
+ <h2>Members</h2>
|
|
|
+ <div class="ui checkbox" style="margin-bottom: 1em;">
|
|
|
+ <input id="showUnauthorizedMembers" type="checkbox" onchange="changeUnauthorizedVisibility(this.checked);">
|
|
|
+ <label>Show Unauthorized Members</label>
|
|
|
+ </div>
|
|
|
+ <div class="" style="overflow-x: auto;">
|
|
|
+ <table class="ui celled unstackable table">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th>Auth</th>
|
|
|
+ <th>Address</th>
|
|
|
+ <th>Name/Description</th>
|
|
|
+ <th>Managed IP</th>
|
|
|
+ <th>Last Seen</th>
|
|
|
+ <th>Version</th>
|
|
|
+ <th>Remove</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody id="networkMemeberTable">
|
|
|
+ <tr>
|
|
|
+
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
<br><br>
|
|
|
</div>
|
|
|
<script>
|
|
|
+ $(".checkbox").checkbox();
|
|
|
var currentGANetID = "";
|
|
|
+ var currentGANNetMemeberListener = undefined;
|
|
|
var currentGaNetDetails = {};
|
|
|
+ var currentGANMemberList = [];
|
|
|
+ var netRanges = {
|
|
|
+ "10.147.17.*": "10.147.17.0/24",
|
|
|
+ "10.147.18.*": "10.147.18.0/24",
|
|
|
+ "10.147.19.*": "10.147.19.0/24",
|
|
|
+ "10.147.20.*": "10.147.20.0/24",
|
|
|
+ "10.144.*.*": "10.144.0.0/16",
|
|
|
+ "10.241.*.*": "10.241.0.0/16",
|
|
|
+ "10.242.*.*": "10.242.0.0/16",
|
|
|
+ "10.243.*.*": "10.243.0.0/16",
|
|
|
+ "10.244.*.*": "10.244.0.0/16",
|
|
|
+ "172.22.*.*": "172.22.0.0/15",
|
|
|
+ "172.23.*.*": "172.23.0.0/16",
|
|
|
+ "172.24.*.*": "172.24.0.0/14",
|
|
|
+ "172.25.*.*": "172.25.0.0/16",
|
|
|
+ "172.26.*.*": "172.26.0.0/15",
|
|
|
+ "172.27.*.*": "172.27.0.0/16",
|
|
|
+ "172.28.*.*": "172.28.0.0/15",
|
|
|
+ "172.29.*.*": "172.29.0.0/16",
|
|
|
+ "172.30.*.*": "172.30.0.0/15",
|
|
|
+ "192.168.191.*": "192.168.191.0/24",
|
|
|
+ "192.168.192.*": "192.168.192.0/24",
|
|
|
+ "192.168.193.*": "192.168.193.0/24",
|
|
|
+ "192.168.194.*": "192.168.194.0/24",
|
|
|
+ "192.168.195.*": "192.168.195.0/24",
|
|
|
+ "192.168.196.*": "192.168.196.0/24"
|
|
|
+ }
|
|
|
+
|
|
|
+ function generateIPRangeTable(netRanges) {
|
|
|
+ $("#ganetRangeTable").empty();
|
|
|
+ const tableBody = document.getElementById('ganetRangeTable');
|
|
|
+ const cidrs = Object.values(netRanges);
|
|
|
+
|
|
|
+ // Set the number of rows and columns to display in the table
|
|
|
+ const numRows = 6;
|
|
|
+ const numCols = 4;
|
|
|
+
|
|
|
+ let row = document.createElement('tr');
|
|
|
+ let col = 0;
|
|
|
+ for (let i = 0; i < cidrs.length; i++) {
|
|
|
+ if (col >= numCols) {
|
|
|
+ tableBody.appendChild(row);
|
|
|
+ row = document.createElement('tr');
|
|
|
+ col = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ const td = document.createElement('td');
|
|
|
+ td.setAttribute('class', `clickable iprange`);
|
|
|
+ td.setAttribute('CIDR', cidrs[i]);
|
|
|
+ td.innerHTML = cidrs[i];
|
|
|
+ let thisCidr = cidrs[i];
|
|
|
+ td.onclick = function(){
|
|
|
+ selectNetworkRange(thisCidr);
|
|
|
+ };
|
|
|
+
|
|
|
+ row.appendChild(td);
|
|
|
+ col++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Add any remaining cells to the table
|
|
|
+ if (col > 0) {
|
|
|
+ for (let i = col; i < numCols; i++) {
|
|
|
+ row.appendChild(document.createElement('td'));
|
|
|
+ }
|
|
|
+ tableBody.appendChild(row);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function highlightCurrentGANetCIDR(){
|
|
|
+ var currentCIDR = currentGaNetDetails.routes[0].target;
|
|
|
+ $(".iprange").each(function(){
|
|
|
+ if ($(this).attr("CIDR") == currentCIDR){
|
|
|
+ $(this).addClass("active");
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ function selectNetworkRange(cidr){
|
|
|
+ alert(cidr);
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
function saveNameAndDesc(object=undefined){
|
|
|
var name = $("#gaNetNameInput").val();
|
|
@@ -82,11 +206,192 @@
|
|
|
});
|
|
|
}
|
|
|
|
|
|
+ function initNetDetails(){
|
|
|
+ //Get the details of the net
|
|
|
+ $.get("/api/gan/network/list?netid=" + currentGANetID, function(data){
|
|
|
+ if (data.error !== undefined){
|
|
|
+ msgbox(data.error, false, 6000);
|
|
|
+ }else{
|
|
|
+ currentGaNetDetails = data;
|
|
|
+ highlightCurrentGANetCIDR();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ //Member table populate
|
|
|
+ function renderMemeberTable(forceUpdate = false) {
|
|
|
+ $.ajax({
|
|
|
+ url: '/api/gan/members/list?netid=e7dd1ce7bfd3b1f9&detail=true',
|
|
|
+ type: 'GET',
|
|
|
+ success: function(data) {
|
|
|
+ const tableBody = $('#networkMemeberTable');
|
|
|
+ data.sort((a, b) => a.address.localeCompare(b.address));
|
|
|
+ //Check if the new object equal to the old one
|
|
|
+ if (objectEqual(currentGANMemberList, data) && !forceUpdate){
|
|
|
+ //Do not need to update it
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ tableBody.empty();
|
|
|
+ currentGANMemberList = data;
|
|
|
+
|
|
|
+ data.forEach((member) => {
|
|
|
+ let lastAuthTime = new Date(member.lastAuthorizedTime).toLocaleString();
|
|
|
+ if (member.lastAuthorizedTime == 0){
|
|
|
+ lastAuthTime = "Never";
|
|
|
+ }
|
|
|
+
|
|
|
+ let version = `${member.vMajor}.${member.vMinor}.${member.vProto}.${member.vRev}`;
|
|
|
+ if (member.vMajor == -1){
|
|
|
+ version = "Unknown";
|
|
|
+ }
|
|
|
+
|
|
|
+ let authorizedCheckbox = `<div class="ui fitted checkbox">
|
|
|
+ <input type="checkbox" addr="${member.address}" name="isAuthrozied" onchange="handleMemberAuth(this);">
|
|
|
+ <label></label>
|
|
|
+ </div>`;
|
|
|
+ if (member.authorized){
|
|
|
+ authorizedCheckbox = `<div class="ui fitted checkbox">
|
|
|
+ <input type="checkbox" addr="${member.address}" name="isAuthrozied" onchange="handleMemberAuth(this);" checked="">
|
|
|
+ <label></label>
|
|
|
+ </div>`
|
|
|
+ }
|
|
|
+
|
|
|
+ let rowClass = "authorized";
|
|
|
+ let unauthorizedStyle = "";
|
|
|
+ if (!$("#showUnauthorizedMembers")[0].checked && !member.authorized){
|
|
|
+ unauthorizedStyle = "display:none;";
|
|
|
+ }
|
|
|
+ if (!member.authorized){
|
|
|
+ rowClass = "unauthorized"
|
|
|
+ }
|
|
|
+ const row = $(`<tr class="GANetMemberEntity ${rowClass}" style="${unauthorizedStyle}">`);
|
|
|
+ row.append($(`<td class="GANetMember ${rowClass}" style="text-align: center;">`).html(authorizedCheckbox));
|
|
|
+ row.append($('<td>').text(member.address));
|
|
|
+ row.append($('<td>').text(""));
|
|
|
+ row.append($('<td>').text(member.ipAssignments || ''));
|
|
|
+ row.append($('<td>').text(lastAuthTime));
|
|
|
+ row.append($('<td>').text(version));
|
|
|
+ row.append($(`<td style="text-align: center;" onclick="handleMemberDelete('${member.address}');">`).html(`<button class="ui basic mini icon button"><i class="red remove icon"></i></button>`));
|
|
|
+
|
|
|
+ tableBody.append(row);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ error: function(xhr, status, error) {
|
|
|
+ console.log('Error:', error);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ function objectEqual(obj1, obj2) {
|
|
|
+ // compare types
|
|
|
+ if (typeof obj1 !== typeof obj2) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // compare values
|
|
|
+ if (typeof obj1 !== 'object' || obj1 === null) {
|
|
|
+ return obj1 === obj2;
|
|
|
+ }
|
|
|
+
|
|
|
+ const keys1 = Object.keys(obj1);
|
|
|
+ const keys2 = Object.keys(obj2);
|
|
|
+
|
|
|
+ // compare keys
|
|
|
+ if (keys1.length !== keys2.length) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const key of keys1) {
|
|
|
+ if (!keys2.includes(key)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // recursively compare values
|
|
|
+ if (!objectEqual(obj1[key], obj2[key])) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ function changeUnauthorizedVisibility(visable){
|
|
|
+ if(visable){
|
|
|
+ $(".GANetMemberEntity.unauthorized").show();
|
|
|
+ }else{
|
|
|
+ $(".GANetMemberEntity.unauthorized").hide();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function handleMemberAuth(object){
|
|
|
+ let targetMemberAddr = $(object).attr("addr");
|
|
|
+ let isAuthed = object.checked;
|
|
|
+ $.ajax({
|
|
|
+ url: "/api/gan/members/authorize",
|
|
|
+ method: "POST",
|
|
|
+ data: {
|
|
|
+ netid:currentGANetID,
|
|
|
+ memid: targetMemberAddr,
|
|
|
+ auth: isAuthed
|
|
|
+ },
|
|
|
+ success: function(data){
|
|
|
+ if (data.error != undefined){
|
|
|
+ msgbox(data.error, false, 6000);
|
|
|
+ }else{
|
|
|
+ if (isAuthed){
|
|
|
+ msgbox("Member Authorized");
|
|
|
+ }else{
|
|
|
+ msgbox("Member Deauthorized");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ renderMemeberTable(true);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ function handleMemberDelete(addr){
|
|
|
+ if (confirm("Confirm delete member " + addr + " ?")){
|
|
|
+ $.ajax({
|
|
|
+ url: "/api/gan/members/delete",
|
|
|
+ method: "POST",
|
|
|
+ data: {
|
|
|
+ netid:currentGANetID,
|
|
|
+ memid: addr,
|
|
|
+ },
|
|
|
+ success: function(data){
|
|
|
+ if (data.error != undefined){
|
|
|
+ msgbox(data.error, false, 6000);
|
|
|
+ }else{
|
|
|
+ msgbox("Member Deleted");
|
|
|
+ }
|
|
|
+ renderMemeberTable(true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
//Entry points
|
|
|
function initGanetDetails(ganetId){
|
|
|
currentGANetID = ganetId;
|
|
|
$(".ganetID").text(ganetId);
|
|
|
initNetNameAndDesc(ganetId);
|
|
|
+ generateIPRangeTable(netRanges);
|
|
|
+ initNetDetails();
|
|
|
+ renderMemeberTable(true);
|
|
|
+
|
|
|
+ //Setup a listener to listen for member list change
|
|
|
+ if (currentGANNetMemeberListener == undefined){
|
|
|
+ currentGANNetMemeberListener = setInterval(function(){
|
|
|
+ if ($('#networkMemeberTable').length > 0 && currentGANetID){
|
|
|
+ renderMemeberTable();
|
|
|
+ }
|
|
|
+ }, 3000);
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
//Exit point
|