diskmg.html 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. <html>
  2. <head>
  3. <meta charset="UTF-8">
  4. <link rel="stylesheet" href="../../../script/tocas/tocas.css">
  5. <script type='text/javascript' src="../../../script/tocas/tocas.js"></script>
  6. <script src="../../../script/jquery.min.js"></script>
  7. <script src="../../../script/ao_module.js"></script>
  8. <title>Diskmg</title>
  9. <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  10. <style>
  11. body{
  12. height: 100%;
  13. }
  14. .customFitted.item{
  15. padding-top:5px !important;
  16. padding-bottom:5px !important;
  17. }
  18. #diskListTable{
  19. max-height:250px !important;
  20. overflow-y: auto;
  21. }
  22. #diskVisualization{
  23. overflow-y:auto;
  24. }
  25. .diskPartTable{
  26. width:100%;
  27. border-bottom:1px solid #9c9c9c;
  28. overflow-x:hidden;
  29. }
  30. .sideblock{
  31. background-color:#f0f0f0;
  32. height:100px;
  33. width:100px;
  34. padding:8px;
  35. /*
  36. border-right:1px solid #9c9c9c;
  37. */
  38. font-size:90%;
  39. display:inline-block;
  40. }
  41. .partitionRepresentation{
  42. border:1px solid #e8e8e8;
  43. display:inline-block;
  44. height:100px;
  45. vertical-align: top;
  46. overflow:hidden;
  47. /*
  48. border-left:1px solid #6e6e6e;
  49. */
  50. cursor:pointer;
  51. }
  52. .partitionTopBar{
  53. background-color:#4287f5;
  54. width:100%;
  55. height:15px;
  56. margin-bottom:3px;
  57. }
  58. .partitionTopBar.unallocate{
  59. background-color:#1f1f1f;
  60. }
  61. .partitionTopBar.unmounted{
  62. background-color:#ab8a29;
  63. }
  64. .partitionDescription{
  65. padding-left:8px;
  66. padding:3px;
  67. }
  68. #rightClickMenu{
  69. position:absolute;
  70. }
  71. .selectable:hover{
  72. background-color:#f0f0f0;
  73. }
  74. .focusedPart{
  75. background-color: #e3f0ff;
  76. }
  77. .disabled{
  78. background-color:#e6e6e6;
  79. color:#787878 !important;
  80. cursor:no-drop !important;
  81. }
  82. .funcmenu{
  83. position:fixed;
  84. top:10%;
  85. right:20%;
  86. left:20%;
  87. bottom:10%;
  88. overflow-y:auto;
  89. z-index:100;
  90. background-color:#f7f7f7;
  91. padding:12px;
  92. display:none;
  93. border: 1px solid #9c9c9c;
  94. }
  95. .functMenuDimmer{
  96. z-index:90;
  97. position:absolute;
  98. width:100%;
  99. height:100%;
  100. left:0px;
  101. top:0px;
  102. background:rgba(48,48,48,0.5);
  103. display:none;
  104. }
  105. .funcmenuBottom{
  106. position:absolute;
  107. width:100%;
  108. bottom:0px;
  109. left:0px;
  110. padding:12px;
  111. }
  112. </style>
  113. </head>
  114. <body>
  115. <div id="diskListTable">
  116. <table class="ts celled striped attached table" style="padding-left:3px;padding-right:3px;">
  117. <thead>
  118. <tr>
  119. <th>
  120. Volume
  121. </th>
  122. <th class="windowsonly" style="display:none;">
  123. Name
  124. </th>
  125. <th class="windowsonly" style="display:none;">
  126. Type
  127. </th>
  128. <th class="linuxonly" style="display:none;">
  129. Mount Point
  130. </th>
  131. <th>
  132. File System
  133. </th>
  134. <th>
  135. Capacity
  136. </th>
  137. <th class="windowsonly" style="display:none;">
  138. Free Space
  139. </th>
  140. <th class="windowsonly" style="display:none;">
  141. % Free
  142. </th>
  143. <th class="linuxonly" style="display:none;">
  144. Used Space
  145. </th>
  146. <th class="linuxonly" style="display:none;">
  147. % Used
  148. </th>
  149. </tr>
  150. </thead>
  151. <tbody id="diskInfoTable">
  152. <tr>
  153. <td class="collapsing">
  154. <i class="disk outline icon"></i>/dev/sda1
  155. </td>
  156. <td class="collapsing">/media/storage1</td>
  157. <td class="right aligned collapsing">NTFS</td>
  158. <td class="right aligned collapsing">64 GB</td>
  159. <td class="right aligned collapsing">12.5 GB</td>
  160. <td class="right aligned collapsing">19.7%</td>
  161. </tr>
  162. </tbody>
  163. </table>
  164. </div>
  165. <div id="diskVisualization">
  166. <div class="diskPartTable">
  167. <div class="sideblock">
  168. <i class="disk outline icon" style="margin-right:0px;font-weight: bold;"></i>
  169. <b style="font-weight: bold;">Drive 0</b><br>
  170. N/A
  171. </div><div class="partitionRepresentation" style="width:calc(100% - 150px);">
  172. <div class="partitionTopBar"></div>
  173. <div class="partitionDescription">
  174. Connecting to Virtual Disk Services
  175. </div>
  176. </div>
  177. </div>
  178. </div>
  179. <div id="rightClickMenu" class="ts contextmenu">
  180. <!--
  181. <div id="openbtn" class="item disabled selectable" onClick="openInFileExplorer(this);">
  182. <i class="folder open icon"></i> Open
  183. </div>
  184. -->
  185. <div id="formatDisk" class="item selectable" onClick="toggleFormatInterface(this);">
  186. <i class="disk outline icon"></i> Format Disk
  187. </div>
  188. <div id="mtbtn" class="item selectable" onClick="toggleMount(this);">
  189. <i class="usb icon"></i> Mount
  190. </div>
  191. </div>
  192. <!-- Sections for functional menus-->
  193. <div id="formatOptions" class="funcmenu">
  194. <div class="ts header">
  195. Disk Format
  196. <div class="sub header" style="font-weight:120%;color:red;">Warning! The format process will wipe all data from the selected partition.</div>
  197. </div>
  198. <div class="ts inverted negative segment">
  199. <p style="font-size:120%;">Danger Zone</p>
  200. <p>Format on any drive or partition will wipe all data within that drive or partition. Please make sure you have backup all necessary files and your drive / partition selection is correct.</p>
  201. </div>
  202. <div class="ts header">
  203. <i class="disk outline icon"></i>
  204. <div id="selectedDiskDisplay" class="content">
  205. /dev/sda1 (120 GB)
  206. </div>
  207. </div>
  208. <div class="ts form">
  209. <div class="field">
  210. <label>Target File System Format</label>
  211. <div class="ts checkboxes">
  212. <div class="ts radio checkbox">
  213. <input id="ext4" type="radio" name="format" checked>
  214. <label for="ext4">EXT4</label>
  215. </div>
  216. <div class="ts radio checkbox">
  217. <input id="ntfs" type="radio" name="format">
  218. <label for="ntfs">NTFS</label>
  219. </div>
  220. <div class="ts radio checkbox">
  221. <input id="vfat" type="radio" name="format">
  222. <label for="vfat">VFAT</label>
  223. </div>
  224. </div>
  225. </div>
  226. </div>
  227. <div class="funcmenuBottom" align="right">
  228. <button class="ts tiny negative button" onClick="formatThisDev();">Format</button>
  229. <button class="ts tiny button" onClick="hideAllFuncMenu();">Close</button>
  230. </div>
  231. </div>
  232. <div id="mountOptions" class="funcmenu">
  233. <div class="ts header">
  234. Disk Mount
  235. <div class="sub header">Select a mount point for this device</div>
  236. </div>
  237. <div id="mtptlist" class="ts segmented list" style="max-height:300px;overflow-y:auto;">
  238. <div class="mountpt item selectable userdefine" onclick="selectThis(this);">
  239. <p>User defined mount point</p>
  240. <div class="ts fluid mini input">
  241. <input id="userDefinedMountPoint" type="text" placeholder="/">
  242. </div>
  243. </div>
  244. </div>
  245. <div class="funcmenuBottom" align="right">
  246. <button class="ts tiny primary button" onClick="mountThisDev();">Mount</button>
  247. <button class="ts tiny button" onClick="hideAllFuncMenu();">Close</button>
  248. </div>
  249. </div>
  250. <!-- dimmers-->
  251. <div id="loaderUI" class="ts active dimmer" style="display:none;">
  252. <div class="ts text loader">Waiting for System Response<br>Do Not Close This Tab</div>
  253. </div>
  254. <div class="functMenuDimmer" onClick="hideAllFuncMenu();">
  255. </div>
  256. <script>
  257. var mode = "linux";
  258. var viewMode = "human"; //Accept {human / raw}
  259. var diskInformation; //Tmp variable for holding disk return results
  260. var displayScaleRatio = 0.1; //Maxium differential ratio, default 0.3, it means the minium disk will show as 70% screen width
  261. var fwmode = false;
  262. var formatPendingDevInfo;
  263. //Init floatWindow events
  264. //It is a submodule inside System Setting, which shouldn't change the window title
  265. /*
  266. if (ao_module_virtualDesktop){
  267. ao_module_setWindowTitle("Disk Manager");
  268. fwmode = true;
  269. }else{
  270. }
  271. */
  272. //Updates Nov 2020, added platform detection
  273. $.get(ao_root + "system/disk/diskmg/platform", function(data){
  274. if (data == "windows"){
  275. mode = "windows";
  276. }else{
  277. mode = "linux"
  278. }
  279. //Init data loading process
  280. initView();
  281. initPartitionTable();
  282. initMountPointList();
  283. })
  284. //Mount pt selection interface
  285. $(".mountpt").on('click',function(e){
  286. $(".selected").removeClass("selected");
  287. $(this).addClass("selected");
  288. });
  289. function hideAllFuncMenu(){
  290. $(".funcmenu").fadeOut('fast');
  291. $(".functMenuDimmer").fadeOut('fast');
  292. }
  293. function initMountPointList(){
  294. $.get(ao_root + "system/disk/diskmg/mpt", function(data){
  295. if (data == null){
  296. //On Windows
  297. return
  298. }
  299. data.forEach(mpt => {
  300. $("#mtptlist").prepend(`<div class="mountpt selectable item" style="cursor:pointer;" onclick="selectThis(this);" ondblclick="mountThisDev(this)">${mpt}</div>`)
  301. });
  302. });
  303. }
  304. function selectThis(object){
  305. $(".selected.selectable.item").removeClass('selected');
  306. $(object).addClass("selected");
  307. }
  308. function formatThisDev(){
  309. var targetFormat = $("input[name='format']:checked").attr("id");
  310. var targetDisk = formatPendingDevInfo;
  311. console.log("Formating Disk: " + targetDisk + " to " + targetFormat);
  312. if(targetFormat){
  313. $("#loaderUI").show();
  314. if (confirm("THIS OPERATION WILL WIPE ALL DATA ON /dev/" + targetDisk[0] + ". ARE YOU SURE?")){
  315. $("#formatOptions").fadeOut('fast');
  316. $(".functMenuDimmer").fadeOut('fast');
  317. $.get(ao_root + "system/disk/diskmg/format?dev=" + targetDisk[0] + "&format=" + targetFormat,function(e){
  318. if (e.error !== undefined){
  319. alert(e.error );
  320. }
  321. initView();
  322. initPartitionTable();
  323. $("#loaderUI").hide();
  324. });
  325. }else{
  326. $("#loaderUI").hide();
  327. }
  328. }
  329. }
  330. function toggleFormatInterface(btnObject){
  331. if ($(btnObject).hasClass("disabled") == true){
  332. return;
  333. }
  334. $("#formatOptions").fadeIn('fast');
  335. $(".functMenuDimmer").fadeIn('fast');
  336. hideRightclickMenu();
  337. var diskInfo = $(".focusedPart").attr("metadata");
  338. diskInfo = ao_module_utils.attrToObject(diskInfo);
  339. formatPendingDevInfo = diskInfo;
  340. $("#selectedDiskDisplay").text(diskInfo[0] + " (" + bytesToSize(parseInt(diskInfo[5])) + ") ");
  341. }
  342. function mountThisDev(object=null){
  343. if (object !== null && !$(object).hasClass(".selected.item")){
  344. $(".selected").removeClass("selected");
  345. $(object).addClass("selected");
  346. }
  347. var selectedMpt = $(".selected.item");
  348. var mountPoint = $(selectedMpt).text().trim();
  349. if (selectedMpt.hasClass("userdefine")){
  350. var mountPoint = $("#userDefinedMountPoint").val();
  351. }
  352. $("#loaderUI").show();
  353. $("#mountOptions").fadeOut('fast');
  354. $(".functMenuDimmer").fadeOut('fast');
  355. var diskInfo = $(".focusedPart").attr("metadata");
  356. diskInfo = ao_module_utils.attrToObject(diskInfo);
  357. $.get(ao_root + "system/disk/diskmg/mount?dev=" + diskInfo[0] + "&format=" + diskInfo[2] + "&mnt=" + mountPoint,function(data){
  358. if (data.error != undefined){
  359. $("#loaderUI").hide();
  360. alert(data.error);
  361. return;
  362. }
  363. //Reload the UI
  364. initView();
  365. initPartitionTable();
  366. $("#loaderUI").hide();
  367. });
  368. }
  369. function toggleMount(btnObject){
  370. if ($(btnObject).hasClass("disabled") == true){
  371. return;
  372. }
  373. var diskInfo = $(".focusedPart").attr("metadata");
  374. diskInfo = ao_module_utils.attrToObject(diskInfo);
  375. if (diskInfo[3] == false){
  376. //Mount disk
  377. $("#mountOptions").fadeIn('fast');
  378. $(".functMenuDimmer").fadeIn('fast');
  379. }else{
  380. //Unmount disk
  381. var dev = diskInfo[0];
  382. var mnt = diskInfo[1];
  383. var format = diskInfo[2];
  384. hideRightclickMenu();
  385. $("#loaderUI").show();
  386. $.get(ao_root + "system/disk/diskmg/mount?dev=" + dev + "&format=" + format + "&mnt=" + mnt + "&umount=true",function(data){
  387. console.log(data);
  388. //Reload the UI
  389. initView();
  390. initPartitionTable();
  391. $("#loaderUI").hide();
  392. });
  393. }
  394. hideRightclickMenu();
  395. }
  396. function hideRightclickMenu(){
  397. $("#rightClickMenu").hide();
  398. }
  399. /*
  400. function openInFileExplorer(btnObject){
  401. if ($(btnObject).hasClass('disabled')){
  402. return;
  403. }
  404. var diskInfo = $(".focusedPart").attr("metadata");
  405. diskInfo = ao_module_utils.attrToObject(diskInfo);
  406. if (diskInfo[3] == true){
  407. //This disk is mounted
  408. var uid = Date.now();
  409. if (fwmode){
  410. ao_module_newfw("SystemAOB/functions/file_system/index.php?controlLv=2&dir=" + diskInfo[1],"Loading", "folder open outline",uid,1080,580,undefined,undefined,true,true);
  411. }else{
  412. window.open("../../functions/file_system/index.php?controlLv=2&dir=" + diskInfo[1]);
  413. }
  414. }
  415. hideRightclickMenu();
  416. }
  417. */
  418. function createEventHooks(){
  419. $(".partitionRepresentation").contextmenu(function(e){
  420. if (mode == "windows"){
  421. //Switch back to normal menu when under window mode
  422. return true;
  423. }
  424. var px = e.clientX;
  425. var py = e.clientY;
  426. var top = py - $("#rightClickMenu").height();
  427. if (ao_module_virtualDesktop){
  428. top -= 50;
  429. }
  430. $("#rightClickMenu").css({"left": px + "px", "top": top + "px"});
  431. $("#rightClickMenu").show();
  432. console.log(e.target);
  433. $(".focusedPart").removeClass("focusedPart");
  434. var partbody = $(e.target);
  435. if ($(e.target).parent().hasClass("partitionRepresentation")){
  436. //Clicked on the child instead.
  437. $(e.target).parent().addClass("focusedPart");
  438. partbody = $(e.target).parent();
  439. }else{
  440. //Click on the representation body.
  441. $(e.target).addClass("focusedPart");
  442. }
  443. //Create a custom context menu for the operation
  444. var partInfo = ao_module_utils.attrToObject(partbody.attr("metadata"));
  445. console.log(partInfo);
  446. if (partInfo[3] == true){
  447. //This disk is mounted. Provide unmount btn
  448. if (partInfo[1] == "/" || partInfo[1] == "/boot"){
  449. //No, you can't unmount root nor format it
  450. $("#mtbtn").addClass("disabled");
  451. $("#formatDisk").addClass("disabled");
  452. }else{
  453. $("#mtbtn").removeClass("disabled");
  454. $("#formatDisk").removeClass("disabled");
  455. }
  456. $("#mtbtn").html('<i class="usb icon"></i> Unmount');
  457. if (partInfo[1].substring(0,6) == "/media"){
  458. //This can be opened
  459. $("#openbtn").removeClass("disabled");
  460. }else{
  461. $("#openbtn").addClass("disabled");
  462. }
  463. }else{
  464. //This disk is not mounted. Provide mount btn
  465. $("#mtbtn").html('<i class="usb icon"></i> Mount Drive');
  466. $("#openbtn").addClass("disabled");
  467. $("#mtbtn").removeClass("disabled");
  468. $("#formatDisk").removeClass("disabled");
  469. }
  470. //Prevent browser menu from showing
  471. return false;
  472. });
  473. }
  474. function adjustPartitionViewHeight(){
  475. $("#diskVisualization").css("height",window.innerHeight - $("#diskListTable").height() - 80 + "px");
  476. }
  477. function initView(){
  478. if (mode == "windows"){
  479. $(".windowsonly").show();
  480. //Runing on top of Window Host
  481. $.get(ao_root + "system/disk/diskmg/view",function(data){
  482. $("#diskInfoTable").html("");
  483. if (data.error == undefined){
  484. for (var i = 0; i < data.length; i++){
  485. var thisDisk = data[i];
  486. var driveName = thisDisk[2];
  487. if (thisDisk[2] == "" && thisDisk[0] == "C:\\"){
  488. driveName = "Primary Drive";
  489. }else if (thisDisk[2] == ""){
  490. driveName = "Local Disk";
  491. }else if (driveName == undefined){
  492. driveName = "No Media"
  493. }
  494. if (thisDisk[3] == undefined){
  495. //Unknown File System
  496. thisDisk[3] = "N/A"
  497. }
  498. var cap = bytesToSize(thisDisk[6]);
  499. if (thisDisk[6] == undefined){
  500. cap = "N/A";
  501. }
  502. var free = bytesToSize(thisDisk[5]);
  503. if (thisDisk[5] == undefined){
  504. free = "N/A";
  505. }
  506. var perc = Math.round(thisDisk[5] / thisDisk[6] * 100);
  507. if (isNaN(perc)){
  508. perc = "0";
  509. }
  510. $("#diskInfoTable").append('<tr>\
  511. <td class="collapsing">\
  512. <i class="disk outline icon"></i>' + thisDisk[0] + '\
  513. </td>\
  514. <td class="">' + driveName + '</td>\
  515. <td class="collapsing">' + thisDisk[1] + '</td>\
  516. <td class="right aligned collapsing">' + thisDisk[3] + '</td>\
  517. <td class="right aligned collapsing">' + cap + '</td>\
  518. <td class="right aligned collapsing">' + free + '</td>\
  519. <td class="right aligned collapsing">' + perc + '%</td>\
  520. </tr>');
  521. }
  522. }
  523. });
  524. }else{
  525. //Runing on top of Linux Host
  526. $(".linuxonly").show();
  527. $.get(ao_root + "system/disk/diskmg/view",function(data){
  528. $("#diskInfoTable").html("");
  529. if (data.error == undefined){
  530. var disks = data[0]["blockdevices"];
  531. var partitions = data[1];
  532. for (var i = 0; i < disks.length; i++){
  533. var thisDisk = disks[i]["children"];
  534. if (thisDisk === undefined || thisDisk === null){
  535. let thisSize = disks[i]["size"] || 0;
  536. let thisPartitionID = disks[i]["name"] || "✖";
  537. let mountPoint = disks[i]["mountpoint"] || "[NO PARTITION]";
  538. $("#diskInfoTable").append('<tr>\
  539. <td class="collapsing">\
  540. <i class="disk outline icon"></i>' + thisPartitionID + '\
  541. </td>\
  542. <td class="">' + mountPoint + '</td>\
  543. <td class="right aligned collapsing"></td>\
  544. <td class="right aligned collapsing">' + bytesToSize(thisSize) + '</td>\
  545. <td class="right aligned collapsing">' + bytesToSize(0) + '</td>\
  546. <td class="right aligned collapsing"></td>\
  547. </tr>');
  548. continue;
  549. }
  550. for (var j =0; j < thisDisk.length; j++){
  551. var thisPartition = thisDisk[j];
  552. var mtPoint = thisPartition["mountpoint"];
  553. if (mtPoint === null){
  554. mtPoint = "Not Mounted";
  555. }
  556. //Get the filesystem from another command return results
  557. var disksFormats = data[1]["blockdevices"][i]["children"][j];
  558. var fstype = disksFormats["fstype"];
  559. if (fstype === null){
  560. fstype = "raw";
  561. }
  562. //console.log(disksFormats);
  563. //Read freesapce from the last command return results
  564. var freeSpacesRatio = "0%";
  565. for (var k =0; k < data[2].length; k++){
  566. if (data[2][k][5] == thisPartition["mountpoint"]){
  567. //This device is mounted at the same path as current partition. It should be this volume
  568. freeSpacesRatio = data[2][k][4];
  569. }
  570. }
  571. if (freeSpacesRatio === undefined){
  572. freeSpacesRatio = "0%";
  573. }
  574. var numericalFreeSpace = parseInt(freeSpacesRatio.replace("%","")) * thisPartition["size"] / 100;
  575. //Print the results to the interface
  576. //console.log(thisPartition);
  577. $("#diskInfoTable").append('<tr>\
  578. <td class="collapsing">\
  579. <i class="disk outline icon"></i>' + thisPartition["name"] + '\
  580. </td>\
  581. <td class="">' + mtPoint + '</td>\
  582. <td class="right aligned collapsing">' + fstype + '</td>\
  583. <td class="right aligned collapsing">' + bytesToSize(thisPartition["size"]) + '</td>\
  584. <td class="right aligned collapsing">' + bytesToSize(numericalFreeSpace) + '</td>\
  585. <td class="right aligned collapsing">' + freeSpacesRatio + '</td>\
  586. </tr>');
  587. }
  588. }
  589. }
  590. });
  591. }
  592. }
  593. function initPartitionTable(){
  594. if (mode == "windows"){
  595. $.get(ao_root + "system/disk/diskmg/view?partition=true",function(data){
  596. var disks = {};
  597. for(var i =0; i < data.length; i++){
  598. var thisPart = data[i];
  599. //var diskID = thisPart[9].replace(":","");
  600. var diskID = thisPart[0].replace(/\\+.+\\/,"");
  601. if (disks == undefined || disks[diskID] == undefined){
  602. disks[diskID] = {"partitionsTotalSize":thisPart[14],"partitionNames":[thisPart[16]],"partitionID":[ thisPart[9]],"partitionVolume":[thisPart[14]],"Type":[thisPart[5]],"Mounted":[thisPart[4]=="True"],"Format":[thisPart[12]]};
  603. }else{
  604. disks[diskID]["partitionsTotalSize"] = parseInt(disks[diskID]["partitionsTotalSize"]) + parseInt(thisPart[14]);
  605. disks[diskID]["partitionVolume"].push(thisPart[14]);
  606. disks[diskID]["partitionNames"].push(thisPart[16]);
  607. disks[diskID]["partitionID"].push(thisPart[9]);
  608. disks[diskID]["Type"].push(thisPart[5]);
  609. disks[diskID]["Format"].push(thisPart[12]);
  610. disks[diskID]["Mounted"].push(thisPart[4]=="True");
  611. }
  612. }
  613. diskInformation = JSON.parse(JSON.stringify(disks));
  614. drawDartitionTable();
  615. });
  616. }else{
  617. //This is a Linux Host
  618. $.get(ao_root + "system/disk/diskmg/view?partition=true",function(data){
  619. var disks = {};
  620. var diskInfo = data[0]["blockdevices"];
  621. for (var i =0; i < diskInfo.length; i++){
  622. let thisDisk = diskInfo[i];
  623. let diskID = thisDisk["name"];
  624. if (thisDisk["children"] === undefined || thisDisk["children"] === null){
  625. //This disk do not have any child. Assume a large read-only raw partition.
  626. let thisSize = thisDisk["size"] || 0;
  627. let thisPartitionID = thisDisk["name"] || "✖";
  628. disks[diskID] = {
  629. "partitionsTotalSize":thisSize,
  630. "partitionNames":[""],
  631. "partitionID":[thisPartitionID],
  632. "partitionVolume":[thisSize],
  633. "Type":[thisDisk["type"]],
  634. "Mounted":[thisDisk["mountpoint"] !== null],
  635. "Format":["raw"]
  636. };
  637. continue;
  638. }
  639. for (var j =0; j < thisDisk["children"].length;j++){
  640. var thisPart = thisDisk["children"][j];
  641. var disksFormats = data[1]["blockdevices"][i]["children"][j];
  642. if (disks == undefined || disks[diskID] == undefined){
  643. disks[diskID] = {
  644. "partitionsTotalSize":thisPart["size"],
  645. "partitionNames":[thisPart["mountpoint"]],
  646. "partitionID":[thisPart["name"]],
  647. "partitionVolume":[thisPart["size"]],
  648. "Type":[thisPart["type"]],
  649. "Mounted":[thisPart["mountpoint"] != ""],
  650. "Format":[disksFormats["fstype"]]
  651. };
  652. }else{
  653. disks[diskID]["partitionsTotalSize"] = parseInt(disks[diskID]["partitionsTotalSize"]) + parseInt(thisPart["size"]);
  654. disks[diskID]["partitionVolume"].push(thisPart["size"]);
  655. disks[diskID]["partitionNames"].push(thisPart["mountpoint"]);
  656. disks[diskID]["partitionID"].push(thisPart["name"]);
  657. disks[diskID]["Type"].push(thisPart["type"]);
  658. disks[diskID]["Format"].push(disksFormats["fstype"]);
  659. console.log(thisPart["name"], thisPart["mountpoint"]);
  660. disks[diskID]["Mounted"].push(thisPart["mountpoint"] !== "");
  661. }
  662. }
  663. }
  664. diskInformation = JSON.parse(JSON.stringify(disks));
  665. drawDartitionTable();
  666. });
  667. }
  668. }
  669. function drawDartitionTable(){
  670. var disks = JSON.parse(JSON.stringify(diskInformation));
  671. console.log(diskInformation);
  672. //Clear the old diskpart table
  673. $("#diskVisualization").html("");
  674. //Render the partition table
  675. var maxWidth = window.innerWidth * 0.8 - 200;
  676. var maxCapDisk = -1;
  677. var keys = [];
  678. for (key in disks){
  679. keys.push(key);
  680. var thisDiskSize = disks[key]["partitionsTotalSize"];
  681. if (thisDiskSize > maxCapDisk){
  682. maxCapDisk = thisDiskSize;
  683. }
  684. }
  685. keys.sort();
  686. for (var i =0; i < keys.length; i++){
  687. var diskInfo = disks[keys[i]];
  688. var diskID = keys[i];
  689. var mountState = "Mounted";
  690. var shortenType = diskInfo["Type"][0].split(" ").shift();
  691. var thisMaxWidth = maxWidth - (1- (diskInfo["partitionsTotalSize"] / maxCapDisk)) * (window.innerWidth * displayScaleRatio);
  692. if (diskInfo["Mounted"].length == 1 && diskInfo["Mounted"][0] == false){
  693. mountState = "Unmounted";
  694. }else if(diskInfo["Mounted"].length > 1){
  695. mountState = "Mixed";
  696. }
  697. console.log(diskID,diskInfo["Mounted"]);
  698. //Append the disk info block
  699. $("#diskVisualization").append('<div class="diskPartTable">');
  700. $("#diskVisualization").append('<div class="sideblock">\
  701. <i class="disk outline icon" style="margin-right:0px;font-weight: bold;"></i>\
  702. <b style="font-weight: bold;">Drive ' + i + '</b><br>\
  703. ' + shortenType + '<br>\
  704. ' + bytesToSize(diskInfo["partitionsTotalSize"]) + '<br>\
  705. ' + mountState + '\
  706. </div>');
  707. var partitionIDs = diskInfo["partitionID"];
  708. for (var k =0; k < partitionIDs.length; k++){
  709. var thisWidth = thisMaxWidth * (parseInt(diskInfo["partitionVolume"][k]) / diskInfo["partitionsTotalSize"]);
  710. var topbarExtraClass = "";
  711. if (diskInfo["partitionVolume"][k] == 0){
  712. topbarExtraClass = " unallocate";
  713. }else if (diskInfo["partitionNames"][k] == "" && mode == "linux"){
  714. topbarExtraClass = " unmounted";
  715. diskInfo["partitionNames"][k] = "Not Mounted";
  716. if (diskInfo.Format.length == 1 && diskInfo.Format[0] == "raw"){
  717. topbarExtraClass = " unallocate"
  718. diskInfo["partitionNames"][k] = "Unallocated / Unpartitioned";
  719. }
  720. }else if (diskInfo["partitionNames"][k] == "" && mode == "windows"){
  721. //All viewable disks on Windows must be mounted
  722. if (diskInfo["partitionID"][0] == "C:"){
  723. diskInfo["partitionNames"][k] = "Primary Disk";
  724. }else{
  725. diskInfo["partitionNames"][k] = "Local Disk";
  726. }
  727. }
  728. $("#diskVisualization").append('<div class="partitionRepresentation" style="width:' + thisWidth + 'px;" metaData="\
  729. ' + ao_module_utils.objectToAttr([diskInfo["partitionID"][k],diskInfo["partitionNames"][k],diskInfo["Format"][k],diskInfo["Mounted"][k],diskInfo["Type"][k],diskInfo["partitionVolume"][k]]) + '">\
  730. <div class="partitionTopBar' + topbarExtraClass + '"></div>\
  731. <div class="partitionDescription">\
  732. ' + diskInfo["partitionNames"][k] +" (" + diskInfo["partitionID"][k] + ')<br>\
  733. ' + bytesToSize(parseInt(diskInfo["partitionVolume"][k])) + ' ' + diskInfo["Format"][k] + '<br>\
  734. </div>\
  735. </div>');
  736. }
  737. $("#diskVisualization").append('</div>');
  738. }
  739. setTimeout(function(){
  740. adjustPartitionViewHeight();
  741. },500);
  742. createEventHooks();
  743. }
  744. $(window).on("resize",function(){
  745. adjustPartitionViewHeight();
  746. drawDartitionTable();
  747. });
  748. $("#diskVisualization").on('click',function(e){
  749. var target = e.target;
  750. //console.log($(target).parents(".partitionRepresentation"));
  751. if ($(target).parents(".partitionRepresentation").length == 0 && !$(target).hasClass("partitionRepresentation")){
  752. $("#rightClickMenu").hide();
  753. }else if (e.button == 0){
  754. if ($(target).parents(".partitionRepresentation").length > 0 || $(target).hasClass("partitionRepresentation")){
  755. $(".focusedPart").removeClass("focusedPart");
  756. if ($(target).parent().hasClass("partitionRepresentation")){
  757. $(target).parent().addClass("focusedPart");
  758. }else{
  759. $(target).addClass("focusedPart");
  760. }
  761. }
  762. $("#rightClickMenu").hide();
  763. }
  764. });
  765. function bytesToSize(bytes) {
  766. if (viewMode == "human"){
  767. var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
  768. if (bytes == 0) return '0 Byte';
  769. var i = parseFloat(Math.floor(Math.log(bytes) / Math.log(1024)));
  770. return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
  771. }else if (viewMode == "raw"){
  772. return bytes + " B";
  773. }
  774. }
  775. </script>
  776. </body>
  777. </html>