enclosure-disks.component.html 15.6 KB
<mat-card
  class="view-card rackmount"
  [ngClass]="{'multiple-enclosures': system && system.profile && system.profile.length > 1}"
  id="{{currentTab.alias}}"
  (window:resize)="onResize()"
  ngClass.gt-md="gt-md"
  ngClass.md="md"
  ngClass.sm="sm"
  ngClass.xs="xs">

  <mat-toolbar id="Disks-toolbar">
    <div *ngIf="selectedEnclosure" class="mat-card-title-text">
      {{currentTab.alias}} on
      {{system.enclosures[selectedEnclosure.enclosureKey].label == system.enclosures[selectedEnclosure.enclosureKey].name ? selectedEnclosure.model : system.enclosures[selectedEnclosure.enclosureKey].label}}
      ({{selectedEnclosure.enclosureKey}})
    </div>

    <!-- ENCLOSURE MODEL -->
    <div class="model dom-overlay">
      <div class="model-inner">
      </div>
    </div>

    <!-- ENCLOSURE RENAME -->
    <div class="enclosure-label-actions">
      <button (click)="labelForm()" mat-button color="default">{{ 'EDIT LABEL' | translate }}</button>
    </div>

  </mat-toolbar>

  <!-- Tabs other than Disks -->
  <tab-content class="other-tab" *ngIf="currentTab.alias !== 'Disks'" [data]="system.enclosures[selectedEnclosure.enclosureKey].elements[currentTab.elementIndex]"></tab-content>

  <mat-card-content id="Disks-content" [class]="currentTab.alias">

    <!-- VISUALIZATION/OVERVIEW -->
    <div class="disks-overview-wrapper">
      <div #disksoverview
        id="disks-overview"
        [class]="currentView">

        <!-- POOLS OVERLAY -->
        <div *ngIf="currentView == 'pools' || exitingView == 'pools'" class="pools stage-left dom-overlay" >
          <div class="content">
            <h2>{{ 'Pools' | translate }}</h2>
          </div>
        </div>
        <div *ngIf="currentView == 'pools' || exitingView == 'pools'" class="pools stage-right dom-overlay list">
          <div class="content">

            <div *ngIf="enclosurePools.length > 0; else noPools" class="legend">
              <div *ngFor="let pool of enclosurePools; let i=index">
                <div class="swatch"
                  [style.background]="subenclosure ? theme[themeKey(theme.accentColors[subenclosure.poolKeys[pool]])] : theme[themeKey(theme.accentColors[selectedEnclosure.poolKeys[pool]])]">
                </div>
                {{pool}}
                <span *ngIf="!system.pools[selectedEnclosure.poolKeys[pool]] || !system.pools[selectedEnclosure.poolKeys[pool]].healthy">
                  <mat-icon fontSet="mdi-set" role="img" fontIcon="mdi-alert"></mat-icon>
                </span>
              </div>

              <!-- UNASSIGNED DISKS -->
              <div>
                <div class="swatch unassigned"></div>
                {{ 'Unassigned' | translate }}
              </div>
            </div>

            <ng-template #noPools>
              <div class="legend">
                <div>{{ 'No pools on this enclosure.' | translate }}</div>
                <!-- UNASSIGNED DISKS -->
                <div>
                  <div class="swatch unassigned"></div>
                  {{ 'Unassigned' | translate }}
                </div>
              </div>
            </ng-template>

          </div>
        </div>

        <!-- STATUS OVERLAY -->
        <div *ngIf="currentView == 'status' || exitingView == 'status'" class="status stage-left dom-overlay">
          <div class="content">
            <h2>{{ 'Status' | translate }}</h2>
          </div>
        </div>
        <div *ngIf="currentView == 'status' || exitingView == 'status'" class="status stage-right dom-overlay list">
          <div class="content">
            <div class="legend">
              <div><div class="swatch" [style.background]="theme.green"></div>{{ 'ONLINE' | translate }}</div>
              <div><div class="swatch" [style.background]="theme.yellow"></div>{{ 'OTHER' | translate }}</div>
              <div><div class="swatch" [style.background]="theme.red"></div>{{ 'FAULT' | translate }}</div>
              <div><div class="swatch available"></div>{{ 'AVAILABLE' | translate }}</div>
            </div>
          </div>
        </div>

        <!-- DETAILS OVERLAY -->
        <div *ngIf="currentView == 'details' || exitingView == 'details'" class="details stage-left dom-overlay">
          <div class="content">
            <h1 class="disk-name {{selectedDisk.name}}">{{selectedDisk.name}}</h1>
            <div class="title">
              <span class="semibold">{{ 'vdev' | translate }}: </span>
              <span *ngIf="selectedVdev.type == 'DISK'">{{ 'NONE' | translate }}</span>
              <span *ngIf="selectedVdev.type !== 'DISK'">{{selectedVdev.type == 'None' ? 'UNASSIGNED' : selectedVdev.type}}</span>
            </div>
            <div *ngIf="selectedVdev.type !== 'None'" class="title">
              <span class="semibold">{{ 'Function' | translate }}:</span>
              <span> {{$any(selectedVdev).topology == 'None' ? 'UNKNOWN' : selectedVdev.topology.toUpperCase()}}</span>
            </div>
            <div class="title">
              <span class="semibold">{{ 'Slot' | translate}}: </span>
              <span>{{selectedDisk.enclosure.slot}}</span>
            </div>
          </div>
        </div>

        <div #domLabels *ngIf="currentView == 'details' || exitingView == 'details'" class="details stage-right dom-overlay">
          <div class="content" (mouseenter)="toggleHighlightMode('on')" (mouseleave)="toggleHighlightMode('off')">

            <div *ngIf="selectedVdevDisks; else noVdevDisks;" class="legend">
              <div *ngFor="let disk of selectedVdevDisks; let i = index" class="vdev-disk {{disk}}"(mouseenter)="highlightPath(disk)" (mouseleave)="unhighlightPath(disk)"><div class="swatch" [style.background]="selectedDisk.devname == disk ? theme.yellow : theme.cyan"></div>{{disk}} <span> {{ selectedEnclosure.disks[disk] }}</span>
                <span *ngIf="!selectedVdev.slots[disk]">({{ selectedVdev.diskEnclosures[disk] == system.rearIndex ? 'Rear' : selectedVdev.diskEnclosures[disk] }})</span>
              </div>
            </div>

            <ng-template #noVdevDisks>
              <div class="legend">
                <div class="vdev-disk ">{{ 'No vdev info for disk.' | translate }}</div>
              </div>
            </ng-template>

          </div>
        </div>

        <!-- CAPTION OVERLAY -->
        <div *ngIf="showCaption && chassis && !chassis.rear && !chassis.internal" class="caption dom-overlay">{{ 'Choose a Disk' | translate }}</div>

        <!-- FRONT/REAR TOGGLE -->
        <!--<div *ngIf="subenclosure && currentView != 'expanders'" class="caption dom-overlay front-rear-toggle">-->
        <div *ngIf="chassis && (chassis.rear || chassis.internal) && currentView != 'expanders'" class="caption dom-overlay front-rear-toggle">
          <button mat-button (click)="enclosureOverride(EnclosureLocation.Front)">{{ 'FRONT' | translate }}</button>
          <button *ngIf="chassis.rear" mat-button (click)="enclosureOverride(EnclosureLocation.Rear)">{{ 'REAR' | translate }}</button>
          <button *ngIf="chassis.internal" mat-button (click)="enclosureOverride('rear')">{{ 'Internal' | translate }}</button>
        </div>

        <!-- CANVAS/SVG OVERLAY -->
        <div #visualizer id="visualizer" class="visualizer dom-overlay"></div>

        <!-- EXPANDERS OVERLAY -->
        <div *ngIf="currentView == 'expanders' || exitingView == 'expanders'" class="expanders full-stage dom-overlay">
          <div *ngIf="expanders" class="content" >
            <div *ngFor="let expander of expanders" [style.width]="(100 / expanders.length).toString() + '%'" class="expander-item">
              <div class="primary-number" >{{ expander.status }}</div>
              <div class="title">{{expander.descriptor}}</div>
              <div class="subtitle">{{ 'Expander Status' | translate }}</div>
            </div>
          </div>
        </div>

      </div>
    </div>

    <!-- DETAILS/TITLE -->
    <div id="disks-details-header" [class]="currentView">
      <a class="btn-default back fn-theme-primary" (click)="clearDisk()" *ngIf="currentView == 'details'"><mat-icon role="img">chevron_left</mat-icon></a>
      {{selectedDisk ? 'Disk Details for ' + selectedDisk.name : 'Disks Overview'}}
    </div>

    <!-- DETAILS/OVERVIEW -->
    <div *ngIf="selectedDisk; then details else overview ;"></div>
    <ng-template #overview>
      <div #disksdetails id="disks-details">
        <div class="details-wrapper" id="view-selector" fxFill fxLayout="row" fxLayoutAlign="space-around stretch">

          <!-- ZeroState -->
          <ng-template #loading>
            <div fxFlex class="tiles" [class.active]="currentView == 'pools' " fxLayout="column" fxLayoutAlign="center center">
              Loading...
            </div>
          </ng-template>

          <div *ngIf="system && system.pools && enclosurePools; else loading" fxFlex class="tiles" [class.active]="currentView == 'pools' " fxLayout="column" fxLayoutAlign="center center">
            <div class="primary-number" >{{ enclosurePools.length }}</div>
            <div class="title"> {{ 'Pools in Enclosure' | translate }}</div>
            <div *ngIf="unhealthyPools && unhealthyPools.length == 1" class="subtitle">Pool "{{unhealthyPools[0].name}}" is {{unhealthyPools[0].status}}.</div>
            <div *ngIf="unhealthyPools && unhealthyPools.length > 1" class="subtitle">{{unhealthyPools[0]}} and {{unhealthyPools.length - 1}} other pools are not healthy.</div>
            <div *ngIf="unhealthyPools && unhealthyPools.length < 1" class="subtitle">{{ 'All pools are online.' | translate }}</div>
            <button mat-button color="default" (click)="setCurrentView('pools')">{{ 'SHOW POOLS' | translate }}</button>
          </div>

          <div *ngIf="system; else loading" fxFlex class="tiles" [class.active]="currentView == 'status' " fxLayout="column" fxLayoutAlign="center center">
            <div class="primary-number" >{{failedDisks.length}}</div>
            <div class="title">Failed Disk<span *ngIf="failedDisks.length != 1">s</span></div>
            <div class="subtitle">
              <span *ngIf="failedDisks.length < 1">All disks healthy</span>
              <span *ngIf="failedDisks.length > 1">Check {{failedDisks[0].disk}} and {{failedDisks.length - 1}} other disk<span *ngIf="failedDisks.length > 2">s</span></span>
              <span *ngIf="failedDisks.length == 1">Check {{failedDisks[0].disk}}
                <span *ngIf="!subenclosure"> in enclosure {{failedDisks[0].enclosure}}</span>
                <span *ngIf="subenclosure"> {{failedDisks[0].location}} slot {{failedDisks[0].slot}}</span>
              </span>
            </div>
            <button mat-button color="default" (click)="setCurrentView('status')">{{ 'SHOW STATUS' | translate }}</button>
          </div>

          <div *ngIf="system && expanders && expanders.length > 0" fxFlex class="tiles" [class.active]="currentView == 'expanders' " fxLayout="column" fxLayoutAlign="center center">
            <div class="primary-number" >{{expanders.length}}</div>
            <div class="title">{{ 'SAS Expanders' | translate }}</div>
            <div class="subtitle">{{ 'on this enclosure' | translate }}</div>
            <button mat-button color="default" (click)="setCurrentView('expanders')">{{ 'SHOW EXPANDER STATUS' | translate }}</button>
          </div>

        </div>
      </div>
    </ng-template>

    <!-- DETAILS/DISK -->
    <ng-template #details>
      <div  #diskdetails id="disks-details">
        <div class="details-wrapper" fxFill fxLayout="row" fxLayoutAlign="space-around stretch">

          <div fxFlex="25" class="disk-basic-details" fxLayout="column" fxLayoutAlign="center center">
            <disk-ui [data]="selectedDisk"></disk-ui><!-- disk icon + labels -->
            <div class="capacity">{{converter(selectedDisk.size)}}</div>
            <div class="disk-actions">
              <button id="identify-btn" mat-button color="primary" (click)="toggleSlotStatus()">{{ 'Identify Drive' | translate }}</button>
            </div>
          </div>

          <div fxFlex="75" class="tiles disk-advanced-details" >

            <div class="details-wrapper" fxLayout="row wrap" fxLayoutGap="16px">

              <div fxFlex="calc(25% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'Pool' | translate }}</div>
                  <div class="value">{{selectedDisk.vdev ? selectedDisk.vdev.pool : 'Disk not attached to any pools.'}}</div>
                </div>
              </div>

              <div fxFlex="calc(25% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'Model' | translate }}</div>
                  <div class="value">{{selectedDisk.model}}</div>
                </div>
              </div>

              <div fxFlex="calc(25% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'Serial' | translate }}</div>
                  <div class="value">{{selectedDisk.serial}}</div>
                </div>
              </div>

              <div fxFlex="calc(25% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'Status' | translate }}</div>
                  <div class="value">{{selectedDisk.status}}</div>
                </div>
              </div>

              <div fxFlex="calc(25% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'Adv. Power Mgmt.' | translate }}</div>
                  <div class="value">{{selectedDisk.advpowermgmt}}</div>
                </div>
              </div>

              <div fxFlex="calc(25% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'S.M.A.R.T. Enabled' | translate }}</div>
                  <div class="value">{{selectedDisk.togglesmart ? 'Yes' : 'No'}}</div>
                </div>
              </div>

              <div fxFlex="calc(25% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'S.M.A.R.T. Options' | translate }}</div>
                  <div class="value">{{selectedDisk.smartoptions ? selectedDisk.smartoptions : 'None'}}</div>
                </div>
              </div>

              <div fxFlex="calc(25% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'Transfer Mode' | translate }}</div>
                  <div class="value">{{selectedDisk.transfermode}}</div>
                </div>
              </div>

              <div fxFlex="calc(25% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'HDD Standby' | translate }}</div>
                  <div class="value">{{selectedDisk.hddstandby}}</div>
                </div>
              </div>

              <div fxFlex="calc(25% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'Description' | translate }}</div>
                  <div class="value">{{selectedDisk.description ? selectedDisk.description : 'None'}}</div>
                </div>
              </div>

              <div fxFlex="calc(50% - 16px)" class="detail" fxLayout="column" fxLayoutAlign="start start">
                <div>
                  <div class="label">{{ 'Rotation Rate' | translate }}</div>
                  <div class="value">{{selectedDisk.rotationrate}}{{'RPM' | translate}}</div>
                </div>
              </div>

            </div>
          </div>

        </div>
      </div>
    </ng-template>

  </mat-card-content>
</mat-card>