raid_new.html 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. <!-- This will be shown in a ts-modal in the raid.html-->
  2. <style>
  3. .new-raid-modal-content{
  4. max-height: 70vh;
  5. overflow-y: auto;
  6. }
  7. @media screen and (max-width: 767px) {
  8. .new-raid-modal-content {
  9. max-height: none;
  10. }
  11. }
  12. .new-raid-disk-info{
  13. cursor: pointer;
  14. }
  15. .new-raid-disk-info:hover{
  16. opacity: 0.5;
  17. }
  18. /* RAID Type space visualizer */
  19. .raidTypeSpaceVisualizer{
  20. width: 100%;
  21. display: flex;
  22. height: 42px;
  23. }
  24. .raidTypeSpaceVisualizer .bars {
  25. flex: 1; /* Occupy the remaining space */
  26. display: flex; /* Nested flex container */
  27. min-height: 2.6em;
  28. border-radius: 0.4em;
  29. overflow: hidden;
  30. background-color: var(--ts-gray-500);
  31. }
  32. .raidTypeSpaceVisualizer .bar{
  33. text-align: center;
  34. float: left;
  35. color: white;
  36. padding-top: 0.6em;
  37. }
  38. .raidTypeSpaceVisualizer .bar.protected{
  39. background-color: var(--ts-primary-500);
  40. min-width: 100px;
  41. }
  42. .raidTypeSpaceVisualizer .bar.usable{
  43. background-color: var(--ts-positive-400);
  44. min-width: 100px;
  45. }
  46. .raidTypeSpaceVisualizer .bar.wasted{
  47. background-color: var(--ts-gray-500);
  48. width: 0%;
  49. }
  50. </style>
  51. <div class="content">
  52. <div class="ts-content">
  53. <div class="ts-header" i18n>Create New RAID Array
  54. // 建立 RAID 陣列
  55. </div>
  56. </div>
  57. <div class="ts-divider"></div>
  58. <div class="ts-content new-raid-modal-content">
  59. <div class="ts-grid mobile:is-stacked" >
  60. <div class="column is-3-wide">
  61. <div class="ts-procedure is-vertical has-top-spaced-large" style="position: sticky; top: 0;">
  62. <a step="1" class="item is-active">
  63. <div class="content">
  64. <div class="indicator"></div>
  65. <div class="label" i18n>RAID Name
  66. // 陣列名稱
  67. </div>
  68. </div>
  69. </a>
  70. <a step="2" class="item">
  71. <div class="content">
  72. <div class="indicator"></div>
  73. <div class="label" i18n>Select Disks
  74. // 選擇磁碟
  75. </div>
  76. </div>
  77. </a>
  78. <a step="3" class="item">
  79. <div class="content">
  80. <div class="indicator"></div>
  81. <div class="label" i18n>Raid Type
  82. // 陣列類型
  83. </div>
  84. </div>
  85. </a>
  86. <a step="4" class="item">
  87. <div class="content">
  88. <div class="indicator"></div>
  89. <div class="label" i18n>Confirm
  90. // 確認設定
  91. </div>
  92. </div>
  93. </a>
  94. </div>
  95. </div>
  96. <div class="column is-13-wide" style="overflow-y: auto;">
  97. <div class="ts-content">
  98. <!-- Array Name -->
  99. <div class="ts-text" i18n>RAID Name
  100. // 陣列名稱
  101. </div>
  102. <div class="ts-input has-top-spaced-small">
  103. <input type="text" placeholder="my-raid" id="raid_name" i18n>
  104. <span class="ts-icon is-circle-check-icon raid_name_valid_icon" style="color: var(--ts-positive-400); display:none;"></span>
  105. </div>
  106. <div class="ts-text is-description" i18n>Only alphabet, digits, _ (underscore) and - (hyphen) are allowed
  107. // 只允許字母、數字、_ (底線) 和 - (連字符)
  108. </div>
  109. <!-- Select Disks -->
  110. <div class="ts-divider has-top-spaced-small has-bottom-spaced-large"></div>
  111. <div id="new_raid_disk_select">
  112. <div class="ts-content">
  113. <div class="ts-text is-description" i18n>Loading disks, please wait...
  114. // 正在載入磁碟,請稍候...
  115. </div>
  116. </div>
  117. </div>
  118. <div class="ts-text is-description has-top-spaced-small" i18n> Tips: For any extra disks selected, it will be used as spare disks.
  119. // 提示:選擇的任何額外磁碟將用作備用磁碟。
  120. </div>
  121. <div class="ts-wrap is-end-aligned">
  122. <button class="ts-button is-outlined" i18n>Refresh
  123. // 重新整理
  124. </button>
  125. </div>
  126. <!-- Array Type -->
  127. <div class="ts-divider has-top-spaced-small has-bottom-spaced-small"></div>
  128. <div class="ts-text" i18n>RAID Type
  129. // 陣列類型
  130. </div>
  131. <button class="ts-button is-start-icon has-top-spaced-small" data-dropdown="new_raid_type_select">
  132. <span class="ts-icon is-chevron-down-icon"></span>
  133. <span class="raid_type_selected" i18n>Select RAID Type
  134. // 選擇陣列類型
  135. </span>
  136. </button>
  137. <div class="ts-dropdown is-end-icon" id="new_raid_type_select">
  138. <button class="item raid_type" value="raid1">RAID 1 <span class="ts-icon is-star-icon" style="color: var(--ts-warning-400);"></span></button>
  139. <button class="item raid_type" value="raid6">RAID 6 <span class="ts-icon is-star-icon" style="color: var(--ts-warning-400);"></span></button>
  140. <button class="item raid_type" value="raid5">RAID 5 </button>
  141. <button class="item raid_type" value="raid0">RAID 0</button>
  142. </div>
  143. <!-- Not enough disks warning -->
  144. <div id="notEnoughDisksWarning" class="ts-blankslate is-negative" style="display: none;">
  145. <div class="description" i18n>
  146. Not enough disks selected for the chosen RAID type. Please select more disks to proceed.
  147. // 選擇的磁碟不足以建立所選的 RAID 類型。請選擇更多磁碟以繼續。
  148. </div>
  149. </div>
  150. <!-- Space Estimation -->
  151. <div class="ts-divider has-top-spaced-small has-bottom-spaced-small"></div>
  152. <div class="ts-text" i18n>Usable Space
  153. // 可使用空間
  154. </div>
  155. <div class="ts-blankslate" id="capacityVisualizerInformationSlate" style="pointer-events: none; user-select: none; opacity: 0.5;">
  156. <div class="description" i18n> Select disks and RAID type to estimate usable space.
  157. // 選擇磁碟和陣列類型以估算可用空間。
  158. </div>
  159. </div>
  160. <div id="capacityVisualizer" class="ts-content" style="display: none;">
  161. <div class="raidTypeSpaceVisualizer">
  162. <div class="bars">
  163. <div class="bar usable" id="estimatedUsableSpace">0%</div>
  164. <div class="bar protected" id="estimatedProtectionSpace">0%</div>
  165. <div class="bar wasted" id="estimatedWastedSpace">0%</div>
  166. </div>
  167. </div>
  168. <div class="ts-content" style="float: right;">
  169. <div class="ts-badge is-spaced-small" style="background-color: var(--ts-positive-400); color: white;" i18n>Available Space
  170. // 可用空間
  171. </div>
  172. <div class="ts-badge is-spaced-small" style="background-color: var(--ts-primary-500); color: white;" i18n>Redundancy
  173. // 冗餘
  174. </div>
  175. <div class="ts-badge is-spaced-small" style="background-color: var(--ts-gray-500); color: white;" i18n>Unused
  176. // 未使用
  177. </div>
  178. </div>
  179. <br>
  180. </div>
  181. </div>
  182. </div>
  183. </div>
  184. </div>
  185. <div class="ts-divider"></div>
  186. <div class="ts-content is-tertiary">
  187. <div class="ts-wrap is-end-aligned">
  188. <button onclick="showConfirmNewRaidDialog();" class="ts-button" i18n>Confirm
  189. // 確認
  190. </button>
  191. <button onclick="cancelCreateNewRAIDArray(); //parent function" class="ts-button is-outlined" i18n>Cancel
  192. // 取消
  193. </button>
  194. </div>
  195. </div>
  196. <dialog id="new_raid_warning" class="ts-modal" style="background: rgba(0, 0, 0, 0.9);">
  197. <div class="ts-content">
  198. <div class="ts-header" i18n>Warning
  199. // 警告
  200. </div>
  201. <div class="ts-text is-description" i18n>
  202. Creating a new RAID array will format all selected disks and erase all data on them. This action cannot be undone. Are you sure you want to proceed?
  203. // 建立新的 RAID 陣列將格式化所有選定的磁碟並清除其上的所有資料。此操作無法撤銷。您確定要繼續嗎?
  204. </div>
  205. <div class="ts-text is-description has-top-spaced-small">
  206. <strong i18n>Selected Disks:
  207. // 選定的磁碟:
  208. </strong>
  209. <span id="selected_disks_list"></span>
  210. </div>
  211. <div class="ts-wrap is-end-aligned has-top-spaced-large">
  212. <button class="ts-button is-negative" onclick="createNewRAIDArray(true);" i18n>Proceed
  213. // 繼續
  214. </button>
  215. <button class="ts-button is-negative is-outlined" onclick="createNewRAIDArray(false);" i18n>Proceed w/o superblock format
  216. // 不格式化 superblock 繼續
  217. </button>
  218. <button class="ts-button is-outlined" onclick="document.getElementById('new_raid_warning').close();" i18n>Cancel
  219. // 取消
  220. </button>
  221. </div>
  222. </div>
  223. </dialog>
  224. <script>
  225. /* RAID name validation */
  226. $("#raid_name").on("keydown", function() {
  227. validateRaidName();
  228. });
  229. $("#raid_name").on("change", function() {
  230. validateRaidName();
  231. });
  232. function validateRaidName(){
  233. var raidName = $("#raid_name").val().trim();
  234. var isValid = /^[a-zA-Z0-9_-]+$/.test(raidName) && raidName.trim() !== "";
  235. if (raidName == ""){
  236. $("#raid_name").parent().removeClass("is-end-icon");
  237. $("a[step='1']").removeClass("is-completed").removeClass("is-active");
  238. $("a[step='2']").removeClass("is-active");
  239. $(".ts-icon.raid_name_valid_icon").hide();
  240. } else if (isValid) {
  241. $("#raid_name").parent().removeClass("is-negative");
  242. $("a[step='1']").removeClass("is-active").addClass("is-completed");
  243. $("a[step='2']").addClass("is-active");
  244. $("#raid_name").parent().addClass("is-end-icon");
  245. $(".ts-icon.raid_name_valid_icon").show();
  246. } else {
  247. $("#raid_name").parent().addClass("is-negative");
  248. $("a[step='1']").removeClass("is-completed").addClass("is-active");
  249. $("a[step='2']").removeClass("is-active");
  250. $("#raid_name").parent().removeClass("is-end-icon");
  251. $(".ts-icon.raid_name_valid_icon").hide();
  252. }
  253. }
  254. /* Disk selection */
  255. function initNewRAIDDiskList(){
  256. $.get("./api/info/list", function(data) {
  257. if (data) {
  258. var disks = data;
  259. var diskList = $("#new_raid_disk_select");
  260. diskList.empty();
  261. for (var i = 0; i < disks.length; i++) {
  262. let disk = disks[i];
  263. let partitionTable = "";
  264. let encodedDiskInfo = encodeURIComponent(JSON.stringify(disk));
  265. let diskIsMounted = false;
  266. let diskIsAlreadyRAID = false; //The disk already belongs to another RAID array
  267. // Render the partition table
  268. if (disk.partitions.length > 0) {
  269. partitionTable += `<table class="ts-table is-bordered is-striped">
  270. <thead>
  271. <tr>
  272. <th i18n>Partition Name
  273. // 分割區
  274. </th>
  275. <th i18n>Size
  276. // 大小
  277. </th>
  278. <th i18n>Type
  279. // 類型
  280. </th>
  281. <th i18n>Mount Point
  282. // 掛載點
  283. </th>
  284. </tr>
  285. </thead>
  286. <tbody>`;
  287. for (var j = 0; j < disk.partitions.length; j++) {
  288. let partition = disk.partitions[j];
  289. partitionTable += `<tr>
  290. <td>${partition.name}</td>
  291. <td>${humanFileSize(partition.size)}</td>
  292. <td>${partition.fstype || partition.blocktype}</td>
  293. <td>${partition.mountpoint || ""}</td>
  294. </tr>`;
  295. if (partition.mountpoint) {
  296. diskIsMounted = true;
  297. }
  298. if (partition.blocktype.includes("raid")) {
  299. diskIsAlreadyRAID = true;
  300. }
  301. }
  302. partitionTable += `</tbody></table>`;
  303. } else {
  304. partitionTable = `<div class="ts-text is-description" i18n>No Partitions
  305. // 無分割區
  306. </div>`;
  307. }
  308. let warningClass = "";
  309. let warningMessage = `<div class="ts-text is-negative" i18n>
  310. This disk is mounted and might be in use.
  311. // 此磁碟已被掛載,可能正在使用中。
  312. </div>`;
  313. if (diskIsMounted) {
  314. warningClass = "is-negative is-start-indicated";
  315. }
  316. let disabledClass = "";
  317. if (diskIsAlreadyRAID) {
  318. disabledClass = "is-disabled";
  319. }
  320. // Append disk information with partition table
  321. diskList.append(`<div class="ts-box ts-content has-top-spaced-small new-raid-disk-info ${warningClass} ${disabledClass}" data-disk-info='${encodedDiskInfo}'>
  322. ${diskIsMounted ? warningMessage : ""}
  323. <div class="ts-item">
  324. <div class="ts-header">${disk.model} <span class="ts-badge has-start-spaced-small">${humanFileSize(disk.size)}</span></div>
  325. <div class="ts-text is-description">
  326. /dev/${disk.name}
  327. </div>
  328. </div>
  329. <div class="has-top-spaced-small">
  330. ${partitionTable}
  331. </div>
  332. <div class="new_raid_disk_selected">
  333. <span class="ts-icon is-circle-check-icon" style="color: var(--ts-positive-400); font-size: 1.5rem;"></span>
  334. </div>
  335. </div>`);
  336. }
  337. } else {
  338. console.error("Failed to load disk info: " + data.message);
  339. }
  340. //Bind click event to each disk info
  341. $(".new-raid-disk-info").off("click").on("click", function() {
  342. var selectedDisk = $(this);
  343. var selectedIcon = selectedDisk.find(".new_raid_disk_selected");
  344. var isSelected = $(this).hasClass("selected");
  345. if (isSelected) {
  346. selectedDisk.removeClass("selected");
  347. selectedIcon.hide();
  348. } else {
  349. selectedDisk.addClass("selected");
  350. selectedIcon.show();
  351. }
  352. // Check if any disk is selected
  353. if ($(".new-raid-disk-info.selected").length > 0) {
  354. // Mark step 2 as completed and step 3 as active
  355. $("a[step='2']").removeClass("is-active").addClass("is-completed");
  356. $("a[step='3']").addClass("is-active");
  357. } else {
  358. // Restore the not complete state of the steps
  359. $("a[step='2']").removeClass("is-completed").addClass("is-active");
  360. $("a[step='3']").removeClass("is-active");
  361. }
  362. //Render the space estimation if any disk is selected
  363. renderNewRaidSpaceEstimation();
  364. });
  365. relocale();
  366. });
  367. }
  368. initNewRAIDDiskList();
  369. /* RAID type selection */
  370. $(".raid_type").click(function() {
  371. var raid_type = $(this).text();
  372. var raid_type_value = $(this).val();
  373. $(".raid_type_selected").text(raid_type);
  374. $(".raid_type_selected").val(raid_type_value);
  375. $("#new_raid_type_select").removeClass("is-active");
  376. $("#new_raid_type_select").removeAttr("data-dropdown");
  377. $("#new_raid_type_select").attr("data-dropdown", "new_raid_type_select");
  378. $(".raid_type").removeClass("is-active");
  379. $(this).addClass("is-active");
  380. $(".raid_type").removeAttr("aria-pressed");
  381. $(this).attr("aria-pressed", "true");
  382. $(".raid_type").removeAttr("aria-selected");
  383. $(this).attr("aria-selected", "true");
  384. $(".raid_type").removeAttr("aria-expanded");
  385. $(this).attr("aria-expanded", "true");
  386. $(".raid_type").removeAttr("aria-hidden");
  387. $(this).attr("aria-hidden", "false");
  388. //Write the selected type to attribute
  389. var selectedRAIDType = $(this).val();
  390. $(".raid_type_selected").attr("value", selectedRAIDType);
  391. // Mark step 3 as completed and step 2 as active
  392. $("a[step='3']").removeClass("is-active").addClass("is-completed");
  393. $("a[step='2']").addClass("is-active");
  394. renderNewRaidSpaceEstimation();
  395. });
  396. function getCurrentSelectedDisks(){
  397. var selectedDisks = [];
  398. $(".new-raid-disk-info.selected").each(function() {
  399. var diskInfo = $(this).attr("data-disk-info");
  400. var disk = JSON.parse(decodeURIComponent(diskInfo));
  401. selectedDisks.push(disk);
  402. });
  403. return selectedDisks;
  404. }
  405. function getCurrentSelectedRAIDType(){
  406. var selectedRAIDType = $(".raid_type_selected").val();
  407. if (selectedRAIDType == undefined || selectedRAIDType == "") {
  408. selectedRAIDType = "";
  409. }
  410. return selectedRAIDType;
  411. }
  412. /* Render the space estimation */
  413. function renderNewRaidSpaceEstimation(){
  414. function bytesToHumanReadable(size){
  415. var i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
  416. return +((size / Math.pow(1024, i)).toFixed(1)) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
  417. }
  418. //Check if any disk is selected and raid type is selected
  419. let selectedDisks = getCurrentSelectedDisks();
  420. let selectedRAIDType = getCurrentSelectedRAIDType();
  421. if (selectedDisks.length == 0 || selectedRAIDType == "") {
  422. $("#capacityVisualizer").hide();
  423. $("3capacityVisualizerInformationSlate").show();
  424. return;
  425. } else {
  426. $("#capacityVisualizer").show();
  427. $("#capacityVisualizerInformationSlate").hide();
  428. }
  429. console.log(selectedDisks, selectedRAIDType);
  430. //Calculate the total size of selected disks
  431. let totalSize = 0;
  432. let totalUsableSpace = 0;
  433. let totalRedundancySpace = 0;
  434. let totalWastedSpace = 0;
  435. let totalDiskCount = selectedDisks.length;
  436. let diskCountIsEnough = false;
  437. if (selectedRAIDType == "raid0"){
  438. // RAID 0: No redundancy, all space is usable
  439. // Usable space is determined by the smallest disk size * the number of disks
  440. let smallestDiskSize = 0;
  441. selectedDisks.forEach(disk => {
  442. totalSize += disk.size;
  443. if (smallestDiskSize == 0 || disk.size < smallestDiskSize) {
  444. smallestDiskSize = disk.size;
  445. }
  446. });
  447. totalUsableSpace = smallestDiskSize * totalDiskCount;
  448. totalRedundancySpace = 0;
  449. totalWastedSpace = totalSize - totalUsableSpace;
  450. if (totalDiskCount >= 2){
  451. diskCountIsEnough = true;
  452. }
  453. }else if (selectedRAIDType == "raid1"){
  454. // RAID 1: Mirroring, usable space is the size of the smallest disk
  455. let smallestDiskSize = 0;
  456. selectedDisks.forEach(disk => {
  457. totalSize += disk.size;
  458. if (smallestDiskSize == 0 || disk.size < smallestDiskSize) {
  459. smallestDiskSize = disk.size;
  460. }
  461. });
  462. totalUsableSpace = smallestDiskSize;
  463. totalRedundancySpace = smallestDiskSize * (totalDiskCount - 1);
  464. totalWastedSpace = totalSize - totalUsableSpace - totalRedundancySpace;
  465. if (totalDiskCount >= 2){
  466. diskCountIsEnough = true;
  467. }
  468. }else if (selectedRAIDType == "raid5"){
  469. // RAID 5: Striping with parity, usable space is total size - size of one disk
  470. let smallestDiskSize = 0;
  471. selectedDisks.forEach(disk => {
  472. totalSize += disk.size;
  473. if (smallestDiskSize == 0 || disk.size < smallestDiskSize) {
  474. smallestDiskSize = disk.size;
  475. }
  476. });
  477. totalUsableSpace = smallestDiskSize * (totalDiskCount - 1);
  478. totalRedundancySpace = smallestDiskSize;
  479. totalWastedSpace = totalSize - totalUsableSpace - totalRedundancySpace;
  480. if (totalDiskCount >= 3){
  481. diskCountIsEnough = true;
  482. }
  483. }else if (selectedRAIDType == "raid6"){
  484. // RAID 6: Striping with double parity, usable space is total size - size of two disks
  485. let smallestDiskSize = 0;
  486. selectedDisks.forEach(disk => {
  487. totalSize += disk.size;
  488. if (smallestDiskSize == 0 || disk.size < smallestDiskSize) {
  489. smallestDiskSize = disk.size;
  490. }
  491. });
  492. totalUsableSpace = smallestDiskSize * (totalDiskCount - 2);
  493. totalRedundancySpace = smallestDiskSize * 2;
  494. totalWastedSpace = totalSize - totalUsableSpace - totalRedundancySpace;
  495. if (totalDiskCount >= 4){
  496. diskCountIsEnough = true;
  497. }
  498. }else{
  499. console.error("Unknown RAID type: " + selectedRAIDType);
  500. return;
  501. }
  502. //Check if the disk count is enough for the selected RAID type
  503. if (!diskCountIsEnough){
  504. $("#capacityVisualizer").hide();
  505. $("3capacityVisualizerInformationSlate").show();
  506. $("a[step='3']").removeClass("is-completed").addClass("is-active");
  507. $("a[step='4']").removeClass("is-active");
  508. $("button[onclick='showConfirmNewRaidDialog();']").prop("disabled", true);
  509. $("#notEnoughDisksWarning").show();
  510. return;
  511. }else{
  512. $("a[step='3']").removeClass("is-active").addClass("is-completed");
  513. $("a[step='4']").addClass("is-active");
  514. $("button[onclick='showConfirmNewRaidDialog();']").prop("disabled", false);
  515. $("#notEnoughDisksWarning").hide();
  516. }
  517. //Update the visualizer
  518. let barMinWidth = 100;
  519. let usableSpacePercentage = (totalUsableSpace / totalSize) * 100;
  520. let redundancySpacePercentage = (totalRedundancySpace / totalSize) * 100;
  521. let wastedSpacePercentage = (totalWastedSpace / totalSize) * 100;
  522. $("#estimatedUsableSpace").text(bytesToHumanReadable(totalUsableSpace));
  523. $("#estimatedProtectionSpace").text(bytesToHumanReadable(totalRedundancySpace));
  524. $("#estimatedWastedSpace").text(bytesToHumanReadable(totalWastedSpace));
  525. $("#estimatedUsableSpace").css("width", usableSpacePercentage + "%");
  526. if (usableSpacePercentage == 0){
  527. $("#estimatedUsableSpace").css("min-width", "0");
  528. }else{
  529. $("#estimatedUsableSpace").css("min-width", barMinWidth + "px");
  530. }
  531. $("#estimatedProtectionSpace").css("width", redundancySpacePercentage + "%");
  532. if (redundancySpacePercentage == 0 ){
  533. $("#estimatedProtectionSpace").css("min-width", "0");
  534. }else{
  535. $("#estimatedProtectionSpace").css("min-width", barMinWidth + "px");
  536. }
  537. $("#estimatedWastedSpace").css("width", wastedSpacePercentage + "%");
  538. }
  539. /* Reset Selections */
  540. function resetNewRAIDUserInputs(){
  541. // Reset RAID name
  542. $("#raid_name").val("");
  543. $("#raid_name").parent().removeClass("is-end-icon");
  544. $("a[step='1']").removeClass("is-completed").removeClass("is-active");
  545. $("a[step='2']").removeClass("is-active");
  546. $(".ts-icon.raid_name_valid_icon").hide();
  547. // Reset disk selection
  548. $(".new-raid-disk-info").removeClass("selected");
  549. $(".new_raid_disk_selected").hide();
  550. $("a[step='2']").removeClass("is-completed").addClass("is-active");
  551. $("a[step='3']").removeClass("is-active");
  552. // Reset RAID type
  553. $(".raid_type_selected").text("Select RAID Type");
  554. $(".raid_type_selected").val("");
  555. $("#new_raid_type_select .item").removeClass("is-active");
  556. $("a[step='3']").removeClass("is-completed").addClass("is-active");
  557. // Reset space estimation
  558. $("#capacityVisualizer").hide();
  559. $("#capacityVisualizerInformationSlate").show();
  560. $("#estimatedUsableSpace").text("0%");
  561. $("#estimatedProtectionSpace").text("0%");
  562. $("#estimatedWastedSpace").text("0%");
  563. $("#estimatedUsableSpace").css("width", "0%");
  564. $("#estimatedProtectionSpace").css("width", "0%");
  565. $("#estimatedWastedSpace").css("width", "0%");
  566. }
  567. /* Get the selection for new RAID arrays */
  568. function getNewRAIDArraySelection(){
  569. let selectedDisks = getCurrentSelectedDisks();
  570. let selectedRAIDType = getCurrentSelectedRAIDType();
  571. let raidName = $("#raid_name").val().trim();
  572. return {
  573. disks: selectedDisks,
  574. type: selectedRAIDType,
  575. name: raidName
  576. };
  577. }
  578. function showConfirmNewRaidDialog(){
  579. let selectedDisks = getCurrentSelectedDisks();
  580. let selectedRAIDType = getCurrentSelectedRAIDType();
  581. let raidName = $("#raid_name").val().trim();
  582. //Check if the raid name is valid
  583. if (raidName == "" || !/^[a-zA-Z0-9_-]+$/.test(raidName)){
  584. $("#raid_name").parent().addClass("is-negative");
  585. $(".new-raid-modal-content").animate({
  586. scrollTop: $("#raid_name").offset().top - $(".new-raid-modal-content").offset().top
  587. }, "smooth");
  588. return;
  589. }
  590. let selectedDisksList = "";
  591. selectedDisks.forEach(disk => {
  592. selectedDisksList += "/dev/" + disk.name + " ";
  593. });
  594. $("#selected_disks_list").text(selectedDisksList);
  595. $("#new_raid_warning")[0].showModal();
  596. }
  597. function hideConfirmNewRaidDialog(){
  598. $("#new_raid_warning")[0].close();
  599. }
  600. </script>