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 6afb794
Show file tree
Hide file tree
Showing 20 changed files with 476 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,127 @@
<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>
<mat-checkbox class="form-field-full-width" formControlName="is_subobject">Is Subobject?</mat-checkbox>
<mat-form-field class="form-field-full-width">
<mat-label>Tree Build Time</mat-label>
<input matInput type="text" formControlName="tree_build_time"/>
</mat-form-field>
<!-- TODO: autoinstall_meta -->
<!-- TODO: boot_files -->
<ng-container class="form-field-full-width">
<mat-form-field>
<mat-label>Boot Loaders</mat-label>
<mat-select formControlName="boot_loaders" multiple>
@for (boot_loader of ["ipxe", "grub", "pxe"]; track boot_loader) {
<mat-option [value]="boot_loader">{{boot_loader}}</mat-option>
}
</mat-select>
</mat-form-field>
<mat-checkbox formControlName="bootloader_inherited">Inherited</mat-checkbox>
</ng-container>
<mat-form-field class="form-field-full-width">
<mat-label>Breed</mat-label>
<input matInput type="text" formControlName="breed"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>Comment</mat-label>
<input matInput type="text" formControlName="comment"/>
</mat-form-field>
<!-- TODO: fetchable_files -->
<mat-form-field class="form-field-full-width">
<mat-label>kernel</mat-label>
<input matInput type="text" formControlName="kernel"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>initrd</mat-label>
<input matInput type="text" formControlName="initrd"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>Remote Boot Initrd</mat-label>
<input matInput type="text" formControlName="remote_boot_initrd"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>Remote Boot Kernel</mat-label>
<input matInput type="text" formControlName="remote_boot_kernel"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>Remote GRUB Initrd</mat-label>
<input matInput type="text" formControlName="remote_grub_initrd"/>
</mat-form-field>
<mat-form-field class="form-field-full-width">
<mat-label>Remote GRUB Kernel</mat-label>
<input matInput type="text" formControlName="remote_grub_kernel"/>
</mat-form-field>
<!-- TODO: kernel_options -->
<!-- TODO: kernel_options_post -->
<!-- TODO: mgmt_classes -->
<mat-form-field class="form-field-full-width">
<mat-label>Operating System Version</mat-label>
<input matInput type="text" formControlName="os_version"/>
</mat-form-field>
<!-- TODO: owners -->
<mat-form-field class="form-field-full-width">
<mat-label>RedHat Management Key</mat-label>
<input matInput type="text" formControlName="redhat_management_key"/>
</mat-form-field>
<!-- TODO: template_files -->
@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,146 @@
import {Component, inject, OnInit} from '@angular/core';
import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatButton, MatIconButton} from '@angular/material/button';
import {MatCheckbox} from '@angular/material/checkbox';
import {MatFormField, MatLabel} from '@angular/material/form-field';
import {MatIcon} from '@angular/material/icon';
import {MatInput} from '@angular/material/input';
import {MatOption, MatSelect} from '@angular/material/select';
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,
MatCheckbox,
MatSelect,
MatOption,
],
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}),
is_subobject: new FormControl({value: false, disabled: true}),
tree_build_time: new FormControl({value: "", disabled: true}),
breed: new FormControl({value: "", disabled: true}),
comment: new FormControl({value: "", disabled: true}),
kernel: new FormControl({value: "", disabled: true}),
initrd: new FormControl({value: "", disabled: true}),
remote_boot_initrd: new FormControl({value: "", disabled: true}),
remote_boot_kernel: new FormControl({value: "", disabled: true}),
remote_grub_initrd: new FormControl({value: "", disabled: true}),
remote_grub_kernel: new FormControl({value: "", disabled: true}),
os_version: new FormControl({value: "", disabled: true}),
redhat_management_key: new FormControl({value: "", disabled: true}),
boot_loaders: new FormControl({value: [], disabled: true}),
bootloader_inherited: new FormControl({value: false, 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)
this.distroFormGroup.controls.is_subobject.setValue(this.distro.is_subobject)
this.distroFormGroup.controls.tree_build_time.setValue(new Date(this.distro.tree_build_time * 1000).toString())
this.distroFormGroup.controls.breed.setValue(this.distro.breed)
this.distroFormGroup.controls.comment.setValue(this.distro.comment)
this.distroFormGroup.controls.kernel.setValue(this.distro.kernel)
this.distroFormGroup.controls.initrd.setValue(this.distro.initrd)
this.distroFormGroup.controls.remote_boot_initrd.setValue(this.distro.remote_boot_initrd)
this.distroFormGroup.controls.remote_boot_kernel.setValue(this.distro.remote_boot_kernel)
this.distroFormGroup.controls.remote_grub_initrd.setValue(this.distro.remote_grub_initrd)
this.distroFormGroup.controls.remote_grub_kernel.setValue(this.distro.remote_grub_kernel)
this.distroFormGroup.controls.os_version.setValue(this.distro.os_version)
this.distroFormGroup.controls.redhat_management_key.setValue(this.distro.redhat_management_key)
if (typeof this.distro.boot_loaders === "string") {
this.distroFormGroup.controls.bootloader_inherited.setValue(true)
} else {
this.distroFormGroup.controls.bootloader_inherited.setValue(false)
this.distroFormGroup.controls.boot_loaders.setValue(this.distro.boot_loaders)
}
}, 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;
}
}
Loading

0 comments on commit 6afb794

Please sign in to comment.