Bläddra i källkod

Added space estimation bar

TC 1 vecka sedan
förälder
incheckning
9cdf1dcf5b
1 ändrade filer med 229 tillägg och 1 borttagningar
  1. 229 1
      web/components/raid_new.html

+ 229 - 1
web/components/raid_new.html

@@ -18,6 +18,42 @@
     .new-raid-disk-info:hover{
         opacity: 0.5;
     }
+
+    /* RAID Type space visualizer */
+    .raidTypeSpaceVisualizer{
+        width: 100%;
+        display: flex;
+        height: 42px;
+    }
+
+    .raidTypeSpaceVisualizer .bars {
+        flex: 1; /* Occupy the remaining space */
+        display: flex; /* Nested flex container */
+        min-height: 2.6em;
+        border-radius: 0.4em;
+        overflow: hidden;
+        background-color: var(--ts-gray-500);
+    }
+
+    .raidTypeSpaceVisualizer .bar{
+        text-align: center;
+        float: left;
+        color: white;
+        padding-top: 0.6em;
+    }
+
+    .raidTypeSpaceVisualizer .bar.protected{
+        background-color: var(--ts-primary-500);
+        min-width: 100px;
+    }
+    .raidTypeSpaceVisualizer .bar.usable{
+        background-color: var(--ts-positive-400);
+        min-width: 100px;
+    }
+    .raidTypeSpaceVisualizer .bar.wasted{
+        background-color: var(--ts-gray-500);
+        width: 0%;
+    }
 </style>
 <div class="content">
 <div class="ts-content">
@@ -114,6 +150,39 @@
                     <button class="item raid_type" value="raid5">RAID 5 </button>
                     <button class="item raid_type" value="raid0">RAID 0</button>
                 </div>
+
+                <!-- Space Estimation -->
+                <div class="ts-divider has-top-spaced-small has-bottom-spaced-small"></div>
+                <div class="ts-text" i18n>Usable Space
+                    // 可使用空間
+                </div>
+                <div class="ts-blankslate" id="capacityVisualizerInformationSlate" style="pointer-events: none; user-select: none; opacity: 0.5;">
+                    <div class="description" i18n> Select disks and RAID type to estimate usable space.
+                        // 選擇磁碟和陣列類型以估算可用空間。
+                    </div>
+                </div>
+                <div id="capacityVisualizer" class="ts-content" style="display: none;">
+                    <div class="raidTypeSpaceVisualizer">
+                        <div class="bars">
+                            <div class="bar usable" id="estimatedUsableSpace">0%</div>
+                            <div class="bar protected" id="estimatedProtectionSpace">0%</div>
+                            <div class="bar wasted" id="estimatedWastedSpace">0%</div>
+                        </div>
+                    
+                    </div>
+                    <div class="ts-content" style="float: right;">
+                        <div class="ts-badge is-spaced-small" style="background-color: var(--ts-positive-400); color: white;" i18n>Available Space
+                            // 可用空間
+                        </div>
+                        <div class="ts-badge is-spaced-small" style="background-color: var(--ts-primary-500); color: white;" i18n>Redundancy
+                            // 冗餘
+                        </div>
+                        <div class="ts-badge is-spaced-small" style="background-color: var(--ts-gray-500); color: white;" i18n>Unused
+                            // 未使用
+                        </div>
+                    </div>
+                    <br>
+                </div>
             </div>
             
         </div>
@@ -178,6 +247,7 @@
                 for (var i = 0; i < disks.length; i++) {
                     let disk = disks[i];
                     let partitionTable = "";
+                    let encodedDiskInfo = encodeURIComponent(JSON.stringify(disk));
                     let diskIsMounted = false;
                     let diskIsAlreadyRAID = false; //The disk already belongs to another RAID array
                     // Render the partition table
@@ -237,7 +307,7 @@
                     } 
 
                     // Append disk information with partition table
-                    diskList.append(`<div class="ts-box ts-content has-top-spaced-small new-raid-disk-info ${warningClass} ${disabledClass}">
+                    diskList.append(`<div class="ts-box ts-content has-top-spaced-small new-raid-disk-info ${warningClass} ${disabledClass}" data-disk-info='${encodedDiskInfo}'>
                                         ${diskIsMounted ? warningMessage : ""}
                                         <div class="ts-item">
                                             <div class="ts-header">${disk.model} <span class="ts-badge has-start-spaced-small">${humanFileSize(disk.size)}</span></div>
@@ -280,6 +350,9 @@
                     $("a[step='2']").removeClass("is-completed").addClass("is-active");
                     $("a[step='3']").removeClass("is-active");
                 }
+
+                //Render the space estimation if any disk is selected
+                renderNewRaidSpaceEstimation();
             });
             relocale();
         });
@@ -306,8 +379,163 @@
         $(".raid_type").removeAttr("aria-hidden");
         $(this).attr("aria-hidden", "false");
 
+        //Write the selected type to attribute
+        var selectedRAIDType = $(this).val();
+        $(".raid_type_selected").attr("value", selectedRAIDType);
+
         // Mark step 3 as completed and step 2 as active
         $("a[step='3']").removeClass("is-active").addClass("is-completed");
         $("a[step='2']").addClass("is-active");
+
+        renderNewRaidSpaceEstimation();
     });
+
+    function getCurrentSelectedDisks(){
+        var selectedDisks = [];
+        $(".new-raid-disk-info.selected").each(function() {
+            var diskInfo = $(this).attr("data-disk-info");
+            var disk = JSON.parse(decodeURIComponent(diskInfo));
+            selectedDisks.push(disk);
+        });
+        return selectedDisks;
+    }
+
+    function getCurrentSelectedRAIDType(){
+        var selectedRAIDType = $(".raid_type_selected").val();
+        if (selectedRAIDType == undefined || selectedRAIDType == "") {
+            selectedRAIDType = "";
+        }
+        return selectedRAIDType;
+    }
+
+
+    /* Render the space estimation */
+    function renderNewRaidSpaceEstimation(){
+        function bytesToHumanReadable(size){
+            var i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024));
+            return +((size / Math.pow(1024, i)).toFixed(1)) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i];
+        }
+        //Check if any disk is selected and raid type is selected
+        let selectedDisks = getCurrentSelectedDisks();
+        let selectedRAIDType = getCurrentSelectedRAIDType();
+        if (selectedDisks.length == 0 || selectedRAIDType == "") {
+            $("#capacityVisualizer").hide();
+            $("3capacityVisualizerInformationSlate").show();
+            return;
+        } else {
+            $("#capacityVisualizer").show();
+            $("#capacityVisualizerInformationSlate").hide();
+        }
+        
+        console.log(selectedDisks, selectedRAIDType);
+
+        //Calculate the total size of selected disks
+        let totalSize = 0;
+        let totalUsableSpace = 0;
+        let totalRedundancySpace = 0;
+        let totalWastedSpace = 0;
+        let totalDiskCount = selectedDisks.length;
+        let diskCountIsEnough = false;
+        if (selectedRAIDType == "raid0"){
+            // RAID 0: No redundancy, all space is usable
+            // Usable space is determined by the smallest disk size * the number of disks
+            let smallestDiskSize = 0;
+            selectedDisks.forEach(disk => {
+                totalSize += disk.size;
+                if (smallestDiskSize == 0 || disk.size < smallestDiskSize) {
+                    smallestDiskSize = disk.size;
+                }
+            });
+
+            totalUsableSpace = smallestDiskSize * totalDiskCount;
+            totalRedundancySpace = 0;
+            totalWastedSpace = totalSize - totalUsableSpace;
+            if (totalDiskCount >= 2){
+                diskCountIsEnough = true;
+            }
+        }else if (selectedRAIDType == "raid1"){
+            // RAID 1: Mirroring, usable space is the size of the smallest disk
+            let smallestDiskSize = 0;
+            selectedDisks.forEach(disk => {
+                totalSize += disk.size;
+                if (smallestDiskSize == 0 || disk.size < smallestDiskSize) {
+                    smallestDiskSize = disk.size;
+                }
+            });
+
+            totalUsableSpace = smallestDiskSize;
+            totalRedundancySpace = smallestDiskSize * (totalDiskCount - 1);
+            totalWastedSpace = totalSize - totalUsableSpace;
+
+            if (totalDiskCount >= 2){
+                diskCountIsEnough = true;
+            }
+        }else if (selectedRAIDType == "raid5"){
+            // RAID 5: Striping with parity, usable space is total size - size of one disk
+            let smallestDiskSize = 0;
+            selectedDisks.forEach(disk => {
+                totalSize += disk.size;
+                if (smallestDiskSize == 0 || disk.size < smallestDiskSize) {
+                    smallestDiskSize = disk.size;
+                }
+            });
+
+            totalUsableSpace = smallestDiskSize * (totalDiskCount - 1);
+            totalRedundancySpace = smallestDiskSize;
+            totalWastedSpace = totalSize - totalUsableSpace - totalRedundancySpace;
+            if (totalDiskCount >= 3){
+                diskCountIsEnough = true;
+            }
+        }else if (selectedRAIDType == "raid6"){
+            // RAID 6: Striping with double parity, usable space is total size - size of two disks
+            let smallestDiskSize = 0;
+            selectedDisks.forEach(disk => {
+                totalSize += disk.size;
+                if (smallestDiskSize == 0 || disk.size < smallestDiskSize) {
+                    smallestDiskSize = disk.size;
+                }
+            });
+
+            totalUsableSpace = smallestDiskSize * (totalDiskCount - 2);
+            totalRedundancySpace = smallestDiskSize * 2;
+            totalWastedSpace = totalSize - totalUsableSpace - totalRedundancySpace;
+            if (totalDiskCount >= 4){
+                diskCountIsEnough = true;
+            }
+        }else{
+            console.error("Unknown RAID type: " + selectedRAIDType);
+            return;
+        }
+
+        //Check if the disk count is enough for the selected RAID type
+        if (!diskCountIsEnough){
+            $("#capacityVisualizer").hide();
+            $("3capacityVisualizerInformationSlate").show();
+            $("a[step='3']").removeClass("is-completed").addClass("is-active");
+            $("a[step='4']").removeClass("is-active");
+            return;
+        }
+        //Update the visualizer
+        let barMinWidth = 100;
+        let usableSpacePercentage = (totalUsableSpace / totalSize) * 100;
+        let redundancySpacePercentage = (totalRedundancySpace / totalSize) * 100;
+        let wastedSpacePercentage = (totalWastedSpace / totalSize) * 100;
+        $("#estimatedUsableSpace").text(bytesToHumanReadable(totalUsableSpace));
+        $("#estimatedProtectionSpace").text(bytesToHumanReadable(totalRedundancySpace));
+        $("#estimatedWastedSpace").text(bytesToHumanReadable(totalWastedSpace));
+        $("#estimatedUsableSpace").css("width", usableSpacePercentage + "%");
+        if (usableSpacePercentage == 0){
+            $("#estimatedUsableSpace").css("min-width", "0");
+        }else{
+            $("#estimatedUsableSpace").css("min-width", barMinWidth + "px");
+        }
+        $("#estimatedProtectionSpace").css("width", redundancySpacePercentage + "%");
+        if (redundancySpacePercentage == 0 ){
+            $("#estimatedProtectionSpace").css("min-width", "0");
+        }else{
+            $("#estimatedProtectionSpace").css("min-width", barMinWidth + "px");
+        }
+        $("#estimatedWastedSpace").css("width", wastedSpacePercentage + "%");
+
+    }
 </script>