diskoverview.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. <div class="diskoverview">
  2. <style>
  3. #diskrender{
  4. max-height: 300px;
  5. overflow-y: auto;
  6. overflow-x: hidden;
  7. }
  8. #diskrender .ui.avatar.image{
  9. border-radius: 0 !important;
  10. margin-top: 1em;
  11. }
  12. #diskrender .content{
  13. width: calc(100% - 40px);
  14. }
  15. #diskrender .driveinfo:hover{
  16. border-radius: 6px;
  17. }
  18. #diskrender .diskspace{
  19. margin-top: 0.6em;
  20. }
  21. #diskrender .progress .bar:not(.raiddev){
  22. background-color: rgb(82, 201, 255);
  23. }
  24. #diskrender .progress .bar.lowspace{
  25. background-color: #b51d1d !important;
  26. }
  27. #diskrender .progress .bar.raiddev.failing{
  28. background-color: #f5ef42 !important;
  29. }
  30. #diskrender .progress .bar.raiddev.healthy{
  31. background-color: #5cd858 !important;
  32. }
  33. #diskrender .progress .bar .progress{
  34. background-color: transparent !important;
  35. }
  36. #diskrender .raidVolStateIcon{
  37. position: absolute;
  38. left: 2.0em;
  39. top: 2.5em;
  40. background: white;
  41. border-radius: 50%;
  42. width: 1.2em;
  43. }
  44. #diskrender .inactive.driveinfo{
  45. opacity: 0.5;
  46. }
  47. #refreshDiskRenderBtn{
  48. float: right;
  49. }
  50. </style>
  51. <div id="diskrender">
  52. <div class="ui list" id="diskspaceList">
  53. </div>
  54. <div class="ui list" id="raidVolList">
  55. </div>
  56. </div>
  57. <script>
  58. // This is intented to be loaded on the desktop.system interface
  59. // use paths from web root instead of relative path from this script
  60. updateDiskSpaceOverview();
  61. function updateDiskSpaceOverview(){
  62. $("#diskspaceList").html(`<div style="text-align: center; margin-top: 2em;"><i class="ui loading spinner icon"></i></div>`);
  63. $.ajax({
  64. url: "./system/disk/diskmg/view",
  65. success: function(data){
  66. if (data.error != undefined){
  67. //Unable to load API, hide the util
  68. $("#diskrender").hide();
  69. return;
  70. }
  71. if (data[0] && typeof(data[0]["blockdevices"]) != "undefined"){
  72. //This is a linux host
  73. $("#diskspaceList").html("");
  74. for (var i = 0; i < data[0]["blockdevices"].length; i++){
  75. let thisDiskInfo = data[0]["blockdevices"][i];
  76. let driveId = thisDiskInfo.name;
  77. let diskName = "";
  78. let isRaid = false;
  79. if (thisDiskInfo.children == null){
  80. //This is a disk that is not formated or damaged
  81. continue;
  82. }
  83. console.log(data[1]["blockdevices"][i]);
  84. if (data[1]["blockdevices"][i].fstype == "linux_raid_member"){
  85. //RAID source partition / drive
  86. continue; //Remove this line to also render RAID disk
  87. isRaid = true;
  88. }
  89. if (thisDiskInfo.children.length > 0){
  90. //Try to extract mountpoint as name
  91. let mountpoint = thisDiskInfo.children[0].mountpoint;
  92. if (mountpoint == null || mountpoint == undefined || mountpoint == ""){
  93. //Not mounted via arozos. Try to get the mountpoint from other partitions
  94. if (thisDiskInfo.children.length > 1){
  95. //Multiple partitions, combine them into /dev/sdX(1+2+3)
  96. mountpoint = "/dev/" + thisDiskInfo.children[0].name;
  97. mountpoint = mountpoint.replace(/[0-9]/g, ""); //Remove the partition number
  98. mountpoint += "[";
  99. for (var j = 0; j < thisDiskInfo.children.length; j++){
  100. let partitionNumber = thisDiskInfo.children[j].name.replace(/[a-zA-Z]/g, "");
  101. mountpoint += partitionNumber + "+";
  102. }
  103. mountpoint = mountpoint.slice(0, -1); //Remove the last +
  104. mountpoint += "]";
  105. }else{
  106. //Single partition
  107. mountpoint = "/dev/" + thisDiskInfo.children[0].name;
  108. }
  109. }
  110. diskName = mountpoint;
  111. }
  112. let remainingSpace = 0;
  113. let totalSpace = thisDiskInfo.size;
  114. //Try to get the remaining space from mounted partitions
  115. if (data[2].length > 0){
  116. let accumulateTotalSpace = 0;
  117. let accumulateRemainingSpace = 0;
  118. for (var j = 0; j < data[2].length; j++){
  119. //For each mounted partitions
  120. let thisPartInfo = data[2][j];
  121. let thisPartName = thisPartInfo[0]; //e.g. /dev/sdc1
  122. if (thisPartName.includes("/" + driveId)){
  123. //Check if part name include drive id, e.g. /sdc
  124. //If yes, add the parition remaining space to acc
  125. accumulateRemainingSpace += thisPartInfo[3];
  126. accumulateTotalSpace += thisPartInfo[1];
  127. }
  128. }
  129. remainingSpace = accumulateRemainingSpace;
  130. totalSpace = accumulateTotalSpace;
  131. }
  132. let usedSpace = totalSpace - remainingSpace;
  133. let usedPercentage = (usedSpace / totalSpace) * 100;
  134. let colorClass = "";
  135. if (usedPercentage > 90){
  136. colorClass = "lowspace";
  137. }
  138. if (usedPercentage >= 100){
  139. //Prevent overflow
  140. usedPercentage = 100;
  141. }
  142. //Check if raid. As raid is controlled by mdadm, we don't know how much storage it has
  143. if (isRaid){
  144. usedPercentage = 100;
  145. colorClass = "raiddev";
  146. diskName = "[RAID Disk]"
  147. }
  148. $("#diskspaceList").append(`<div class="item driveinfo">
  149. <img class="ui avatar image" src="img/system/drive.svg">
  150. <div class="content">
  151. <div class="header">${diskName} (${driveId})
  152. <span style="float: right;font-size: 0.85em;">${usedPercentage.toFixed(1)}% | ${ao_module_utils.formatBytes(thisDiskInfo.size, 1)}</span>
  153. </div>
  154. <div class="description">
  155. <div class="ui active small fluid progress diskspace">
  156. <div class="bar ${colorClass}" style="width: ${usedPercentage}%">
  157. <div class="progress"></div>
  158. </div>
  159. </div>
  160. </div>
  161. </div>
  162. </div>`);
  163. }
  164. }else if (data[0].length == 7){
  165. //This is a Window hosts
  166. $("#diskspaceList").html("");
  167. for (var i = 0; i < data.length; i++){
  168. let thisDiskInfo = data[i];
  169. if (thisDiskInfo.length < 6){
  170. //Not a HDD
  171. continue;
  172. }
  173. let driveId = thisDiskInfo[0].replace("\\\\", "\\");
  174. let diskName = thisDiskInfo[2];
  175. let remainingSpace = thisDiskInfo[5];
  176. let totalSpace = thisDiskInfo[6];
  177. let usedSpace = totalSpace - remainingSpace;
  178. let usedPercentage = (usedSpace / totalSpace) * 100;
  179. let colorClass = "";
  180. if (usedPercentage > 90){
  181. colorClass = "lowspace";
  182. }
  183. if (usedPercentage >= 100){
  184. //Prevent overflow
  185. usedPercentage = 100;
  186. }
  187. $("#diskspaceList").append(`<div class="item driveinfo">
  188. <img class="ui avatar image" src="img/system/drive.svg">
  189. <div class="content">
  190. <div class="header">
  191. ${diskName} (${driveId})
  192. <span style="float: right;font-size: 0.85em;">${usedPercentage.toFixed(1)}% | ${ao_module_utils.formatBytes(totalSpace, 1)}</span>
  193. </div>
  194. <div class="description">
  195. <div class="ui active small fluid progress diskspace">
  196. <div class="bar ${colorClass}" style="width: ${usedPercentage}%">
  197. <div class="progress"></div>
  198. </div>
  199. </div>
  200. </div>
  201. </div>
  202. </div>`);
  203. }
  204. }else{
  205. //Something else
  206. $("#diskrender").text("Platform not supported");
  207. }
  208. //Update themecolor, see desktop.system setThemeColor();
  209. $("#diskrender .progress .bar").css({
  210. "background-color": desktopThemeColor
  211. });
  212. updateRAIDVolumeOverview();
  213. }, error: function(){
  214. $("#diskspaceList").html(`<div style="text-align: center; margin-top: 1em; height: 2em;"><i class="ui red ban icon"></i><i class="ui grey hdd icon"></i></div>`);
  215. }
  216. });
  217. }
  218. function updateRAIDVolumeOverview(){
  219. $("#raidVolList").html("");
  220. $.ajax({
  221. url: "/system/disk/raid/overview",
  222. method: "GET",
  223. success: function(data){
  224. if (data.error != undefined){
  225. //Hide the section
  226. $("#raidVolList").hide();
  227. }else{
  228. //Render the data
  229. $("#raidVolList").show();
  230. let containUnhealthy = false;
  231. data.forEach(raidinfo => {
  232. let usedPercentage = (raidinfo.UsedSize / raidinfo.TotalSize) * 100;
  233. let colorClass = "raiddev healthy";
  234. if (!raidinfo.IsHealthy){
  235. colorClass = "raiddev failing";
  236. containUnhealthy = true;
  237. }
  238. let activeClass = ""
  239. if (!raidinfo.Status.includes("active")){
  240. activeClass = "inactive";
  241. }
  242. $("#raidVolList").append(`<div class="item ${activeClass} driveinfo">
  243. <img class="ui avatar image" src="img/system/cluster.svg">
  244. <div class="content">
  245. <div class="header">${raidinfo.Name} (${raidinfo.Level.toUpperCase()} | ${raidinfo.Status})
  246. <span style="float: right;font-size: 0.85em;">${usedPercentage.toFixed(1)}% | ${ao_module_utils.formatBytes(raidinfo.TotalSize, 1)}</span>
  247. </div>
  248. <div class="description">
  249. <div class="ui active small fluid progress diskspace">
  250. <div class="bar ${colorClass}" style="width: ${usedPercentage}%">
  251. <div class="progress"></div>
  252. </div>
  253. </div>
  254. </div>
  255. </div>
  256. <span class="raidVolStateIcon">${raidinfo.IsHealthy?'<i class="ui green check circle icon"></i>':'<i class="ui red times circle icon"></i>'}</span>
  257. </div>`);
  258. });
  259. if (data.length == 0){
  260. //No raid devices
  261. }
  262. if (containUnhealthy){
  263. //Set require attension
  264. setTimeout(function(){
  265. updateSystemOverviewStatusText(1);
  266. }, 1000);
  267. }
  268. }
  269. },
  270. error: function(){
  271. //Unknown error, hide raid vol list
  272. $("#raidVolList").hide();
  273. }
  274. });
  275. }
  276. //Update the overview every 15 minutes
  277. setInterval(function(){
  278. updateDiskSpaceOverview();
  279. }, 900 * 1000);
  280. </script>
  281. </div>