123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- <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>
|