File

projects/cobbler-frontend/src/app/signatures/signatures.component.ts

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods

Constructor

constructor(userService: UserService, cobblerApiService: CobblerApiService, _snackBar: MatSnackBar)
Parameters :
Name Type Optional
userService UserService No
cobblerApiService CobblerApiService No
_snackBar MatSnackBar No

Methods

generateSignatureUiData
generateSignatureUiData()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
updateSignatures
updateSignatures()
Returns : void

Properties

Private _transformer
Default value : () => {...}
columns
Type : []
Default value : [ { columnDef: 'key', header: 'Attribute', cell: (element: TableRow) => `${element.key}`, }, { columnDef: 'value', header: 'Value', cell: (element: TableRow) => `${element.value}`, }, ]
dataSource
Default value : new MatTreeFlatDataSource(this.treeControl, this.treeFlattener)
displayedColumns
Default value : this.columns.map((c) => c.columnDef)
hasChild
Default value : () => {...}
hasOsVersion
Default value : () => {...}
Public isLoading
Default value : true
Private ngUnsubscribe
Default value : new Subject<void>()
treeControl
Default value : new FlatTreeControl<OsBreedFlatNode>( (node) => node.level, (node) => node.expandable, )
treeFlattener
Default value : new MatTreeFlattener( this._transformer, (node) => node.level, (node) => node.expandable, (node) => node.children, )
Public userService
Type : UserService
import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { MatDivider } from '@angular/material/divider';
import { MatList, MatListItem } from '@angular/material/list';
import { MatProgressSpinner } from '@angular/material/progress-spinner';
import { MatSnackBar } from '@angular/material/snack-bar';
import {
  MatCell,
  MatCellDef,
  MatColumnDef,
  MatHeaderCell,
  MatHeaderCellDef,
  MatHeaderRow,
  MatHeaderRowDef,
  MatRow,
  MatRowDef,
  MatTable,
} from '@angular/material/table';
import { filter, repeat, take, takeUntil } from 'rxjs/operators';
import { UserService } from '../services/user.service';
import { CobblerApiService } from 'cobbler-api';
import {
  MatTree,
  MatTreeFlatDataSource,
  MatTreeFlattener,
  MatTreeNode,
  MatTreeNodeDef,
  MatTreeNodePadding,
  MatTreeNodeToggle,
} from '@angular/material/tree';
import { FlatTreeControl } from '@angular/cdk/tree';
import { MatIcon } from '@angular/material/icon';
import { MatIconButton } from '@angular/material/button';
import { Subject } from 'rxjs';
import Utils from '../utils';

interface TableRow {
  key: string;
  value: any;
}

/**
 * Food data with nested structure.
 * Each node has a name and an optional list of children.
 */
interface OsNode {
  data: string | Array<TableRow>;
  children?: OsNode[];
}

/** Flat node with expandable and level information */
interface OsBreedFlatNode {
  expandable: boolean;
  data: string | Array<TableRow>;
  level: number;
}

@Component({
  selector: 'cobbler-signatures',
  standalone: true,
  imports: [
    MatTree,
    MatTreeNode,
    MatIcon,
    MatIconButton,
    MatTreeNodeToggle,
    MatTreeNodePadding,
    MatTreeNodeDef,
    MatTable,
    MatHeaderCell,
    MatCell,
    MatHeaderRow,
    MatRow,
    MatColumnDef,
    MatHeaderCellDef,
    MatCellDef,
    MatHeaderRowDef,
    MatRowDef,
    MatDivider,
    AsyncPipe,
    MatList,
    MatListItem,
    MatProgressSpinner,
    NgForOf,
    NgIf,
  ],
  templateUrl: './signatures.component.html',
  styleUrl: './signatures.component.scss',
})
export class SignaturesComponent implements OnInit, OnDestroy {
  // Unsubscribe
  private ngUnsubscribe = new Subject<void>();

  // Table
  columns = [
    {
      columnDef: 'key',
      header: 'Attribute',
      cell: (element: TableRow) => `${element.key}`,
    },
    {
      columnDef: 'value',
      header: 'Value',
      cell: (element: TableRow) => `${element.value}`,
    },
  ];

  displayedColumns = this.columns.map((c) => c.columnDef);

  // Tree
  private _transformer = (node: OsNode, level: number) => {
    return {
      expandable: !!node.children && node.children.length > 0,
      data: node.data,
      level: level,
    };
  };

  treeControl = new FlatTreeControl<OsBreedFlatNode>(
    (node) => node.level,
    (node) => node.expandable,
  );

  treeFlattener = new MatTreeFlattener(
    this._transformer,
    (node) => node.level,
    (node) => node.expandable,
    (node) => node.children,
  );
  dataSource = new MatTreeFlatDataSource(this.treeControl, this.treeFlattener);

  // Spinner
  public isLoading = true;

  constructor(
    public userService: UserService,
    private cobblerApiService: CobblerApiService,
    private _snackBar: MatSnackBar,
  ) {}

  ngOnInit(): void {
    this.generateSignatureUiData();
  }

  ngOnDestroy(): void {
    this.ngUnsubscribe.next();
    this.ngUnsubscribe.complete();
  }

  hasChild = (_: number, node: OsBreedFlatNode) => node.expandable;

  hasOsVersion = (_: number, node: OsBreedFlatNode) =>
    typeof node.data !== 'string';

  generateSignatureUiData(): void {
    this.cobblerApiService
      .get_signatures(this.userService.token)
      .pipe(takeUntil(this.ngUnsubscribe))
      .subscribe(
        (value) => {
          const newData: Array<OsNode> = [];
          for (const k in value.breeds) {
            const children: Array<OsNode> = [];
            for (const j in value.breeds[k]) {
              const osVersionData: Array<TableRow> = [];
              for (const i in value.breeds[k][j]) {
                osVersionData.push({ key: i, value: value.breeds[k][j][i] });
              }
              children.push({
                data: j,
                children: [{ data: osVersionData, children: [] }],
              });
            }
            newData.push({ data: k, children: children });
          }
          this.dataSource.data = newData;
          this.isLoading = false;
        },
        (error) => {
          // HTML encode the error message since it originates from XML
          this._snackBar.open(Utils.toHTML(error.message), 'Close');
        },
      );
  }

  updateSignatures(): void {
    this.isLoading = true;
    this.cobblerApiService
      .background_signature_update(this.userService.token)
      .pipe(takeUntil(this.ngUnsubscribe))
      .subscribe(
        (value) => {
          this.cobblerApiService
            .get_task_status(value)
            .pipe(
              repeat(),
              filter(
                (data) => data.state === 'failed' || data.state === 'complete',
              ),
              take(1),
            )
            .subscribe((value1) => {
              this.isLoading = false;
              this.generateSignatureUiData();
            });
        },
        (error) => {
          // HTML encode the error message since it originates from XML
          this._snackBar.open(Utils.toHTML(error.message), 'Close');
        },
      );
  }
}
<div class="title-table">
  <div class="title-row">
    <h1 class="title title-cell-text">Signatures</h1>
    <span class="title-cell-button">
      <button mat-icon-button (click)="this.updateSignatures()">
        <mat-icon>refresh</mat-icon>
      </button>
    </span>
  </div>
</div>

<mat-spinner *ngIf="isLoading" style="margin: 0 auto"></mat-spinner>
<ng-container *ngIf="!isLoading">
  <mat-tree [dataSource]="dataSource" [treeControl]="treeControl">
    <!-- This is the tree node template for leaf nodes -->
    <mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding>
      <!-- use a disabled button to provide padding for tree leaf -->
      <button mat-icon-button disabled></button>
      {{ node.data }}
    </mat-tree-node>
    <!-- This is the tree node template for expandable nodes -->
    <mat-tree-node
      *matTreeNodeDef="let node; when: hasChild"
      matTreeNodePadding
    >
      <button
        mat-icon-button
        matTreeNodeToggle
        [attr.aria-label]="'Toggle ' + node.data"
      >
        <mat-icon class="mat-icon-rtl-mirror">
          {{ treeControl.isExpanded(node) ? "expand_more" : "chevron_right" }}
        </mat-icon>
      </button>
      {{ node.data }}
    </mat-tree-node>
    <!-- This is the tree node template for expandable nodes with an OS version as data -->
    <mat-tree-node
      *matTreeNodeDef="let node; when: hasOsVersion"
      matTreeNodePadding
    >
      <button mat-icon-button disabled></button>
      <table mat-table [dataSource]="node.data" class="mat-elevation-z8">
        @for (column of columns; track column) {
          <ng-container [matColumnDef]="column.columnDef">
            <th mat-header-cell *matHeaderCellDef>
              {{ column.header }}
            </th>
            <td mat-cell *matCellDef="let row">
              {{ column.cell(row) }}
            </td>
          </ng-container>
        }
        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
        <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
      </table>
    </mat-tree-node>
  </mat-tree>
</ng-container>
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""