/* * This file is part of Linode Manager Classic. * * Linode Manager Classic is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Linode Manager Classic is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Linode Manager Classic. If not, see . */ import { settings, elements, apiGet, apiPost, parseParams, regionNames, setupHeader, timeString } from "/global.js"; (function() { // Element names specific to this page elements.backupAge = "backup-age"; elements.backupConfigs = "backup-configs"; elements.backupDate = "backup-date"; elements.backupDisks = "backup-disks"; elements.backupLabel = "backup-label"; elements.backupLocation = "backup-location"; elements.backupSize = "backup-size"; elements.backupType = "backup-type"; elements.destLabel = "dest-label"; elements.destLinodes = "dest-linodes"; elements.destLocation = "dest-location"; elements.destPlan = "dest-plan"; elements.destSpace = "dest-space"; elements.linodeLabel = "linode-label"; elements.linodeTag = "linode-tag"; elements.linodeTagLink = "linode-tag-link"; elements.loading = "loading-linodes"; elements.lmcRow = "lmc-tr3"; elements.newLinode = "new-linode"; elements.restorePrefix = "restore-"; elements.selectPrefix = "select-"; elements.subnav = "subnav-link"; elements.subnavActive = "subnav-link-active"; elements.unallocatedPrefix = "unallocated-"; // Data recieved from API calls var data = {}; data.backup = {}; data.linode = {}; data.linodes = []; data.region = {}; data.types = []; // Static references to UI elements var ui = {}; ui.backupAge = {}; ui.backupConfigs = {}; ui.backupDate = {}; ui.backupDisks = {}; ui.backupLabel = {}; ui.backupLocation = {}; ui.backupSize = {}; ui.backupType = {}; ui.destLabel = {}; ui.destLinodes = {}; ui.destLocation = {}; ui.destPlan = {}; ui.destSpace = {}; ui.linodeLabel = {}; ui.linodeTag = {}; ui.linodeTagLink = {}; ui.loading = {}; ui.newLinode = {}; // Temporary state var state = {}; state.haveTypes = false; // Generate a linode table row var createLinodeRow = function(linode) { var row = document.createElement("tr"); row.className = elements.lmcRow; var label = document.createElement("td"); label.innerHTML = linode.label; row.appendChild(label); var plan = document.createElement("td"); if (linode.type) { plan.innerHTML = linode.type; for (var i = 0; i < data.types.length; i++) { if (data.types[i].id == linode.type) { plan.innerHTML = data.types[i].label; break; } } } else { plan.innerHTML = "Unknown"; } if (plan.innerHTML == "") translatePlan(linode.type, plan); row.appendChild(plan); var location = document.createElement("td"); if (data.region.label && data.region.label.length) location.innerHTML = data.region.label; else if (regionNames[linode.region]) location.innerHTML = regionNames[linode.region]; else location.innerHTML = linode.region; row.appendChild(location); var freeSpace = document.createElement("td"); freeSpace.id = elements.unallocatedPrefix + linode.id; row.appendChild(freeSpace); var select = document.createElement("td"); select.id = elements.selectPrefix + linode.id; row.appendChild(select); return row; }; // Callback for backup details API call var displayBackup = function(response) { data.backup = response; // Populate info table if (data.backup.label) ui.backupLabel.innerHTML = data.backup.label; var now = new Date(); var backupStart = new Date(data.backup.created + "Z"); ui.backupDate.innerHTML = backupStart.toLocaleString(); ui.backupAge.innerHTML = timeString(now - backupStart, true); ui.backupType.innerHTML = data.backup.type; if (regionNames[data.backup.region]) { ui.backupLocation.innerHTML = regionNames[data.backup.region]; ui.destLocation.innerHTML = regionNames[data.backup.region]; } else { ui.backupLocation.innerHTML = data.backup.region; ui.destLocation.innerHTML = data.backup.region; } apiGet("/regions/" + data.backup.region, displayRegion, null); for (var i = 0; i < data.backup.configs.length; i++) { var li = document.createElement("li"); li.innerHTML = data.backup.configs[i]; ui.backupConfigs.appendChild(li); } data.backup.totalSize = 0; for (var i = 0; i < data.backup.disks.length; i++) { data.backup.totalSize += data.backup.disks[i].size; var li = document.createElement("li"); li.innerHTML = data.backup.disks[i].label + " (" + data.backup.disks[i].filesystem + ") – " + data.backup.disks[i].size + "MB"; ui.backupDisks.appendChild(li); } ui.backupSize.innerHTML = data.backup.totalSize + " MB"; if (state.haveTypes) insertTypes(); }; // Callback for linode details API call var displayDetails = function(response) { data.linode = response; // Set page title and header stuff document.title += " // " + data.linode.label; ui.linodeLabel.innerHTML = data.linode.label; if (data.linode.tags.length == 1) { ui.linodeTagLink.href = "/linodes?tag=" + data.linode.tags[0]; ui.linodeTagLink.innerHTML = "(" + data.linode.tags[0] + ")"; ui.linodeTag.style.display = "inline"; } }; // Callback for linode disks API call var displayDisks = function(response) { // Find the linode this response is for var lid = parseInt(response['_endpoint'].split("/")[3]); var index = -1; for (var i = 0; i < data.linodes.length; i++) { if (data.linodes[i].id == lid) { index = i; break; } } if (index == -1) return; // Add disks to array data.linodes[index].disks = data.linodes[index].disks.concat(response.data); // Request the next page if there are more pages if (response.page != response.pages) { apiGet("/linode/instances/" + data.linodes[index].id + "/disks?page=" + (response.page + 1), displayDisks, null); return; } // Calculate Linode's free space var free = data.linodes[index].specs.disk; for (var i = 0; i < data.linodes[index].disks.length; i++) free -= data.linodes[index].disks[i].size; // Update table var freeCell = document.getElementById(elements.unallocatedPrefix + data.linodes[index].id); var selectCell = document.getElementById(elements.selectPrefix + data.linodes[index].id); freeCell.innerHTML = free + " MB"; if (free >= data.backup.totalSize) { var restoreLink = document.createElement("a"); restoreLink.id = elements.restorePrefix + data.linodes[index].id; restoreLink.href = "#"; restoreLink.innerHTML = "Restore to this Linode"; restoreLink.addEventListener("click", handleRestore); selectCell.appendChild(restoreLink); } else { selectCell.innerHTML = "--- not enough free space ---"; } }; // Callback for linodes API call var displayLinodes = function(response) { // Add linodes to array data.linodes = data.linodes.concat(response.data); // Request the next page if there are more pages if (response.page != response.pages) { var filter = { "region": data.backup.region }; apiGet("/linode/instances?page=" + (response.page + 1), displayLinodes, filter); return; } ui.loading.remove(); for (var i = 0; i < data.linodes.length; i++) { // Create row in the table ui.destLinodes.appendChild(createLinodeRow(data.linodes[i])); // Get the linode's disks data.linodes[i].disks = []; apiGet("/linode/instances/" + data.linodes[i].id + "/disks", displayDisks, null); } }; // Callback for region API call var displayRegion = function(response) { data.region = response; if (data.region.label && data.region.label.length) { ui.backupLocation.innerHTML = response.label; ui.destLocation.innerHTML = response.label; } }; // Callback for linode types API call var displayTypes = function(response) { // Add types to array data.types = data.types.concat(response.data); // Request the next page if there are more pages if (response.page != response.pages) { apiGet("/linode/types?page=" + (response.page + 1), displayTypes, null); return; } state.haveTypes = true; if (data.backup.id) insertTypes(); }; // Handler for create linode button var handleCreate = function(event) { if (event.currentTarget.disabled) return; // Find the selected type var index = -1; for (var i = 0; i < data.types.length; i++) { if (data.types[i].id == ui.destPlan.value) { index = i; break; } } if (index == -1) return; if (!confirm("Create a new " + data.types[i].label + " from this backup? This new instance will cost $" + data.types[i].price.monthly.toFixed(2) + " per month and backups will be enabled per your global account setting.")) return; var req = { "label": ui.destLabel.value, "type": ui.destPlan.value, "region": data.backup.region, "backup_id": data.backup.id }; var callback = function(response) { location.href = "/linodes/dashboard?lid=" + response.id; }; apiPost("/linode/instances", req, callback); }; // Handler for backup restore links var handleRestore = function(event) { // Find the linode associated with this link var lid = parseInt(event.currentTarget.id.replace(elements.restorePrefix, "")); var index = -1; for (var i = 0; i < data.linodes.length; i++) { if (data.linodes[i].id == lid) { index = i; break; } } if (index == -1) return; if (!confirm("Restore to Linode " + data.linodes[index].label + "?")) return; var req = { "linode_id": lid, "overwrite": false }; var callback = function(response) { location.href = "/linodes/dashboard?lid=" + lid; }; apiPost("/linode/instances/" + data.params.lid + "/backups/" + data.backup.id + "/restore", req, callback); }; // Insert linode types into selector var insertTypes = function() { for (var i = 0; i < data.types.length; i++) { if (data.types[i].disk < data.backup.totalSize) continue; var option = document.createElement("option"); option.value = data.types[i].id; option.innerHTML = data.types[i].label; ui.destPlan.appendChild(option); } updateSpace(null); ui.newLinode.disabled = false; var filter = { "region": data.backup.region }; apiGet("/linode/instances", displayLinodes, filter); }; // Initial setup var setup = function() { // Parse URL parameters data.params = parseParams(); // We need a Linode ID, so die if we don't have it if (!data.params.lid) { alert("No Linode ID supplied!"); return; } // We also need a backup ID if (!data.params.bid) { alert("No Backup ID supplied!"); return; } setupHeader(); // Update links on page to include proper Linode ID var anchors = document.getElementsByTagName("a"); for (var i = 0; i < anchors.length; i++) anchors[i].href = anchors[i].href.replace("lid=0", "lid=" + data.params.lid); // Highlight the backups subnav link var subnavLinks = document.getElementsByClassName(elements.subnav); for (var i = 0; i < subnavLinks.length; i++) { if (subnavLinks[i].pathname == "/linodes/backups") subnavLinks[i].className += " " + elements.subnavActive; } // Get element references ui.backupAge = document.getElementById(elements.backupAge); ui.backupConfigs = document.getElementById(elements.backupConfigs); ui.backupDate = document.getElementById(elements.backupDate); ui.backupDisks = document.getElementById(elements.backupDisks); ui.backupLabel = document.getElementById(elements.backupLabel); ui.backupLocation = document.getElementById(elements.backupLocation); ui.backupSize = document.getElementById(elements.backupSize); ui.backupType = document.getElementById(elements.backupType); ui.destLabel = document.getElementById(elements.destLabel); ui.destLinodes = document.getElementById(elements.destLinodes); ui.destLocation = document.getElementById(elements.destLocation); ui.destPlan = document.getElementById(elements.destPlan); ui.destSpace = document.getElementById(elements.destSpace); ui.linodeLabel = document.getElementById(elements.linodeLabel); ui.linodeTag = document.getElementById(elements.linodeTag); ui.linodeTagLink = document.getElementById(elements.linodeTagLink); ui.loading = document.getElementById(elements.loading); ui.newLinode = document.getElementById(elements.newLinode); // Register event handlers ui.destPlan.addEventListener("input", updateSpace); ui.newLinode.addEventListener("click", handleCreate); // Get data from API apiGet("/linode/instances/" + data.params.lid, displayDetails, null); apiGet("/linode/instances/" + data.params.lid + "/backups/" + data.params.bid, displayBackup, null); apiGet("/linode/types", displayTypes, null); }; // Update the given element with the given type's label var translatePlan = function(type, el) { var callback = function(response) { el.innerHTML = response.label; }; apiGet("/linode/types/" + type, callback, null); }; // Update the price display var updateSpace = function(event) { // Find the selected type var type = null; for (var i = 0; i < data.types.length; i++) { if (data.types[i].id == ui.destPlan.value) { type = data.types[i]; break; } } if (!type) return; ui.destSpace.innerHTML = type.disk; }; // Attach onload handler window.addEventListener("load", setup); })();