Skip to content

Commit

Permalink
Cobbler-Frontend: Progress View/Edit screens (dict component)
Browse files Browse the repository at this point in the history
  • Loading branch information
SchoolGuy committed Jul 28, 2024
1 parent 3dc739b commit b1d461a
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<mat-card appearance="outlined">
<mat-card-header>
<mat-card-title>{{label}}</mat-card-title>
</mat-card-header>
@if (Object.keys(this.keyValueOptions).length === 0) {
<p style="text-align: center">Empty list of options</p>
} @else {
<div cdkDropList [cdkDropListDisabled]="isDisabled" class="example-list" [formGroup]="keyOrderFormGroup" (cdkDropListDropped)="drop($event)">
@for (key of keyOrder; track key) {
<form class="example-box" formGroupName="{{key}}FormGroup">
<mat-form-field>
<input matInput formControlName="key" placeholder="Key" value="{{key}}" />
</mat-form-field>
&nbsp;=&nbsp;
<mat-form-field>
<input matInput formControlName="value" placeholder="Value" value="{{ keyValueOptions[key] }}"/>
</mat-form-field>
<button mat-icon-button [disabled]="isDisabled" (click)="deleteKey(key)"><mat-icon>delete</mat-icon></button>
<button mat-icon-button [disabled]="isDisabled" cdkDrag><mat-icon>menu</mat-icon></button>
</form>
}
</div>
}
</mat-card>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.example-list {
width: 80%;
max-width: 100%;
border: solid 1px #ccc;
min-height: 60px;
display: block;
background: white;
border-radius: 4px;
overflow: hidden;
}

.example-box {
margin: 20px 10px;
padding: 10px;
border: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: move;
background: white;
font-size: 14px;
}

.cdk-drag-preview {
border: none;
box-sizing: border-box;
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14),
0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

.cdk-drag-placeholder {
opacity: 0;
}

.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.example-box:last-child {
border: none;
}

.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

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

import { KeyValueEditorComponent } from './key-value-editor.component';

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

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

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

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import {CdkDrag, CdkDragDrop, CdkDropList, moveItemInArray} from '@angular/cdk/drag-drop';
import {Component, Input, OnInit} from '@angular/core';
import {
AbstractControl,
ControlValueAccessor, FormControl, FormGroup,
NG_VALIDATORS,
NG_VALUE_ACCESSOR, ReactiveFormsModule,
ValidationErrors,
Validator
} from '@angular/forms';
import {MatIconButton} from '@angular/material/button';
import {MatCard, MatCardHeader, MatCardTitle} from '@angular/material/card';
import {MatFormField} from '@angular/material/form-field';
import {MatIcon} from '@angular/material/icon';
import {MatInput} from '@angular/material/input';

@Component({
selector: 'cobbler-key-value-editor',
standalone: true,
imports: [
MatCard,
MatCardHeader,
MatCardTitle,
CdkDropList,
CdkDrag,
MatFormField,
MatInput,
MatIconButton,
MatIcon,
ReactiveFormsModule,
],
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: KeyValueEditorComponent,
},
{
provide: NG_VALIDATORS,
multi: true,
useExisting: KeyValueEditorComponent
},
],
templateUrl: './key-value-editor.component.html',
styleUrl: './key-value-editor.component.scss'
})
export class KeyValueEditorComponent implements ControlValueAccessor, Validator{
@Input() label = "";
@Input() keyValueOptions = {}
onChange = (options: string[]) => {};
onTouched = (options: string[]) => {};
keyOrder = Object.keys(this.keyValueOptions);
keyOrderFormGroup = new FormGroup({})
isDisabled = true;

registerOnChange(fn: any): void {
this.onChange = fn;
}

registerOnTouched(fn: any): void {
this.onTouched = fn;
}

registerOnValidatorChange(fn: () => void): void {
}

setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
this.setFormGroupDisabledState(isDisabled)
}

setFormGroupDisabledState(isDisabled: boolean): void {
if (isDisabled) {
this.keyOrderFormGroup.disable();
} else {
this.keyOrderFormGroup.enable();
}
}

validate(control: AbstractControl): ValidationErrors | null {
return undefined;
}

writeValue(obj: any): void {
this.keyValueOptions = obj
this.keyOrder = Object.keys(this.keyValueOptions);
this.buildFormGroup()
}

buildFormGroup(): void {
for (let key of this.keyOrder) {
const formGroupControls = {
key: new FormControl({value: key, disabled: true}),
value: new FormControl({value: this.keyValueOptions[key], disabled: true}),
}
this.keyOrderFormGroup.addControl(key + "FormGroup", new FormGroup(formGroupControls))
}
this.setFormGroupDisabledState(this.isDisabled)
}

deleteKey(key: string): void {
// TODO: Delete key
}

drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.keyOrder, event.previousIndex, event.currentIndex);
}

protected readonly Object = Object;
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ <h1 class="title title-cell-text">Name: {{ name }}</h1>
<mat-label>Tree Build Time</mat-label>
<input matInput type="text" formControlName="tree_build_time"/>
</mat-form-field>
<!-- TODO: autoinstall_meta -->
<ng-container class="form-field-full-width">
<cobbler-key-value-editor label="Automatic Installation Template Metadata" [keyValueOptions]="distroAutoinstallMeta" formControlName="autoinstall_meta"></cobbler-key-value-editor>
<mat-checkbox formControlName="autoinstall_meta_inherited">Inherited</mat-checkbox>
</ng-container>
<!-- TODO: boot_files -->
<ng-container class="form-field-full-width">
<cobbler-multi-select label="Boot Loaders" [multiSelectOptions]='["ipxe", "grub", "pxe"]' formControlName="boot_loaders"></cobbler-multi-select>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ 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 {KeyValueEditorComponent} from '../../../common/key-value-editor/key-value-editor.component';
import {MultiSelectComponent} from '../../../common/multi-select/multi-select.component';
import {UserService} from '../../../services/user.service';

Expand All @@ -30,6 +31,7 @@ import {UserService} from '../../../services/user.service';
MatSelect,
MatOption,
MultiSelectComponent,
KeyValueEditorComponent,
],
templateUrl: './distro-edit.component.html',
styleUrl: './distro-edit.component.scss'
Expand Down Expand Up @@ -63,6 +65,8 @@ export class DistroEditComponent implements OnInit{
owners_inherited: new FormControl({value: false, disabled: true}),
mgmt_classes: new FormControl({value: [], disabled: true}),
mgmt_classes_inherited: new FormControl({value: false, disabled: true}),
autoinstall_meta: new FormControl({value: {}, disabled: true}),
autoinstall_meta_inherited: new FormControl({value: false, disabled: true}),
});
isEditMode: boolean = false;

Expand Down Expand Up @@ -113,6 +117,12 @@ export class DistroEditComponent implements OnInit{
this.distroFormGroup.controls.owners_inherited.setValue(false)
this.distroFormGroup.controls.owners.setValue(this.distro.owners)
}
if (typeof this.distro.autoinstall_meta === "string") {
this.distroFormGroup.controls.autoinstall_meta_inherited.setValue(true)
} else {
this.distroFormGroup.controls.autoinstall_meta_inherited.setValue(false)
this.distroFormGroup.controls.autoinstall_meta.setValue(this.distro.autoinstall_meta)
}
}, error => {
// HTML encode the error message since it originates from XML
this._snackBar.open(this.toHTML(error.message), 'Close');
Expand Down Expand Up @@ -161,6 +171,16 @@ export class DistroEditComponent implements OnInit{
return []
}

get distroAutoinstallMeta(): object {
if (this.distro && this.distro.autoinstall_meta) {
const autoinstallMetaResult = this.distro.autoinstall_meta
if (typeof autoinstallMetaResult !== 'string') {
return autoinstallMetaResult
}
}
return {}
}

toHTML(input: string): any {
// FIXME: Deduplicate method
return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@ <h1 class="title title-cell-text">Name: {{ name }}</h1>
<mat-label>Server</mat-label>
<input matInput type="text" formControlName="server"/>
</mat-form-field>
<!-- TODO: autoinstall_meta -->
<ng-container class="form-field-full-width">
<cobbler-key-value-editor label="Automatic Installation Template Metadata" [keyValueOptions]="profileAutoinstallMeta" formControlName="autoinstall_meta"></cobbler-key-value-editor>
<mat-checkbox formControlName="autoinstall_meta_inherited">Inherited</mat-checkbox>
</ng-container>
<!-- TODO: boot_files -->
<!-- TODO: fetchable_files -->
<!-- TODO: kernel_options -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,29 @@ import {MatSnackBar} from '@angular/material/snack-bar';
import {MatTooltip} from '@angular/material/tooltip';
import {ActivatedRoute, Router} from '@angular/router';
import {CobblerApiService, Profile} from 'cobbler-api';
import {KeyValueEditorComponent} from '../../../common/key-value-editor/key-value-editor.component';
import {MultiSelectComponent} from '../../../common/multi-select/multi-select.component';
import {UserService} from '../../../services/user.service';

@Component({
selector: 'cobbler-edit',
standalone: true,
imports: [
MatIcon,
MatIconButton,
MatTooltip,
FormsModule,
MatButton,
MatCheckbox,
MatFormField,
MatInput,
MatLabel,
MatOption,
MatSelect,
ReactiveFormsModule,
MultiSelectComponent
],
imports: [
MatIcon,
MatIconButton,
MatTooltip,
FormsModule,
MatButton,
MatCheckbox,
MatFormField,
MatInput,
MatLabel,
MatOption,
MatSelect,
ReactiveFormsModule,
MultiSelectComponent,
KeyValueEditorComponent
],
templateUrl: './profile-edit.component.html',
styleUrl: './profile-edit.component.scss'
})
Expand Down Expand Up @@ -62,6 +64,8 @@ export class ProfileEditComponent implements OnInit{
bootloader_inherited: new FormControl({value: false, disabled: true}),
owners: new FormControl({value: [], disabled: true}),
owners_inherited: new FormControl({value: false, disabled: true}),
autoinstall_meta: new FormControl({value: {}, disabled: true}),
autoinstall_meta_inherited: new FormControl({value: false, disabled: true}),
});
isEditMode: boolean = false;

Expand Down Expand Up @@ -112,6 +116,12 @@ export class ProfileEditComponent implements OnInit{
this.profileFormGroup.controls.owners_inherited.setValue(false)
this.profileFormGroup.controls.owners.setValue(this.profile.owners)
}
if (typeof this.profile.autoinstall_meta === "string") {
this.profileFormGroup.controls.autoinstall_meta_inherited.setValue(true)
} else {
this.profileFormGroup.controls.autoinstall_meta_inherited.setValue(false)
this.profileFormGroup.controls.autoinstall_meta.setValue(this.profile.autoinstall_meta)
}
}, error => {
// HTML encode the error message since it originates from XML
this._snackBar.open(this.toHTML(error.message), 'Close');
Expand Down Expand Up @@ -160,6 +170,16 @@ export class ProfileEditComponent implements OnInit{
return []
}

get profileAutoinstallMeta(): object {
if (this.profile && this.profile.autoinstall_meta) {
const autoinstallMetaResult = this.profile.autoinstall_meta
if (typeof autoinstallMetaResult !== 'string') {
return autoinstallMetaResult
}
}
return {}
}

toHTML(input: string): any {
// FIXME: Deduplicate method
return new DOMParser().parseFromString(input, 'text/html').documentElement.textContent;
Expand Down

0 comments on commit b1d461a

Please sign in to comment.