Skip to content

Commit

Permalink
Cobbler-Frontend: Add UI for distro overview and detail view
Browse files Browse the repository at this point in the history
  • Loading branch information
SchoolGuy committed Jul 20, 2024
1 parent 81f1ad7 commit 3abe8b2
Show file tree
Hide file tree
Showing 20 changed files with 375 additions and 436 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {UserService} from '../../services/user.service';
@Component({
selector: 'cobbler-check-sys',
templateUrl: './check-sys.component.html',
styleUrls: ['./check-sys.component.css'],
styleUrls: ['./check-sys.component.scss'],
standalone: true,
imports: [
RouterOutlet,
Expand Down
6 changes: 4 additions & 2 deletions projects/cobbler-frontend/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import { SyncComponent } from './actions/sync/sync.component';
import {ValidateAutoinstallsComponent} from './actions/validate-autoinstalls/validate-autoinstalls.component';
import { AppEventsComponent } from './app-events/app-events.component';
import { AppManageComponent } from './appManage';
import { DistrosComponent } from './items/distros/distros.component';
import {DistroEditComponent} from './items/distro/edit/distro-edit.component';
import { DistrosOverviewComponent } from './items/distro/overview/distros-overview.component';
import { FilesComponent } from './items/files/files.component';
import { ImagesComponent } from './items/images/images.component';
import { ManagementClassesComponent } from './items/management-classes/management-classes.component';
Expand All @@ -36,7 +37,8 @@ export const routes: Routes = [
{path: '', pathMatch: 'full', redirectTo: '/login' },
{path: 'unauthorized', component: UnauthorizedComponent},
{path: 'manage', component: AppManageComponent, canActivate: [AuthGuardService]},
{path: 'distros', component: DistrosComponent, canActivate: [AuthGuardService]},
{path: 'distro', component: DistrosOverviewComponent, canActivate: [AuthGuardService]},
{path: 'distro/:name', component: DistroEditComponent, canActivate: [AuthGuardService]},
{path: 'profiles', component: ProfilesComponent, canActivate: [AuthGuardService]},
{path: 'systems', component: SystemsComponent, canActivate: [AuthGuardService]},
{path: 'repos', component: ReposComponent, canActivate: [AuthGuardService]},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<div class="title-table">
<div class="title-row">
<h1 class="title title-cell-text">Name: {{ name }}</h1>
<span class="title-cell-button">
<button
mat-icon-button
(click)="this.refreshData()"
matTooltip="Refresh data"
><mat-icon>refresh</mat-icon></button>
</span>
<span class="title-cell-button">
<button
mat-icon-button
(click)="this.copyDistro()"
matTooltip="Copy"
><mat-icon>content_copy</mat-icon></button>
</span>
<span class="title-cell-button">
<button
mat-icon-button
(click)="this.editDistro()"
matTooltip="Edit"
><mat-icon>edit</mat-icon></button>
</span>
<span class="title-cell-button">
<button
mat-icon-button
(click)="this.removeDistro()"
matTooltip="Delete"
><mat-icon>delete</mat-icon></button>
</span>
</div>
</div>

<form class="form-replicate" [formGroup]="distroFormGroup">
<mat-form-field class="form-field-full-width">
<mat-label>Name</mat-label>
<input matInput type="text" formControlName="name"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>UID</mat-label>
<input matInput type="text" formControlName="uid"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>Last modified time</mat-label>
<input matInput type="text" formControlName="mtime"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>Creation time</mat-label>
<input matInput type="text" formControlName="ctime"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>Depth</mat-label>
<input matInput type="number" formControlName="depth"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>Architecture</mat-label>
<input matInput type="text" formControlName="arch"/>
</mat-form-field>
@if (isEditMode) {
<button mat-button (click)="saveDistro()">Save Distro</button>
}
</form>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.title-table {
display: table;
width: 100%;
}

.title-row {
display: table-cell;
width: 100%;
}

.title-cell-text {
display: table-cell;
width: 100%;
vertical-align: middle;
}

.title-cell-button {
display: table-cell;
}

.form-replicate {
min-width: 150px;
max-width: 600px;
width: 100%;
}

.form-field-full-width {
width: 100%;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { DistroEditComponent } from './distro-edit.component';

describe('EditComponent', () => {
let component: DistroEditComponent;
let fixture: ComponentFixture<DistroEditComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [DistroEditComponent]
})
.compileComponents();

fixture = TestBed.createComponent(DistroEditComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import {Component, inject, OnInit} from '@angular/core';
import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatButton, MatIconButton} from '@angular/material/button';
import {MatFormField, MatLabel} from '@angular/material/form-field';
import {MatIcon} from '@angular/material/icon';
import {MatInput} from '@angular/material/input';
import {MatSnackBar} from '@angular/material/snack-bar';
import {MatTooltip} from '@angular/material/tooltip';
import {ActivatedRoute, Router} from '@angular/router';
import {CobblerApiService, Distro} from 'cobbler-api';
import {UserService} from '../../../services/user.service';

@Component({
selector: 'cobbler-edit',
standalone: true,
imports: [
MatIcon,
MatIconButton,
ReactiveFormsModule,
MatFormField,
MatInput,
MatLabel,
FormsModule,
MatTooltip,
MatButton,
],
templateUrl: './distro-edit.component.html',
styleUrl: './distro-edit.component.scss'
})
export class DistroEditComponent implements OnInit{
name: string;
distro: Distro;
private readonly _formBuilder = inject(FormBuilder);
distroFormGroup = this._formBuilder.group({
name: new FormControl({value: "", disabled: true}),
uid: new FormControl({value: "", disabled: true}),
mtime: new FormControl({value: "", disabled: true}),
ctime: new FormControl({value: "", disabled: true}),
depth: new FormControl({value: 0, disabled: true}),
arch: new FormControl({value: "", disabled: true}),
});
isEditMode: boolean = false;

constructor(
private route: ActivatedRoute,
private userService: UserService,
private cobblerApiService: CobblerApiService,
private _snackBar: MatSnackBar,
private router: Router,
) {
this.name = this.route.snapshot.paramMap.get("name");
}

ngOnInit(): void {
this.refreshData()
}

refreshData(): void {
this.cobblerApiService.get_distro(this.name, false, false, this.userService.token).subscribe(value => {
this.distro = value
this.distroFormGroup.controls.name.setValue(this.distro.name)
this.distroFormGroup.controls.uid.setValue(this.distro.uid)
this.distroFormGroup.controls.mtime.setValue(new Date(this.distro.mtime * 1000).toString())
this.distroFormGroup.controls.ctime.setValue(new Date(this.distro.ctime * 1000).toString())
this.distroFormGroup.controls.depth.setValue(this.distro.depth)
this.distroFormGroup.controls.arch.setValue(this.distro.arch)
}, error => {
// HTML encode the error message since it originates from XML
this._snackBar.open(this.toHTML(error.message), 'Close');
})
}

removeDistro(): void {
this.cobblerApiService.remove_distro(this.name, this.userService.token, false).subscribe(value => {
if (value) {
this.router.navigate(["/distro"])
}
// HTML encode the error message since it originates from XML
this._snackBar.open("Delete failed! Check server logs for more information.", 'Close');
}, error => {
// HTML encode the error message since it originates from XML
this._snackBar.open(this.toHTML(error.message), 'Close');
})
}

editDistro(): void {
// TODO
this._snackBar.open("Not implemented at the moment!", "Close")
}

copyDistro(): void {
this.cobblerApiService.copy_distro("", "", this.userService.token)
.subscribe(value => {
// TODO
}, error => {
// HTML encode the error message since it originates from XML
this._snackBar.open(this.toHTML(error.message), 'Close');
})
}

saveDistro(): void {
// TODO
}

toHTML(input: string): any {
// FIXME: Deduplicate method
return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<h1 class="title">DISTROS</h1>

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!-- Name Column -->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>Name</th>
<td mat-cell *matCellDef="let element">{{element.name}}</td>
</ng-container>

<!-- Breed Column -->
<ng-container matColumnDef="breed">
<th mat-header-cell *matHeaderCellDef>Breed</th>
<td mat-cell *matCellDef="let element">{{element.breed}}</td>
</ng-container>

<!-- OsVersion Column -->
<ng-container matColumnDef="os_version">
<th mat-header-cell *matHeaderCellDef>Operating System Version</th>
<td mat-cell *matCellDef="let element">{{element.os_version}}</td>
</ng-container>

<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let element">
<button mat-icon-button [matMenuTriggerFor]="menu"><mat-icon>more_vert</mat-icon></button>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="showDistro(element.uid, element.name)">
<mat-icon>visibility</mat-icon>
<span>Show details</span>
</button>
<button mat-menu-item (click)="editDistro(element.uid, element.name)">
<mat-icon>edit</mat-icon>
<span>Rename</span>
</button>
<button mat-menu-item (click)="deleteDistro(element.uid, element.name)">
<mat-icon>delete</mat-icon>
<span>Delete</span>
</button>
</mat-menu>
</td>
</ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>

Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ import { MatTabsModule } from '@angular/material/tabs';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import {provideRouter} from '@angular/router';

import { DistrosComponent } from './distros.component';
import { DistrosOverviewComponent } from './distros-overview.component';


describe('DistrosComponent', () => {
let component: DistrosComponent;
let fixture: ComponentFixture<DistrosComponent>;
let component: DistrosOverviewComponent;
let fixture: ComponentFixture<DistrosOverviewComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
Expand All @@ -23,7 +23,7 @@ describe('DistrosComponent', () => {
MatTabsModule,
MatTableModule,
NoopAnimationsModule,
DistrosComponent,
DistrosOverviewComponent,
],
providers: [
provideRouter([]),
Expand All @@ -32,7 +32,7 @@ describe('DistrosComponent', () => {
});

beforeEach(() => {
fixture = TestBed.createComponent(DistrosComponent);
fixture = TestBed.createComponent(DistrosOverviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
Expand Down
Loading

0 comments on commit 3abe8b2

Please sign in to comment.