diff --git a/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.html b/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.html
new file mode 100644
index 00000000..06910ba6
--- /dev/null
+++ b/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.html
@@ -0,0 +1,21 @@
+
Copy {{ data.itemType }}
+
+
+ Old name
+
+
+
+
+ New name
+
+
+
+
+
+
+
diff --git a/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.scss b/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.scss
new file mode 100644
index 00000000..cb97d439
--- /dev/null
+++ b/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.scss
@@ -0,0 +1,3 @@
+.form-field-full-width {
+ width: 100%;
+}
diff --git a/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.spec.ts b/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.spec.ts
new file mode 100644
index 00000000..75faa85b
--- /dev/null
+++ b/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.spec.ts
@@ -0,0 +1,39 @@
+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 { DialogItemCopyComponent } from './dialog-item-copy.component';
+
+describe('DialogItemRenameComponent', () => {
+ let component: DialogItemCopyComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [DialogItemCopyComponent, MatDialogModule, NoopAnimationsModule],
+ providers: [
+ {
+ provide: MatDialogRef,
+ useValue: {},
+ },
+ {
+ provide: MAT_DIALOG_DATA,
+ useValue: { itemType: 'Test', itemName: 'test', itemUid: '' },
+ },
+ ],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(DialogItemCopyComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.ts b/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.component.ts
new file mode 100644
index 00000000..3f1a46b3
--- /dev/null
+++ b/projects/cobbler-frontend/src/app/common/dialog-item-copy/dialog-item-copy.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 DialogItemCopyData {
+ itemType: string;
+ itemName: string;
+ itemUid: string;
+}
+
+@Component({
+ selector: 'cobbler-dialog-item-copy',
+ standalone: true,
+ imports: [
+ MatDialogModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ MatFormFieldModule,
+ MatInputModule,
+ FormsModule,
+ ],
+ templateUrl: './dialog-item-copy.component.html',
+ styleUrl: './dialog-item-copy.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class DialogItemCopyComponent {
+ readonly dialogRef = inject(MatDialogRef);
+ readonly dialogCloseSignal = model('');
+
+ constructor(@Inject(MAT_DIALOG_DATA) public data: DialogItemCopyData) {}
+
+ onNoClick(): void {
+ this.dialogRef.close();
+ }
+}
diff --git a/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.html b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.html
index 44e260dc..266cfe51 100644
--- a/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.html
+++ b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.html
@@ -11,7 +11,11 @@ Name: {{ name }}
-
diff --git a/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.ts b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.ts
index a9d0a3c2..5eb54686 100644
--- a/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.ts
+++ b/projects/cobbler-frontend/src/app/items/distro/edit/distro-edit.component.ts
@@ -1,4 +1,4 @@
-import { Component, inject, OnInit } from '@angular/core';
+import { Component, Inject, inject, OnDestroy, OnInit } from '@angular/core';
import {
FormBuilder,
FormControl,
@@ -7,6 +7,7 @@ import {
} from '@angular/forms';
import { MatButton, MatIconButton } from '@angular/material/button';
import { MatCheckbox } from '@angular/material/checkbox';
+import { MatDialog } from '@angular/material/dialog';
import { MatFormField, MatLabel } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInput } from '@angular/material/input';
@@ -15,6 +16,9 @@ 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 { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { DialogItemCopyComponent } from '../../../common/dialog-item-copy/dialog-item-copy.component';
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';
@@ -42,7 +46,11 @@ import Utils from '../../../utils';
templateUrl: './distro-edit.component.html',
styleUrl: './distro-edit.component.scss',
})
-export class DistroEditComponent implements OnInit {
+export class DistroEditComponent implements OnInit, OnDestroy {
+ // Unsubscribe
+ private ngUnsubscribe = new Subject();
+
+ // Form
name: string;
distro: Distro;
private readonly _formBuilder = inject(FormBuilder);
@@ -101,6 +109,7 @@ export class DistroEditComponent implements OnInit {
private cobblerApiService: CobblerApiService,
private _snackBar: MatSnackBar,
private router: Router,
+ @Inject(MatDialog) readonly dialog: MatDialog,
) {
this.name = this.route.snapshot.paramMap.get('name');
}
@@ -109,9 +118,15 @@ export class DistroEditComponent implements OnInit {
this.refreshData();
}
+ ngOnDestroy(): void {
+ this.ngUnsubscribe.next();
+ this.ngUnsubscribe.complete();
+ }
+
refreshData(): void {
this.cobblerApiService
.get_distro(this.name, false, false, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
this.distro = value;
@@ -238,6 +253,7 @@ export class DistroEditComponent implements OnInit {
removeDistro(): void {
this.cobblerApiService
.remove_distro(this.name, this.userService.token, false)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
if (value) {
@@ -261,18 +277,44 @@ export class DistroEditComponent implements OnInit {
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(Utils.toHTML(error.message), 'Close');
- },
- );
+ copyDistro(uid: string, name: string): void {
+ const dialogRef = this.dialog.open(DialogItemCopyComponent, {
+ 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
+ .copy_distro(distroHandle, newItemName, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(
+ (value) => {
+ this.router.navigate(['/items', 'distro', newItemName]);
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ });
}
saveDistro(): void {
diff --git a/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.html b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.html
index 6c9fe404..d9f12435 100644
--- a/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.html
+++ b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.html
@@ -11,7 +11,11 @@ Name: {{ name }}
-
+
content_copy
diff --git a/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.ts b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.ts
index c9dc19be..c8a174a6 100644
--- a/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.ts
+++ b/projects/cobbler-frontend/src/app/items/file/edit/file-edit.component.ts
@@ -1,4 +1,4 @@
-import { Component, inject, OnInit } from '@angular/core';
+import { Component, Inject, inject, OnDestroy, OnInit } from '@angular/core';
import {
FormBuilder,
FormControl,
@@ -8,6 +8,7 @@ import {
import { MatOption } from '@angular/material/autocomplete';
import { MatButton, MatIconButton } from '@angular/material/button';
import { MatCheckbox } from '@angular/material/checkbox';
+import { MatDialog } from '@angular/material/dialog';
import { MatFormField, MatLabel } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInput } from '@angular/material/input';
@@ -16,6 +17,9 @@ import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTooltip } from '@angular/material/tooltip';
import { ActivatedRoute, Router } from '@angular/router';
import { CobblerApiService, File } from 'cobbler-api';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { DialogItemCopyComponent } from '../../../common/dialog-item-copy/dialog-item-copy.component';
import { UserService } from '../../../services/user.service';
import Utils from '../../../utils';
@@ -39,7 +43,11 @@ import Utils from '../../../utils';
templateUrl: './file-edit.component.html',
styleUrl: './file-edit.component.scss',
})
-export class FileEditComponent implements OnInit {
+export class FileEditComponent implements OnInit, OnDestroy {
+ // Unsubscribe
+ private ngUnsubscribe = new Subject();
+
+ // Form
name: string;
file: File;
private readonly _formBuilder = inject(FormBuilder);
@@ -68,6 +76,7 @@ export class FileEditComponent implements OnInit {
private cobblerApiService: CobblerApiService,
private _snackBar: MatSnackBar,
private router: Router,
+ @Inject(MatDialog) readonly dialog: MatDialog,
) {
this.name = this.route.snapshot.paramMap.get('name');
}
@@ -76,9 +85,15 @@ export class FileEditComponent implements OnInit {
this.refreshData();
}
+ ngOnDestroy(): void {
+ this.ngUnsubscribe.next();
+ this.ngUnsubscribe.complete();
+ }
+
refreshData(): void {
this.cobblerApiService
.get_file(this.name, false, false, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
this.file = value;
@@ -112,6 +127,7 @@ export class FileEditComponent implements OnInit {
removeFile(): void {
this.cobblerApiService
.remove_file(this.name, this.userService.token, false)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
if (value) {
@@ -135,16 +151,44 @@ export class FileEditComponent implements OnInit {
this._snackBar.open('Not implemented at the moment!', 'Close');
}
- copyFile(): void {
- this.cobblerApiService.copy_file('', '', this.userService.token).subscribe(
- (value) => {
- // TODO
+ copyFile(uid: string, name: string): void {
+ const dialogRef = this.dialog.open(DialogItemCopyComponent, {
+ data: {
+ itemType: 'File',
+ itemName: name,
+ itemUid: uid,
},
- (error) => {
- // HTML encode the error message since it originates from XML
- this._snackBar.open(Utils.toHTML(error.message), 'Close');
- },
- );
+ });
+
+ 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
+ .copy_file(fileHandle, newItemName, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(
+ (value) => {
+ this.router.navigate(['/items', 'file', newItemName]);
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ });
}
saveFile(): void {
diff --git a/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.html b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.html
index 61c4cf9e..59c2c57b 100644
--- a/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.html
+++ b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.html
@@ -11,7 +11,11 @@ Name: {{ name }}
-
+
content_copy
diff --git a/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.ts b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.ts
index a401c942..8d820799 100644
--- a/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.ts
+++ b/projects/cobbler-frontend/src/app/items/image/edit/image-edit.component.ts
@@ -1,4 +1,4 @@
-import { Component, inject, OnInit } from '@angular/core';
+import { Component, Inject, inject, OnDestroy, OnInit } from '@angular/core';
import {
FormBuilder,
FormControl,
@@ -8,6 +8,7 @@ import {
import { MatOption } from '@angular/material/autocomplete';
import { MatButton, MatIconButton } from '@angular/material/button';
import { MatCheckbox } from '@angular/material/checkbox';
+import { MatDialog } from '@angular/material/dialog';
import { MatFormField, MatLabel } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInput } from '@angular/material/input';
@@ -16,6 +17,9 @@ import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTooltip } from '@angular/material/tooltip';
import { ActivatedRoute, Router } from '@angular/router';
import { CobblerApiService, Image } from 'cobbler-api';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { DialogItemCopyComponent } from '../../../common/dialog-item-copy/dialog-item-copy.component';
import { MultiSelectComponent } from '../../../common/multi-select/multi-select.component';
import { UserService } from '../../../services/user.service';
import Utils from '../../../utils';
@@ -41,7 +45,11 @@ import Utils from '../../../utils';
templateUrl: './image-edit.component.html',
styleUrl: './image-edit.component.scss',
})
-export class ImageEditComponent implements OnInit {
+export class ImageEditComponent implements OnInit, OnDestroy {
+ // Unsubscribe
+ private ngUnsubscribe = new Subject();
+
+ // Form
name: string;
image: Image;
private readonly _formBuilder = inject(FormBuilder);
@@ -75,6 +83,7 @@ export class ImageEditComponent implements OnInit {
private cobblerApiService: CobblerApiService,
private _snackBar: MatSnackBar,
private router: Router,
+ @Inject(MatDialog) readonly dialog: MatDialog,
) {
this.name = this.route.snapshot.paramMap.get('name');
}
@@ -83,9 +92,15 @@ export class ImageEditComponent implements OnInit {
this.refreshData();
}
+ ngOnDestroy(): void {
+ this.ngUnsubscribe.next();
+ this.ngUnsubscribe.complete();
+ }
+
refreshData(): void {
this.cobblerApiService
.get_image(this.name, false, false, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
this.image = value;
@@ -143,6 +158,7 @@ export class ImageEditComponent implements OnInit {
removeImage(): void {
this.cobblerApiService
.remove_image(this.name, this.userService.token, false)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
if (value) {
@@ -166,16 +182,44 @@ export class ImageEditComponent implements OnInit {
this._snackBar.open('Not implemented at the moment!', 'Close');
}
- copyImage(): void {
- this.cobblerApiService.copy_image('', '', this.userService.token).subscribe(
- (value) => {
- // TODO
+ copyImage(uid: string, name: string): void {
+ const dialogRef = this.dialog.open(DialogItemCopyComponent, {
+ data: {
+ itemType: 'Image',
+ itemName: name,
+ itemUid: uid,
},
- (error) => {
- // HTML encode the error message since it originates from XML
- this._snackBar.open(Utils.toHTML(error.message), 'Close');
- },
- );
+ });
+
+ 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
+ .copy_image(imageHandle, newItemName, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(
+ (value) => {
+ this.router.navigate(['/items', 'image', newItemName]);
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ });
}
saveImage(): void {
diff --git a/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.html b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.html
index f98cad19..6f4f7a5a 100644
--- a/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.html
+++ b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.html
@@ -11,7 +11,16 @@ Name: {{ name }}
-
+
content_copy
diff --git a/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.ts b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.ts
index 71a08260..ed5e5bbb 100644
--- a/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.ts
+++ b/projects/cobbler-frontend/src/app/items/management-class/edit/management-class-edit.component.ts
@@ -1,4 +1,4 @@
-import { Component, inject, OnInit } from '@angular/core';
+import { Component, Inject, inject, OnDestroy, OnInit } from '@angular/core';
import {
FormBuilder,
FormControl,
@@ -8,6 +8,7 @@ import {
import { MatOption } from '@angular/material/autocomplete';
import { MatButton, MatIconButton } from '@angular/material/button';
import { MatCheckbox } from '@angular/material/checkbox';
+import { MatDialog } from '@angular/material/dialog';
import { MatFormField, MatLabel } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInput } from '@angular/material/input';
@@ -16,6 +17,9 @@ import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTooltip } from '@angular/material/tooltip';
import { ActivatedRoute, Router } from '@angular/router';
import { CobblerApiService, Mgmgtclass } from 'cobbler-api';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { DialogItemCopyComponent } from '../../../common/dialog-item-copy/dialog-item-copy.component';
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';
@@ -43,7 +47,11 @@ import Utils from '../../../utils';
templateUrl: './management-class-edit.component.html',
styleUrl: './management-class-edit.component.scss',
})
-export class ManagementClassEditComponent implements OnInit {
+export class ManagementClassEditComponent implements OnInit, OnDestroy {
+ // Unsubscribe
+ private ngUnsubscribe = new Subject();
+
+ // Form
name: string;
managementClass: Mgmgtclass;
private readonly _formBuilder = inject(FormBuilder);
@@ -72,6 +80,7 @@ export class ManagementClassEditComponent implements OnInit {
private cobblerApiService: CobblerApiService,
private _snackBar: MatSnackBar,
private router: Router,
+ @Inject(MatDialog) readonly dialog: MatDialog,
) {
this.name = this.route.snapshot.paramMap.get('name');
}
@@ -80,9 +89,15 @@ export class ManagementClassEditComponent implements OnInit {
this.refreshData();
}
+ ngOnDestroy(): void {
+ this.ngUnsubscribe.next();
+ this.ngUnsubscribe.complete();
+ }
+
refreshData(): void {
this.cobblerApiService
.get_mgmtclass(this.name, false, false, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
this.managementClass = value;
@@ -145,6 +160,7 @@ export class ManagementClassEditComponent implements OnInit {
removeManagementClass(): void {
this.cobblerApiService
.remove_mgmtclass(this.name, this.userService.token, false)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
if (value) {
@@ -168,18 +184,52 @@ export class ManagementClassEditComponent implements OnInit {
this._snackBar.open('Not implemented at the moment!', 'Close');
}
- copyProfile(): void {
- this.cobblerApiService
- .copy_mgmtclass('', '', this.userService.token)
- .subscribe(
- (value) => {
- // TODO
- },
- (error) => {
- // HTML encode the error message since it originates from XML
- this._snackBar.open(Utils.toHTML(error.message), 'Close');
- },
- );
+ copyMgmtClass(uid: string, name: string): void {
+ const dialogRef = this.dialog.open(DialogItemCopyComponent, {
+ data: {
+ itemType: 'Mangement Class',
+ itemName: name,
+ itemUid: uid,
+ },
+ });
+
+ dialogRef.afterClosed().subscribe((newItemName) => {
+ if (newItemName === undefined) {
+ // Cancel means we don't need to rename the management class
+ return;
+ }
+ this.cobblerApiService
+ .get_mgmtclass_handle(name, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(
+ (mgmtClassHandle) => {
+ this.cobblerApiService
+ .copy_mgmtclass(
+ mgmtClassHandle,
+ newItemName,
+ this.userService.token,
+ )
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(
+ (value) => {
+ this.router.navigate([
+ '/items',
+ 'management-class',
+ newItemName,
+ ]);
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ });
}
saveProfile(): void {
diff --git a/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.html b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.html
index 48c2ffd1..2a0a77e0 100644
--- a/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.html
+++ b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.html
@@ -11,7 +11,11 @@ Name: {{ name }}
-
+
content_copy
diff --git a/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.ts b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.ts
index 03e3e7e2..a1e591cf 100644
--- a/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.ts
+++ b/projects/cobbler-frontend/src/app/items/package/edit/package-edit.component.ts
@@ -1,4 +1,4 @@
-import { Component, inject, OnInit } from '@angular/core';
+import { Component, Inject, inject, OnDestroy, OnInit } from '@angular/core';
import {
FormBuilder,
FormControl,
@@ -8,6 +8,7 @@ import {
import { MatOption } from '@angular/material/autocomplete';
import { MatButton, MatIconButton } from '@angular/material/button';
import { MatCheckbox } from '@angular/material/checkbox';
+import { MatDialog } from '@angular/material/dialog';
import { MatFormField, MatLabel } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInput } from '@angular/material/input';
@@ -16,6 +17,9 @@ import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTooltip } from '@angular/material/tooltip';
import { ActivatedRoute, Router } from '@angular/router';
import { CobblerApiService, Package } from 'cobbler-api';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { DialogItemCopyComponent } from '../../../common/dialog-item-copy/dialog-item-copy.component';
import { MultiSelectComponent } from '../../../common/multi-select/multi-select.component';
import { UserService } from '../../../services/user.service';
import Utils from '../../../utils';
@@ -41,7 +45,11 @@ import Utils from '../../../utils';
templateUrl: './package-edit.component.html',
styleUrl: './package-edit.component.scss',
})
-export class PackageEditComponent implements OnInit {
+export class PackageEditComponent implements OnInit, OnDestroy {
+ // Unsubscribe
+ private ngUnsubscribe = new Subject();
+
+ // Form
name: string;
package: Package;
private readonly _formBuilder = inject(FormBuilder);
@@ -73,6 +81,7 @@ export class PackageEditComponent implements OnInit {
private cobblerApiService: CobblerApiService,
private _snackBar: MatSnackBar,
private router: Router,
+ @Inject(MatDialog) readonly dialog: MatDialog,
) {
this.name = this.route.snapshot.paramMap.get('name');
}
@@ -81,9 +90,15 @@ export class PackageEditComponent implements OnInit {
this.refreshData();
}
+ ngOnDestroy(): void {
+ this.ngUnsubscribe.next();
+ this.ngUnsubscribe.complete();
+ }
+
refreshData(): void {
this.cobblerApiService
.get_package(this.name, false, false, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
this.package = value;
@@ -129,6 +144,7 @@ export class PackageEditComponent implements OnInit {
removePackage(): void {
this.cobblerApiService
.remove_package(this.name, this.userService.token, false)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
if (value) {
@@ -152,18 +168,44 @@ export class PackageEditComponent implements OnInit {
this._snackBar.open('Not implemented at the moment!', 'Close');
}
- copyPackage(): void {
- this.cobblerApiService
- .copy_package('', '', this.userService.token)
- .subscribe(
- (value) => {
- // TODO
- },
- (error) => {
- // HTML encode the error message since it originates from XML
- this._snackBar.open(Utils.toHTML(error.message), 'Close');
- },
- );
+ copyPackage(uid: string, name: string): void {
+ const dialogRef = this.dialog.open(DialogItemCopyComponent, {
+ data: {
+ itemType: 'Package',
+ 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
+ .copy_package(packageHandle, newItemName, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(
+ (value) => {
+ this.router.navigate(['/items', 'package', newItemName]);
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ });
}
savePackage(): void {
diff --git a/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.html b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.html
index f288a587..00053cff 100644
--- a/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.html
+++ b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.html
@@ -11,7 +11,11 @@ Name: {{ name }}
-
+
content_copy
diff --git a/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.ts b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.ts
index 45e8051b..a98672c3 100644
--- a/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.ts
+++ b/projects/cobbler-frontend/src/app/items/profile/edit/profile-edit.component.ts
@@ -1,4 +1,4 @@
-import { Component, inject, OnInit } from '@angular/core';
+import { Component, Inject, inject, OnDestroy, OnInit } from '@angular/core';
import {
FormBuilder,
FormControl,
@@ -8,6 +8,7 @@ import {
import { MatOption } from '@angular/material/autocomplete';
import { MatButton, MatIconButton } from '@angular/material/button';
import { MatCheckbox } from '@angular/material/checkbox';
+import { MatDialog } from '@angular/material/dialog';
import { MatFormField, MatLabel } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInput } from '@angular/material/input';
@@ -16,6 +17,9 @@ 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 { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { DialogItemCopyComponent } from '../../../common/dialog-item-copy/dialog-item-copy.component';
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';
@@ -43,7 +47,11 @@ import Utils from '../../../utils';
templateUrl: './profile-edit.component.html',
styleUrl: './profile-edit.component.scss',
})
-export class ProfileEditComponent implements OnInit {
+export class ProfileEditComponent implements OnInit, OnDestroy {
+ // Unsubscribe
+ private ngUnsubscribe = new Subject();
+
+ // Form
name: string;
profile: Profile;
private readonly _formBuilder = inject(FormBuilder);
@@ -110,6 +118,7 @@ export class ProfileEditComponent implements OnInit {
private cobblerApiService: CobblerApiService,
private _snackBar: MatSnackBar,
private router: Router,
+ @Inject(MatDialog) readonly dialog: MatDialog,
) {
this.name = this.route.snapshot.paramMap.get('name');
}
@@ -118,9 +127,15 @@ export class ProfileEditComponent implements OnInit {
this.refreshData();
}
+ ngOnDestroy(): void {
+ this.ngUnsubscribe.next();
+ this.ngUnsubscribe.complete();
+ }
+
refreshData(): void {
this.cobblerApiService
.get_profile(this.name, false, false, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
this.profile = value;
@@ -284,6 +299,7 @@ export class ProfileEditComponent implements OnInit {
removeProfile(): void {
this.cobblerApiService
.remove_profile(this.name, this.userService.token, false)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
if (value) {
@@ -307,18 +323,44 @@ export class ProfileEditComponent implements OnInit {
this._snackBar.open('Not implemented at the moment!', 'Close');
}
- copyProfile(): void {
- this.cobblerApiService
- .copy_profile('', '', this.userService.token)
- .subscribe(
- (value) => {
- // TODO
- },
- (error) => {
- // HTML encode the error message since it originates from XML
- this._snackBar.open(Utils.toHTML(error.message), 'Close');
- },
- );
+ copyProfile(uid: string, name: string): void {
+ const dialogRef = this.dialog.open(DialogItemCopyComponent, {
+ 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
+ .copy_profile(profileHandle, newItemName, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(
+ (value) => {
+ this.router.navigate(['/items', 'profile', newItemName]);
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ });
}
saveProfile(): void {
diff --git a/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.html b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.html
index ced76ba0..c65b3a5a 100644
--- a/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.html
+++ b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.html
@@ -11,7 +11,11 @@ Name: {{ name }}
-
+
content_copy
diff --git a/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.ts b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.ts
index 90171ee3..0e4cacc0 100644
--- a/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.ts
+++ b/projects/cobbler-frontend/src/app/items/repository/edit/repository-edit.component.ts
@@ -1,4 +1,4 @@
-import { Component, inject, OnInit } from '@angular/core';
+import { Component, Inject, inject, OnDestroy, OnInit } from '@angular/core';
import {
FormBuilder,
FormControl,
@@ -8,6 +8,7 @@ import {
import { MatOption } from '@angular/material/autocomplete';
import { MatButton, MatIconButton } from '@angular/material/button';
import { MatCheckbox } from '@angular/material/checkbox';
+import { MatDialog } from '@angular/material/dialog';
import { MatFormField, MatLabel } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInput } from '@angular/material/input';
@@ -16,6 +17,9 @@ import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTooltip } from '@angular/material/tooltip';
import { ActivatedRoute, Router } from '@angular/router';
import { CobblerApiService, Repo } from 'cobbler-api';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { DialogItemCopyComponent } from '../../../common/dialog-item-copy/dialog-item-copy.component';
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';
@@ -43,7 +47,11 @@ import Utils from '../../../utils';
templateUrl: './repository-edit.component.html',
styleUrl: './repository-edit.component.scss',
})
-export class RepositoryEditComponent implements OnInit {
+export class RepositoryEditComponent implements OnInit, OnDestroy {
+ // Unsubscribe
+ private ngUnsubscribe = new Subject();
+
+ // Form
name: string;
repository: Repo;
private readonly _formBuilder = inject(FormBuilder);
@@ -82,6 +90,7 @@ export class RepositoryEditComponent implements OnInit {
private cobblerApiService: CobblerApiService,
private _snackBar: MatSnackBar,
private router: Router,
+ @Inject(MatDialog) readonly dialog: MatDialog,
) {
this.name = this.route.snapshot.paramMap.get('name');
}
@@ -90,9 +99,15 @@ export class RepositoryEditComponent implements OnInit {
this.refreshData();
}
+ ngOnDestroy(): void {
+ this.ngUnsubscribe.next();
+ this.ngUnsubscribe.complete();
+ }
+
refreshData(): void {
this.cobblerApiService
.get_repo(this.name, false, false, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
this.repository = value;
@@ -177,6 +192,7 @@ export class RepositoryEditComponent implements OnInit {
removeRepository(): void {
this.cobblerApiService
.remove_repo(this.name, this.userService.token, false)
+ .pipe(takeUntil(this.ngUnsubscribe))
.subscribe(
(value) => {
if (value) {
@@ -200,16 +216,44 @@ export class RepositoryEditComponent implements OnInit {
this._snackBar.open('Not implemented at the moment!', 'Close');
}
- copyRepository(): void {
- this.cobblerApiService.copy_repo('', '', this.userService.token).subscribe(
- (value) => {
- // TODO
+ copyRepository(uid: string, name: string): void {
+ const dialogRef = this.dialog.open(DialogItemCopyComponent, {
+ data: {
+ itemType: 'Repository',
+ itemName: name,
+ itemUid: uid,
},
- (error) => {
- // HTML encode the error message since it originates from XML
- this._snackBar.open(Utils.toHTML(error.message), 'Close');
- },
- );
+ });
+
+ dialogRef.afterClosed().subscribe((newItemName) => {
+ if (newItemName === undefined) {
+ // Cancel means we don't need to rename the repository
+ return;
+ }
+ this.cobblerApiService
+ .get_repo_handle(name, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(
+ (repositoryHandle) => {
+ this.cobblerApiService
+ .copy_repo(repositoryHandle, newItemName, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(
+ (value) => {
+ this.router.navigate(['/items', 'repository', newItemName]);
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ });
}
saveRepository(): void {
diff --git a/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.html b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.html
index 769ce560..c7f49e64 100644
--- a/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.html
+++ b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.html
@@ -11,7 +11,11 @@ Name: {{ name }}
-
+
content_copy
diff --git a/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.ts b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.ts
index 78b2fb18..4db15dbe 100644
--- a/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.ts
+++ b/projects/cobbler-frontend/src/app/items/system/edit/system-edit.component.ts
@@ -1,4 +1,4 @@
-import { Component, inject, OnInit } from '@angular/core';
+import { Component, Inject, inject, OnDestroy, OnInit } from '@angular/core';
import {
FormBuilder,
FormControl,
@@ -8,6 +8,7 @@ import {
import { MatOption } from '@angular/material/autocomplete';
import { MatButton, MatIconButton } from '@angular/material/button';
import { MatCheckbox } from '@angular/material/checkbox';
+import { MatDialog } from '@angular/material/dialog';
import { MatFormField, MatLabel } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInput } from '@angular/material/input';
@@ -16,6 +17,9 @@ import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTooltip } from '@angular/material/tooltip';
import { ActivatedRoute, Router } from '@angular/router';
import { CobblerApiService, System } from 'cobbler-api';
+import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+import { DialogItemCopyComponent } from '../../../common/dialog-item-copy/dialog-item-copy.component';
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';
@@ -43,7 +47,11 @@ import Utils from '../../../utils';
templateUrl: './system-edit.component.html',
styleUrl: './system-edit.component.scss',
})
-export class SystemEditComponent implements OnInit {
+export class SystemEditComponent implements OnInit, OnDestroy {
+ // Unsubscribe
+ private ngUnsubscribe = new Subject();
+
+ // Form
name: string;
system: System;
private readonly _formBuilder = inject(FormBuilder);
@@ -132,6 +140,7 @@ export class SystemEditComponent implements OnInit {
private cobblerApiService: CobblerApiService,
private _snackBar: MatSnackBar,
private router: Router,
+ @Inject(MatDialog) readonly dialog: MatDialog,
) {
this.name = this.route.snapshot.paramMap.get('name');
}
@@ -140,6 +149,11 @@ export class SystemEditComponent implements OnInit {
this.refreshData();
}
+ ngOnDestroy(): void {
+ this.ngUnsubscribe.next();
+ this.ngUnsubscribe.complete();
+ }
+
refreshData(): void {
this.cobblerApiService
.get_system(this.name, false, false, this.userService.token)
@@ -393,18 +407,44 @@ export class SystemEditComponent implements OnInit {
this._snackBar.open('Not implemented at the moment!', 'Close');
}
- copySystem(): void {
- this.cobblerApiService
- .copy_system('', '', this.userService.token)
- .subscribe(
- (value) => {
- // TODO
- },
- (error) => {
- // HTML encode the error message since it originates from XML
- this._snackBar.open(Utils.toHTML(error.message), 'Close');
- },
- );
+ copySystem(uid: string, name: string): void {
+ const dialogRef = this.dialog.open(DialogItemCopyComponent, {
+ 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
+ .copy_system(systemHandle, newItemName, this.userService.token)
+ .pipe(takeUntil(this.ngUnsubscribe))
+ .subscribe(
+ (value) => {
+ this.router.navigate(['/items', 'system', newItemName]);
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ },
+ (error) => {
+ // HTML encode the error message since it originates from XML
+ this._snackBar.open(Utils.toHTML(error.message), 'Close');
+ },
+ );
+ });
}
saveSystem(): void {