Menu="Dashboard"
Nchan="wg_poller,update_1,update_2,update_3,ups_status,vm_dashusage"
---
<?PHP
/* Copyright 2005-2025, Lime Technology
 * Copyright 2012-2025, Bergware International.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version 2,
 * as published by the Free Software Foundation.
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
*/

function export_settings($protocol,$share) {
  if ($protocol!='yes' || $share['export']=='-') return "-";
  if ($share['export']=='e') return _(ucfirst($share['security']));
  return '<em>'._(ucfirst($share['security'])).'</em>';
}
function vpn_peers($file) {
  $peers = [];
  $entries = array_filter(array_map('trim',preg_split('/\[(Interface|Peer)\]/',file_get_contents($file))));
  foreach($entries as $key => $entry) {
    $noname = true;
    foreach (explode("\n",$entry) as $row) {
      if ($key>1 && $row[0]=='#') {$peers[$key-1] = substr($row,1); $noname = false;}
    }
    if ($key>1 && $noname) $peers[$key-1] = "Peer ".($key-1);
  }
  return $peers;
}
function customTiles($column) {
  global $mytiles;
  if (isset($mytiles)) foreach ($mytiles as $tile) if (!empty($tile[$column])) echo $tile[$column];
}

// adjust the text color in log window
$themeHelper->updateDockerLogColor($docroot); // $themeHelper set in DefaultPageLayout.php
exec("/etc/rc.d/rc.docker status >/dev/null",$dummy,$dockerd);
exec("/etc/rc.d/rc.libvirt status >/dev/null",$dummy,$libvirtd);

$dockerd    = $dockerd==0;
$libvirtd   = $libvirtd==0;
$apcupsd    = file_exists('/var/run/apcupsd.pid');
$cookie     = '/boot/config/dashboard_settings.json';
$conf       = glob('/etc/wireguard/wg*.conf');
$wireguard  = is_executable('/usr/bin/wg') && count($conf);
$started    = _var($var,'fsState')=='Started';
$sleep      = isset($display['sleep']);
$poolsOnly  = (_var($var,'SYS_ARRAY_SLOTS') == 0 ) ? true : false;
$array_size = $array_used = 0;
$extra_size = $extra_used = 0;
$cache_size = $cache_used = [];
$cache_type = $cache_rate = [];
$parity     = _var($var,'mdResync');
$mover      = file_exists('/var/run/mover.pid');
$btrfs      = exec('pgrep --ns $$ -cf /sbin/btrfs');
$vdisk      = exec("grep -Pom1 '^DOCKER_IMAGE_TYPE=\"\\K[^\"]+' /boot/config/docker.cfg 2>/dev/null")!='folder' ? _('Docker vdisk') : _('Docker folder');
$dot        = _var($display,'number','.,')[0];
$zfs        = count(array_filter(array_column($disks,'fsType'),function($fs){return str_replace('luks:','',$fs??'')=='zfs';}));

$domain_cfgfile = "/boot/config/domain.cfg";
$domain_cfg = parse_ini_file($domain_cfgfile);
$vmusage = isset($domain_cfg['USAGE']) ? $domain_cfg['USAGE'] : 'N';

// enable/disable graph elements by making hook script executable or not
chmod("$docroot/webGui/system/VM",$libvirtd ? 0755 : 0644);
chmod("$docroot/webGui/system/ZFS_cache",$zfs ? 0755 : 0644);

foreach ($disks as $disk) {
  switch (_var($disk,'type')) {
  case 'Data':
    if (isset($disk['fsFree'])) {
      $array_size += _var($disk,'fsSize',0);
      $array_used += _var($disk,'fsSize',0)-_var($disk,'fsFree',0);
    }
    break;
  case 'Cache':
    $name = _var($disk,'name');
    if (in_array($name,$pools)) {
      $cache_size[$name] = _var($disk,'fsSize',0);
      $cache_used[$name] = _var($disk,'fsSize',0)-_var($disk,'fsFree',0);
      $cache_type[$name] = _var($disk,'rotational') ? (_var($disk,'luksState') ? 'disk-encrypted' : 'disk') : 'nvme';
      $cache_rate[$name] = number_format(100*$cache_used[$name]/($cache_size[$name] ?: 1),1,$dot,'');
      if (empty($disks[$name]['devices'])) unset($pools[array_search($name,$pools)]);
    }
    break;
  }
}

foreach ($devs as $disk) {
  $extra_size += _var($disk,'sectors',0)*_var($disk,'sector_size',0);
}

$array_percent = number_format(100*$array_used/($array_size ?: 1),1,$dot,'');
exec('cat /sys/devices/system/cpu/*/topology/thread_siblings_list|sort -nu', $cpus);
$wg_up      = $wireguard ? exec("wg show interfaces") : '';
$wg_up      = $wg_up ? explode(' ',$wg_up) : [];
$up         = count($wg_up);
$down       = max(count($conf)-$up,0);
$fans       = exec("sensors -uA 2>/dev/null|grep -c 'fan[0-9]_input'");
$autofan    = is_executable("$docroot/plugins/dynamix.system.autofan/scripts/rc.autofan");
$group      = _var($var,'shareSMBEnabled')=='yes' | _var($var,'shareNFSEnabled')=='yes';
$names      = [];
$SMBpublic = $NFSpublic= 0;
foreach ($sec as $share => $prop) {
  if ( $prop['export'] == "-") continue;
  if ( $prop['security'] == "public") {
    if ( $share == "flash" || (! isset($disks[$share]) || (isset($disks[$share]) && ($var['shareDisk']??"") == "yes" && $share !=="flash") ) )
     $SMBpublic++;
  }
  if ( ($var['shareDisk']??"") !== "yes"  && $share !=="flash" ) continue;
  if ( ! $started && isset($disks[$share]) && $share !=="flash" ) continue;
  if ( (! isset($shares[$share]) && isset($disks[$share]) && ($var['shareDisk']??"") == "yes" ) || $share == "flash" ) {$shares[$share]=$disks[$share]; $shares[$share]['diskexport'] = true;}
}
if ($var['shareNFSEnabled']=='yes') {
  foreach ($sec_nfs as $share => $prop) {
    if ( $prop['export'] == "-") continue;
    if ( $prop['security'] == "public") {
      if ( $share == "flash" || (! isset($disks[$share]) || (isset($disks[$share]) && ($var['shareDisk']??"") == "yes" && $share !== "flash" ) ) )
        $NFSpublic++;
    }
    if ( ($var['shareDisk']??"") == "no"  && $share !=="flash" ) continue;
    if ( ! $started && isset($disks[$share]) && $share !=="flash" ) continue;
    if ( ( ! isset($shares[$share]) && isset($disks[$share]) && ($var['shareDisk']??"") == "yes") || $share == "flash" ) {$shares[$share]=$disks[$share]; $shares[$share]['diskexport'] = true;}
  }
}

$passwd = $nopass = 0;
foreach ($users as $user) if ($user['passwd']=='yes') $passwd++; else $nopass++;

$boot     = "/boot/config/plugins/dynamix";
$myfile   = "case-model.cfg";
$mycase   = file_exists("$boot/$myfile") ? file_get_contents("$boot/$myfile") : false;

$board    = dmidecode('Base Board Information','2',0);
$serial   = _("s/n").": ".($board['Serial Number'] ?? "--");
$board    = ($board['Manufacturer'] ?? "").' '.($board['Product Name'] ?? "").' '.(isset($board['Version']) ? ", "._("Version")." ".$board['Version'] : "");

$bios     = dmidecode('BIOS Information','0',0);
$biosdate = _("BIOS dated").": "._(my_time(strtotime($bios['Release Date'] ?? ""),$display['date']),0);
$bios     = $bios['Vendor'].(isset($bios['Version']) ? ", "._("Version")." ".$bios['Version'] : "");

$cpu      = dmidecode('Processor Information','4',0);
$cpumodel = str_ireplace(["Processor","(C)","(R)","(TM)"],["","&#169;","&#174;","&#8482;"],exec("grep -Pom1 '^model name\s+:\s*\K.+' /proc/cpuinfo") ?: $cpu['Version']);
$cpumodel .= (strpos($cpumodel,'@')===false && !empty($cpu['Current Speed']) ? " @ {$cpu['Current Speed']}" : "");
$cpu_vendor = $cpu['Manufacturer'] ?? "";

$total = exec("awk '/^MemTotal/{print $2*1024}' /proc/meminfo");
unset($ports); exec("ls --indicator-style=none /sys/class/net|grep -Po '^(bond|eth|wlan)\d+$'",$ports);
$ports[] = 'lo';

$sizes = ['MB','GB','TB'];
$memory_type = $ecc = '';
$memory_installed = $memory_maximum = 0;
$memory_devices = dmidecode('Memory Device','17');
foreach ($memory_devices as $device) {
  if (!is_numeric($device['Size'][0])) continue;
  [$size, $unit] = my_explode(' ',$device['Size']??'');
  $base = array_search($unit,$sizes);
  if ($base!==false) $memory_installed += $size*pow(1024,$base);
  if (!$memory_type && isset($device['Type']) && $device['Type']!='Unknown') $memory_type = $device['Type'];
}
$memory_array = dmidecode('Physical Memory Array','16');
foreach ($memory_array as $device) {
  [$size, $unit] = my_explode(' ',$device['Maximum Capacity']??'');
  $base = array_search($unit,$sizes);
  if ($base>=1) $memory_maximum += $size*pow(1024,$base);
  if (!$ecc && isset($device['Error Correction Type']) && $device['Error Correction Type']!='None') $ecc = "{$device['Error Correction Type']} ";
}
if ($memory_installed >= 1048576) {
  $memory_installed = round($memory_installed/1048576);
  $memory_maximum = round($memory_maximum/1048576);
  $unit = 'TiB';
} else { 
if ($memory_installed >= 1024) {
  $memory_installed = round($memory_installed/1024);
  $memory_maximum = round($memory_maximum/1024);
  $unit = 'GiB';}
else $unit = 'MiB'; }

// get system resources size
exec("df --output=size /boot /var/log /var/lib/docker 2>/dev/null|awk '(NR>1){print $1*1024}'",$df);
$flashsize  = my_scale($df[0],$unit,0,-1,1024)." $unit";
$logsize    = my_scale($df[1],$unit,0,-1,1024)." $unit";
$dockersize = my_scale($df[2],$unit,0,-1,1024)." $unit";
$ramsize    = my_scale($total,$unit,0,-1,1024)." $unit";

// If maximum < installed then roundup maximum to the next power of 2 size of installed. E.g. 6 -> 8 or 12 -> 16
$low = $memory_maximum < $memory_installed;
if ($low) $memory_maximum = pow(2,ceil(log($memory_installed)/log(2)));

switch ($themeHelper->getThemeName()) { // $themeHelper set in DefaultPageLayout.php
  case 'white': $color = '#1c1b1b'; $grid = '#e3e3e3'; $c0 = '#a8a8a8'; $c1 = '#dcdcdc'; break;
  case 'black': $color = '#f2f2f2'; $grid = '#2b2b2b'; $c0 = '#787878'; $c1 = '#444444'; break;
  case 'azure': $color = '#606e7f'; $grid = '#f3f0f4'; $c0 = '#606e7f'; $c1 = '#eceaec'; break;
  case 'gray' : $color = '#606e7f'; $grid = '#0c0f0b'; $c0 = '#606e7f'; $c1 = '#232523'; break;
  default     : $color = '#1c1b1b'; $grid = '#e3e3e3'; $c0 = '#a8a8a8'; $c1 = '#dcdcdc'; break;
}
?>

<link type="text/css" rel="stylesheet" href="<?autov('/webGui/styles/jquery.switchbutton.css')?>">
<script src="<?autov('/webGui/javascript/smoothie.js')?>"></script>
<script src="<?autov('/webGui/javascript/jquery.switchbutton.js')?>"></script>
<script src="<?autov('/plugins/dynamix.docker.manager/javascript/docker.js')?>"></script>
<script src="<?autov('/plugins/dynamix.vm.manager/javascript/vmmanager.js')?>"></script>

<div class='frame'>
    <div class='grid'>

        <div class='tile' id='tile1'>
            <table id='db_box1' class='dashboard'>
                <tbody class='system'>
                    <tr>
                        <td>
                            <span class='tile-header'>
                                <span class='tile-header-left'>
                                    <i class='icon-performance f32'></i>

                                    <div class='section'>
                                        <h3 class='tile-header-main'><?=_var($var,'NAME')?></h3>
                                        <span><?=htmlspecialchars(_var($var,'COMMENT'))?></span>
                                        <span id="current_time_" class="switch head_time"></span><br>
                                    </div>
                                </span>

                                <span class='tile-header-right'>
                                    <span class='tile-ctrl flex flex-row items-center gap-4'>
                                        <?if ($parity||$mover||$btrfs):?>
                                            <span class='fa fa-fw fa-<?=$started?'stop':'play'?>-circle busy' title="<?=$started?_("Stop the array"):_("Start the array")?>"></span>
                                        <?else:?>
                                            <span class='fa fa-fw fa-<?=$started?'stop':'play'?>-circle hand' title="<?=$started?_("Stop the array"):_("Start the array")?>" onclick='<?=$started?'Stop':'Start'?>Array()'></span>
                                        <?endif;?>
                                        <?if ($sleep):?>
                                            <span class='fa fa-fw fa-moon-o hand' title="_(Put system to sleep)_" onclick='Sleep()'></span>
                                        <?endif;?>
                                        <span class='fa fa-fw fa-refresh hand' title="_(Reboot the system)_" onclick='Reboot()'></span>
                                        <span class='fa fa-fw fa-power-off hand' title="_(Shutdown the system)_" onclick='Shutdown()'></span>
                                    </span>

                                    <span class='tile-header-right-controls'>
                                        <a href='/Dashboard/Settings/Identification'>
                                            <i class='fa fa-fw fa-cog control' title="_(Go to identification settings)_"></i>
                                        </a>
                                        <i class='fa fa-fw fa-wrench control tile' onclick='contentMgmt()' title="_(Tile Management)_"></i>
                                    </span>
                                </span>
                            </span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <div class='leftside'>
                                <a href="/Settings/DateTime" class="hand none">
                                    <span id="current_time"></span>
                                </a><br>
                                <span id="current_date"></span><br><br>
                                <span class='header'>
                                    <i class='indent fa fa-file-text-o'></i>_(Model)_
                                </span><br>
                                <i class='indent'></i><?=htmlspecialchars(_var($var,'SYS_MODEL'))?:'---'?><br><br>
                                <span class='header'>
                                    <i class='indent fa fa-id-badge'></i>_(Registration)_
                                </span><br>
                                <i class='indent'></i>Unraid OS <b><em><?=_var($var,'regTy')?></em></b><br><br>
                                <span class='header'>
                                    <i class='indent fa fa-clock-o'></i>_(Uptime)_
                                </span><br>
                                <i class='indent'></i><span class='uptime'></span>
                            </div>
                            <div class='rightside'>
                                <div
                                  id='casing'
                                  class='tile-select-case'
                                  title='_(Select Case Model)_'
                                  onclick='openChanges("select_case <?=$myfile?>", "_(Select Case Model)_", "selectcase")'
                                >
                                    <?if ($mycase):?>
                                        <?if (substr($mycase,-4)!='.png'):?>
                                            <i id='mycase' class='case-<?=$mycase?>'></i><br>
                                        <?else:?>
                                            <img id='mycase' src='<?=autov("/webGui/images/$mycase")?>'><br>
                                        <?endif;?>
                                    <?else:?>
                                        <i id='mycase' class='fa fa-hdd-o'></i><br>
                                    <?endif;?>
                                </div>
                            </div>
                        </td>
                    </tr>
                </tbody>

                <tbody title="_(Motherboard Information)_">
                    <tr>
                        <td>
                            <span class='tile-header'>
                              <span class='tile-header-left'>
                                <i class='icon-motherboard f32'></i>
                                <div class='section'>
                                    <h3 class='tile-header-main'>_(Motherboard)_</h3>
                                    <span id='mb-temp'></span><br>
                                </div>
                              </span>
                              <span class='tile-header-right'>
                                <span class='tile-header-right-controls'>
                                  <a href='#' onclick='InfoButton();' title="_(Show Information)_">
                                      <i class='fa fa-fw fa-info-circle control'></i>
                                  </a>
                                </span>
                              </span>
                            </span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <?=$board?><br>
                            <?=$bios?><br>
                            <?=$biosdate?>
                        </td>
                    </tr>
                </tbody>

                <?
                $is_intel_cpu = is_intel_cpu();
                $core_types = $is_intel_cpu ? get_intel_core_types() : [];
                ?>

                <tbody title="_(Processor Information)_" data="toggleCPU(true)">
                    <tr>
                        <td>
                            <span class='tile-header'>
                                <span class='tile-header-left'>
                                  <i class='icon-cpu f32'></i>
                                  <div class='section'>
                                      <h3 class='tile-header-main'>_(Processor)_</h3>
                                      <?=$cpumodel?>
                                  </div>
                                </span>
                                <span class='tile-header-right'>
                                    <span class='tile-header-right-controls'>
                                        <a href='/Dashboard/Settings/CPUset' title="_(Go to CPU pinning settings)_">
                                            <i class='fa fa-fw fa-cog control'></i>
                                        </a>
                                    </span>
                                </span>
                            </span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <span class='flex flex-row flex-wrap items-center gap-4'>
                                <span class="head_info">
                                    <span id='cpu-temp'></span>
                                </span>
                                <span class="switch">
                                    _(Load)_:<span class="head_bar">
                                    <span class='cpu_ load'>0%</span>
                                    <div class='usage-disk sys'>
                                        <span id='cpu_'></span>
                                        <span></span>
                                    </div>
                                </span>
                                <br>
                            </span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <span class='w26'>_(Overall Load)_:</span>
                            <span class='w72'>
                                <span class='cpu load resize'>0%</span>
                                <div class='usage-disk sys'>
                                    <span id='cpu'></span>
                                    <span></span>
                                </div>
                            </span>
                        </td>
                    </tr>
                    <tr id='cpu_main'>
                        <td>
                            <span class='flex flex-row items-center justify-between gap-4'>
                                <a onclick='toggleCPU()' title="_(Click to toggle details)_" class='cpu_close'>_(Show details)_</a>
                                <span id='chart-toggle' class='flex flex-row items-center gap-4'>
                                    <span>
                                        <select id='cpuline' class='auto' title="_(Select time frame)_" onchange='changeCPUline(this.value)'>
                                            <?=mk_option("","10", _("10 s"));?>
                                            <?=mk_option("","30", _("30 s"));?>
                                            <?=mk_option("","60", _("1 m"));?>
                                            <?=mk_option("","120", _("2 m"));?>
                                            <?=mk_option("","300", _("5 m"));?>
                                        </select>
                                    </span>
                                    <a onclick='toggleChart()' title="_(Click to toggle CPU chart)_">
                                        <span class="fa fa-fw fa-bar-chart hand"></span>
                                    </a>
                                </span>
                            </span>
                        </td>
                    </tr>

                    <?
                    foreach ($cpus as $pair) {
                        [$cpu1, $cpu2] = my_preg_split('/[,-]/',$pair);
                        echo "<tr class='cpu_open'>";
                        if ($is_intel_cpu && count($core_types) > 0)
                            $core_type = "({$core_types[$cpu1]})";
                        else
                            $core_type = "";

                        if ($cpu2)
                            echo "<td><span class='w26'>CPU $cpu1 $core_type - HT $cpu2 </span><span class='dashboard w36'><span class='cpu$cpu1 load resize'>0%</span><div class='usage-disk sys'><span id='cpu$cpu1'></span><span></span></div></span><span class='dashboard w36'><span class='cpu$cpu2 load resize'>0%</span><div class='usage-disk sys'><span id='cpu$cpu2'></span><span></span></div></span></td>";
                        else
                            echo "<td><span class='w26'>CPU $cpu1 $core_type</span><span class='w72'><span class='cpu$cpu1 load resize'>0%</span><div class='usage-disk sys'><span id='cpu$cpu1'></span><span></span></div></span></td>";
                        echo "</tr>";
                    }
                    ?>
                    <tr id='cpu_chart'>
                        <td>
                            <canvas id='cpuchart' style='width:100%; height:96px'></canvas>
                        </td>
                    </tr>
                </tbody>

                <tbody title="_(Memory Utilization)_">
                    <tr>
                        <td>
                            <span class='tile-header'>
                                <span class='tile-header-left'>
                                    <i class='icon-ram f32'></i>
                                    <div class='section'>
                                        <h3 class='tile-header-main'>_(System)_</h3>
                                        <span class='flex flex-row flex-wrap items-center gap-4'>
                                            <span class="head_info">
                                                <span>
                                                    <i class='ups fa fa-line-chart'></i>_(Memory)_: <?="$memory_installed $unit $memory_type $ecc"?>
                                                </span>
                                            </span>
                                            <span class="switch">
                                                _(RAM)_:<span class="head_bar">
                                                    <span class='sys0_ load'>0%</span>
                                                    <div class='usage-disk sys'>
                                                        <span id='sys0_'></span>
                                                        <span></span>
                                                    </div>
                                                </span>
                                            </span><br>
                                        </span>
                                    </div>
                                </span>
                                <span class='tile-header-right'>
                                    <span class='tile-header-right-controls'>
                                        <a href='/Dashboard/Tools/Processes' title="_(View Running Processes)_">
                                            <i class='fa fa-fw fa-info-circle control'></i>
                                        </a>
                                    </span>
                                </span>
                            </span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <div class="tile-system-memory-body">
                                <div class="tile-system-memory-labels">
                                    <div>
                                        <i class='ups fa fa-compress'></i>_(Usable size)_: <?=$ramsize?><br>
                                        <i class='ups fa fa-expand'></i>_(Maximum size)_: <?="$memory_maximum $unit"?><?=$low?'*':''?>
                                    </div>
                                    <div>
                                        <legend>_(Legend)_</legend>
                                        <span id='dynamic'></span>
                                    </div>
                                </div>
                                <div class='tile-system-memory-charts'>
                                  <span>
                                      <a class='info hand none'>_(RAM usage)_<span>_(Percent of total used memory)_ (<?=$ramsize?>)</span></a>
                                      <div class='pie' id='sys0'><span class='sys0'></span><span class='var0'></span></div>
                                  </span>
                                  <span>
                                      <a class='info hand none'>_(Flash device)_<span>_(Percent usage of flash usb device)_ (<?=$flashsize?>)</span></a>
                                      <div class='pie' id='sys1'><span class='sys1'></span><span class='var1'></span></div>
                                  </span>
                                  <span>
                                      <a class='info hand none'>_(Log filesystem)_<span>_(Percent usage of LOG file system)_ (<?=$logsize?>)</span></a>
                                      <div class='pie' id='sys2'><span class='sys2'></span><span class='var2'></span></div>
                                  </span>
                                  <span>
                                      <a class='info hand none'><?=$vdisk?><span><?=_("Percent usage of $vdisk")?> (<?=$dockersize?>)</span></a>
                                      <div class='pie' id='sys3'><span class='sys3'></span><span class='var3'></span></div>
                                  </span>
                                </div>
                            </div>
                        </td>
                    </tr>
                </tbody>

                <tbody title="_(Interface Information)_" class="mixed">
                    <tr>
                        <td>
                            <span class='tile-header'>
                                <span class='tile-header-left'>
                                    <i class='icon-ethernet f32'></i>
                                    <div class='section'>
                                        <span class='flex flex-row items-center gap-4'>
                                          <h3 class='tile-header-main'>_(Interface)_</h3>
                                          <span class="head_gap flex flex-row items-center gap-4 network-selects">
                                              <i class='ups fa fa-angle-double-right'></i>
                                              <select name="port_select" class="network-select network-interface" onchange="portSelect(this.value)">
                                                  <?foreach ($ports as $port):?>
                                                      <?=mk_option("",$port,_($port))?>
                                                  <?endforeach;?>
                                              </select>
                                              <select name="enter_view" class="network-select network-type" onchange="changeView(this.value)">
                                                  <?=mk_option("", "0", _("General info"))?>
                                                  <?=mk_option("", "1", _("Counters info"))?>
                                                  <?=mk_option("", "2", _("Errors info"))?>
                                                  <?=mk_option("", "3", _("Network traffic"))?>
                                              </select>
                                          </span><br>
                                        </span>
                                        <span class='flex flex-row flex-wrap items-center gap-4'>
                                            <span class='head_info'>
                                                <i class='ups fa fa-angle-double-down'></i>_(Inbound)_: <span id='inbound'>---</span>
                                            </span>
                                            <span>
                                                <i class='ups fa fa-angle-double-up'></i>_(Outbound)_: <span id='outbound'>---</span>
                                            </span><br>
                                        </span>
                                    </div>
                                </span>

                                <span class="tile-header-right">
                                    <span class='tile-header-right-controls'>
                                        <a href='/Dashboard/Settings/NetworkSettings' title="_(Go to network settings)_">
                                            <i class='fa fa-fw fa-cog control'></i>
                                        </a>
                                    </span>
                                </span>
                            </span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <span class='w26'>
                                &nbsp;
                            </span>
                            <span class='w36'>
                                <i class='view1'>_(Mode of operation)_</i>
                                <i class='view2'>_(Received packets)_</i>
                                <i class='view3'>_(Receive counters)_</i>
                                <i class='fa fa-fw fa-arrow-down view4 red-text'></i>&nbsp;
                                <i class='view4 red-text'>_(Inbound)_</i>
                            </span>
                            <span class='w36'>
                                <i class='view1'></i>
                                <i class='view2'>_(Transmitted packets)_</i>
                                <i class='view3'>_(Transmit counters)_</i>
                                <i class='fa fa-fw fa-arrow-up view4 orange-text'></i>&nbsp;
                                <i class='view4 orange-text'>_(Outbound)_</i>
                                <span class='view4' style='float:right'>
                                    <select id='netline' class='auto' title="_(Select time frame)_" onchange='changeNetline(this.value)'>
                                        <?=mk_option("","10", _("10 s"))?>
                                        <?=mk_option("","30", _("30 s"))?>
                                        <?=mk_option("","60", _("1 m"))?>
                                        <?=mk_option("","120", _("2 m"))?>
                                        <?=mk_option("","300", _("5 m"))?>
                                    </select>
                                </span>
                            </span>
                        </td>
                    </tr>
                    <?
                    $c = 0;
                    foreach ($ports as $port) {
                        $last = $port=='lo' ? ' last' : '';
                        echo "<tr class='view1{$last}'><td><span class='w26'>$port</span><span class='w72' id='main".($c++)."'></span></td></tr>";
                    }
                    $c = 0;
                    foreach ($ports as $port) {
                        $last = $port=='lo' ? ' last' : '';
                        echo "<tr class='view2{$last}'><td><span class='w26'>$port</span><span class='w36' id='port{$c}'></span><span class='w36' id='port".($c+1)."'></span></td></tr>";
                        $c += 2;
                    }
                    $c = 0;
                    foreach ($ports as $port) {
                        $last = $port=='lo' ? ' last' : '';
                        echo "<tr class='view3{$last}'><td><span class='w26'>$port</span><span class='w36' id='link{$c}'></span><span class='w36' id='link".($c+1)."'></span></td></tr>";
                        $c += 2;
                    }
                    ?>
                    <tr class="view4">
                        <td>
                            <canvas id="netchart" style='width:100%; height:120px'></canvas>
                        </td>
                    </tr>
                </tbody>

                <?if ($wireguard):?>
                <tbody title="_(VPN Connections)_">
                    <tr>
                        <td>
                            <span class='tile-header'>
                                <span class='tile-header-left gap-2'>
                                    <i class='icon-vpn f32'></i>
                                    <div class='section'>
                                        <h3 class='tile-header-main'>_(VPN)_</h3>
                                        <span class='flex flex-row flex-wrap items-center gap-4'>
                                            <span class='head_info'>
                                                <i class='ups fa fa-play-circle'></i>_(Active tunnels)_: <span id='vpn-active'><?=$up?></span>
                                            </span>
                                            <span>
                                              <i class='ups fa fa-pause-circle'></i>_(Inactive tunnels)_: <span id='vpn-inactive'><?=$down?></span>
                                            </span>
                                        </span><br>
                                    </div>
                                </span>

                                <span class='tile-header-right'>
                                    <span class='tile-header-right-controls'>
                                        <a href='/Settings/VPNmanager' title="_(Go to VPN settings)_">
                                            <i class='fa fa-fw fa-cog control'></i>
                                        </a>
                                    </span>
                                </span>
                            </span>
                        </td>
                    </tr>
                    <?foreach ($conf as $wg):?>
                        <?$vpn = basename($wg,'.conf'); $peers = vpn_peers($wg);?>
                        <tr>
                            <td class='vpn'>
                                <span class='w26'>
                                    <i class='icon-vpn vpn<?=in_array($vpn,$wg_up)?'':' inactive'?>' onclick="toggleVPN($(this),'<?=$vpn?>')" title="Toggle tunnel state"></i>
                                    <?="Tunnel $vpn"?>
                                </span>
                                <span class='w36 vpn right'>_(Activity)_</span>
                                <span class='w36 vpn right'>_(Handshake)_</span>
                            </td>
                        </tr>
                        <?foreach ($peers as $i => $peer):?>
                            <tr>
                                <td>
                                    <span class='w26 wg1'><?=$peer?></span>
                                    <span class='w36 wg2' id='<?="$vpn-rx-".($i-1)?>'>---</span>
                                    <span class='w36 wg2' id='<?="$vpn-hs-".($i-1)?>'>_(inactive)_</span>
                                </td>
                            </tr>
                        <?endforeach;?>
                    <?endforeach;?>
                </tbody>
                <?endif;?>

                <?if ($apcupsd):?>
                <tbody title="_(Power Status)_">
                    <tr>
                        <td>
                            <span class='tile-header'>
                                <span class='tile-header-left'>
                                    <i class='icon-ups f32'></i>
                                    <div class='section'>
                                        <h3 class='tile-header-main'>_(Power)_</h3>
                                        <span class="flex flex-row flex-wrap items-center gap-4">
                                            <span class='switch head_gap' id='ups_status_'></span>
                                            <br>
                                            <span class="head_info">
                                                <span>
                                                    <i class='ups fa fa-bar-chart'></i>_(UPS Model)_:
                                                </span>
                                                <span id='ups_model'></span>
                                            </span>
                                            <span class="switch">
                                                <span>_(Load)_:</span>
                                                <span class="head_gap" id='ups_loadpct_'></span>
                                            </span><br>
                                        </span>
                                    </div>
                                </span>
                                <span class='tile-header-right'>
                                    <span class='tile-header-right-controls'>
                                        <a href='/Dashboard/Settings/UPSsettings' title="_(Go to UPS settings)_">
                                            <i class='fa fa-fw fa-cog control'></i>
                                        </a>
                                    </span>
                                </span>
                            </span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <span class='w36'>
                                <i class='ups fa fa-fw fa-plug'></i>_(UPS status)_:
                            </span>
                            <span id='ups_status'></span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <span class='w36'>
                                <i class='ups fa fa-fw fa-bars'></i>_(UPS Load)_:
                            </span>
                            <span id='ups_loadpct'></span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <span class='w36'>
                                <i class='ups fa fa-fw fa-battery'></i>_(Battery charge)_:
                            </span>
                            <span id='ups_bcharge'></span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <span class='w36'>
                                <i class='ups fa fa-fw fa-clock-o'></i>_(Runtime left)_:
                            </span>
                            <span id='ups_timeleft'></span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <span class='w36'>
                                <i class='ups fa fa-fw fa-bolt'></i>_(Nominal power)_:
                            </span>
                            <span id='ups_nompower'></span>
                        </td>
                    </tr>
                    <tr>
                        <td>
                            <span class='w36'>
                                <i class='ups fa fa-fw fa-ellipsis-h'></i>_(Output voltage)_:
                            </span>
                            <span id='ups_outputv'></span>
                        </td>
                    </tr>
                </tbody>
                <?endif;?>

                <?if ($fans):?>
                <tbody title="_(Fan Information)_">
                    <tr>
                        <td>
                            <span class='tile-header'>
                                <span class='tile-header-left'>
                                    <i class='icon-fan f32'></i>
                                    <div class='section'>
                                        <h3 class='tile-header-main'>_(Airflow)_</h3>
                                        <span>
                                            <i class='ups fa fa-sort-amount-asc'></i>_(Fan count)_: <?=$fans?>
                                        </span><br>
                                    </div>
                                </span>
                                <?if ($autofan):?>
                                    <span class='tile-header-right'>
                                        <span class='tile-header-right-controls'>
                                            <a href='/Dashboard/Settings/FanSettings' title="_(Go to fan settings)_">
                                                <i class='fa fa-fw fa-cog control'></i>
                                            </a>
                                        </span>
                                    </span>
                                <?endif;?>
                            </span>
                        </td>
                    </tr>
                    <?
                    $label = $value = [];
                    $i = 0;
                    for ($fan=0; $fan<$fans; $fan++) {
                        if ($fan > 0 && $fan % 3 == 0) $i++;
                        $class = $fan % 3 == 2 ? "" : " class='fan'";
                        $label[$i][] = "<span{$class}>"._('FAN')." ".($fan+1)."</span>";
                    }
                    $i = 0;
                    for ($fan=0; $fan<$fans; $fan++) {
                        if ($fan > 0 && $fan % 3 == 0) $i++;
                        $class = $fan % 3 == 2 ? "" : " class='fan'";
                        $value[$i][] = "<span{$class} id='fan$fan'>--</span>";
                    }
                    echo "<tr><td>";
                    for ($i = 0; $i < count($label); $i++) {
                        foreach ($label[$i] as $data) echo $data;
                        echo "<br>";
                        foreach ($value[$i] as $data) echo $data;
                        echo "<br>";
                        if ($i < count($value)-1) echo "<br>";
                    }
                    echo "</td></tr>";
                    ?>
                </tbody>
                <?endif;?>

                <?customTiles('column1');?>
            </table>
        </div>

        <div class='tile' id='tile2'>
            <table id='db_box2' class='dashboard'>
                <?if ($dockerd):?>
                    <tbody id='docker_view' title="_(Docker Containers)_" data="noApps()">
                        <tr>
                            <td>
                                <span class='tile-header'>
                                    <span class='tile-header-left'>
                                        <i class='icon-docker f32'></i>
                                        <div class='section'>
                                            <h3 class='tile-header-main'>_(Docker Containers)_</h3>
                                            <span class='apps button'>
                                                <input type='checkbox' id='apps'>
                                            </span>
                                            <span class='apps switch'></span><br>
                                        </div>
                                    </span>
                                    <span class='tile-header-right'>
                                        <span class='tile-header-right-controls'>
                                            <a href='/Dashboard/Settings/DockerSettings' title="_(Go to Docker settings)_">
                                                <i class='fa fa-fw fa-cog control'></i>
                                            </a>
                                        </span>
                                    </span>
                                </span>
                            </td>
                        </tr>
                    </tbody>
                <?endif;?>
                <?if ($libvirtd):?>
                    <tbody id='vm_view' title="_(Virtual Machines)_" data="noVMs()">
                        <tr>
                            <td>
                                <span class='tile-header'>
                                    <span class='tile-header-left'>
                                        <i class='icon-virtualization f32'></i>
                                        <div class='section'>
                                            <h3 class='tile-header-main'>_(Virtual Machines)_</h3>
                                            <span class='vms button'>
                                                <input type='checkbox' id='vms'>
                                            </span>
                                            <span class='vms switch'></span><br>
                                        </div>
                                    </span>

                                    <span class='tile-header-right'>
                                        <span class='tile-header-right-controls'>
                                            <a href='/Dashboard/Settings/VMSettings' title="_(Go to VM settings)_">
                                                <i class='fa fa-fw fa-cog control'></i>
                                            </a>
                                        </span>
                                    </span>
                                </span>
                            </td>
                        </tr>
                    </tbody>

                    <?if ($vmusage == "Y"):?>
                        <tbody id='vm_view_usage' title="_(Virtual Machines Usage)_" >
                            <tr>
                                <td>
                                    <span class='tile-header'>
                                        <span class='tile-header-left'>
                                            <i class='icon-virtualization f32'></i>
                                            <div class='section'>
                                              <h3 class='tile-header-main'>_(Virtual Machines Usage)_</h3>
                                            </div>
                                        </span>
                                        <span class='tile-header-right'>
                                            <span class='tile-header-right-controls'>
                                                <a href='/Dashboard/Settings/VMSettings' title="_(Go to VM settings)_">
                                                    <i class='fa fa-fw fa-cog control'></i>
                                                </a>
                                            </span>
                                        </span>
                                    </span>
                                </td>
                            </tr>
                        </tbody>
                    <?endif;?>
                <?endif;?>

                <tbody title="_(Shares Information)_"<?if ($group):?> class="mixed"<?endif;?>>
                    <tr>
                        <td>
                            <span class='tile-header'>
                                <span class='tile-header-left'>
                                    <i class='icon-folder f32'></i>
                                    <div class='section'>
                                        <span class='flex flex-row flex-wrap items-center gap-4'>
                                          <h3 class='tile-header-main'>_(Shares)_</h3>
                                            <?if ($group):?>
                                              <i class='ups fa fa-angle-double-right'></i>
                                                <span class="head_gap flex flex-row flex-wrap items-center gap-4">
                                                    <select name="enter_share" onchange="changeMode(this.value)">
                                                        <?if (_var($var,'shareSMBEnabled')=='yes'):?>
                                                            <?=mk_option("", "0", "SMB")?>
                                                        <?endif;?>
                                                        <?if (_var($var,'shareNFSEnabled')=='yes'):?>
                                                            <?=mk_option("", "2", "NFS")?>
                                                        <?endif;?>
                                                    </select>
                                                </span>
                                            <?endif;?>
                                        </span>
                                        <span>
                                            <?=sprintf(_("Share count: %s with %s public SMB and %s public NFS"),count($shares),$SMBpublic,$NFSpublic)?>
                                        </span><br>
                                    </div>
                                </span>

                                <span class='tile-header-right'>
                                    <span class='tile-header-right-controls'>
                                        <a href='/Shares' title="_(Go to Share settings)_">
                                            <i class='fa fa-fw fa-cog control'></i>
                                        </a>
                                    </span>
                                </span>
                            </span>
                        </td>
                    </tr>
                    <tr class='header'>
                        <td>
                            <span class='w26'>_(Name)_</span>
                            <span class='w44'>_(Description)_</span>
                            <span class='w18'>_(Security)_</span>
                            <span>_(Streams)_</span>
                        </td>
                    </tr>
                    <?
                    if (_var($var,'shareSMBEnabled')=='yes') {
                        $i = 0;
                        foreach ($shares as $name => $share) {
                            $list = "<a href=\"/Dashboard/Shares/".(isset($share['diskexport']) ? "Disk" : "Share")."?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
                            $comment = $share['comment'] ?: '-';
                            $security = export_settings(_var($var,'shareSMBEnabled'), $sec[$name]);
                            $last = $name==array_key_last($shares) ? ' last' : '';
                            echo "<tr class='smb share share1{$last}'><td><span class='w26'><i class='icon-folder f14'></i>$list</span><span class='w44'>".htmlspecialchars($comment)."</span><span class='w18'>$security</span><span id='share",$i++,"'>0</span></td></tr>";
                        }
                        if (!count($shares)) echo "<tr class='smb share share1'><td class='none'>"._("No shares present")."</td></tr>";
                    }
                    if (_var($var,'shareNFSEnabled')=='yes') {
                        foreach ($shares as $name => $share) {
                            if ( ! isset($sec_nfs[$name]) ) continue;
                            $list = "<a href=\"/Dashboard/Shares/".(isset($share['diskexport']) ? "Disk" : "Share")."?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
                            $comment = $share['comment'] ?: '-';
                            $security = export_settings(_var($var,'shareNFSEnabled'), $sec_nfs[$name]);
                            $last = $name==array_key_last($shares) ? ' last' : '';
                            echo "<tr class='nfs share share3{$last}'><td><span class='w26'><i class='icon-folder f14'></i>$list</span><span class='w44'>".htmlspecialchars($comment)."</span><span class='w18'>$security</span><span>-</span></td></tr>";
                        }
                        if (!count($shares)) echo "<tr class='nfs share share3'><td class='none'>"._("No shares present")."</td></tr>";
                    }
                    if (!$group) {
                        foreach ($shares as $name => $share) {
                            $list = "<a href=\"/Dashboard/Shares/".(isset($share['diskexport']) ? "Disk" : "Share")."?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
                            $comment = $share['comment'] ?: '-';
                            echo "<tr class='share'><td><span class='w26'><i class='icon-folder f14'></i>$list</span><span class='w44'>".htmlspecialchars($comment)."</span><span class='w18'>-</span><span>-</span></td></tr>";
                        }
                        if (!count($shares)) echo "<tr class='share'><td class='none'>"._("No shares present")."</td></tr>";
                    }
                    ?>
                </tbody>

                <tbody title="_(Users Information)_"<?if ($group):?> class="mixed"<?endif;?>>
                    <tr>
                        <td>
                            <span class='tile-header'>
                                <span class='tile-header-left'>
                                    <i class='icon-users f32'></i>
                                    <div class='section'>
                                        <h3 class='tile-header-main'>_(Users)_</h3>
                                        <?if ($group):?>
                                            <span class="head_gap">
                                                <i class='ups fa fa-angle-double-right unused'></i>
                                                <select name="enter_user" class="unused">
                                                    <?if (_var($var,'shareSMBEnabled')=='yes'):?>
                                                        <?=mk_option("", "0", "SMB")?>
                                                    <?endif;?>
                                                    <?if (_var($var,'shareNFSEnabled')=='yes'):?>
                                                        <?=mk_option("", "2", "NFS")?>
                                                    <?endif;?>
                                                </select>
                                            </span>
                                        <?endif;?>
                                        <span>
                                            <?=sprintf(_("User count: %s with %s unprotected"),count($users),$nopass)?>
                                        </span>
                                    </div>
                                </span>
                                <span class='tile-header-right'>
                                    <span class='tile-header-right-controls'>
                                        <a href='/Users' title="_(Go to User settings)_">
                                            <i class='fa fa-fw fa-cog control'></i>
                                        </a>
                                    </span>
                                </span>
                            </span>
                        </td>
                    </tr>
                    <tr class='header'>
                        <td>
                            <span class='w26'>_(Name)_</span>
                            <span class='w44'>_(Description)_</span>
                            <span class='w18'>_(Write)_</span>
                            <span>_(Read)_</span>
                        </td>
                    </tr>
                    <?
                    if (_var($var,'shareSMBEnabled')=='yes') {
                        foreach ($users as $user) {
                            $name = $user['name'];
                            $list = "<a href=\"/Dashboard/Users/UserEdit?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
                            $desc = $user['desc'] ?: '-';
                            if ($name=='root') {
                                $write = $read = '-';
                            } else {
                                $write = $read = 0;
                                foreach ($shares as $share) {
                                    $access = $sec[$share['name']];
                                    if ($access['export']=='-') continue;
                                    switch ($access['security']) {
                                        case 'public':
                                            $write++;
                                            $read++;
                                            break;
                                        case 'secure':
                                            if (in_array($name,explode(',',$access['writeList']))) {$write++; $read++;} else $read++;
                                            break;
                                        case 'private':
                                            if (in_array($name,explode(',',$access['writeList']))) {$write++; $read++;}
                                            if (in_array($name,explode(',',$access['readList']))) $read++;
                                            break;
                                    }
                                }
                            }
                            if ($user['passwd']!='yes') $list = str_replace('blue-text','orange-text',$list);
                            $last = $name==array_key_last($users) ? ' last' : '';
                            echo "<tr class='smb user user1{$last}'><td><span class='w26'><i class='icon-user f14'></i>$list</span><span class='w44'>".htmlspecialchars($desc)."</span><span class='w18'>$write</span><span>$read</span></td></tr>";
                        }
                    }
                    if (_var($var,'shareNFSEnabled')=='yes') {
                        foreach ($users as $user) {
                            $name = $user['name'];
                            $list = "<a href=\"/Dashboard/Users/UserEdit?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
                            $desc = $user['desc'] ?: '-';
                            $write = '-'; $read = '-';
                            if ($user['passwd']!='yes') $list = str_replace('blue-text','orange-text',$list);
                            $last = $name==array_key_last($users) ? ' last' : '';
                            echo "<tr class='nfs user user3{$last}'><td><span class='w26'><i class='icon-user f14'></i>$list</span><span class='w44'>".htmlspecialchars($desc)."</span><span class='w18'>$write</span><span>$read</span></td></tr>";
                        }
                    }
                    if (!$group) {
                        foreach ($users as $user) {
                            $name = $user['name'];
                            $list = "<a href=\"/Dashboard/Users/UserEdit?name=".urlencode($name)."\" class=\"blue-text\" title=\"$name settings\">$name</a>";
                            $desc = $user['desc'] ?: '-';
                            if ($user['passwd']!='yes') $list = str_replace('blue-text','orange-text',$list);
                            echo "<tr class='user'><td><span class='w26'><i class='icon-user f14'></i>$list</span><span class='w44'>".htmlspecialchars($desc)."</span><span class='w18'>-</span><span>-</span></td></tr>";
                        }
                    }
                    ?>
                </tbody>

                <?customTiles('column2');?>
            </table>
        </div>

        <div class='tile' id='tile3'>
            <table id='db_box3' class='dashboard'>
                <?if (!$poolsOnly):?>
                    <tbody title="_(Parity Information)_">
                        <tr>
                            <td>
                                <span class='tile-header'>
                                    <span class='tile-header-left'>
                                        <i class='icon-health f32'></i>
                                        <div class='section'>
                                            <h3 class='tile-header-main'>_(Parity)_</h3>
                                            <span class='parity'></span><br>
                                        </div>
                                    </span>
                                    <span class='tile-header-right'>
                                        <span class='tile-header-right-controls'>
                                        <a href='/Dashboard/Settings/Scheduler' title="_(Go to scheduler settings)_">
                                            <i class='fa fa-fw fa-cog control'></i>
                                        </a>
                                    </span>
                                </span>
                            </td>
                        </tr>
                        <tr>
                            <td id='parity' class="wrap"></td>
                        </tr>
                        <tr>
                            <td id='program' class="wrap"></td>
                        </tr>
                    </tbody>

                    <?$power = _var($display,'power') && in_array('nvme',array_column(main_filter($disks),'transport')) ? ' / '._('Power') : '';?>
                    <tbody id='array_list' title="_(Array Information)_">
                        <tr>
                            <td>
                                <span class='tile-header'>
                                    <span class='tile-header-left'>
                                        <i class='icon-disks f32'></i>
                                        <div class='section'>
                                            <h3 class='tile-header-main'>_(Array)_<?if (!$started):?> (_(stopped)_)<?endif;?></h3>
                                            <span>
                                                <?if ($started):?>
                                                    <?=sprintf(_("%s used of %s (%s %%)"),my_scale($array_used*1024,$unit)." $unit",my_scale($array_size*1024,$unit,-1,-1)." $unit",$array_percent)?>
                                                <?endif;?>
                                            </span><br>
                                        </div>
                                    </span>
                                    <span class='tile-header-right'>
                                        <span class='tile-header-right-controls'>
                                            <a href='/Dashboard/Settings/DiskSettings' title="_(Go to disk settings)_">
                                                <i class='fa fa-fw fa-cog control'></i>
                                            </a>
                                        </span>
                                    </span>
                                </span>
                            </td>
                        </tr>
                        <tr>
                            <td id='array_info'></td>
                        </tr>
                        <tr class='header'>
                            <td>
                                <span class='w26'>_(Device)_</span>
                                <span class='w18'>_(Status)_</span>
                                <span class='w18'>_(Temp)_<?=$power?></span>
                                <span class='w18'>_(SMART)_</span>
                                <span class='w18'>_(Utilization)_</span>
                            </td>
                        </tr>
                    </tbody>
                <?endif;?>

                <?$i=0?>
                <?foreach ($pools as $pool):
                    $cache = array_filter(cache_filter($disks),function($disk) use ($pool){return prefix($disk['name'])==$pool;});
                    $power = _var($display,'power') && in_array('nvme',array_column($cache,'transport')) ? ' / '._('Power') : '';
                ?>
                    <tbody id='pool_list<?=$i?>' title="_(<?=ucfirst($pool)?> Information)_">
                        <tr>
                            <td>
                                <span class='tile-header'>
                                    <span class='tile-header-left'>
                                        <i class='icon-disk f32'></i>
                                        <div class='section'>
                                            <h3 class='tile-header-main'><?=_(native($pool),3).($started ? '' : ' ('._('stopped').')')?></h3>
                                            <span>
                                                <?if ($started):?>
                                                    <?=sprintf(_("%s used of %s (%s %%)"),my_scale($cache_used[$pool]*1024,$unit)." $unit",my_scale($cache_size[$pool]*1024,$unit,-1,-1)." $unit",$cache_rate[$pool])?>
                                                <?endif;?>
                                          </span><br>
                                        </div>
                                    </span>
                                    <span class='tile-header-right'>
                                        <span class='tile-header-right-controls'>
                                            <a href='/Dashboard/Settings/Device?name=<?=$pool?>' title="_(Go to disk settings)_">
                                                <i class='fa fa-fw fa-cog control'></i>
                                            </a>
                                        </span>
                                    </span>
                                </span>
                            </td>
                        </tr>
                        <tr>
                            <td id='pool_info<?=$i++?>'></td>
                        </tr>
                        <tr class='header'>
                            <td>
                                <span class='w26'>_(Device)_</span>
                                <span class='w18'>_(Status)_</span>
                                <span class='w18'>_(Temp)_<?=$power?></span>
                                <span class='w18'>_(SMART)_</span>
                                <span class='w18'>_(Utilization)_</span>
                            </td>
                        </tr>
                    </tbody>
                <?endforeach;?>

                <?if ($devs):?>
                    <?$power = _var($display,'power') && in_array('nvme',array_column($devs,'transport')) ? ' / '._('Power') : '';?>
                    <tbody id='devs_list' title="_(Unassigned Devices)_">
                        <tr>
                            <td>
                                <span class='tile-header'>
                                    <span class='tile-header-left'>
                                        <i class='icon-disc f32'></i>
                                        <div class='section'>
                                            <h3 class='tile-header-main'>_(Unassigned)_<?if (!$started):?> (_(stopped)_)<?endif;?></h3>
                                            <span></span><br>
                                        </div>
                                    </span>
                                    <span class='tile-header-right'>
                                        <span class='tile-header-right-controls'>
                                            <a href='/Dashboard/Settings/DiskSettings' title="_(Go to disk settings)_">
                                                <i class='fa fa-fw fa-cog control'></i>
                                            </a>
                                        </span>
                                    </span>
                                </span>
                            </td>
                        </tr>
                        <tr>
                            <td id='devs_info'></td>
                        </tr>
                        <tr class='header'>
                            <td>
                                <span class='w26'>_(Device)_</span>
                                <span class='w18'>_(Status)_</span>
                                <span class='w18'>_(Temp)_<?=$power?></span>
                                <span class='w18'>_(SMART)_</span>
                                <span class='w18'>_(Utilization)_</span>
                            </td>
                        </tr>
                    </tbody>
                <?endif;?>

                <?customTiles('column3');?>
            </table>
        </div>

    </div>
</div>

<form name='boot' method='POST' action='/webGui/include/Boot.php'>
<input type='hidden' name='cmd' value=''>
</form>

<div id="iframe-popup"></div>

<div id="templateContentMgmt" class="template">
<!--!
<style>
.item{display:inline-block;width:210px;float:left;height:4rem}
</style>
<script>
var table = $('table.dashboard');
var index = [], sort = [], checked = [];
table.find('tbody').not('.system').each(function(){
  index.push($(this).attr('title'));
  sort.push($(this).attr('sort'));
  checked.push($(this).is(':visible') ? 'checked' : '');
});
for (let n=0,x; x=index[n]; n++) {
  $('div#list').append("<span class='item'><input class='checker' type='checkbox' "+checked[n]+">"+x+"</span>");
}
function hideShow() {
  let n = 0, inactive = [];
  var count = {'db_box1':0, 'db_box2':0, 'db_box3':0};
  $('input.checker').each(function(){
    var tbody = $('table.dashboard').find('tbody[sort="'+sort[n]+'"]');
    var id = tbody.parent().prop('id');
    if ($(this).prop('checked')) {
      tbody.show();
      tbody.prev().show();
      count[id]++;
    } else {
      tbody.hide();
      tbody.prev().hide();
      inactive.push(sort[n]);
    }
    n++;
  });
  count[table.find('tbody.system').parent().prop('id')]++;
  if (count['db_box1']>0) $('div#tile1').show(); else $('div#tile1').hide();
  if (count['db_box2']>0) $('div#tile2').show(); else $('div#tile2').hide();
  if (count['db_box3']>0) $('div#tile3').show(); else $('div#tile3').hide();
  if (inactive.length>0) {
    cookie.inactive_content = inactive.join(';');
  } else {
    delete cookie.inactive_content;
  }
  saveCookie();
}
</script>
<div id="list"></div>
!-->
</div>

<div id="templateClone" class="template">
    <table class="snapshot">
        <tr>
            <td>_(VM Being Cloned)_:</td>
            <td><span id="VMBeingCloned"></span></td>
        </tr>
        <tr>
            <td>_(New VM)_:</td>
            <td><input type="text" id="target" autocomplete="off" spellcheck="false" value="" onclick="this.select()"></td>
        </tr>
        <tr>
            <td>_(Overwrite)_:</td>
            <td><input type="checkbox" id="Overwrite" value=""></td>
        </tr>
        <tr hidden>
            <td>_(Start Cloned VM)_:</td>
            <td><input type="checkbox" id="Start" value=""></td>
        </tr>
        <tr hidden>
            <td>_(Edit VM after clone)_:</td>
            <td><input type="checkbox" id="Edit" value=""></td>
        </tr>
        <tr>
            <td>_(Regenerate MAC addresses)_:</td>
            <td><input type="checkbox" id="Regenmac" value="" checked></td>
        </tr>
        <tr>
            <td>_(Check free space)_:</td>
            <td><input type="checkbox" id="Free" value=""></td>
        </tr>
    </table>
</div>

<div id="templatesnapshotcreate" class="template">
    <table id="snapshot" class="snapshot">
        <tr>
            <td>_(VM Name)_:</td>
            <td><label id="VMName"></label></td>
        </tr>
        <tr>
            <td>_(Snapshot Name)_:</td>
            <td>
                <input type="text" id="targetsnap" autocomplete="off" spellcheck="false" value="--generate" onclick="this.select()">
                _(Check free space)_:<input type="checkbox" id="targetsnapfspc" checked>
            </td>
        </tr>
        <tr>
            <td>_(Description)_:</td>
            <td><input type="text" id="targetsnapdesc" autocomplete="off" spellcheck="false" value="" onclick="this.select()"></td>
        </tr>
        <tr id="memoryline">
            <td>_(Memory dump)_:</td>
            <td><input type="checkbox" id="targetsnapmem" checked></td>
        </tr>
        <tr id="fstypeline">
            <td>_(FS Native Snapshot)_:</td>
            <td>
                <label id="fstype"></label>
                <input type="checkbox" id="targetsnapfstype">
                _(Unchecked will use QEMU External Snapshot)_
            </td>
        </tr>
    </table>
</div>

<script>
Number.prototype.pad = function(size){var s=String(this);while(s.length<(size||2)){s='0'+s;}return s;}
Array.prototype.tail = function(t){return this.slice(-t).map(function(o){return o.y;}).join(';');}
String.prototype.build = function(){return this.replace(/\n(<!--!|!-->)\n/g,'');}
jQuery.prototype.alive = function(width,color){return this.finish().animate({width:width},{step:function(){$(this).css({'overflow':'visible'}).removeClass().addClass(color);}});}
String.prototype.md5 = function(){
  // Original copyright (c) Paul Johnston & Greg Holt.
  var hc = '0123456789abcdef';
  function rh(n){var j,s='';for (j=0;j<=3;j++) s+=hc.charAt((n>>(j*8+4))&0x0F)+hc.charAt((n>>(j*8))&0x0F);return s;}
  function ad(x,y){var l=(x&0xFFFF)+(y&0xFFFF);var m=(x>>16)+(y>>16)+(l>>16);return (m<<16)|(l&0xFFFF);}
  function rl(n,c){return (n<<c)|(n>>>(32-c));}
  function cm(q,a,b,x,s,t){return ad(rl(ad(ad(a,q),ad(x,t)),s),b);}
  function ff(a,b,c,d,x,s,t){return cm((b&c)|((~b)&d),a,b,x,s,t);}
  function gg(a,b,c,d,x,s,t){return cm((b&d)|(c&(~d)),a,b,x,s,t);}
  function hh(a,b,c,d,x,s,t){return cm(b^c^d,a,b,x,s,t);}
  function ii(a,b,c,d,x,s,t){return cm(c^(b|(~d)),a,b,x,s,t);}
  function sb(x) {
    var i;var nblk=((x.length+8)>>6)+1;var blks=new Array(nblk*16);for (i=0;i<nblk*16;i++) blks[i]=0;
    for (i=0;i<x.length;i++) blks[i>>2]|=x.charCodeAt(i)<<((i%4)*8);
    blks[i>>2]|=0x80<<((i%4)*8);blks[nblk*16-2]=x.length*8;return blks;
  }
  var i,x=sb(''+this),a=1732584193,b=-271733879,c=-1732584194,d=271733878,olda,oldb,oldc,oldd;
  for (i=0;i<x.length;i+=16) {olda=a;oldb=b;oldc=c;oldd=d;
    a=ff(a,b,c,d,x[i+ 0], 7, -680876936);d=ff(d,a,b,c,x[i+ 1],12, -389564586);c=ff(c,d,a,b,x[i+ 2],17,  606105819);
    b=ff(b,c,d,a,x[i+ 3],22,-1044525330);a=ff(a,b,c,d,x[i+ 4], 7, -176418897);d=ff(d,a,b,c,x[i+ 5],12, 1200080426);
    c=ff(c,d,a,b,x[i+ 6],17,-1473231341);b=ff(b,c,d,a,x[i+ 7],22,  -45705983);a=ff(a,b,c,d,x[i+ 8], 7, 1770035416);
    d=ff(d,a,b,c,x[i+ 9],12,-1958414417);c=ff(c,d,a,b,x[i+10],17,     -42063);b=ff(b,c,d,a,x[i+11],22,-1990404162);
    a=ff(a,b,c,d,x[i+12], 7, 1804603682);d=ff(d,a,b,c,x[i+13],12,  -40341101);c=ff(c,d,a,b,x[i+14],17,-1502002290);
    b=ff(b,c,d,a,x[i+15],22, 1236535329);a=gg(a,b,c,d,x[i+ 1], 5, -165796510);d=gg(d,a,b,c,x[i+ 6], 9,-1069501632);
    c=gg(c,d,a,b,x[i+11],14,  643717713);b=gg(b,c,d,a,x[i+ 0],20, -373897302);a=gg(a,b,c,d,x[i+ 5], 5, -701558691);
    d=gg(d,a,b,c,x[i+10], 9,   38016083);c=gg(c,d,a,b,x[i+15],14, -660478335);b=gg(b,c,d,a,x[i+ 4],20, -405537848);
    a=gg(a,b,c,d,x[i+ 9], 5,  568446438);d=gg(d,a,b,c,x[i+14], 9,-1019803690);c=gg(c,d,a,b,x[i+ 3],14, -187363961);
    b=gg(b,c,d,a,x[i+ 8],20, 1163531501);a=gg(a,b,c,d,x[i+13], 5,-1444681467);d=gg(d,a,b,c,x[i+ 2], 9,  -51403784);
    c=gg(c,d,a,b,x[i+ 7],14, 1735328473);b=gg(b,c,d,a,x[i+12],20,-1926607734);a=hh(a,b,c,d,x[i+ 5], 4,    -378558);
    d=hh(d,a,b,c,x[i+ 8],11,-2022574463);c=hh(c,d,a,b,x[i+11],16, 1839030562);b=hh(b,c,d,a,x[i+14],23,  -35309556);
    a=hh(a,b,c,d,x[i+ 1], 4,-1530992060);d=hh(d,a,b,c,x[i+ 4],11, 1272893353);c=hh(c,d,a,b,x[i+ 7],16, -155497632);
    b=hh(b,c,d,a,x[i+10],23,-1094730640);a=hh(a,b,c,d,x[i+13], 4,  681279174);d=hh(d,a,b,c,x[i+ 0],11, -358537222);
    c=hh(c,d,a,b,x[i+ 3],16, -722521979);b=hh(b,c,d,a,x[i+ 6],23,   76029189);a=hh(a,b,c,d,x[i+ 9], 4, -640364487);
    d=hh(d,a,b,c,x[i+12],11, -421815835);c=hh(c,d,a,b,x[i+15],16,  530742520);b=hh(b,c,d,a,x[i+ 2],23, -995338651);
    a=ii(a,b,c,d,x[i+ 0], 6, -198630844);d=ii(d,a,b,c,x[i+ 7],10, 1126891415);c=ii(c,d,a,b,x[i+14],15,-1416354905);
    b=ii(b,c,d,a,x[i+ 5],21,  -57434055);a=ii(a,b,c,d,x[i+12], 6, 1700485571);d=ii(d,a,b,c,x[i+ 3],10,-1894986606);
    c=ii(c,d,a,b,x[i+10],15,   -1051523);b=ii(b,c,d,a,x[i+ 1],21,-2054922799);a=ii(a,b,c,d,x[i+ 8], 6, 1873313359);
    d=ii(d,a,b,c,x[i+15],10,  -30611744);c=ii(c,d,a,b,x[i+ 6],15,-1560198380);b=ii(b,c,d,a,x[i+13],21, 1309151649);
    a=ii(a,b,c,d,x[i+ 4], 6, -145523070);d=ii(d,a,b,c,x[i+11],10,-1120210379);c=ii(c,d,a,b,x[i+ 2],15,  718787259);
    b=ii(b,c,d,a,x[i+ 9],21, -343485551);a=ad(a,olda);b=ad(b,oldb);c=ad(c,oldc);d=ad(d,oldd);
  }
  return rh(a)+rh(b)+rh(c)+rh(d);
}
jQuery.prototype.hideMe = function() {
  var hidden = cookie.hidden_content;
  hidden = hidden ? hidden.split(';') : [];
  if (hidden.indexOf(this.attr('sort'))>=0) this.find('tr:gt(0)').hide();
}
jQuery.prototype.mixedView = function(s) {
  if (s==0) {
    this.find('tr:gt(0)').hide();
    this.find('span.switch').show();
    this.find('span.button').hide();
    return;
  }
  this.find('tr:gt(0)').show();
  this.find('span.switch').hide();
  this.find('span.button').show();
  if (this.attr('data')) {
    setTimeout(this.attr('data'));
  }
  if (this.hasClass('mixed')) {
    var select = this.find('select[name^="enter"]');
    select = parseInt(select.val())+1;
    this.find('tr:gt(0)').each(function(){
      var names = ($(this).attr('class')||'').split(' ');
      for (let n=0,name; name=names[n]; n++) if (/[0-9]/.test(name.slice(-1)) && name.slice(-1)!=select) $(this).hide();
    });
  }
}

<?
$cookie_content = @file_get_contents($cookie);
if ( @json_decode($cookie_content,true) ):?>
var cookie  = JSON.parse('<?=trim($cookie_content);?>');
<?else:?>
var cookie  = {};
<?endif;?>
var colors  = ['<?=$c0?>','<?=$c1?>','#d77e0d','#d4ac0d','#cd5c5c','#ffc0cb','#e6e6fa','#9370db','#7cfc00','#228b22','#00ffff','#4682b4'];
var blue    = '#486dba'; // fallback color when too many graph elements exist
var ports   = [<?=implode(',',array_map('escapestring',$ports))?>];
var cpu     = [];
var rxd     = [];
var txd     = [];
var cputime = 0;
var nettime = 0;
var cpuline = parseInt(cookie.cpuline)||30;
var netline = parseInt(cookie.netline)||30;
var update2 = true;
var box     = null;
var startup = true;
var stopgap = '<thead class="stopgap"><tr><td class="stopgap"></td></tr></thead>';
var recall  = null;
var recover = null;

// Helper function to calculate millisPerPixel based on container width
function getMillisPerPixel(timeInSeconds, containerId) {
  var container = document.getElementById(containerId);
  var width = (container && container.offsetWidth > 0) ? container.offsetWidth : 600; // fallback to 600 if not found or zero width
  return (timeInSeconds * 1000) / width;
}

// SmoothieCharts initialization
var cpuchart = new SmoothieChart({
  millisPerPixel: (cpuline * 1000) / 600, // Safe initial value
  minValue: -1,
  maxValue: 100,
  responsive: true,
  grid: {
    strokeStyle: '<?=$grid?>',
    fillStyle: 'transparent',
    lineWidth: 1,
    millisPerLine: 5000,
    verticalSections: 4
  },
  labels: {
    fillStyle: '<?=$color?>',
    fontSize: 11,
    precision: 0
  },
  timestampFormatter: function(date) { return ''; },
  minValueScale: 1.02,
  maxValueScale: 1.02,
  yMinFormatter: function(value) {
    return Math.max(0, Math.floor(value)) + ' %';
  },
  yMaxFormatter: function(value) {
    return Math.max(0, Math.min(100, Math.ceil(value))) + ' %';
  }
});

var netchart = new SmoothieChart({
  millisPerPixel: (netline * 1000) / 600, // Safe initial value
  minValue: 0,
  responsive: true,
  grid: {
    strokeStyle: '<?=$grid?>',
    fillStyle: 'transparent',
    lineWidth: 1,
    millisPerLine: 5000,
    verticalSections: 4
  },
  labels: {
    fillStyle: '<?=$color?>',
    fontSize: 11,
    placement: 'left'
  },
  timestampFormatter: function(date) { return ''; },
  minValueScale: 1.02,
  maxValueScale: 1.02,
  yMaxFormatter: function(value) {
    if (value >= 1000) {
      return Math.floor(value / 1000) + ' Mbps';
    }
    return Math.floor(value) + ' kbps';
  },
  yMinFormatter: function(value) {
    return Math.floor(value) + ' kbps';
  }
});

// Create TimeSeries for CPU and Network data
var cpuTimeSeries = new TimeSeries();
var rxTimeSeries = new TimeSeries();
var txTimeSeries = new TimeSeries();

// Add TimeSeries to charts with colors
cpuchart.addTimeSeries(cpuTimeSeries, { strokeStyle: '#ff8c2f', lineWidth: 1 });
netchart.addTimeSeries(rxTimeSeries, { strokeStyle: '#e22828', lineWidth: 1 });
netchart.addTimeSeries(txTimeSeries, { strokeStyle: '#ff8c2f', lineWidth: 1 });

// Custom data for chart state management
netchart.customData = {
  isVisible: false
};

cpuchart.customData = {
  isVisible: false,
  coresVisible: false,
  cpuData: null,
  cpuLoad: 0
};

$(function() {
  // Visibility observer for #netchart
  const netchartElement = document.querySelector('#netchart');
  const netchartObserver = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.target === netchartElement) {
        netchart.customData.isVisible = entry.isIntersecting;
        // Chart visibility changed
        if (netchart.customData.isVisible) {
          // SmoothieCharts handles visibility automatically
        }
      }
    });
  }, {
    root: null, // Use viewport as root
    rootMargin: '0px', // No margin
    threshold: 0.1 // Trigger when 10% of element is visible
  });

  // Start observing the netchart element
  if (netchartElement) {
    netchartObserver.observe(netchartElement);
  } else {
    console.warn('NetChart element not found for visibility observer');
  }

  // Visibility observer for #cpuchart
  const cpuchartElement = document.querySelector('#cpuchart');
  const cpuchartObserver = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (entry.target === cpuchartElement) {
        cpuchart.customData.isVisible = entry.isIntersecting;
        // Chart visibility changed
        if (cpuchart.customData.isVisible) {
          // SmoothieCharts handles visibility automatically
        }
      }
    });
  }, {
    root: null, // Use viewport as root
    rootMargin: '0px', // No margin
    threshold: 0.1 // Trigger when 10% of element is visible
  });

   // Start observing the cpuchart element
   if (cpuchartElement) {
     cpuchartObserver.observe(cpuchartElement);
   } else {
     console.warn('CpuChart element not found for visibility observer');
   }

   // Visibility observer for the cpu core load visibility
   // Set the visibility true if one or more are visible
   const cpuOpenElements = document.querySelectorAll('.cpu_open');
   let cpuOpenVisibilityStates = new Map(); // Track visibility state of each element

   const cpuOpenObserver = new IntersectionObserver((entries) => {
     let stateChanged = false;

     entries.forEach(entry => {
       const element = entry.target;
       const isVisible = entry.isIntersecting;
       const wasVisible = cpuOpenVisibilityStates.get(element) || false;

       // Only update if state actually changed
       if (wasVisible !== isVisible) {
         cpuOpenVisibilityStates.set(element, isVisible);
         stateChanged = true;
       }
     });

     // Only dispatch event if at least one element changed state
     if (stateChanged) {
       // Check if ALL elements have the same visibility state
       const allHidden = Array.from(cpuOpenVisibilityStates.values()).every(state => state === false);

       cpuchart.customData.coresVisible = !allHidden;
     }
   }, {
     root: null, // Use viewport as root
     rootMargin: '0px', // No margin
     threshold: 0.1 // Trigger when 10% of element is visible
   });

   // Start observing all .cpu_open elements
   cpuchart.customData.coresVisible = false;
   if (cpuOpenElements.length > 0) {
     cpuOpenElements.forEach(element => {
       cpuOpenObserver.observe(element);
     });
   } else {
     console.warn('No .cpu_open elements found for visibility observer');
   }
});

// Debounced resize handler to account for animationEnd not firing if ApexCharts has the viewport resized
let viewportResizeTimeout;
window.addEventListener('resize', function(){
  clearTimeout(viewportResizeTimeout);
  viewportResizeTimeout = setTimeout(function(){
    // Update millisPerPixel based on new container sizes
    cpuchart.options.millisPerPixel = getMillisPerPixel(cpuline, 'cpuchart');
    netchart.options.millisPerPixel = getMillisPerPixel(netline, 'netchart');
  }, 250); // Wait 250ms after resize stops before executing
});

if (cookie.port_select && !ports.includes(cookie.port_select)) {
  delete cookie.port_select;
  saveCookie();
}
var port_select = cookie.port_select||ports[0];

function saveCookie() {
  $.post('/webGui/include/InitCharts.php',{cmd:'cookie',data:JSON.stringify(cookie)});
}

function sanitizeMultiCookie(cookieName, delimiter, removeDuplicates=false) {
  // Some browser states leave multi-value cookies with nulls, empties or duplicates.
  // This function cleans up any such cookies so that they do not break functionality.
  try {
    var uncleanCookie = $.cookie(cookieName);
    if (uncleanCookie) {
      uncleanCookie = uncleanCookie.split(delimiter);
      var cleanCookie = uncleanCookie.filter(n => n);
      if (removeDuplicates) { cleanCookie = [...new Set(cleanCookie)]; }
      if (JSON.stringify(uncleanCookie) !== JSON.stringify(cleanCookie)) {
        $.cookie(cookieName,cleanCookie.join(delimiter),{expires:3650});
        return true;
      } else {
        return false;
      }
    } else {
      return false;
    }
  } catch (ex) {
    return false;
  }
}

function initCharts(clear) {
  // SmoothieCharts manages its own data through TimeSeries
  if (clear) {
    // Clear the TimeSeries data if needed
    rxTimeSeries.clear();
    txTimeSeries.clear();
  }
}

function resetCharts() {
  // SmoothieCharts automatically manages data retention
  // No manual cleanup needed
}

function addChartCpu(load) {
  // Add data point to SmoothieCharts TimeSeries
  cpuTimeSeries.append(new Date().getTime(), load);
}

function addChartNet(rx, tx) {
  // Add data points to SmoothieCharts TimeSeries (convert bps to kbps)
  var now = new Date().getTime();
  rxTimeSeries.append(now, Math.floor(rx / 1000));
  txTimeSeries.append(now, Math.floor(tx / 1000));
}

// Cache for last values to avoid unnecessary DOM updates
var lastCpuValues = {
  load: -1,
  color: '',
  fontColor: '',
  coreValues: {}
};

function updateCPUBarCharts() {
  if (!isPageVisible()) {
    return;
  }
  // prevent an initial JS error if the first datapoint isn't available yet
  // Update CPU bar charts based on current data
  const customData = cpuchart.customData;
  if (!customData.cpuData?.cpus || typeof customData.cpuLoad === 'undefined') {
    return;
  }

  const cpuLoad = customData.cpuLoad;
  const critical = <?=$display['critical']?>;
  const warning = <?=$display['warning']?>;

  // Only update DOM if values have changed
  if (cpuLoad !== lastCpuValues.load) {
    const cpuLoadText = cpuLoad + '%';
    const cpuLoadColor = setColor(cpuLoad, critical, warning);
    const cpuLoadFontColor = fontColor(cpuLoad, critical, warning);

    // Batch DOM updates for overall CPU load
    const $cpuElements = $('.cpu_, .cpu');
    const $cpuAliveElements = $('#cpu_, #cpu');

    $cpuElements.text(cpuLoadText).css({'color': cpuLoadFontColor});

    // Only call alive() if color actually changed
    //if (cpuLoadColor !== lastCpuValues.color) {
      $cpuAliveElements.alive(cpuLoadText, cpuLoadColor);
      lastCpuValues.color = cpuLoadColor;
   // }

    lastCpuValues.load = cpuLoad;
    lastCpuValues.fontColor = cpuLoadFontColor;
  }

  // Update individual CPU cores if they are visible
  if (customData.coresVisible) {
    const cpus = customData.cpuData.cpus;

    // Batch DOM updates for CPU cores
    const cpuCoreUpdates = [];
    const cpuAliveUpdates = [];

    cpus.forEach((cpuCore, index) => {
      const coreLoad = Math.floor(cpuCore.percentTotal);

      // Only process if value changed
      if (!lastCpuValues.coreValues[index] || lastCpuValues.coreValues[index].load !== coreLoad) {
        const coreLoadText = coreLoad + '%';
        const coreColor = setColor(coreLoad, critical, warning);
        const coreFontColor = fontColor(coreLoad, critical, warning);

        cpuCoreUpdates.push({
          selector: '.cpu' + index,
          text: coreLoadText,
          color: coreFontColor
        });

        // Only update alive() if color changed
        const lastCore = lastCpuValues.coreValues[index] || {};
        //if (coreColor !== lastCore.color) {
          cpuAliveUpdates.push({
            selector: '#cpu' + index,
            text: coreLoadText,
            color: coreColor
          });
          lastCore.color = coreColor;
       // }

        // Update cache
        lastCpuValues.coreValues[index] = {
          load: coreLoad,
          color: coreColor,
          fontColor: coreFontColor
        };
      }
    });

    // Apply batch updates only for changed values
    if (cpuCoreUpdates.length > 0) {
      cpuCoreUpdates.forEach(update => {
        $(update.selector).text(update.text).css({'color': update.color});
      });
    }

    if (cpuAliveUpdates.length > 0) {
      cpuAliveUpdates.forEach(update => {
        $(update.selector).alive(update.text, update.color);
      });
    }
  }
}


function isPageVisible() {
  // SmoothieCharts handles visibility automatically
  return !document.hidden;
}

<?if ($wireguard):?>
function toggleVPN(id,vtun) {
  var up = $('#vpn-active');
  var down = $('#vpn-inactive');
  if (id.hasClass('inactive')) {
    $.post('/webGui/include/update.wireguard.php',{'#cmd':'toggle','#wg':'start','#vtun':vtun},function(on){if (on){
      id.removeClass('inactive');
      up.text(up.text()*1+1);
      if (down.text()>0) down.text(down.text()*1-1);
    }});
  } else {
    $.post('/webGui/include/update.wireguard.php',{'#cmd':'toggle','#wg':'stop','#vtun':vtun});
    id.addClass('inactive');
    down.text(down.text()*1+1);
    if (up.text()>0) up.text(up.text()*1-1);
    $('span[id^="'+vtun+'-hs"]').text('inactive');
    $('span[id^="'+vtun+'-rx"]').text('---');
  }
}
<?endif;?>

function noApps() {
  if ($('span.outer.apps:visible').length==0) $('#no_apps').show(); else $('#no_apps').hide();
}

function noVMs() {
  if ($('span.outer.vms:visible').length==0) $('#no_vms').show(); else $('#no_vms').hide();
}

function loadlist(init) {
  if (init) {
    $('#apps').switchButton({labels_placement:'right', off_label:"_(All Apps)_", on_label:"_(Started only)_", checked:cookie.my_apps=='startedOnly'});
    $('#vms').switchButton({labels_placement:'right', off_label:"_(All VMs)_", on_label:"_(Started only)_", checked:cookie.my_vms=='startedOnly'});
    $('#apps').change(function(){
      $('span.outer.apps.stopped').finish().toggle('fast',function(){noApps();})
      $('#apps').is(':checked') ? cookie.my_apps = 'startedOnly' : delete cookie.my_apps;
      saveCookie();
    });
    $('#vms').change(function(){
      $('span.outer.vms.stopped').finish().toggle('fast',function(){noVMs();});
      $('#vms').is(':checked') ? cookie.my_vms = 'startedOnly' : delete cookie.my_vms;
      saveCookie();
    });
  }
  $.post('/webGui/include/DashboardApps.php',{docker:'<?=$dockerd?>',vms:'<?=$libvirtd?>',vmusage:'<?=$vmusage?>'},function(d) {
    var data = d.split('\0');
    $('#docker_view tr.updated').remove();
    $('#docker_view').append(data[0]).hideMe();
    $('#vm_view tr.updated').remove();
    $('#vm_view').append(data[1]).hideMe();
    var started_apps = $('#docker_view').find('span.outer.apps.started').length;
    var stopped_apps = $('#docker_view').find('span.outer.apps.stopped').length;
    var paused_apps  = $('#docker_view').find('span.outer.apps.paused').length;
    var started_vms  = $('#vm_view').find('span.outer.vms.started').length;
    var stopped_vms  = $('#vm_view').find('span.outer.vms.stopped').length;
    var paused_vms   = $('#vm_view').find('span.outer.vms.paused').length;
    $('#vm_view_usage tr.useupdated').remove();
    $('#vm_view_usage').append(data[2]).hideMe();
    $('.apps.switch').html("_(Containers)_ -- _(Started)_: "+started_apps+", _(Stopped)_: "+stopped_apps+", _(Paused)_: "+paused_apps);
    $('.vms.switch').html("_(VMs)_ -- _(Started)_: "+started_vms+", _(Stopped)_: "+stopped_vms+", _(Paused)_: "+paused_vms);
    if (cookie.my_apps!=null) $('span.apps.stopped').hide(0,noApps());
    if (cookie.my_vms!=null) $('span.vms.stopped').hide(0,noVMs());
  });
}

function getCase() {
  $.post('/webGui/include/SelectCase.php',{mode:'get',file:'<?=$myfile?>'},function(model){
    if (!model) {
      $('#casing').html("<i id='mycase' class='fa fa-hdd-o'></i><br>");
    } else if (model.indexOf('.png')<0) {
      $('#casing').html("<i id='mycase' class='case-"+model+"'></i><br>");
    } else {
      var now = new Date();
      $('#casing').html("<img id='mycase' src='/webGui/images/"+model+"?v="+now.getTime()+"'><br>");
    }
  });
}

function changeMode(item) {
  if (item==0) delete cookie.enter_share; else cookie.enter_share = item;
  if (!startup) saveCookie();
<?if (_var($var,'shareSMBEnabled')=='yes'):?>
  if (startup || $('.smb.share1').parent().find('tr:eq(1)').is(':visible')) {
    if (item==0) $('.smb.share1').show(); else $('.smb.share1').hide();
  }
  if (startup || $('.smb.user1').parent().find('tr:eq(1)').is(':visible')) {
    if (item==0) $('.smb.user1').show(); else $('.smb.user1').hide();
  }
<?endif;?>
<?if (_var($var,'shareNFSEnabled')=='yes'):?>
  if ($('.nfs.share3').parent().find('tr:eq(1)').is(':visible')) {
    if (item==2) $('.nfs.share3').show(); else $('.nfs.share3').hide();
  }
  if ($('.nfs.user3').parent().find('tr:eq(1)').is(':visible')) {
    if (item==2) $('.nfs.user3').show(); else $('.nfs.user3').hide();
  }
<?endif;?>
  $('select[name="enter_user"]').val(item);
}

function changeView(item) {
  if (item==0) delete cookie.enter_view; else cookie.enter_view = item;
  if (!startup) saveCookie();
  if (item==0) $('.view1').show(); else $('.view1').hide();
  if (item==1) $('.view2').show(); else $('.view2').hide();
  if (item==2) $('.view3').show(); else $('.view3').hide();
  if (item==3) $('.view4').show(); else $('.view4').hide();
}

function changeCPUline(val) {
  cpuline = parseInt(val);
  if (val==30) delete cookie.cpuline; else cookie.cpuline = val;
  saveCookie();
  // Update chart range
  // Update SmoothieChart time window based on actual chart width
  cpuchart.options.millisPerPixel = getMillisPerPixel(cpuline, 'cpuchart');
  // No need to stop and restart, just update the option
}

function changeNetline(val) {
  netline = parseInt(val);
  if (val==30) delete cookie.netline; else cookie.netline = val;
  saveCookie();
  // Update chart range
  // Update SmoothieChart time window based on actual chart width
  netchart.options.millisPerPixel = getMillisPerPixel(netline, 'netchart');
  // No need to stop and restart, just update the option
}

function smartMenu(table) {
  $(table).find('[id^="smart-"]').each(function() {
    var opts = [];
    var id = '#'+$(this).attr('id');
    var page = $(this).attr('name');
    var view = $(this).attr('class');
    var disk = id.substr(id.indexOf('-')+1);
    opts.push({text:"_(Attributes)_",icon:'fa-sitemap',action:function(e){e.preventDefault();attributes(page,disk);}});
    opts.push({divider:true});
    opts.push({text:"_(Capabilities)_",icon:'fa-user',action:function(e){e.preventDefault();capabilities(page,disk);}});
    opts.push({divider:true});
    opts.push({text:"_(Identity)_",icon:'fa-home',action:function(e){e.preventDefault();identity(page,disk);}});
    if (view.search('green-text') == -1) {
      opts.push({divider:true});
      opts.push({text:"_(Acknowledge)_",icon:'fa-check-square-o',action:function(e){e.preventDefault();acknowledge(id,disk);}});
    }
    $(id).bind('click',function(){update2=false;}).bind('mouseout',function(){setTimeout(function(){update2=true;},15000);});
    context.destroy(id);
    context.attach(id,opts);
  });
}

function portMenu() {
  var select = 'select[name="port_select"]';
  var option = $(select+' option');
  for (var i=0; i < option.length; i++) {
    if (option[i].value == port_select) {option[i].selected = true; break;}
  }
}

function portSelect(name) {
  cookie.port_select = name;
  saveCookie();
  initCharts(true);
  port_select = name;
}

function moreInfo(data,table) {
  var info = [];
  if (data[1]>0) info.push(data[1]+' '+(data[1]==1 ? "_(device warning)_" : "_(device warnings)_"));
  if (data[2]>0) info.push(data[2]+' '+(data[2]==1 ? "_(heat warning)_" : "_(heat warnings)_"));
  if (data[3]>0) info.push(data[3]+' '+(data[3]==1 ? "_(SMART error)_" : "_(SMART errors)_"));
  if (data[4]>0) info.push(data[4]+' '+(data[4]==1 ? "_(utilization warning)_" : "_(utilization warnings)_"));
  return info.length ? "<div class='last'><i class='icon-u-triangle failed'></i><span class='failed'>"+table+" _(has)_ "+info.join('. ')+".</span></div>" : "";
}

function autoscale(value,text,size,kilo) {
  if (kilo==null) kilo = 1000;
  var unit = kilo==1024 ? ['','ki','Mi','Gi','Ti','Pi','Ei'] : ['','k','M','G','T','P','E'];
  var base = value>1?Math.floor(Math.log(value)/Math.log(kilo)):0;
  var data = base<unit.length?value/Math.pow(kilo, base):0;
  var scale = (data<100?100:10)/size;
  if (data==0) base=0;
  return ((Math.round(scale*data)/scale)+' '+unit[base]+text).replace(".","<?=_var($display,'number','.,')[0]?>");
}

function update900() {
  // prevent chart overflowing, reset every 5 minutes
  resetCharts();
  setTimeout(update900,300000);
}

function attributes(page,disk) {
  var tab = page=='New' ? 'tab2' : 'tab3';
  $.cookie('one',tab);
  location.replace('/Dashboard/'+page+'?name='+disk);
}

function capabilities(page,disk) {
  var tab = page=='New' ? 'tab3' : 'tab4';
  $.cookie('one',tab);
  location.replace('/Dashboard/'+page+'?name='+disk);
}

function identity(page,disk) {
  var tab = page=='New' ? 'tab4' : 'tab5';
  $.cookie('one',tab);
  location.replace('/Dashboard/'+page+'?name='+disk);
}

function acknowledge(id,disk) {
  $.post('/webGui/include/Acknowledge.php',{disk:disk},function(){
    $(id).removeClass('fa-thumbs-o-down orange-text').addClass('fa-thumbs-o-up green-text');$(id.replace('smart','text')).text("<?=_('healthy')?>");
  });
}

function dropdown(menu) {
  var select = 'select[name="'+menu+'"]';
  var size   = $(select+' option').length;
  var option = cookie[menu]||0;
  if (option >= size) option = 0;
  $(select+' option')[option].selected = true;
  $(select).change();
}

function toggleCPU(init) {
  if (!init) {
    if (!cookie.cpu) cookie.cpu = 'close'; else delete cookie.cpu;
    saveCookie();
  }
  if (!cookie.cpu) {
    $('.cpu_open').show();
    $('.cpu_close').text("_(Hide details)_");
  } else {
    $('.cpu_open').hide();
    $('.cpu_close').text("_(Show details)_");
  }
  setTimeout(function(){toggleChart(true);});
}

function toggleChart(init) {
  if (!init) {
    if (!cookie.cpu_chart) cookie.cpu_chart = 'close'; else delete cookie.cpu_chart;
    saveCookie();
  }
  $('#cpu_main').removeClass('last');
  $('.cpu_open:last').removeClass('last');
  if (!cookie.cpu_chart) {
    var hidden = cookie.hidden_content;
    hidden = hidden ? hidden.split(';') : [];
    if (hidden.indexOf($('#cpu_main').parent().attr('sort'))==-1) {
      $('#cpu_chart').show();
      $('#cpuline').show();
    } else {
      $('#cpu_chart').hide();
      $('#cpuline').hide();
    }
  } else {
    $('#cpu_chart').hide();
    $('#cpuline').hide();
    if ($('.cpu_open').is(':visible')) $('.cpu_open:last').addClass('last'); else $('#cpu_main').addClass('last');
  }
}

function StopArray() {
<?if ($confirm['stop']):?>
  swal({title:"_(Proceed)_?",text:"_(This will stop the array)_",type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(){StopArrayNow();});
<?else:?>
   StopArrayNow();
<?endif;?>
}

function StopArrayNow() {
  $('span.hand').prop('onclick',null).off('click').addClass('busy').css({'cursor':'default'});
  $.post('/update.htm',{startState:'<?=htmlspecialchars(_var($var,'mdState'))?>', cmdStop:'Stop'},function(){refresh();});
}

function StartArray() {
<?if ($confirm['stop']):?>
  swal({title:"_(Proceed)_?",text:"_(This will start the array)_",type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(){StartArrayNow();});
<?else:?>
  StartArrayNow();
<?endif;?>
}

function StartArrayNow() {
  $('span.hand').prop('onclick',null).off('click').addClass('busy').css({'cursor':'default'});
  $.post('/update.htm',{startState:'<?=htmlspecialchars(_var($var,'mdState'))?>', cmdStart:'Start'},function(){refresh();});
}

function Reboot() {
<?if ($confirm['down']):?>
  swal({title:"_(Proceed)_?",text:"_(This will reboot the system)_",type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(){RebootNow();});
<?else:?>
  RebootNow();
<?endif;?>
}

function RebootNow() {
  document.boot.cmd.value = 'reboot';
  document.boot.submit();
}

function Shutdown() {
<?if ($confirm['down']):?>
  swal({title:"_(Proceed)_?",text:"_(This will shutdown the system)_",type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(){ShutdownNow();});
<?else:?>
  ShutdownNow();
<?endif;?>
}

function ShutdownNow() {
  document.boot.cmd.value = 'shutdown';
  document.boot.submit();
}

<?if ($sleep):?>
function Sleep() {
<?if ($confirm['sleep']):?>
  swal({title:"_(Proceed)_?",text:"_(This will put the system to sleep)_",type:'warning',html:true,showCancelButton:true,confirmButtonText:"_(Proceed)_",cancelButtonText:"_(Cancel)_"},function(){SleepNow();});
<?else:?>
  SleepNow();
<?endif;?>
}

function SleepNow() {
  $('#statusraid').append('&nbsp;&bullet;&nbsp;<span class="warning" style="font-weight:bold">System in sleep mode</span>');
  $.get('/plugins/dynamix.s3.sleep/include/SleepMode.php',function(){refresh();});
}
<?endif;?>

function sortTables() {
  $('table.dashboard').each(function(){
    var table = $(this);
    var index = cookie[table.prop('id')];
    // sorting list exists
    if (index != null) {
      index = index.split(';');
      for (var i=0,n; n=index[i]; i++) {
        var tbody = table.find('tbody[sort="'+n+'"]');
        // element not in this table?
        if (tbody.length==0) {
          // search the other tables to find the element
          $('table.dashboard').not(table).each(function(){
            var other = $(this).find('tbody[sort="'+n+'"]');
            if (other.length) tbody = other;
          });
        }
        tbody.appendTo(table);
      }
    }
  });
  $('table.dashboard tbody').before(stopgap);
}

function addProperties() {
  $('div.frame tbody.system').addClass('sortable').attr('sort','_system_information_'.md5());
  $('div.frame tbody.system').find('td:first .tile-header-right .tile-header-right-controls').append("<i class='fa fa-fw fa-eject control' onclick='openClose()' title=\"_(Show/Hide All Content)_\"></i>");
  $('div.frame tbody').each(function(){
    $(this).find('td:first .tile-header-right .tile-header-right-controls').append("<i class='fa fa-fw fa-chevron-up control openclose' onclick='openClose($(this))' title=\"_(Show/Hide Content)_\"></i>");
  });
  $('div.frame tbody').not('.system').each(function(){
    $(this).addClass('sortable').attr('sort',$(this).attr('title').md5());
    $(this).find('td:first').prepend("<i class='fa fa-fw fa-close control tile' onclick='dismiss($(this))' title=\"_(Close Tile)_\"></i>");
  });
  $('div.frame tr').attr('title','');
  $('div#sys0').hover(function(){$('.sys0').hide();$('.var0').show();},function(){$('.sys0').show();$('.var0').hide();});
  $('div#sys1').hover(function(){$('.sys1').hide();$('.var1').show();},function(){$('.sys1').show();$('.var1').hide();});
  $('div#sys2').hover(function(){$('.sys2').hide();$('.var2').show();},function(){$('.sys2').show();$('.var2').hide();});
  $('div#sys3').hover(function(){$('.sys3').hide();$('.var3').show();},function(){$('.sys3').show();$('.var3').hide();});
  $('#current_time').hover(function(){$.post('/webGui/include/DashboardApps.php',{ntp:'ntp'},function(ntp){$('#current_time').prop('title',ntp+"\n_(Go to date and time settings)_");});});
  // make truncated descriptions fully visible when hovering over them
  $('span.w18').not('.static').hover(
    function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {recall = $(this).next(); recover=recall.html(); recall.html('&nbsp;');}},
    function(){if ($(this)[0].offsetWidth < $(this)[0].scrollWidth) {recall.html(recover); recall=null;}}
  );
}

function showContent() {
  var count = {'db_box1':$('table#db_box1 tbody').length, 'db_box2':$('table#db_box2 tbody').length, 'db_box3':$('table#db_box3 tbody').length}
  var inactive = cookie.inactive_content;
  if (inactive) {
    inactive = inactive.split(';');
    for (let n=0,md5; md5=inactive[n]; n++) {
      var tbody = $('table.dashboard tbody[sort="'+md5+'"]');
      var id = tbody.parent().prop('id');
      count[id]--;
      tbody.hide();
      tbody.prev().hide();
    }
  }
  var hidden = cookie.hidden_content;
  if (hidden) {
    hidden = hidden.split(';');
    for (let n=0,md5; md5=hidden[n]; n++) {
      var tbody = $('div.frame tbody[sort="'+md5+'"]');
      tbody.find('.openclose').removeClass('fa-chevron-up fa-chevron-down').addClass('fa-chevron-down');
      tbody.find('tr:gt(0)').hide();
      tbody.find('span.switch').show();
      tbody.find('span.button').hide();
    }
  }
  if (count['db_box1']>0) $('div#tile1').show();
  if (count['db_box2']>0) $('div#tile2').show();
  if (count['db_box3']>0) $('div#tile3').show();
}

function setColor(l, t1, t2) {
  switch (true) {
  case (t1 > 0 && l >= t1): return 'redbar';
  case (t2 > 0 && l >= t2): return 'orangebar';
  default: return '';}
}

function fontColor(l, t1, t2) {
  switch (true) {
  case (t1 > 0 && l >= t1): return '#f0000c';
  case (t2 > 0 && l >= t2): return '#e68a00';
  default: return '#4f8a10';}
}

function openClose(button) {
  var hidden = cookie.hidden_content;
  hidden = hidden ? hidden.split(';') : [];
  if (button) {
    // show/hide single tile content
    var tbody = button.closest('tbody');
    if (button.hasClass('fa-chevron-up')) {
      button.removeClass('fa-chevron-up fa-chevron-down').addClass('fa-chevron-down');
      tbody.mixedView(0);
      hidden.push(tbody.attr('sort'));
    } else {
      button.removeClass('fa-chevron-up fa-chevron-down').addClass('fa-chevron-up');
      tbody.mixedView(1);
      hidden.splice(hidden.indexOf(tbody.attr('sort')),1);
    }
    cookie.hidden_content = hidden.join(';');
  } else {
    // show/hide all tiles content
    if (hidden.length==0) {
      $('div.frame tbody').each(function(){
        $(this).find('.openclose').removeClass('fa-chevron-up fa-chevron-down').addClass('fa-chevron-down');
        $(this).mixedView(0);
        hidden.push($(this).attr('sort'));
      });
      cookie.hidden_content = hidden.join(';');
    } else {
      $('div.frame tbody').each(function(){
        $(this).find('.openclose').removeClass('fa-chevron-up fa-chevron-down').addClass('fa-chevron-up');
        $(this).mixedView(1);
      });
      delete cookie.hidden_content;
    }
  }
  saveCookie();
}

function dismiss(button) {
  var tbody = button.closest('tbody');
  var table = tbody.parent();
  var tile = table.parent();
  var inactive = cookie.inactive_content;
  tbody.hide();
  tbody.prev().hide();
  if (table.find('tbody:visible').length>0) tile.show(); else tile.hide();
  inactive = inactive ? inactive.split(';') : [];
  inactive.push(tbody.attr('sort'));
  cookie.inactive_content = inactive.join(';');
  saveCookie();
}

function dialogStyle() {
  $('.ui-dialog-titlebar-close').css({'display':'none'});
  $('.ui-dialog-title').css({'text-align':'center','width':'100%','font-size':'1.8rem'});
  $('.ui-dialog-content').css({'padding-top':'15px','vertical-align':'bottom'});
  $('.ui-button-text').css({'padding':'0px 5px'});
  <? if ($themeHelper->isSidebarTheme()):?>
    $('.ui-dialog').css({'z-index':'2001'});
  <? endif;?>
}

function contentMgmt() {
  box = $("#iframe-popup");
  box.html($("#templateContentMgmt").html().build());
  box.dialog({
    title: "_(Tile Management)_",
    height: 'auto',
    width: 'auto',
    resizable: false,
    modal: true,
    buttons: {
      "_(Reset)_": function(){
        cookie = {};
        saveCookie();
        box.dialog('close');
        location.reload();
      },
      "_(All)_": function(){
        $('input.checker').each(function(){$(this).prop('checked',true);});
      },
      "_(None)_": function(){
        $('input.checker').each(function(){$(this).prop('checked',false);});
      },
      "_(Apply)_": function(){
        hideShow();
        box.dialog('close');
      },
      "_(Cancel)_": function(){
        box.dialog('close');
      }
    }
  });
  dialogStyle();
}

function VMClone(uuid, name){
  box = $("#iframe-popup");
  box.html($("#templateClone").html());
  box.find('#VMBeingCloned').html(name).change();
  box.find('#target').val(name + "_clone");
  document.getElementById("Free").checked = true;
  document.getElementById("Overwrite").checked = true;
  box.dialog({
    title: "_(VM Clone)_",
    height: 'auto',
    width: 600,
    resizable: false,
    modal: true,
    buttons: {
      "_(Clone)_": function(){
        var target = box.find('#target');
        if (target.length) {
          target = target.val();
          //if (!target) {errorTarget(); return;}
        } else target = '';
        var clone = box.find("#target").prop('value');
        var start = box.find('#Start').prop('checked') ? 'yes' : 'no';
        var edit = box.find('#Edit').prop('checked') ? 'yes' : 'no';
        var overwrite = box.find('#Overwrite').prop('checked') ? 'yes' : 'no';
        var free = box.find('#Free').prop('checked') ? 'yes' : 'no';
        var regenmac = box.find('#Regenmac').prop('checked') ? 'yes' : 'no';
        var scripturl = "VMClone.php " + encodeURIComponent("/usr/local/emhttp/plugins/dynamix.vm.manager/include/VMClone.php&" + $.param({action:"clone", name:name, clone:clone, overwrite:overwrite, edit:edit, start:start, free:free, regenmac:regenmac}));
        openVMAction((scripturl),"VM Clone", "dynamix.vm.manager", "loadlist");
        box.dialog('close');
      },
      "_(Cancel)_": function(){
        box.dialog('close');
      }
    }
  });
  dialogStyle();
}

function selectsnapshot(uuid, name ,snaps, opt, getlist, state,fstype){
  box = $("#iframe-popup");
  box.html($("#templatesnapshot"+opt).html());
  const capopt = opt.charAt(0).toUpperCase() + opt.slice(1);
  var optiontext = capopt + " _(Snapshot)_";
  box.find('#VMName').html(name);
  box.find('#fstype').html(fstype);
  if (fstype == "QEMU") box.find('#fstypeline').prop('hidden',true);
  box.find('#targetsnap').val(snaps);
  box.find('#targetsnapl').html(snaps);
  if (getlist) {
    var only = (opt == "remove") ? 0 : 1;
    $.post("/plugins/dynamix.vm.manager/include/VMajax.php",{action:"snap-images",uuid:uuid,snapshotname:snaps,only:only},function(data){if (data.html) box.find('#targetsnapimages').html(data.html);},'json');
  }
  var memorydump = "no";
  document.getElementById("targetsnapfspc").checked = true;
  if (fstype == "ZFS") {
    box.find('#targetsnaprmv').prop('disabled',true);
    box.find('#targetsnaprmvmeta').prop('disabled',true);
  }
  if (state != "running") {
    box.find('#memoryline').prop('hidden',true);
    box.find('#targetsnapmem').prop('hidden',true);
    box.find('#targetsnapmem').prop('checked',false);
  } else {
    box.find('#memoryline').prop('hidden',false);
    box.find('#targetsnapmem').prop('hidden',false);
    box.find('#targetsnapmem').prop('checked',true);
  }
  box.dialog({
    title: optiontext,
    height: 'auto',
    width: 600,
    resizable: false,
    modal: true,
    buttons: {
      "_(Proceed)_": function(){
        var target = box.find('#targetsnap');
        if (target.length) {
          target = target.val();
          if (!target) {errorTarget(); return;}
        } else target = '';
        var remove = 'yes';
        var removemeta = 'yes';
        var keep = 'yes';
        var free = 'yes';
        var desc = '';
        box.find('#targetsnap').prop('disabled',true);
        if (opt == "revert") {
          remove = box.find('#targetsnaprmv').prop('checked') ? 'yes' : 'no';
          removemeta = box.find('#targetsnaprmvmeta').prop('checked') ? 'yes' : 'no';
          keep = box.find('#targetsnapkeep').prop('checked') ? 'yes' : 'no';
        }
        if (opt == "create") {
          free = box.find('#targetsnapfspc').prop('checked') ? 'yes' : 'no';
          desc = box.find("#targetsnapdesc").prop('value');
          memorydump = box.find('#targetsnapmem').prop('checked') ? 'yes' : 'no';
          fstypeuse = box.find('#targetsnapfstype').prop('checked') ? 'yes' : 'no';
          if (fstypeuse == "no") fstype ="QEMU";
        }
        ajaxVMDispatch({action:"snap-" + opt +'-external', uuid:uuid, snapshotname:target, remove:remove, free:free, desc:desc, fstype:fstype,memorydump:memorydump}, "loadlist");
        box.dialog('close');
      },
      "_(Cancel)_": function(){
        box.dialog('close');
      }
    }
  });
  dialogStyle();
}

var sortableHelper = function(e,ui){
  ui.prev().remove();
  ui.find('tr:first').children().each(function(){$(this).width($(this).width());});
  return ui;
};

function LockButton() {
  if ($.cookie('lockbutton') == null) {
    $.cookie('lockbutton','lockbutton');
<?if ($themeHelper->isTopNavTheme()):?>
    $('div.nav-item.LockButton a').prop('title',"_(Lock sortable items)_");
    $('div.nav-item.LockButton b').removeClass('icon-u-lock green-text').addClass('icon-u-lock-open red-text');
<?endif;?>
    $('i.tile').show();
    $('tbody.sortable').css({'cursor':'move'});
    $('div.nav-item.LockButton span').text("_(Lock sortable items)_");
    $('#db_box1,#db_box2,#db_box3').sortable({connectWith:'#db_box1,#db_box2,#db_box3'});
    $('table.dashboard').sortable({helper:sortableHelper,items:'.sortable',cursor:'grab',opacity:0.6,placeholder:'dashboard-sortable',zIndex:9999,forceHelperSize:true,forcePlaceholderSize:true,
    receive:function(e,ui){
      var table = ui.sender, index = [];
      var tile = table.parent();
      var gap = ui.item.prev();
      if (table.find('tbody:visible').length > 0) {
        tile.show();
        gap.show();
      } else {
        tile.hide();
        gap.hide();
      }
      table.find('tbody').each(function(){index.push($(this).attr('sort'));});
      cookie[table.prop('id')] = index.join(';');
    },
    stop:function(e,ui){
      var table = ui.item.parent(), index = [];
      if (ui.item.prev().html().search('stopgap')>0) ui.item.after(stopgap); else ui.item.before(stopgap);
      table.find('tbody').each(function(){index.push($(this).attr('sort'));});
      cookie[table.prop('id')] = index.join(';');
      saveCookie();
    }});
  } else {
    $.removeCookie('lockbutton');
<?if ($themeHelper->isTopNavTheme()):?>
    $('div.nav-item.LockButton a').prop('title',"_(Unlock sortable items)_");
    $('div.nav-item.LockButton b').removeClass('icon-u-lock-open red-text').addClass('icon-u-lock green-text');
<?endif;?>
    $('i.tile').hide();
    $('tbody.sortable').css({'cursor':'default'});
    $('div.nav-item.LockButton span').text("_(Unlock sortable items)_");
    $('table.dashboard').sortable('destroy');
  }
}

function cpu_parse(msg) {
  var parse = {}, section = '';
  msg.split('\n').forEach(function(row) {
    if (row.substr(0,1) == '[') {
      section = row.substr(1,row.length-2);
      parse[section] = {};
    } else {
      var data = row.split('=');
      parse[section][data[0]] = data[1];
    }
  });
  return parse;
}

<?if ($vmusage == "Y"):?>
var vmdashusage = new NchanSubscriber('/sub/vm_dashusage',{subscriber:'websocket', reconnectTimeout:5000});
vmdashusage.on('message', function(msg){
  var data = JSON.parse(msg);
  for (const [vm, vmdata] of Object.entries(data)) {
    for (const [displayitem, value] of Object.entries(vmdata)) {
    $('#vmmetrics-'+displayitem + '-' + vm ).html(value);
    }
  }
  });
<?endif;?>

// GraphQL subscription for CPU metrics
let CPU_SUBSCRIPTION = null;
let cpuSubscription = null;

var dashboard = new NchanSubscriber('/sub/update1,update2,update3<?=$wireguard?",wireguard":""?>',{subscriber:'websocket', reconnectTimeout:5000});
dashboard.on('message',function(msg,meta) {
  switch (meta.id.channel()) {
  case 0:
    var get = JSON.parse(msg);
    // memory & disk load
    var load = get.ram[0].slice(0,-1);
    $('.sys0').text(get.ram[0]).css({'color':fontColor(load,<?=$display['critical']?>,<?=$display['warning']?>)});
    $('.var0').text(get.ram[1]);
    var color = setColor(load,<?=$display['critical']?>,<?=$display['warning']?>);
    $('.sys0_').text(get.ram[0]);
    $('#sys0_').alive(get.ram[0],color);
    var start = 0;
    var end = parseInt(get.ram[4]);
    var ring = [colors[0]+' '+start+'% '+end+'%']
    // create individual elements of the RAM graph
    for (var i=6; i < get.ram.length; i=i+2) {
      start = end;
      end += parseInt(get.ram[i]);
      ring.push((colors[(i-2)/2]||blue)+' '+start+'% '+end+'%');
    }
    ring.push(colors[1]+' '+get.ram[0]+' 100%');
    $('#sys0').css({'background':'conic-gradient('+ring.join(',')+')'});
    // dynamic info from hook scripts
    var html = [];
    for (var i=0,name; name=get.name[i]; i++) if (i!=1) html.push("<i class='ups fa fa-circle' style='color:"+(colors[i]||blue)+"'></i>"+name+": "+(i==0?get.ram[5]:get.ram[i*2+3]));
    html.push("<i class='ups fa fa-circle' style='color:"+colors[1]+"'></i>"+get.name[1]+": "+get.ram[3]);
    $('#dynamic').html(html.join('<br>'));
    // flash, Log & Docker graphs
    for (var k=1,sys; sys=get.sys[k-1]; k++) {
      var load = sys[0].slice(0,-1);
      $('.sys'+k).text(sys[0]).css({'color':fontColor(load,<?=$display['critical']?>,<?=$display['warning']?>)});
      $('.var'+k).text(sys[1]);
      $('#sys'+k).css({'background':'conic-gradient('+colors[0]+' 0% '+sys[0]+','+colors[1]+' '+sys[0]+' 100%)'});
    }
<?if ($fans):?>
    // fans rpm
    for (var k=0; k < get.fan.length; k++) $('#fan'+k).html(get.fan[k]);
<?endif;?>
<?if (_var($var,'fsState')=='Started' && $group):?>
    // stream counters (smb only)
    if ($('.smb').is(':visible')) for (var k=0; k < get.stream.length; k++) {$('#share'+k).html(get.stream[k]); $('#share'+k).removeClass(); if (get.stream[k]>0) $('#share'+k).addClass('orange-text');}
<?endif;?>
    break;
  case 1:
    if (!update2) break;
    var get  = JSON.parse(msg);
    if(document.getElementById('array_list') != null) {
      var info = moreInfo(get.disk,"_(Array)_");
      // array devices
      $('#array_list tr.updated').remove();
      $('#array_list').append(get.disk[0]).hideMe();
      $('#array_info').parent().css({'display':info?'':'none'});
      $('#array_info').html(info);
      smartMenu('#array_list');
    }
    // pool devices
    if(get.pool) {
      for (let i=0; i < get.pool.length; i++) {
        var info = moreInfo(get.pool[i],"_(Pool)_");
        $('#pool_list'+i+' tr.updated').remove();
        $('#pool_list'+i).append(get.pool[i][0]).hideMe();
        $('#pool_info'+i).parent().css({'display':info?'':'none'});
        $('#pool_info'+i).html(info);
        smartMenu('#pool_list'+i);
      }
    }
<?if ($devs):?>
    // unassigned devices
    var info = moreInfo(get.open,"_(Unassigned)_");
    $('#devs_list tr.updated').remove();
    $('#devs_list').append(get.open[0]).hideMe();
    $('#devs_info').parent().css({'display':info?'':'none'});
    $('#devs_info').html(info);
    smartMenu('#devs_list');
<?endif;?>
    // parity status
    $('span.parity').html(get.parity);
    // parity schedule
    $('#parity').html(get.schedule[0]);
    $('#program').html(get.schedule[1]);
    break;
  case 2:
    var get = JSON.parse(msg);
    // rx & tx speeds
    for (let i=0,port; port=get.port[i]; i++) {
      if (port[0] == port_select) {
        // Cache for network values to avoid unnecessary DOM updates
        if (!window.lastNetValues) window.lastNetValues = { inbound: '', outbound: '' };

        // Only update DOM if values changed
        if (port[1] !== window.lastNetValues.inbound) {
          $('#inbound').text(port[1]);
          window.lastNetValues.inbound = port[1];
        }
        if (port[2] !== window.lastNetValues.outbound) {
          $('#outbound').text(port[2]);
          window.lastNetValues.outbound = port[2];
        }

        // update the netchart but only send to ApexCharts if the chart is visible
        addChartNet(port[3], port[4]);

        break;
      }
    }
    // port counters - batch check for changes
    for (let k=0; k < get.mode.length; k++) {
      const $elem = $('#main'+k);
      const newVal = get.mode[k];
      if ($elem.html() !== newVal) $elem.html(newVal);
    }
    for (let k=0; k < get.rxtx.length; k++) {
      const $elem = $('#port'+k);
      const newVal = get.rxtx[k];
      if ($elem.html() !== newVal) $elem.html(newVal);
    }
    for (let k=0; k < get.stat.length; k++) {
      const $elem = $('#link'+k);
      const newVal = get.stat[k];
      if ($elem.html() !== newVal) $elem.html(newVal);
    }
    // current date and time
    $('#current_time').html(get.time[0]);
    $('#current_time_').html(get.time[0]);
    $('#current_date').html(get.time[1]);
    break;
  case 3:
    // wireguard tunnels
    var get = JSON.parse(msg);
    let n = {};
    for (var i=0,info; info=get[i]; i++) {
      var vtun = info[0];
      if (typeof n[vtun]=='undefined') n[vtun]=0; else n[vtun]++;
      if (info[1] == 0) {
        $('span#'+vtun+'-hs-'+n[vtun]).text("_(not received)_");
      } else if (info[1] > 86400) {
        var d = parseInt(info[1]/86400);
        var s = d==1 ? " _(day)_" : " _(days)_";
        $('span#'+vtun+'-hs-'+n[vtun]).text(sprintf("_(%s ago)_",d+s));
      } else {
        var h = parseInt(info[1]/3600).pad();
        var m = parseInt(info[1]/60%60).pad();
        var s = parseInt(info[1]%60).pad();
        $('span#'+vtun+'-hs-'+n[vtun]).text(sprintf("_(%s ago)_",h+':'+m+':'+s));
      }
      $('span#'+vtun+'-rx-'+n[vtun]).html('<span class="rx"><i class="fa fa-fw fa-arrow-down"></i>&nbsp;'+info[2]+'</span><span><i class="fa fa-fw fa-arrow-up"></i>&nbsp;'+info[3]+'</span>');
    }
    break;
  }
});

<?if ($apcupsd):?>
var apcups = new NchanSubscriber('/sub/apcups',{subscriber:'websocket', reconnectTimeout:5000});
apcups.on('message',function(msg) {
  var get = JSON.parse(msg);
  $('#ups_model').html(get[0]);
  $('#ups_status').html(get[1]);
  $('#ups_status_').html(get[1]);
  $('#ups_bcharge').html(get[2]);
  $('#ups_timeleft').html(get[3]);
  $('#ups_nompower').html(get[4]);
  $('#ups_loadpct').html(get[5]);
  $('#ups_loadpct_').html(get[5]);
  $('#ups_outputv').html(get[6]);
});
<?endif;?>

$(function() {
  // ping subscriber to check for listeners
  var dashboardPing = new NchanSubscriber('/sub/dashboardPing',{subscriber:'websocket', reconnectTimeout:5000});
  dashboardPing.on('message', function(msg){});
  dashboardPing.start();

  initCharts();

  // Start SmoothieCharts streaming
  cpuchart.streamTo(document.getElementById('cpuchart'), 1000);
  netchart.streamTo(document.getElementById('netchart'), 1000);

  // Set millisPerPixel after DOM is ready and charts are attached
  setTimeout(function() {
    cpuchart.options.millisPerPixel = getMillisPerPixel(cpuline, 'cpuchart');
    netchart.options.millisPerPixel = getMillisPerPixel(netline, 'netchart');
  }, 100);

  addProperties();
<?if ($group):?>
  dropdown('enter_share');
<?endif;?>
  dropdown('enter_view');
  startup = false;

  // Start GraphQL CPU subscription with retry logic
  let cpuInitAttempts = 0, cpuRetryMs = 100;
  function initCpuSubscription() {
    if (window.gql && window.apolloClient) {
      // Define the subscription query when GraphQL is available
      CPU_SUBSCRIPTION = window.gql(`
        subscription SystemMetricsCpu {
          systemMetricsCpu {
            percentTotal
            cpus {
              percentTotal
              percentUser
            }
          }
        }
      `);

      cpuSubscription = window.apolloClient.subscribe({
        query: CPU_SUBSCRIPTION
      }).subscribe({
        next: (result) => {
          if (result.data?.systemMetricsCpu) {
            cpuchart.customData.cpuData = result.data.systemMetricsCpu;
            cpuchart.customData.cpuLoad = Math.floor(cpuchart.customData.cpuData.percentTotal);

            //update cpu chart data
            addChartCpu(cpuchart.customData.cpuLoad);
            updateCPUBarCharts();
            
          }
        },
        error: (err) => {
          console.error('CPU subscription error:', err);
          // Try to resubscribe with capped backoff
          if (cpuSubscription) { try { cpuSubscription.unsubscribe(); } catch(e){} }
          setTimeout(initCpuSubscription, Math.min(cpuRetryMs *= 2, 5000));
        }
      });
    } else {
      // Retry with capped backoff if GraphQL client not ready
      cpuInitAttempts++;
      setTimeout(initCpuSubscription, Math.min(cpuRetryMs *= 2, 2000));
    }
  }

  initCpuSubscription();
  dashboard.start();
<?if ($vmusage == "Y"):?>
  vmdashusage.start();
<?endif;?>
<?if ($apcupsd):?>
  apcups.start();
<?endif;?>
  update900();
  toggleChart(true);
  toggleCPU(true);
  portMenu();
  loadlist(true);
  sortTables();
  showContent();
  $('#cpuline').val(cpuline);
  $('#netline').val(netline);
  $.removeCookie('lockbutton');
  
  // Inhibit chart updates until DOM quiets down
  setTimeout(function() {
    // Charts initialized
  },500);
    
  // Cleanup GraphQL subscription on page unload
  $(window).on('beforeunload', function() {
    if (cpuSubscription) {
      cpuSubscription.unsubscribe();
    }
  });
});

</script>
