From 446d4cb5c0a02030d15acff7b4c9f6ee5532f2a9 Mon Sep 17 00:00:00 2001 From: Enno Gotthold Date: Fri, 1 Nov 2024 13:49:03 +0100 Subject: [PATCH] Items: Implement rename operation for overview --- .../dialog-item-rename.component.html | 21 +++++ .../dialog-item-rename.component.scss | 3 + .../dialog-item-rename.component.spec.ts | 43 ++++++++++ .../dialog-item-rename.component.ts | 48 +++++++++++ .../overview/distros-overview.component.html | 2 +- .../overview/distros-overview.component.ts | 81 +++++++++++++++--- .../overview/file-overview.component.html | 2 +- .../file/overview/file-overview.component.ts | 80 +++++++++++++++--- .../overview/image-overview.component.html | 2 +- .../overview/image-overview.component.ts | 80 +++++++++++++++--- .../management-class-overview.component.html | 2 +- .../management-class-overview.component.ts | 84 ++++++++++++++++--- .../overview/package-overview.component.html | 5 +- .../overview/package-overview.component.ts | 84 ++++++++++++++++--- .../overview/profile-overview.component.html | 5 +- .../overview/profile-overview.component.ts | 84 ++++++++++++++++--- .../repository-overview.component.html | 2 +- .../overview/repository-overview.component.ts | 80 +++++++++++++++--- .../overview/system-overview.component.html | 2 +- .../overview/system-overview.component.ts | 80 +++++++++++++++--- 20 files changed, 678 insertions(+), 112 deletions(-) create mode 100644 projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.html create mode 100644 projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.scss create mode 100644 projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.spec.ts create mode 100644 projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.ts diff --git a/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.html b/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.html new file mode 100644 index 00000000..82fdc229 --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.html @@ -0,0 +1,21 @@ +

Rename {{ data.itemType }}

+ + + Old name + + + + + New name + + + + + + + diff --git a/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.scss b/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.scss new file mode 100644 index 00000000..cb97d439 --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.scss @@ -0,0 +1,3 @@ +.form-field-full-width { + width: 100%; +} diff --git a/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.spec.ts b/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.spec.ts new file mode 100644 index 00000000..1c4702ff --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.spec.ts @@ -0,0 +1,43 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { + MAT_DIALOG_DATA, + MatDialogModule, + MatDialogRef, +} from '@angular/material/dialog'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideRouter } from '@angular/router'; + +import { DialogItemRenameComponent } from './dialog-item-rename.component'; + +describe('DialogItemRenameComponent', () => { + let component: DialogItemRenameComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + DialogItemRenameComponent, + MatDialogModule, + NoopAnimationsModule, + ], + providers: [ + { + provide: MatDialogRef, + useValue: {}, + }, + { + provide: MAT_DIALOG_DATA, + useValue: { itemType: 'Test', itemName: 'test', itemUid: '' }, + }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(DialogItemRenameComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.ts b/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.ts new file mode 100644 index 00000000..79cd3ba5 --- /dev/null +++ b/projects/cobbler-frontend/src/app/common/dialog-item-rename/dialog-item-rename.component.ts @@ -0,0 +1,48 @@ +import { + ChangeDetectionStrategy, + Component, + inject, + Inject, + model, +} from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButton, MatButtonModule } from '@angular/material/button'; +import { + MAT_DIALOG_DATA, + MatDialogModule, + MatDialogRef, +} from '@angular/material/dialog'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { MatInputModule } from '@angular/material/input'; + +export interface DialogItemRenameData { + itemType: string; + itemName: string; + itemUid: string; +} + +@Component({ + selector: 'cobbler-dialog-item-rename', + standalone: true, + imports: [ + MatDialogModule, + MatButtonModule, + ReactiveFormsModule, + MatFormFieldModule, + MatInputModule, + FormsModule, + ], + templateUrl: './dialog-item-rename.component.html', + styleUrl: './dialog-item-rename.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DialogItemRenameComponent { + readonly dialogRef = inject(MatDialogRef); + readonly dialogCloseSignal = model(''); + + constructor(@Inject(MAT_DIALOG_DATA) public data: DialogItemRenameData) {} + + onNoClick(): void { + this.dialogRef.close(); + } +} diff --git a/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.html b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.html index 40c2a6b4..254576f2 100644 --- a/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.html +++ b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.html @@ -30,7 +30,7 @@

DISTROS

visibility Show details - diff --git a/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.ts b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.ts index 04d45027..57274c52 100644 --- a/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.ts +++ b/projects/cobbler-frontend/src/app/items/distro/overview/distros-overview.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { MatButton, MatIconButton } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; import { MatSnackBar } from '@angular/material/snack-bar'; @@ -17,6 +18,10 @@ import { } from '@angular/material/table'; import { Router } from '@angular/router'; import { CobblerApiService, Distro } from 'cobbler-api'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { DialogBoxTextConfirmComponent } from '../../../common/dialog-box-text-confirm/dialog-box-text-confirm'; +import { DialogItemRenameComponent } from '../../../common/dialog-item-rename/dialog-item-rename.component'; import { UserService } from '../../../services/user.service'; @Component({ @@ -44,7 +49,11 @@ import { UserService } from '../../../services/user.service'; MatMenuTrigger, ], }) -export class DistrosOverviewComponent implements OnInit { +export class DistrosOverviewComponent implements OnInit, OnDestroy { + // Unsubscribe + private ngUnsubscribe = new Subject(); + + // Table displayedColumns: string[] = ['name', 'breed', 'os_version', 'actions']; dataSource: Array = []; @@ -55,35 +64,81 @@ export class DistrosOverviewComponent implements OnInit { private cobblerApiService: CobblerApiService, private _snackBar: MatSnackBar, private router: Router, + @Inject(MatDialog) readonly dialog: MatDialog, ) {} ngOnInit(): void { this.retrieveDistros(); } + ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } + private retrieveDistros(): void { - this.cobblerApiService.get_distros().subscribe( - (value) => { - this.dataSource = value; - }, - (error) => { - // HTML encode the error message since it originates from XML - this._snackBar.open(this.toHTML(error.message), 'Close'); - }, - ); + this.cobblerApiService + .get_distros() + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.dataSource = value; + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); } showDistro(uid: string, name: string): void { this.router.navigate(['/items', 'distro', name]); } - editDistro(uid: string, name: string): void { - // TODO + renameDistro(uid: string, name: string): void { + const dialogRef = this.dialog.open(DialogItemRenameComponent, { + data: { + itemType: 'Distro', + itemName: name, + itemUid: uid, + }, + }); + + dialogRef.afterClosed().subscribe((newItemName) => { + if (newItemName === undefined) { + // Cancel means we don't need to rename the distro + return; + } + this.cobblerApiService + .get_distro_handle(name, this.userService.token) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (distroHandle) => { + this.cobblerApiService + .rename_distro(distroHandle, newItemName, this.userService.token) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.retrieveDistros(); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }); } deleteDistro(uid: string, name: string): void { this.cobblerApiService .remove_distro(name, this.userService.token, false) + .pipe(takeUntil(this.ngUnsubscribe)) .subscribe( (value) => { this.retrieveDistros(); diff --git a/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.html b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.html index 80c2052f..e3b9845a 100644 --- a/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.html +++ b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.html @@ -30,7 +30,7 @@

FILES

visibility Show details - diff --git a/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.ts b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.ts index 53c7b850..37c4e274 100644 --- a/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.ts +++ b/projects/cobbler-frontend/src/app/items/file/overview/file-overview.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { MatIconButton } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; import { MatSnackBar } from '@angular/material/snack-bar'; @@ -17,6 +18,9 @@ import { } from '@angular/material/table'; import { Router } from '@angular/router'; import { CobblerApiService, File } from 'cobbler-api'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { DialogItemRenameComponent } from '../../../common/dialog-item-rename/dialog-item-rename.component'; import { UserService } from '../../../services/user.service'; @Component({ @@ -42,7 +46,11 @@ import { UserService } from '../../../services/user.service'; templateUrl: './file-overview.component.html', styleUrl: './file-overview.component.scss', }) -export class FileOverviewComponent implements OnInit { +export class FileOverviewComponent implements OnInit, OnDestroy { + // Unsubscribe + private ngUnsubscribe = new Subject(); + + // Table displayedColumns: string[] = ['name', 'action', 'path', 'actions']; dataSource: Array = []; @@ -53,35 +61,81 @@ export class FileOverviewComponent implements OnInit { private cobblerApiService: CobblerApiService, private _snackBar: MatSnackBar, private router: Router, + @Inject(MatDialog) readonly dialog: MatDialog, ) {} ngOnInit(): void { this.retrieveFiles(); } + ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } + private retrieveFiles(): void { - this.cobblerApiService.get_files().subscribe( - (value) => { - this.dataSource = value; - }, - (error) => { - // HTML encode the error message since it originates from XML - this._snackBar.open(this.toHTML(error.message), 'Close'); - }, - ); + this.cobblerApiService + .get_files() + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.dataSource = value; + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); } showDistro(uid: string, name: string): void { this.router.navigate(['/items', 'file', name]); } - editFile(uid: string, name: string): void { - // TODO + renameFile(uid: string, name: string): void { + const dialogRef = this.dialog.open(DialogItemRenameComponent, { + data: { + itemType: 'Repository', + itemName: name, + itemUid: uid, + }, + }); + + dialogRef.afterClosed().subscribe((newItemName) => { + if (newItemName === undefined) { + // Cancel means we don't need to rename the file + return; + } + this.cobblerApiService + .get_file_handle(name, this.userService.token) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (fileHandle) => { + this.cobblerApiService + .rename_file(fileHandle, newItemName, this.userService.token) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.retrieveFiles(); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }); } deleteFile(uid: string, name: string): void { this.cobblerApiService .remove_file(name, this.userService.token, false) + .pipe(takeUntil(this.ngUnsubscribe)) .subscribe( (value) => { this.retrieveFiles(); diff --git a/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.html b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.html index 82ceb61a..4da8227e 100644 --- a/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.html +++ b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.html @@ -36,7 +36,7 @@

IMAGES

visibility Show details - diff --git a/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.ts b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.ts index f01ea4e1..3d56dfd0 100644 --- a/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.ts +++ b/projects/cobbler-frontend/src/app/items/image/overview/image-overview.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { MatIconButton } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; import { MatSnackBar } from '@angular/material/snack-bar'; @@ -17,6 +18,9 @@ import { } from '@angular/material/table'; import { Router } from '@angular/router'; import { CobblerApiService, Image } from 'cobbler-api'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { DialogItemRenameComponent } from '../../../common/dialog-item-rename/dialog-item-rename.component'; import { UserService } from '../../../services/user.service'; @Component({ @@ -42,7 +46,11 @@ import { UserService } from '../../../services/user.service'; templateUrl: './image-overview.component.html', styleUrl: './image-overview.component.scss', }) -export class ImageOverviewComponent implements OnInit { +export class ImageOverviewComponent implements OnInit, OnDestroy { + // Unsubscribe + private ngUnsubscribe = new Subject(); + + // Table displayedColumns: string[] = [ 'name', 'arch', @@ -59,35 +67,81 @@ export class ImageOverviewComponent implements OnInit { private cobblerApiService: CobblerApiService, private _snackBar: MatSnackBar, private router: Router, + @Inject(MatDialog) readonly dialog: MatDialog, ) {} ngOnInit(): void { this.retrieveImages(); } + ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } + private retrieveImages(): void { - this.cobblerApiService.get_images().subscribe( - (value) => { - this.dataSource = value; - }, - (error) => { - // HTML encode the error message since it originates from XML - this._snackBar.open(this.toHTML(error.message), 'Close'); - }, - ); + this.cobblerApiService + .get_images() + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.dataSource = value; + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); } showImage(uid: string, name: string): void { this.router.navigate(['/items', 'image', name]); } - editImage(uid: string, name: string): void { - // TODO + renameImage(uid: string, name: string): void { + const dialogRef = this.dialog.open(DialogItemRenameComponent, { + data: { + itemType: 'Image', + itemName: name, + itemUid: uid, + }, + }); + + dialogRef.afterClosed().subscribe((newItemName) => { + if (newItemName === undefined) { + // Cancel means we don't need to rename the image + return; + } + this.cobblerApiService + .get_image_handle(name, this.userService.token) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (imageHandle) => { + this.cobblerApiService + .rename_image(imageHandle, newItemName, this.userService.token) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.retrieveImages(); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }); } deleteImage(uid: string, name: string): void { this.cobblerApiService .remove_distro(name, this.userService.token, false) + .pipe(takeUntil(this.ngUnsubscribe)) .subscribe( (value) => { this.retrieveImages(); diff --git a/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.html b/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.html index 9aa28a23..b9440124 100644 --- a/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.html +++ b/projects/cobbler-frontend/src/app/items/management-class/overview/management-class-overview.component.html @@ -35,7 +35,7 @@

MANAGEMENT CLASSES

- diff --git a/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.ts b/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.ts index f11df5e5..4f6d7363 100644 --- a/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.ts +++ b/projects/cobbler-frontend/src/app/items/package/overview/package-overview.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { MatIconButton } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; import { MatSnackBar } from '@angular/material/snack-bar'; @@ -17,6 +18,9 @@ import { } from '@angular/material/table'; import { Router } from '@angular/router'; import { CobblerApiService, Package } from 'cobbler-api'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { DialogItemRenameComponent } from '../../../common/dialog-item-rename/dialog-item-rename.component'; import { UserService } from '../../../services/user.service'; @Component({ @@ -42,7 +46,11 @@ import { UserService } from '../../../services/user.service'; templateUrl: './package-overview.component.html', styleUrl: './package-overview.component.scss', }) -export class PackageOverviewComponent implements OnInit { +export class PackageOverviewComponent implements OnInit, OnDestroy { + // Unsubscribe + private ngUnsubscribe = new Subject(); + + // Table displayedColumns: string[] = ['name', 'installer', 'version', 'actions']; dataSource: Array = []; @@ -53,35 +61,85 @@ export class PackageOverviewComponent implements OnInit { private cobblerApiService: CobblerApiService, private _snackBar: MatSnackBar, private router: Router, + @Inject(MatDialog) readonly dialog: MatDialog, ) {} ngOnInit(): void { this.retrievePackages(); } + ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } + private retrievePackages(): void { - this.cobblerApiService.get_packages().subscribe( - (value) => { - this.dataSource = value; - }, - (error) => { - // HTML encode the error message since it originates from XML - this._snackBar.open(this.toHTML(error.message), 'Close'); - }, - ); + this.cobblerApiService + .get_packages() + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.dataSource = value; + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); } showPackage(uid: string, name: string): void { this.router.navigate(['/items', 'package', name]); } - editPackage(uid: string, name: string): void { - // TODO + renamePackage(uid: string, name: string): void { + const dialogRef = this.dialog.open(DialogItemRenameComponent, { + data: { + itemType: 'Repository', + itemName: name, + itemUid: uid, + }, + }); + + dialogRef.afterClosed().subscribe((newItemName) => { + if (newItemName === undefined) { + // Cancel means we don't need to rename the package + return; + } + this.cobblerApiService + .get_package_handle(name, this.userService.token) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (packageHandle) => { + this.cobblerApiService + .rename_package( + packageHandle, + newItemName, + this.userService.token, + ) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.retrievePackages(); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }); } deletePackage(uid: string, name: string): void { this.cobblerApiService .remove_package(name, this.userService.token, false) + .pipe(takeUntil(this.ngUnsubscribe)) .subscribe( (value) => { this.retrievePackages(); diff --git a/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.html b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.html index 8e7a296b..9714c818 100644 --- a/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.html +++ b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.html @@ -30,7 +30,10 @@

PROFILES

visibility Show details - diff --git a/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.ts b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.ts index c9a9fcc2..789e111b 100644 --- a/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.ts +++ b/projects/cobbler-frontend/src/app/items/profile/overview/profile-overview.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { MatIconButton } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; import { MatSnackBar } from '@angular/material/snack-bar'; @@ -17,6 +18,9 @@ import { } from '@angular/material/table'; import { Router } from '@angular/router'; import { CobblerApiService, Profile } from 'cobbler-api'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { DialogItemRenameComponent } from '../../../common/dialog-item-rename/dialog-item-rename.component'; import { UserService } from '../../../services/user.service'; @Component({ @@ -42,7 +46,11 @@ import { UserService } from '../../../services/user.service'; templateUrl: './profile-overview.component.html', styleUrl: './profile-overview.component.scss', }) -export class ProfileOverviewComponent implements OnInit { +export class ProfileOverviewComponent implements OnInit, OnDestroy { + // Unsubscribe + private ngUnsubscribe = new Subject(); + + // Table displayedColumns: string[] = ['name', 'distro', 'server', 'actions']; dataSource: Array = []; @@ -53,35 +61,85 @@ export class ProfileOverviewComponent implements OnInit { private cobblerApiService: CobblerApiService, private _snackBar: MatSnackBar, private router: Router, + @Inject(MatDialog) readonly dialog: MatDialog, ) {} ngOnInit(): void { this.retrieveProfiles(); } + ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } + private retrieveProfiles(): void { - this.cobblerApiService.get_profiles().subscribe( - (value) => { - this.dataSource = value; - }, - (error) => { - // HTML encode the error message since it originates from XML - this._snackBar.open(this.toHTML(error.message), 'Close'); - }, - ); + this.cobblerApiService + .get_profiles() + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.dataSource = value; + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); } showProfile(uid: string, name: string): void { this.router.navigate(['/items', 'profile', name]); } - editProfile(uid: string, name: string): void { - // TODO + renameProfile(uid: string, name: string): void { + const dialogRef = this.dialog.open(DialogItemRenameComponent, { + data: { + itemType: 'Profile', + itemName: name, + itemUid: uid, + }, + }); + + dialogRef.afterClosed().subscribe((newItemName) => { + if (newItemName === undefined) { + // Cancel means we don't need to rename the profile + return; + } + this.cobblerApiService + .get_profile_handle(name, this.userService.token) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (profileHandle) => { + this.cobblerApiService + .rename_profile( + profileHandle, + newItemName, + this.userService.token, + ) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.retrieveProfiles(); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }); } deleteProfile(uid: string, name: string): void { this.cobblerApiService .remove_profile(name, this.userService.token, false) + .pipe(takeUntil(this.ngUnsubscribe)) .subscribe( (value) => { this.retrieveProfiles(); diff --git a/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.html b/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.html index 95485897..a68d4aff 100644 --- a/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.html +++ b/projects/cobbler-frontend/src/app/items/repository/overview/repository-overview.component.html @@ -35,7 +35,7 @@

REPOSITORIES

- diff --git a/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.ts b/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.ts index 900254ff..b4d5b663 100644 --- a/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.ts +++ b/projects/cobbler-frontend/src/app/items/system/overview/system-overview.component.ts @@ -1,5 +1,6 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { MatIconButton } from '@angular/material/button'; +import { MatDialog } from '@angular/material/dialog'; import { MatIcon } from '@angular/material/icon'; import { MatMenu, MatMenuItem, MatMenuTrigger } from '@angular/material/menu'; import { MatSnackBar } from '@angular/material/snack-bar'; @@ -17,6 +18,9 @@ import { } from '@angular/material/table'; import { Router } from '@angular/router'; import { CobblerApiService, System } from 'cobbler-api'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { DialogItemRenameComponent } from '../../../common/dialog-item-rename/dialog-item-rename.component'; import { UserService } from '../../../services/user.service'; @Component({ @@ -42,7 +46,11 @@ import { UserService } from '../../../services/user.service'; templateUrl: './system-overview.component.html', styleUrl: './system-overview.component.scss', }) -export class SystemOverviewComponent implements OnInit { +export class SystemOverviewComponent implements OnInit, OnDestroy { + // Unsubscribe + private ngUnsubscribe = new Subject(); + + // Table displayedColumns: string[] = ['name', 'profile', 'image', 'actions']; dataSource: Array = []; @@ -53,35 +61,81 @@ export class SystemOverviewComponent implements OnInit { private cobblerApiService: CobblerApiService, private _snackBar: MatSnackBar, private router: Router, + @Inject(MatDialog) readonly dialog: MatDialog, ) {} ngOnInit(): void { this.retrieveSystems(); } + ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } + private retrieveSystems(): void { - this.cobblerApiService.get_systems().subscribe( - (value) => { - this.dataSource = value; - }, - (error) => { - // HTML encode the error message since it originates from XML - this._snackBar.open(this.toHTML(error.message), 'Close'); - }, - ); + this.cobblerApiService + .get_systems() + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.dataSource = value; + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); } showSystem(uid: string, name: string): void { this.router.navigate(['/items', 'system', name]); } - editSystem(uid: string, name: string): void { - // TODO + renameSystem(uid: string, name: string): void { + const dialogRef = this.dialog.open(DialogItemRenameComponent, { + data: { + itemType: 'System', + itemName: name, + itemUid: uid, + }, + }); + + dialogRef.afterClosed().subscribe((newItemName) => { + if (newItemName === undefined) { + // Cancel means we don't need to rename the system + return; + } + this.cobblerApiService + .get_system_handle(name, this.userService.token) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (systemHandle) => { + this.cobblerApiService + .rename_system(systemHandle, newItemName, this.userService.token) + .pipe(takeUntil(this.ngUnsubscribe)) + .subscribe( + (value) => { + this.retrieveSystems(); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }, + (error) => { + // HTML encode the error message since it originates from XML + this._snackBar.open(this.toHTML(error.message), 'Close'); + }, + ); + }); } deleteSystem(uid: string, name: string): void { this.cobblerApiService .remove_system(name, this.userService.token, false) + .pipe(takeUntil(this.ngUnsubscribe)) .subscribe( (value) => { this.retrieveSystems();