<div class="ts-content"> <div class="ts-container is-padded"> <div class="ts-grid mobile:is-stacked"> <div class="column is-6-wide"> <div id="raid_array_list" class="ts-menu is-start-icon is-separated"> <a class="item"> <span class="ts-icon is-user-icon"></span> 使用者 </a> <a class="item is-active"> <span class="ts-icon is-house-icon"></span> 首頁 </a> <a class="item"> <span class="ts-icon is-newspaper-icon"></span> 新聞 </a> </div> <div class="ts-divider has-top-spaced-small"></div> <div class="ts-content is-center-aligned"> <button class="ts-button is-start-icon is-positive is-circular"> <span class="ts-icon is-circle-plus-icon" style="color: var(--ts-positive-500);"></span> <span i18n>Create RAID // 新增陣列 </span> </button> <button class="ts-button is-start-icon is-positive is-circular"> <span class="ts-icon is-rotate-icon" style="color: var(--ts-primary-500);"></span> <span i18n>Assemble // 重組陣列 </span> </button> </div> </div> <div class="column is-fluid"> <div id="raid_details"> </div> </div> </div> </div> </div> <script> function initRAIDDeviceList(){ // Utility function to convert bytes to human-readable format function bytesToHumanReadable(bytes) { const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; if (bytes === 0) return '0 B'; const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); return (bytes / Math.pow(1024, i)).toFixed(2) + ' ' + sizes[i]; } $.ajax({ url: './api/raid/list', type: 'GET', dataType: 'json', success: function(data) { $('#raid_array_list').html(""); if (data.error != undefined){ // Handle error response console.error('Error fetching RAID devices:', data.error); $('#raid_array_list').append('<div class="ts-text is-error">Error: ' + data.error + '</div>'); }else{ let isSyncing = false; data.forEach((raid, index) => { // Add a new menu item for each RAID array let icon = ''; if (raid.State.includes('clean') && !raid.State.includes('sync')) { icon = '<span class="ts-icon is-check-icon" style="color: var(--ts-positive-500);"></span>'; } else if (raid.State.includes('sync')) { isSyncing = true; icon = '<span class="ts-icon is-spinning is-rotate-icon" style="color: var(--ts-positive-500);"></span>'; } else if (raid.State.includes('degraded')) { icon = '<span class="ts-icon is-triangle-exclamation-icon" style="color: var(--ts-warning-600);"></span>'; } else if (raid.State.includes('fail')) { icon = '<span class="ts-icon is-circle-xmark-icon" style="color: var(--ts-negative-500);"></span>'; } else { icon = '<span class="ts-icon is-question-icon" style="color: var(--ts-gray-500);"></span>'; } const menuItem = ` <a class="raid-array item ${index==0?'is-active':''}" id="raid_menu_${index}" onclick="showRAIDDetails(${index})"> ${icon} <div class="ts-content is-dense"> <div> <span class="ts-text is-heavy">${raid.DevicePath}</span> | ${raid.RaidLevel.toUpperCase()} </div> <div class="ts-text is-tiny has-top-spaced-small"> ${raid.Name} </div> </div> </a> `; $('#raid_array_list').append(menuItem); // Add a hidden div for each RAID array's details const raidDetails = ` <div id="raid_details_${index}" class="raid-details" style="display: none ;"> <div class="ts-box"> <div class="ts-content is-padded"> <div class="ts-header is-start-icon"> ${icon} ${raid.DevicePath} | ${raid.RaidLevel.toUpperCase()} </div> <div class="ts-text is-description"> ${raid.UUID}<br> ${raid.Name} </div> <div class="ts-text"> <span i18n> State // 狀態 </span>: ${raid.State}<br> <div class="sync-progress has-top-spaced-small ${isSyncing?'need-update-raid-sync-progress':''}" devname="${raid.DevicePath}" style="display: ${isSyncing?"auto":"none"};"> <div class="ts-progress is-processing"> <div class="bar" style="--value: 0"> <div class="text">0%</div> </div> </div> <div class="ts-text is-description has-top-spaced-small"> <span i18n> Synchronized // 已處理</span> <span class="processed_blocks"></span> <span>/</span> <span class="total_blocks"></span> <span i18n> blocks // 個區塊 </span><br> <!-- <span i18n> Speed // 速度 </span>: <span class="speed"></span><br> <span i18n> Expected Time // 預估時間 </span>: <span class="expected_time"></span> --> </div> </div> <span i18n> Array Size // 陣列大小 </span>: ${bytesToHumanReadable(raid.ArraySize * 1024)}<br> <span i18n> Created // 建立時間 </span>: <span>${new Date(raid.CreationTime).toLocaleString()}</span><br> </div> <table class="ts-table is-single-line has-top-spaced-large"> <thead> <tr> <th i18n>Disk Status // 磁碟狀態 </th> <th i18n>Counts // 數量 </th> </tr> </thead> <tbody> <tr> <td i18n> Active Devices // 啟用的磁碟 </td> <td>${raid.ActiveDevices}</td> </tr> <tr> <td i18n> Working Devices // 工作中的磁碟 </td> <td>${raid.WorkingDevices}</td> </tr> <tr> <td i18n> Failed Devices // 故障的磁碟 </td> <td>${raid.FailedDevices}</td> </tr> <tr> <td i18n> Spare Devices // 備用磁碟 </td> <td>${raid.SpareDevices}</td> </tr> </tbody> </table> </div> </div> <div class="ts-box is-padded has-top-spaced-small"> <div class="ts-content"> </div> </div> </div> `; $('#raid_details').append(raidDetails); }); } relocale(); // Recalculate layout syncProgressTicker(); // Start the sync progress ticker }, error: function(xhr, status, error) { console.error('Error fetching RAID devices:', error); } }); } initRAIDDeviceList(); //Create a ticker to check for RAID sync progress function syncProgressTicker(){ let syncProgressTracker = $(".need-update-raid-sync-progress"); if (syncProgressTracker.length > 0){ syncProgressTracker.each(function(){ let devname = $(this).attr("devname"); $.ajax({ url: './api/raid/sync?dev=' + devname, type: 'GET', dataType: 'json', data: { devname: devname }, success: function(data) { if (data.error != undefined){ // Handle error response console.error('Error fetching RAID sync progress:', data.error); //Refresh the RAID list initRAIDDeviceList(); }else{ let progress = parseFloat(data.ResyncPercent); let total_blocks = parseInt(data.TotalBlocks); let processed_blocks = parseInt(data.CompletedBlocks); let expected_time = data.ExpectedTime; let speed = data.Speed; $(`.sync-progress[devname="${devname}"] .bar`).css('--value', progress); $(`.sync-progress[devname="${devname}"] .bar .text`).text(`${progress.toFixed(1)}%`); $(`.sync-progress[devname="${devname}"] .processed_blocks`).text(processed_blocks); $(`.sync-progress[devname="${devname}"] .total_blocks`).text(total_blocks); //$(`.sync-progress[devname="${devname}"] .ts-text.is-description .speed`).text(speed); //$(`.sync-progress[devname="${devname}"] .ts-text.is-description .expected_time`).text(expected_time); } }, error: function(xhr, status, error) { console.error('Error fetching RAID sync progress:', error); } }); }); } } setInterval(syncProgressTicker, 5000); // Check every 5 seconds function showRAIDDetails(index) { $('.raid-details').hide(); // Hide all RAID details $(`#raid_details_${index}`).show(); // Show the selected RAID details $('.raid-array.is-active').removeClass('is-active'); // Remove active class from all menu items $(`#raid_menu_${index}`).addClass('is-active'); // Add active class to the selected menu item relocale(); // Recalculate layout } </script>