Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/app.routes.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/app.routes.ts	(revision 2671)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/app.routes.ts	(working copy)
@@ -15,6 +15,8 @@
   VolumeLicenseDevicesOverview
 } from './components/volume-license-devices-overview/volume-license-devices-overview';
 import {VolumeLicenseOverview} from './components/volume-license-overview/volume-license-overview';
+import {ConfigHub} from './components/config-hub/config-hub';
+import {DeviceBackupFiles} from './components/sub-components/device-backup-files/device-backup-files';
 
 
 export const routes: Routes = [
@@ -99,7 +101,20 @@
           },
         ]
       },
-
+      {
+        path: 'configuration-hub',
+        data: {roles: ['super_admin', 'device_admin', 'common_admin'],},
+        children: [
+          {
+            path: '',
+            component: ConfigHub,
+          },
+          {
+            path: 'backup/:deviceName',
+            component: DeviceBackupFiles
+          },
+        ]
+      },
       {path: '', redirectTo: 'dashboard', pathMatch: 'full'},
       {path: '**', redirectTo: 'dashboard'}
     ]
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/config-hub/config-hub.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/config-hub/config-hub.html	(revision 2671)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/config-hub/config-hub.html	(working copy)
@@ -1 +1,25 @@
-<p>config-hub works!</p>
+<div class="tab-container">
+  <mat-tab-group animationDuration="0ms" [selectedIndex]="selectedTabIndex" (selectedTabChange)="onTabChange($event)">
+    <mat-tab label="Device Configuration Files">
+      <ng-template matTabContent>
+        <div class="tab-content">
+          <app-device-config-overview/>
+        </div>
+      </ng-template>
+    </mat-tab>
+    <mat-tab label="Cloned Files">
+      <ng-template matTabContent>
+        <div class="tab-content">
+          <app-device-cloned-files/>
+        </div>
+      </ng-template>
+    </mat-tab>
+    <mat-tab label="Customized Files">
+      <ng-template matTabContent>
+        <div class="tab-content">
+          <app-device-custom-config-overview/>
+        </div>
+      </ng-template>
+    </mat-tab>
+  </mat-tab-group>
+</div>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/config-hub/config-hub.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/config-hub/config-hub.ts	(revision 2671)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/config-hub/config-hub.ts	(working copy)
@@ -1,11 +1,60 @@
-import { Component } from '@angular/core';
+import {Component, OnInit} from '@angular/core';
+import {SharedModule} from '../../shared/shared-module';
+import {ActivatedRoute, Router} from '@angular/router';
+import {MatTabChangeEvent} from '@angular/material/tabs';
+import {
+  DeviceCustomConfigOverview
+} from '../sub-components/device-custom-config-overview/device-custom-config-overview';
+import {DeviceClonedFiles} from '../sub-components/device-cloned-files/device-cloned-files';
+import {DeviceConfigOverview} from '../sub-components/device-config-overview/device-config-overview';
 
 @Component({
   selector: 'app-config-hub',
-  imports: [],
+  imports: [SharedModule, DeviceCustomConfigOverview, DeviceClonedFiles, DeviceConfigOverview],
   templateUrl: './config-hub.html',
   styleUrl: './config-hub.scss'
 })
-export class ConfigHub {
+export class ConfigHub implements OnInit {
 
+  selectedTabIndex: number = 0;
+  private tabNames: string[] = [
+    'Device Configuration Files',
+    'Cloned Files',
+    'Customized Files'
+  ];
+
+  constructor(private route: ActivatedRoute, private router: Router) {
+  }
+
+  ngOnInit(): void {
+    this.route.queryParams.subscribe(params => {
+      const tabParam = params['tab'];
+      if (tabParam) {
+        const index = this.tabNames.indexOf(tabParam);
+        if (index !== -1) {
+          this.selectedTabIndex = index;
+        } else {
+          this.selectedTabIndex = 0;
+        }
+      } else {
+        this.updateQueryParams(this.selectedTabIndex);
+      }
+    });
+  }
+
+  onTabChange(event: MatTabChangeEvent): void {
+    this.selectedTabIndex = event.index;
+    this.updateQueryParams(event.index);
+  }
+
+  private updateQueryParams(tabIndex: number): void {
+    const tabName = this.tabNames[tabIndex];
+    if (tabName) {
+      this.router.navigate([], {
+        relativeTo: this.route,
+        queryParams: {tab: tabName},
+        queryParamsHandling: 'merge'
+      });
+    }
+  }
 }
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/clone-config.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/clone-config.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/clone-config.html	(working copy)
@@ -0,0 +1,64 @@
+<h2 mat-dialog-title>Clone Configuration</h2>
+<mat-dialog-content>
+  <form
+    (ngSubmit)="onSubmit()"
+    [formGroup]="cloneForm"
+  >
+    <div class="form-field-wrapper">
+      <label for="file_name" class="form-label">Filename *</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <input
+          id="file_name"
+          formControlName="file_name"
+          matInput
+          placeholder="Filename"
+          type="text"
+        />
+        @if (cloneForm.get('file_name')?.invalid && cloneForm.get('file_name')?.touched) {
+          <mat-error>
+            @if (cloneForm.get('file_name')?.errors?.['required']) {
+              Filename is required.
+            } @else if (cloneForm.get('file_name')?.errors) {
+              Invalid filename format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+    <div class="form-field-wrapper">
+      <label for="comment" class="form-label">Comment</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <input
+          id="comment"
+          formControlName="comment"
+          matInput
+          placeholder="Comment"
+          type="text"
+        />
+        @if (cloneForm.get('comment')?.invalid && cloneForm.get('comment')?.touched) {
+          <mat-error>
+            @if (cloneForm.get('comment')?.errors?.['required']) {
+              Comment is required.
+            } @else if (cloneForm.get('comment')?.errors) {
+              Invalid comment format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+  </form>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+  <button
+    mat-raised-button
+    color="primary"
+    (click)="onSubmit()">
+    Submit
+  </button>
+</mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/create-config-backup.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/create-config-backup.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/create-config-backup.html	(working copy)
@@ -0,0 +1,43 @@
+<h2 mat-dialog-title>Backup Configuration</h2>
+<mat-dialog-content>
+  <form
+    (ngSubmit)="onSubmit()"
+    [formGroup]="backupForm"
+  >
+    <div class="form-field-wrapper">
+      <label for="comment" class="form-label">Comment</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <input
+          id="comment"
+          formControlName="comment"
+          matInput
+          placeholder="Comment"
+          type="text"
+        />
+        @if (backupForm.get('comment')?.invalid && backupForm.get('comment')?.touched) {
+          <mat-error>
+            @if (backupForm.get('comment')?.errors?.['required']) {
+              Comment is required.
+            } @else if (backupForm.get('comment')?.errors) {
+              Invalid comment format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+  </form>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+  <button
+    mat-raised-button
+    color="primary"
+    (click)="onSubmit()">
+    Submit
+  </button>
+</mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.html	(working copy)
@@ -0,0 +1,69 @@
+<mat-card class="page-card-1" appearance="filled">
+  <mat-card-header>
+    <mat-card-title>
+      <a class="back-to-main-page" (click)="navigateToDeviceConfiguration()">
+        <fa-icon [icon]="['far', 'circle-left']"></fa-icon>
+        Device Configuration Files
+      </a>
+    </mat-card-title>
+  </mat-card-header>
+</mat-card>
+<mat-card class="page-card-1" appearance="filled">
+  <mat-card-header>
+    <mat-card-title>Historical Backups</mat-card-title>
+    <div>
+      <button mat-raised-button (click)="createDeviceConfigBackup()"
+              matTooltip="Backup device configuration">Create Backup
+      </button>
+    </div>
+  </mat-card-header>
+</mat-card>
+<div class="table-container">
+  <table mat-table [dataSource]="dataSource" class="mat-elevation-z1">
+    <ng-container matColumnDef="serial">
+      <th mat-header-cell *matHeaderCellDef> No.</th>
+      <td mat-cell *matCellDef="let element; let i = index;"> {{ i + 1 }}</td>
+    </ng-container>
+    <ng-container matColumnDef="fileName">
+      <th mat-header-cell *matHeaderCellDef> Filename</th>
+      <td mat-cell *matCellDef="let element">{{ element.name }}</td>
+    </ng-container>
+    <ng-container matColumnDef="fileType">
+      <th mat-header-cell *matHeaderCellDef> File Type</th>
+      <td mat-cell *matCellDef="let element"> {{ element.file_type }}</td>
+    </ng-container>
+    <ng-container matColumnDef="createTime">
+      <th mat-header-cell *matHeaderCellDef> Create Time</th>
+      <td mat-cell *matCellDef="let element">{{ element.create_time }}</td>
+    </ng-container>
+    <ng-container matColumnDef="comment">
+      <th mat-header-cell *matHeaderCellDef> Comment</th>
+      <td mat-cell *matCellDef="let element"> {{ element.comment }}</td>
+    </ng-container>
+    <ng-container matColumnDef="action">
+      <th mat-header-cell *matHeaderCellDef class="action-header w-10"> Action</th>
+      <td mat-cell *matCellDef="let element">
+        <div class="row-action a-link">
+          <fa-icon [icon]="['far', 'clone']" size="lg" matTooltip="Clone"
+                   (click)="cloneDeviceBackupConfig(element)"></fa-icon>
+          <fa-icon [icon]="['far', 'window-restore']" size="lg" matTooltip="Recover"
+                   (click)="recoverDeviceBackupConfig(element)"></fa-icon>
+          <fa-icon [icon]="['fas', 'list-check']" size="lg" matTooltip="Show Task"
+                   (click)="showConfigTask(element)"></fa-icon>
+          <fa-icon [icon]="['far', 'trash-can']" size="lg" class="delete-icon" matTooltip="Delete Backup"
+                   (click)="deleteDeviceBackupConfig(element)"></fa-icon>
+        </div>
+      </td>
+    </ng-container>
+    <tr mat-header-row *matHeaderRowDef="deviceColumns"></tr>
+    <tr mat-row *matRowDef="let row; columns: deviceColumns;"></tr>
+    <tr class="mat-row table-no-data" *matNoDataRow>
+      <td class="mat-cell" colspan="11">No results found.</td>
+    </tr>
+  </table>
+  <mat-paginator
+    [pageSizeOptions]="[10, 15, 20, 25]"
+    [length]="totalRecords"
+    showFirstLastButtons
+  ></mat-paginator>
+</div>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.scss
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.scss	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.scss	(working copy)
@@ -0,0 +1,21 @@
+.page-card-1 {
+  width: 100%;
+  border-radius: 0;
+  background-color: inherit;
+  font-size: 14px !important;
+
+  mat-card-header {
+    color: #1170cf;
+  }
+}
+
+mat-card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 4px 10px;
+}
+
+mat-card-title {
+  font-size: medium;
+}
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.spec.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.spec.ts	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.spec.ts	(working copy)
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DeviceBackupFiles } from './device-backup-files';
+
+describe('DeviceBackupFiles', () => {
+  let component: DeviceBackupFiles;
+  let fixture: ComponentFixture<DeviceBackupFiles>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [DeviceBackupFiles]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(DeviceBackupFiles);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.ts	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/device-backup-files.ts	(working copy)
@@ -0,0 +1,469 @@
+import {AfterViewInit, ChangeDetectorRef, Component, inject, OnInit, ViewChild} from '@angular/core';
+import {ActivatedRoute, Router} from '@angular/router';
+import {SharedModule} from '../../../shared/shared-module';
+import {MatTableDataSource} from '@angular/material/table';
+import {MatPaginator} from '@angular/material/paginator';
+import {MAT_DIALOG_DATA, MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material/dialog';
+import {FormBuilder, FormGroup, Validators} from '@angular/forms';
+import {NotificationService} from '../../../services/notification';
+import {take} from 'rxjs/operators';
+import {DeviceService} from '../../../services/device-service';
+import {SystemService} from '../../../services/system-service';
+import {Confirmation} from '../../../services/confirmation';
+
+@Component({
+  selector: 'app-device-backup-files',
+  imports: [
+    SharedModule
+  ],
+  templateUrl: './device-backup-files.html',
+  styleUrl: './device-backup-files.scss'
+})
+export class DeviceBackupFiles implements OnInit, AfterViewInit {
+
+  totalRecords: number = 0;
+  dataSource: MatTableDataSource<any> = new MatTableDataSource();
+  deviceColumns: string[] = ['serial', 'fileName', 'fileType', 'createTime', 'comment', 'action'];
+  @ViewChild(MatPaginator) paginator!: MatPaginator;
+
+  deviceName: any = '';
+  deviceDetails: any = {};
+  dialog = inject(MatDialog);
+  dialogConfig = new MatDialogConfig();
+  deviceBackupsMap: any = {};
+  deviceLastBackupMap: any = {};
+
+  constructor(
+    private _route: ActivatedRoute,
+    private _router: Router,
+    private _confirmation: Confirmation,
+    private _cdRef: ChangeDetectorRef,
+    private _device: DeviceService,
+    private _notification: NotificationService,
+  ) {
+  }
+
+  ngOnInit() {
+    this.deviceName = this._route.snapshot.paramMap.get('deviceName');
+
+    setTimeout(() => {
+      this.getDeviceConfigFiles();
+    })
+  }
+
+  ngAfterViewInit() {
+    this.dataSource.paginator = this.paginator;
+    this._cdRef.detectChanges();
+  }
+
+  getDeviceConfigFiles() {
+    this.dataSource.data = [];
+
+    this._device.getDeviceConfigFiles().pipe(take(1)).subscribe({
+      next: (result: any) => {
+        this.analyzeBackupData(result);
+
+        this.deviceDetails = {
+          backups: this.deviceBackupsMap[this.deviceName] || []
+        };
+
+        history.state.deviceDetails = this.deviceDetails;
+
+        this.dataSource.data = this.deviceDetails.backups;
+
+        if (this.paginator) {
+          this.dataSource.paginator = this.paginator;
+        } else {
+          setTimeout(() => {
+            this.dataSource.paginator = this.paginator;
+            this._cdRef.detectChanges();
+          });
+        }
+
+        this.totalRecords = this.dataSource.data.length;
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this.dataSource.data = [];
+        this.totalRecords = 0;
+        this._cdRef.detectChanges();
+      }
+    });
+  }
+
+  analyzeBackupData(data: any[]): (any & { lastBackupTime: string })[] {
+    const deviceEntries: any[] = [];
+    this.deviceBackupsMap = {};
+    this.deviceLastBackupMap = {};
+
+    data.forEach(entry => {
+      if (entry.file_type === 'device') {
+        deviceEntries.push(entry);
+        this.deviceLastBackupMap[entry.name] = null;
+      }
+    });
+
+    data.forEach(entry => {
+      if (entry.file_type === 'backup' && entry.name) {
+        const deviceMatch = entry.name.match(/^([a-zA-Z0-9]+)-/);
+        if (deviceMatch && deviceMatch[1]) {
+          const deviceName = deviceMatch[1];
+          const backupTime = new Date(entry.create_time);
+
+          if (this.deviceLastBackupMap.hasOwnProperty(deviceName)) {
+            if (!this.deviceLastBackupMap[deviceName] || backupTime > this.deviceLastBackupMap[deviceName]!) {
+              this.deviceLastBackupMap[deviceName] = backupTime;
+            }
+          } else {
+            this.deviceLastBackupMap[deviceName] = backupTime;
+          }
+
+          if (this.deviceBackupsMap.hasOwnProperty(deviceName)) {
+            this.deviceBackupsMap[deviceName].push(entry);
+          } else {
+            this.deviceBackupsMap[deviceName] = [entry];
+          }
+        }
+      }
+    });
+    return deviceEntries;
+  }
+
+  createDeviceConfigBackup() {
+    this.dialogConfig.data = {
+      deviceName: this.deviceName,
+    }
+    const dialogRef = this.dialog.open(CreateDeviceConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe(() => {
+    })
+  }
+
+  navigateToDeviceConfiguration() {
+    this._router.navigate(['/configuration-hub'], {queryParams: {tab: 'Device Configuration Files'}});
+  }
+
+  cloneDeviceBackupConfig(_config: any) {
+    this.dialogConfig.data = {
+      config: _config,
+    };
+    const dialogRef = this.dialog.open(CloneConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe(() => {
+    })
+  }
+
+  recoverDeviceBackupConfig(_config: any) {
+    this.dialogConfig.data = {
+      config: _config,
+    };
+    const dialogRef = this.dialog.open(RecoverBackupDeviceConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe(() => {
+    })
+  }
+
+  showConfigTask(_config: any) {
+    this.dialogConfig.width = '60%';
+    this.dialogConfig.data = {
+      config: _config,
+    };
+    const dialogRef = this.dialog.open(ShowTasksByNameDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  deleteDeviceBackupConfig(_config: any) {
+    let confirmMsg = `Are you sure you want to delete the device configuration file - ${_config?.name}"?`
+    this._confirmation.openConfirmDialog({
+      title: `Delete Device Configuration File?`,
+      message: confirmMsg,
+      confirmButtonText: 'Yes, Delete It',
+      cancelButtonText: 'No, Keep It',
+      confirmButtonColor: 'warn',
+      cancelButtonColor: 'primary'
+    }).subscribe((result: boolean) => {
+      if (result) {
+        let rawPayload = new FormData();
+        rawPayload.set('pk', JSON.stringify({
+          file_type: _config?.file_type,
+          name: _config?.name
+        }));
+        this._device.deleteDeviceConfigFile(rawPayload)
+          .pipe(take(1))
+          .subscribe({
+            next: (result: any) => {
+              this.getDeviceConfigFiles();
+            },
+            error: (err: any) => {
+              // ToDo: Fix in backend
+              if (err?.status === 200) {
+                // ToDo: Backend fix required.
+                this._notification.showSuccess(`The device configuration file has been deleted successfully!`);
+                // this.getDeviceConfigFiles();
+              } else {
+                this._notification.showError(`Failed to delete the device configuration file: ${err}.`);
+              }
+              this.getDeviceConfigFiles();
+            }
+          })
+      }
+    });
+  }
+}
+
+
+@Component({
+  selector: 'clone-config',
+  templateUrl: './clone-config.html',
+  imports: [SharedModule]
+})
+export class CloneConfigDialog implements OnInit {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<CloneConfigDialog>);
+
+  cloneForm!: FormGroup;
+
+  constructor(
+    private _formBuilder: FormBuilder,
+    private _device: DeviceService,
+    private _notification: NotificationService,
+  ) {
+  }
+
+  ngOnInit() {
+    this.cloneForm = this._formBuilder.group({
+      file_name: ['', [Validators.required]],
+      comment: ['',],
+    });
+  }
+
+  onSubmit(): void {
+    if (this.cloneForm.invalid) {
+      console.log(this.cloneForm.value);
+      this.cloneForm.markAllAsTouched();
+      return;
+    }
+    let rawPayload = new FormData();
+    rawPayload.set('action', 'Clone_file')
+    rawPayload.set('options', JSON.stringify({
+      "__pk_list": [JSON.stringify({
+        name: this.data?.config?.name,
+        file_type: this.data?.config?.file_type,
+        device_type: this.data?.config?.device_type
+      })],
+      file_name: this.cloneForm.value.file_name,
+      comment: this.cloneForm.value.comment,
+      option: true
+    }));
+    this._device.cloneDeviceBackupConfig(rawPayload)
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          if (result[0]) {
+            this._notification.showSuccess('The device backup config clone has been initiated successfully.');
+            this.dialogRef.close(true);
+          } else {
+            this._notification.showError(result[1]);
+          }
+        },
+        error: (err) => {
+          console.error(err);
+          this._notification.showError('Failed to clone the device backup configuration.');
+        }
+      })
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+}
+
+@Component({
+  selector: 'show-tasks-by-name',
+  templateUrl: './show-tasks-by-name.html',
+  imports: [SharedModule]
+})
+export class ShowTasksByNameDialog implements AfterViewInit {
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<ShowTasksByNameDialog>);
+
+  totalRecords: number = 0;
+  dataSource: any = new MatTableDataSource();
+  dataSourceColumns: Array<string> = ['serial', 'name', 'type', 'createTime', 'status'];
+  @ViewChild(MatPaginator) paginator!: MatPaginator;
+
+  constructor(
+    private _system: SystemService,
+    private _notification: NotificationService,
+    private _cdRef: ChangeDetectorRef
+  ) {
+    this.dataSource = new MatTableDataSource([]);
+    this.getTasksByName();
+  }
+
+  ngAfterViewInit() {
+    this.dataSource.paginator = this.paginator;
+  }
+
+  getTasksByName() {
+    this.dataSource.data = [];
+    let payload = new FormData();
+    payload.set('post_data', JSON.stringify({
+      name: this.data?.config?.name,
+      type: this.data?.config?.file_type,
+    }));
+    this._system.getTaskByName(payload)
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          this.dataSource.data = result;
+          this.dataSource.paginator = this.paginator;
+          this.totalRecords = this.dataSource.data.length;
+          this._cdRef.detectChanges();
+        },
+        error: (error: { message: string; }) => {
+          console.log(error);
+          this._notification.showError(error.message);
+          this._cdRef.detectChanges();
+        }
+      })
+  }
+
+  getGlobalSerial(index: number): number {
+    if (this.paginator) {
+      return this.paginator.pageIndex * this.paginator.pageSize + index + 1;
+    }
+    return index + 1;
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+}
+
+@Component({
+  selector: 'create-config-backup',
+  templateUrl: './create-config-backup.html',
+  imports: [SharedModule]
+})
+export class CreateDeviceConfigDialog implements OnInit {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<CreateDeviceConfigDialog>);
+
+  backupForm!: FormGroup;
+
+  constructor(
+    private _formBuilder: FormBuilder,
+    private _device: DeviceService,
+    private _notification: NotificationService,
+  ) {
+  }
+
+  ngOnInit() {
+    this.backupForm = this._formBuilder.group({
+      comment: ['', [Validators.required]],
+    });
+  }
+
+  onSubmit(): void {
+    if (this.backupForm.invalid) {
+      console.log(this.backupForm.value);
+      this.backupForm.markAllAsTouched();
+      return;
+    }
+    let rawPayload = new FormData();
+    rawPayload.set('action', 'Backup')
+    rawPayload.set('options', JSON.stringify({
+      "__pk_list": [JSON.stringify({
+        file_type: 'device',
+        name: this.data?.deviceName
+      })],
+      comment: this.backupForm.value.comment,
+    }));
+    this._device.performDeviceConfigOperation(rawPayload)
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          if (result[0]) {
+            this._notification.showSuccess('The device backup config has been initiated successfully.');
+            this.dialogRef.close(true);
+          } else {
+            this._notification.showError(result[1]);
+          }
+        },
+        error: (err) => {
+          console.error(err);
+          this._notification.showError('Failed to perform the device backup configuration.');
+        }
+      })
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+}
+
+
+@Component({
+  selector: 'recover-backup-config',
+  templateUrl: './recover-backup-config.html',
+  imports: [SharedModule]
+})
+export class RecoverBackupDeviceConfigDialog implements OnInit {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<RecoverBackupDeviceConfigDialog>);
+
+  backupForm!: FormGroup;
+
+  constructor(
+    private _formBuilder: FormBuilder,
+    private _device: DeviceService,
+    private _notification: NotificationService,
+  ) {
+  }
+
+  ngOnInit() {
+    this.backupForm = this._formBuilder.group({
+      enable_backup: [false, [Validators.required]],
+    });
+  }
+
+  onSubmit(): void {
+    if (this.backupForm.invalid) {
+      console.log(this.backupForm.value);
+      this.backupForm.markAllAsTouched();
+      return;
+    }
+    let rawPayload = new FormData();
+    rawPayload.set('action', 'Recover')
+    rawPayload.set('options', JSON.stringify({
+      "__pk_list": [JSON.stringify({
+        file_type: 'backup',
+        name: this.data?.config?.name
+      })],
+      backup: this.backupForm.value.enable_backup,
+    }));
+    this._device.performDeviceConfigOperation(rawPayload)
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          if (result[0]) {
+            this._notification.showSuccess('Configuration recovery initiated.');
+            this.dialogRef.close(true);
+          } else {
+            this._notification.showError(result[1]);
+          }
+        },
+        error: (err) => {
+          console.error(err);
+          this._notification.showError('Failed to restore the device\'s configuration from its backup.');
+        }
+      })
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+}
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/recover-backup-config.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/recover-backup-config.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/recover-backup-config.html	(working copy)
@@ -0,0 +1,27 @@
+<h2 mat-dialog-title>Recover Configuration</h2>
+
+<mat-dialog-content>
+  <form
+    (ngSubmit)="onSubmit()"
+    [formGroup]="backupForm"
+  >
+    <div class="form-field-wrapper">
+      <label for="enable_backup" class="form-label">Backup Before And After Application</label>
+      <mat-slide-toggle formControlName="enable_backup"></mat-slide-toggle>
+    </div>
+  </form>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+  <button
+    mat-raised-button
+    color="primary"
+    (click)="onSubmit()">
+    Submit
+  </button>
+</mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/show-tasks-by-name.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/show-tasks-by-name.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-backup-files/show-tasks-by-name.html	(working copy)
@@ -0,0 +1,46 @@
+<h2 mat-dialog-title>Tasks for configuration</h2>
+
+<mat-dialog-content>
+  <div class="table-container">
+    <table mat-table [dataSource]="dataSource" class="mat-elevation-z1">
+      <ng-container matColumnDef="serial">
+        <th mat-header-cell *matHeaderCellDef> No.</th>
+        <td mat-cell *matCellDef="let element; let i = index;"> {{ getGlobalSerial(i) }}</td>
+      </ng-container>
+      <ng-container matColumnDef="name">
+        <th mat-header-cell *matHeaderCellDef> Filename</th>
+        <td mat-cell *matCellDef="let element">{{ element.name.split('.cfg')[0] + '.cfg'}}</td>
+      </ng-container>
+      <ng-container matColumnDef="type">
+        <th mat-header-cell *matHeaderCellDef> File Type</th>
+        <td mat-cell *matCellDef="let element"> {{ element.type.replaceAll('_', ' ') | titlecase }}</td>
+      </ng-container>
+      <ng-container matColumnDef="createTime">
+        <th mat-header-cell *matHeaderCellDef> Create Time</th>
+        <td mat-cell *matCellDef="let element">{{ element.next_run_time }}</td>
+      </ng-container>
+      <ng-container matColumnDef="status">
+        <th mat-header-cell *matHeaderCellDef> Status</th>
+        <td mat-cell *matCellDef="let element"> {{ element.state | titlecase }}</td>
+      </ng-container>
+      <tr mat-header-row *matHeaderRowDef="dataSourceColumns"></tr>
+      <tr mat-row *matRowDef="let row; columns: dataSourceColumns;"></tr>
+      <tr class="mat-row table-no-data" *matNoDataRow>
+        <td class="mat-cell" colspan="11">No results found.</td>
+      </tr>
+    </table>
+    <mat-paginator
+      [pageSizeOptions]="[10, 15, 20, 25]"
+      [length]="totalRecords"
+      showFirstLastButtons
+    ></mat-paginator>
+  </div>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+</mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/backup-config.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/backup-config.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/backup-config.html	(working copy)
@@ -0,0 +1,72 @@
+<h2 mat-dialog-title>Backup Configuration</h2>
+<mat-dialog-content>
+  <form
+    (ngSubmit)="onSubmit()"
+    [formGroup]="configForm"
+  >
+    <div class="form-field-wrapper">
+      <label for="device" class="form-label">Device *</label>
+      <mat-radio-group formControlName="device">
+        <mat-radio-button value="device">Device</mat-radio-button>
+        <mat-radio-button value="device_group">Device Group</mat-radio-button>
+      </mat-radio-group>
+    </div>
+    @if (configForm.get('device')?.value === 'device') {
+      <div class="form-field-wrapper">
+        <label for="devices" class="form-label">Devices</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="devices" multiple>
+            <mat-option value="ALL">All</mat-option>
+            @for (_option of data?.devices; track _option) {
+              <mat-option [value]="_option.name">{{ _option.name }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('devices')?.invalid && configForm.get('devices')?.touched) {
+            <mat-error>
+              @if (configForm.get('devices')?.errors?.['required']) {
+                Devices is required.
+              } @else {
+                Invalid devices format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    } @else if (configForm.get('device')?.value === 'device_group') {
+      <div class="form-field-wrapper">
+        <label for="device_groups" class="form-label">Device Groups</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="device_groups" multiple>
+            @for (_option of data?.groups; track _option) {
+              <mat-option [value]="_option">{{ _option }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('device_groups')?.invalid && configForm.get('device_groups')?.touched) {
+            <mat-error>
+              @if (configForm.get('device_groups')?.errors?.['required']) {
+                Device groups is required.
+              } @else {
+                Invalid device groups format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    }
+
+  </form>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+  <button
+    mat-raised-button
+    color="primary"
+    (click)="onSubmit()">
+    Submit
+  </button>
+</mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/clone-config.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/clone-config.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/clone-config.html	(working copy)
@@ -0,0 +1,94 @@
+<h2 mat-dialog-title>Clone configuration</h2>
+<mat-dialog-content>
+  <form
+    (ngSubmit)="onSubmit()"
+    [formGroup]="configForm"
+  >
+    <div class="form-field-wrapper">
+      <label for="file_name" class="form-label">Filename *</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <input
+          id="file_name"
+          formControlName="file_name"
+          matInput
+          placeholder="Filename"
+          type="text"
+        />
+        @if (configForm.get('file_name')?.invalid && configForm.get('file_name')?.touched) {
+          <mat-error>
+            @if (configForm.get('file_name')?.errors?.['required']) {
+              Filename is required.
+            } @else if (configForm.get('file_name')?.errors) {
+              Invalid filename format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+<!--    @if (data?.device?.device_type.toLowerCase() === 'apv' || data?.device?.device_type.toLowerCase() === 'vapv') {-->
+<!--      <div class="form-field-wrapper">-->
+<!--        <label for="backup_option" class="form-label">Backup *</label>-->
+<!--        <mat-radio-group formControlName="backup_option">-->
+<!--          <mat-radio-button value="all">All</mat-radio-button>-->
+<!--          <mat-radio-button value="vs">Virtual Services</mat-radio-button>-->
+<!--        </mat-radio-group>-->
+<!--      </div>-->
+<!--      @if (configForm.get('backup_option')?.value === 'vs') {-->
+<!--        <div class="form-field-wrapper">-->
+<!--          <label for="vs" class="form-label">Virtual Service</label>-->
+<!--          <mat-form-field appearance="outline" subscriptSizing="dynamic">-->
+<!--            <mat-select formControlName="vs">-->
+<!--              @for (_vs of virtualServices; track _vs) {-->
+<!--                <mat-option [value]="_vs.value">{{ _vs.displayName }}</mat-option>-->
+<!--              }-->
+<!--            </mat-select>-->
+<!--            @if (configForm.get('vs')?.invalid && configForm.get('vs')?.touched) {-->
+<!--              <mat-error>-->
+<!--                @if (configForm.get('vs')?.errors?.['required']) {-->
+<!--                  Virtual service is required.-->
+<!--                } @else {-->
+<!--                  Invalid virtual service format.-->
+<!--                }-->
+<!--              </mat-error>-->
+<!--            }-->
+<!--          </mat-form-field>-->
+<!--        </div>-->
+<!--      }-->
+<!--    }-->
+    <div class="form-field-wrapper">
+      <label for="comment" class="form-label">Comment</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <input
+          id="comment"
+          formControlName="comment"
+          matInput
+          placeholder="Comment"
+          type="text"
+        />
+        @if (configForm.get('comment')?.invalid && configForm.get('comment')?.touched) {
+          <mat-error>
+            @if (configForm.get('comment')?.errors?.['required']) {
+              Comment is required.
+            } @else if (configForm.get('comment')?.errors) {
+              Invalid comment format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+  </form>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+  <button
+    mat-raised-button
+    color="primary"
+    (click)="onSubmit()">
+    Submit
+  </button>
+</mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/compare-backup-config-version.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/compare-backup-config-version.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/compare-backup-config-version.html	(working copy)
@@ -0,0 +1,156 @@
+<h2 mat-dialog-title>Compare - Backup Config Version</h2>
+<mat-dialog-content>
+  <form
+    (ngSubmit)="onSubmit()"
+    [formGroup]="configForm"
+  >
+    <div class="form-field-wrapper">
+      <label for="source_device" class="form-label">Source Device *</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <mat-select formControlName="source_device" (selectionChange)="onSourceDeviceChange($event)">
+          @for (_option of data?.devices; track _option) {
+            <mat-option [value]="_option.name">{{ _option.name }}</mat-option>
+          }
+        </mat-select>
+        @if (configForm.get('source_device')?.invalid && configForm.get('source_device')?.touched) {
+          <mat-error>
+            @if (configForm.get('source_device')?.errors?.['required']) {
+              Source device is required.
+            } @else {
+              Invalid source device format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+    <div class="form-field-wrapper">
+      <label for="source_config" class="form-label">Source version *</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <mat-select formControlName="source_config">
+          @for (_option of deviceSourceConfigFiles; track _option) {
+            <mat-option [value]="_option.name">{{ _option.name }}</mat-option>
+          }
+        </mat-select>
+        @if (configForm.get('source_config')?.invalid && configForm.get('source_config')?.touched) {
+          <mat-error>
+            @if (configForm.get('source_config')?.errors?.['required']) {
+              Source config is required.
+            } @else {
+              Invalid source config format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+    <div class="form-field-wrapper">
+      <label for="target_type" class="form-label">Comparison Target *</label>
+      <mat-radio-group formControlName="target_type" (change)="onTargetTypeChange()">
+        <mat-radio-button value="device">Single Device</mat-radio-button>
+        <mat-radio-button value="batch">Multiple Devices</mat-radio-button>
+      </mat-radio-group>
+    </div>
+    @if (configForm.get('target_type')?.value === 'device') {
+      <div class="form-field-wrapper">
+        <label for="target_device" class="form-label">Devices</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="target_device" (selectionChange)="onTargetDeviceChange($event)">
+            @for (_option of data?.devices; track _option) {
+              <mat-option [value]="_option.name">{{ _option.name }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('target_device')?.invalid && configForm.get('target_device')?.touched) {
+            <mat-error>
+              @if (configForm.get('target_device')?.errors?.['required']) {
+                Devices is required.
+              } @else {
+                Invalid devices format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+      <div class="form-field-wrapper">
+        <label for="target_config" class="form-label">Target version *</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="target_config">
+            @for (_option of deviceTargetConfigFiles; track _option) {
+              <mat-option [value]="_option.name">{{ _option.name }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('target_config')?.invalid && configForm.get('target_config')?.touched) {
+            <mat-error>
+              @if (configForm.get('target_config')?.errors?.['required']) {
+                Target config is required.
+              } @else {
+                Invalid target config format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    } @else if (configForm.get('target_type')?.value === 'batch') {
+      <div class="form-field-wrapper">
+        <label for="selection_type" class="form-label">Devices / Groups *</label>
+        <mat-radio-group formControlName="selection_type">
+          <mat-radio-button value="device">Device</mat-radio-button>
+          <mat-radio-button value="device_group">Device Group</mat-radio-button>
+        </mat-radio-group>
+      </div>
+      @if (configForm.get('selection_type')?.value === 'device') {
+        <div class="form-field-wrapper">
+          <label for="target_device" class="form-label">Devices</label>
+          <mat-form-field appearance="outline" subscriptSizing="dynamic">
+            <mat-select formControlName="target_device" multiple>
+              @for (_option of data?.devices; track _option) {
+                <mat-option [value]="_option.name">{{ _option.name }}</mat-option>
+              }
+            </mat-select>
+            @if (configForm.get('target_device')?.invalid && configForm.get('target_device')?.touched) {
+              <mat-error>
+                @if (configForm.get('target_device')?.errors?.['required']) {
+                  Devices is required.
+                } @else {
+                  Invalid devices format.
+                }
+              </mat-error>
+            }
+          </mat-form-field>
+        </div>
+      } @else {
+        <div class="form-field-wrapper">
+          <label for="device_groups" class="form-label">Device Groups</label>
+          <mat-form-field appearance="outline" subscriptSizing="dynamic">
+            <mat-select formControlName="device_groups" multiple>
+              @for (_option of data?.groups; track _option) {
+                <mat-option [value]="_option">{{ _option }}</mat-option>
+              }
+            </mat-select>
+            @if (configForm.get('device_groups')?.invalid && configForm.get('device_groups')?.touched) {
+              <mat-error>
+                @if (configForm.get('device_groups')?.errors?.['required']) {
+                  Device groups is required.
+                } @else {
+                  Invalid device groups format.
+                }
+              </mat-error>
+            }
+          </mat-form-field>
+        </div>
+      }
+    }
+  </form>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+  <button
+    mat-raised-button
+    color="primary"
+    (click)="onSubmit()">
+    Submit
+  </button>
+</mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/compare-config-all.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/compare-config-all.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/compare-config-all.html	(working copy)
@@ -0,0 +1,155 @@
+<h2 mat-dialog-title>Compare Configuration All</h2>
+<mat-dialog-content>
+  <form
+    (ngSubmit)="onSubmit()"
+    [formGroup]="configForm"
+  >
+    <div class="form-field-wrapper">
+      <label for="device" class="form-label">Device *</label>
+      <mat-radio-group formControlName="device">
+        <mat-radio-button value="device">Device</mat-radio-button>
+        <mat-radio-button value="device_group">Device Group</mat-radio-button>
+      </mat-radio-group>
+    </div>
+    @if (configForm.get('device')?.value === 'device') {
+      <div class="form-field-wrapper">
+        <label for="devices" class="form-label">Devices</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="devices" multiple>
+            <mat-option value="ALL">All</mat-option>
+            @for (_option of data?.devices; track _option) {
+              <mat-option [value]="_option.name">{{ _option.name }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('devices')?.invalid && configForm.get('devices')?.touched) {
+            <mat-error>
+              @if (configForm.get('devices')?.errors?.['required']) {
+                Devices is required.
+              } @else {
+                Invalid devices format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    } @else if (configForm.get('device')?.value === 'device_group') {
+      <div class="form-field-wrapper">
+        <label for="device_groups" class="form-label">Device Groups</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="device_groups" multiple>
+            @for (_option of data?.groups; track _option) {
+              <mat-option [value]="_option">{{ _option }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('device_groups')?.invalid && configForm.get('device_groups')?.touched) {
+            <mat-error>
+              @if (configForm.get('device_groups')?.errors?.['required']) {
+                Device groups is required.
+              } @else {
+                Invalid device groups format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    }
+    <div class="form-field-wrapper">
+      <label for="option" class="form-label">Option *</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <mat-select formControlName="option">
+          @for (_option of configOptions; track _option) {
+            <mat-option [value]="_option.value">{{ _option.label }}</mat-option>
+          }
+        </mat-select>
+        @if (configForm.get('option')?.invalid && configForm.get('option')?.touched) {
+          <mat-error>
+            @if (configForm.get('option')?.errors?.['required']) {
+              Option is required.
+            } @else {
+              Invalid option format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+    @if (configForm.get('option')?.value === 'deferred') {
+      <div class="form-field-wrapper">
+        <label for="expire_time" class="form-label">Expire Time *</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <input
+            id="expire_time"
+            formControlName="expire_time"
+            matInput
+            placeholder="Expire Time"
+            type="text"
+          />
+          @if (configForm.get('expire_time')?.invalid && configForm.get('expire_time')?.touched) {
+            <mat-error>
+              @if (configForm.get('expire_time')?.errors?.['required']) {
+                Expire time is required.
+              } @else if (configForm.get('expire_time')?.errors) {
+                Invalid expire time format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    } @else if (configForm.get('option')?.value === 'loop') {
+      <div class="form-field-wrapper">
+        <label for="loop_time" class="form-label">Interval *</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <input
+            id="loop_time"
+            formControlName="loop_time"
+            matInput
+            placeholder="Interval"
+            type="number"
+            min="0"
+          />
+          @if (configForm.get('loop_time')?.invalid && configForm.get('loop_time')?.touched) {
+            <mat-error>
+              @if (configForm.get('loop_time')?.errors?.['required']) {
+                Interval is required.
+              } @else if (configForm.get('loop_time')?.errors) {
+                Invalid interval format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+      <div class="form-field-wrapper">
+        <label for="unit" class="form-label">Unit *</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="unit">
+            @for (_option of intervalUnits; track _option) {
+              <mat-option [value]="_option.value">{{ _option.label }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('unit')?.invalid && configForm.get('unit')?.touched) {
+            <mat-error>
+              @if (configForm.get('unit')?.errors?.['required']) {
+                Unit is required.
+              } @else {
+                Invalid unit format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    }
+  </form>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+  <button
+    mat-raised-button
+    color="primary"
+    (click)="onSubmit()">
+    Submit
+  </button>
+</mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/compare-config.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/compare-config.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/compare-config.html	(working copy)
@@ -0,0 +1,136 @@
+<h2 mat-dialog-title>Compare configuration</h2>
+<mat-dialog-content>
+  <form
+    (ngSubmit)="onSubmit()"
+    [formGroup]="configForm"
+  >
+    <div class="form-field-wrapper">
+      <label for="module" class="form-label">Module *</label>
+      <mat-radio-group formControlName="module">
+        <mat-radio-button value="all">All</mat-radio-button>
+        <mat-radio-button value="custom">Custom</mat-radio-button>
+      </mat-radio-group>
+    </div>
+    @if (configForm.get('module')?.value === 'custom') {
+      <div class="form-field-wrapper">
+        <label for="custom" class="form-label">Keyword *</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <input
+            id="custom"
+            formControlName="custom"
+            matInput
+            placeholder="Keyword"
+            type="text"
+          />
+          @if (configForm.get('custom')?.invalid && configForm.get('custom')?.touched) {
+            <mat-error>
+              @if (configForm.get('custom')?.errors?.['required']) {
+                Keyword is required.
+              } @else if (configForm.get('custom')?.errors) {
+                Invalid keyword format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    }
+    <div class="form-field-wrapper">
+      <label for="option" class="form-label">Option *</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <mat-select formControlName="option">
+          @for (_option of configOptions; track _option) {
+            <mat-option [value]="_option.value">{{ _option.label }}</mat-option>
+          }
+        </mat-select>
+        @if (configForm.get('option')?.invalid && configForm.get('option')?.touched) {
+          <mat-error>
+            @if (configForm.get('option')?.errors?.['required']) {
+              Option is required.
+            } @else {
+              Invalid option format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+    @if (configForm.get('option')?.value === 'deferred') {
+      <div class="form-field-wrapper">
+        <label for="expire_time" class="form-label">Expire Time *</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <input
+            id="expire_time"
+            formControlName="expire_time"
+            matInput
+            placeholder="Expire Time"
+            type="text"
+          />
+          @if (configForm.get('expire_time')?.invalid && configForm.get('expire_time')?.touched) {
+            <mat-error>
+              @if (configForm.get('expire_time')?.errors?.['required']) {
+                Expire time is required.
+              } @else if (configForm.get('expire_time')?.errors) {
+                Invalid expire time format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    } @else if (configForm.get('option')?.value === 'loop') {
+      <div class="form-field-wrapper">
+        <label for="loop_time" class="form-label">Interval *</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <input
+            id="loop_time"
+            formControlName="loop_time"
+            matInput
+            placeholder="Interval"
+            type="number"
+            min="0"
+          />
+          @if (configForm.get('loop_time')?.invalid && configForm.get('loop_time')?.touched) {
+            <mat-error>
+              @if (configForm.get('loop_time')?.errors?.['required']) {
+                Interval is required.
+              } @else if (configForm.get('loop_time')?.errors) {
+                Invalid interval format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+      <div class="form-field-wrapper">
+        <label for="unit" class="form-label">Unit *</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="unit">
+            @for (_option of intervalUnits; track _option) {
+              <mat-option [value]="_option.value">{{ _option.label }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('unit')?.invalid && configForm.get('unit')?.touched) {
+            <mat-error>
+              @if (configForm.get('unit')?.errors?.['required']) {
+                Unit is required.
+              } @else {
+                Invalid unit format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    }
+  </form>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+  <button
+    mat-raised-button
+    color="primary"
+    (click)="onSubmit()">
+    Submit
+  </button>
+</mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/device-config-overview.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/device-config-overview.html	(revision 2671)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/device-config-overview.html	(working copy)
@@ -1 +1,83 @@
-<p>device-config-overview works!</p>
+<mat-card class="page-card-1" appearance="filled">
+  <mat-card-header>
+    <div>
+      <button mat-raised-button (click)="compareConfig()">
+        <fa-icon [icon]="['fas', 'code-compare']"></fa-icon>
+        Configuration Comparison
+      </button>&nbsp;&nbsp;
+      <button mat-raised-button (click)="scheduleBackupConfig()">
+        <fa-icon [icon]="['far', 'clock']"></fa-icon>
+        Schedule Backup
+      </button>&nbsp;&nbsp;
+      <button mat-raised-button (click)="compareBackupConfigVersion()">
+        <fa-icon [icon]="['fas', 'code-compare']"></fa-icon>
+        Backup Version Compare
+      </button>&nbsp;&nbsp;
+      <button mat-raised-button (click)="backupConfig()">
+        <fa-icon [icon]="['far', 'copy']"></fa-icon>
+        Backup
+      </button>
+    </div>
+  </mat-card-header>
+</mat-card>
+<div class="table-container">
+  <table mat-table [dataSource]="dataSource" class="mat-elevation-z1">
+    <ng-container matColumnDef="serial">
+      <th mat-header-cell *matHeaderCellDef> No.</th>
+      <td mat-cell *matCellDef="let element; let i = index;"> {{ getGlobalSerial(i) }}</td>
+    </ng-container>
+    <ng-container matColumnDef="deviceName">
+      <th mat-header-cell *matHeaderCellDef>Device Name</th>
+      <td mat-cell *matCellDef="let element">
+        <a class="details-page-link" (click)="viewDeviceConfiguration(element)">{{ element.name }}</a>
+      </td>
+    </ng-container>
+    <ng-container matColumnDef="deviceType">
+      <th mat-header-cell *matHeaderCellDef>Device Type</th>
+      <td mat-cell *matCellDef="let element"> {{ element.device_type }}</td>
+    </ng-container>
+    <ng-container matColumnDef="lastBackupTime">
+      <th mat-header-cell *matHeaderCellDef>Last Backup Time</th>
+      <td mat-cell *matCellDef="let element">{{ element.lastBackupTime }}</td>
+    </ng-container>
+    <ng-container matColumnDef="status">
+      <th mat-header-cell *matHeaderCellDef> Status</th>
+      <td mat-cell *matCellDef="let element">
+        <div class="row-action a-link">
+          @if (element?.status === 'enabled') {
+            <fa-icon [icon]="['far', 'check-circle']" class="success-icon"></fa-icon>
+          } @else {
+            <fa-icon [icon]="['far', 'xmark-circle']" class="delete-icon"></fa-icon>
+          }
+        </div>
+      </td>
+    </ng-container>
+    <ng-container matColumnDef="action">
+      <th mat-header-cell *matHeaderCellDef class="action-header w-10"> Action</th>
+      <td mat-cell *matCellDef="let element">
+        <div class="row-action a-link">
+          <fa-icon [icon]="['fas', 'timeline']" size="lg" matTooltip="View historical backup files"
+                   (click)="viewDeviceConfigFilesHistory(element)"></fa-icon>
+          <fa-icon [icon]="['fas', 'code-compare']" size="lg" matTooltip="Compare with last backup file"
+                   (click)="compareDeviceConfigLastBackup(element)"></fa-icon>
+          <fa-icon [icon]="['far', 'clone']" size="lg" matTooltip="Clone configuration"
+                   (click)="cloneDeviceConfig(element)"></fa-icon>
+          <fa-icon [icon]="['fas', 'list-check']" size="lg" matTooltip="Task for this configuration"
+                   (click)="showDeviceConfigTask(element)"></fa-icon>
+          <fa-icon [icon]="['far', 'copy']" size="lg" matTooltip="Backup device configuration"
+                   (click)="backupDeviceConfig(element)"></fa-icon>
+        </div>
+      </td>
+    </ng-container>
+    <tr mat-header-row *matHeaderRowDef="deviceColumns"></tr>
+    <tr mat-row *matRowDef="let row; columns: deviceColumns;"></tr>
+    <tr class="mat-row table-no-data" *matNoDataRow>
+      <td class="mat-cell" colspan="11">No results found.</td>
+    </tr>
+  </table>
+  <mat-paginator
+    [pageSizeOptions]="[10, 15, 20, 25]"
+    [length]="totalRecords"
+    showFirstLastButtons
+  ></mat-paginator>
+</div>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/device-config-overview.scss
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/device-config-overview.scss	(revision 2671)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/device-config-overview.scss	(working copy)
@@ -0,0 +1,21 @@
+.page-card-1 {
+  width: 100%;
+  border-radius: 0;
+  background-color: inherit;
+  font-size: 14px !important;
+
+  mat-card-header {
+    color: #1170cf;
+  }
+}
+
+mat-card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 4px 10px;
+}
+
+mat-card-title {
+  font-size: medium;
+}
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/device-config-overview.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/device-config-overview.ts	(revision 2671)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/device-config-overview.ts	(working copy)
@@ -1,11 +1,1146 @@
-import { Component } from '@angular/core';
+import {AfterViewInit, ChangeDetectorRef, Component, inject, OnDestroy, OnInit, ViewChild} from '@angular/core';
+import {SharedModule} from '../../../shared/shared-module';
+import {MatTableDataSource} from '@angular/material/table';
+import {MAT_DIALOG_DATA, MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material/dialog';
+import {MatPaginator} from '@angular/material/paginator';
+import {DeviceService} from '../../../services/device-service';
+import {take} from 'rxjs/operators';
+import {NotificationService} from '../../../services/notification';
+import {NewlineToBrPipe} from '../../../pipes/newline-to-br-pipe';
+import {Router} from '@angular/router';
+import {CreateDeviceConfigDialog, ShowTasksByNameDialog} from '../device-backup-files/device-backup-files';
+import {FormBuilder, FormGroup, Validators} from '@angular/forms';
+import {Subscription} from 'rxjs';
 
 @Component({
   selector: 'app-device-config-overview',
-  imports: [],
+  imports: [SharedModule],
   templateUrl: './device-config-overview.html',
   styleUrl: './device-config-overview.scss'
 })
-export class DeviceConfigOverview {
+export class DeviceConfigOverview implements OnInit, AfterViewInit {
+
+  totalRecords: number = 0;
+  dataSource: MatTableDataSource<any> = new MatTableDataSource();
+  deviceColumns: string[] = ['serial', 'deviceName', 'deviceType', 'lastBackupTime', 'action'];
+  @ViewChild(MatPaginator) paginator!: MatPaginator;
+
+  dialog = inject(MatDialog);
+  dialogConfig = new MatDialogConfig();
+  deviceLastBackupMap: { [key: string]: Date | null } = {};
+  deviceBackupsMap: any = {};
+  devices: any = [];
+  groups: any = [];
+  deviceGroups: any = [];
+
+  constructor(
+    private _device: DeviceService,
+    private _cdRef: ChangeDetectorRef,
+    private _notification: NotificationService,
+    private _router: Router
+  ) {
+  }
+
+  ngOnInit() {
+    setTimeout(() => {
+      this.getDeviceConfigFiles();
+      this.getDeviceGroups();
+    })
+  }
+
+  ngAfterViewInit() {
+    this.dataSource.paginator = this.paginator;
+    this._cdRef.detectChanges();
+  }
+
+  getDeviceConfigFiles() {
+    this.dataSource.data = [];
+    this._device.getDeviceConfigFiles().pipe(take(1)).subscribe({
+      next: (result: any) => {
+        this.dataSource.data = this.analyzeBackupData(result);
+        this.dataSource.paginator = this.paginator;
+        this.totalRecords = this.dataSource.data.length;
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+      }
+    })
+  }
+
+  analyzeBackupData(data: any[]): (any & { lastBackupTime: string })[] {
+    const deviceEntries: any[] = [];
+
+    // First pass: Identify all devices and initialize their last backup time
+    data.forEach(entry => {
+      if (entry.file_type === 'device') {
+        deviceEntries.push(entry);
+        this.deviceLastBackupMap[entry.name] = null;
+      }
+    });
+
+    // Second pass: Find the latest backup for each device
+    data.forEach(entry => {
+      if (entry.file_type === 'backup' && entry.name) {
+        const deviceMatch = entry.name.match(/^([a-zA-Z0-9]+)-/);
+        if (deviceMatch && deviceMatch[1]) {
+          const deviceName = deviceMatch[1];
+          const backupTime = new Date(entry.create_time);
+
+          // If this device exists and this backup is newer than the current latest
+          if (this.deviceLastBackupMap.hasOwnProperty(deviceName)) {
+            if (!this.deviceLastBackupMap[deviceName] || backupTime > this.deviceLastBackupMap[deviceName]!) {
+              this.deviceLastBackupMap[deviceName] = backupTime;
+            }
+          }
+          if (this.deviceBackupsMap.hasOwnProperty(deviceName)) {
+            this.deviceBackupsMap[deviceName].push(entry);
+          } else {
+            this.deviceBackupsMap[deviceName] = [entry];
+          }
+        }
+      }
+    });
+
+    // Format the results by merging original device fields with last backup time
+    const results: (any & { lastBackupTime: string })[] = [];
+    deviceEntries.forEach(deviceEntry => {
+      const lastTime = this.deviceLastBackupMap[deviceEntry.name];
+      results.push({
+        ...deviceEntry,
+        lastBackupTime: lastTime ? lastTime.toLocaleString() : "No backup found"
+      });
+    });
+
+    return results;
+  }
+
+  backupConfig() {
+    this.dialogConfig.width = '60%';
+    this.dialogConfig.data = {
+      devices: this.devices,
+      groups: this.groups,
+    }
+    const dialogRef = this.dialog.open(BackupConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  compareConfig() {
+    this.dialogConfig.width = '60%';
+    this.dialogConfig.data = {
+      devices: this.devices,
+      groups: this.groups,
+      deviceGroups: this.deviceGroups,
+      backup: this.deviceBackupsMap
+    }
+    const dialogRef = this.dialog.open(CompareConfigAllDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  scheduleBackupConfig() {
+    this.dialogConfig.width = '60%';
+    this.dialogConfig.data = {
+      devices: this.devices,
+      groups: this.groups,
+      deviceGroups: this.deviceGroups,
+      backup: this.deviceBackupsMap
+    }
+    const dialogRef = this.dialog.open(ScheduleBackupConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  compareBackupConfigVersion() {
+    this.dialogConfig.width = '60%';
+    this.dialogConfig.data = {
+      devices: this.devices,
+      groups: this.groups,
+      deviceGroups: this.deviceGroups,
+      backup: this.deviceBackupsMap
+    }
+    const dialogRef = this.dialog.open(CompareBackupConfigVersionDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  viewDeviceConfiguration(_device: any) {
+    this.dialogConfig.position = {
+      bottom: '0px', right: '0px',
+    }
+    this.dialogConfig.disableClose = true;
+    this.dialogConfig.width = '50%';
+    this.dialogConfig.height = '80%';
+    this.dialogConfig.data = {
+      device: _device
+    }
+    const dialogRef = this.dialog.open(ShowDeviceConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe(() => {
+    })
+  }
+
+  viewDeviceConfigFilesHistory(_device: any) {
+    this._router.navigate(['/configuration-hub/backup', _device.name], {
+      state: {deviceDetails: this.deviceBackupsMap[_device.name]},
+    });
+  }
+
+  getGlobalSerial(index: number): number {
+    if (this.paginator) {
+      return this.paginator.pageIndex * this.paginator.pageSize + index + 1;
+    }
+    return index + 1;
+  }
+
+  compareDeviceConfigLastBackup(_device: any) {
+    this.dialogConfig.width = '60%';
+    this.dialogConfig.data = {
+      device: _device,
+      backup: this.deviceBackupsMap[_device.name],
+    }
+    const dialogRef = this.dialog.open(CompareDeviceConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  cloneDeviceConfig(_device: any) {
+    this.dialogConfig.width = '60%';
+    this.dialogConfig.data = {
+      device: _device,
+      backup: this.deviceBackupsMap[_device.name],
+    }
+    const dialogRef = this.dialog.open(CloneDeviceConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  showDeviceConfigTask(_device: any) {
+    this.dialogConfig.data = {
+      config: _device,
+    };
+    const dialogRef = this.dialog.open(ShowTasksByNameDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  backupDeviceConfig(_device: any) {
+    this.dialogConfig.data = {
+      deviceName: _device?.name,
+    }
+    const dialogRef = this.dialog.open(CreateDeviceConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe(() => {
+    })
+  }
+
+  getDeviceGroups(): void {
+    this.devices = [];
+    this.groups = [];
+    this.deviceGroups = []
+    // ToDo: Update with actual RoleId
+    let roleId = "0"
+    let rawPayload = new FormData();
+    rawPayload.set('action', 'FilterRoleDeviceGroups');
+    rawPayload.set('options', JSON.stringify({"role_id": roleId}));
+    this._device.getDeviceGroups(rawPayload)
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          if (result && result.length > 1) {
+            if (result[1] && 'result' in result[1]) {
+              let groups = result[1].result;
+              groups.forEach((group: any) => {
+                if (group?.device_list.length > 0) {
+                  this.groups.push(group?.group_name);
+                  this.deviceGroups.push(group);
+                }
+                group?.device_list.forEach((device: any) => {
+                  this.devices.push(device);
+                })
+              })
+              this.dataSource = new MatTableDataSource(this.devices);
+            }
+          }
+        }, error: (error: { message: string; }) => {
+          console.log(error);
+          this._notification.showError(error.message);
+        }
+      })
+  }
+
+}
+
+@Component({
+  selector: 'show-device-config',
+  templateUrl: './show-device-config.html',
+  imports: [SharedModule, NewlineToBrPipe]
+})
+export class ShowDeviceConfigDialog implements OnInit {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<ShowDeviceConfigDialog>);
+  deviceConfig: any = '';
+
+  constructor(
+    private _device: DeviceService,
+    private _notification: NotificationService,
+    private _cdRef: ChangeDetectorRef,
+  ) {
+  }
 
+  ngOnInit() {
+    setTimeout(() => {
+      this.getDeviceConfig(this.data?.device?.name);
+    })
+  }
+
+  getDeviceConfig(deviceName: any) {
+    this._device.getDeviceConfiguration(deviceName)
+      .pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result.length > 1) {
+          this.deviceConfig = result[1];
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
 }
+
+
+@Component({
+  selector: 'compare-config',
+  templateUrl: './compare-config.html',
+  imports: [SharedModule]
+})
+export class CompareDeviceConfigDialog implements OnInit {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<CompareDeviceConfigDialog>);
+
+  configForm: FormGroup;
+
+  configOptions: any = [
+    {value: 'immediate', label: 'Immediate'},
+    {value: 'deferred', label: 'Deferred'},
+    {value: 'loop', label: 'Loop'},
+  ]
+
+  intervalUnits: any = [
+    {value: 1, label: 'Hour'},
+    {value: 24, label: 'Day'},
+    {value: 168, label: 'Week'},
+  ]
+
+  constructor(
+    private _device: DeviceService,
+    private _notification: NotificationService,
+    private _formBuilder: FormBuilder,
+    private _cdRef: ChangeDetectorRef,
+  ) {
+    this.configForm = this._formBuilder.group({
+      module: ['all', [Validators.required]],
+      option: ['immediate', [Validators.required]],
+      custom: [''],
+      expire_time: [''],
+      loop_time: [1], // In hours
+      unit: [1],
+    })
+  }
+
+  ngOnInit() {
+    this.configForm.get('module')?.valueChanges.subscribe(value => {
+      this.setCustomValidation(value);
+    });
+    this.configForm.get('option')?.valueChanges.subscribe(value => {
+      this.setOptionValidation(value);
+    });
+    this.setCustomValidation(this.configForm.get('module')?.value);
+    this.setOptionValidation(this.configForm.get('option')?.value);
+  }
+
+  onSubmit(): void {
+    if (this.configForm.invalid) {
+      console.log(this.configForm.value);
+      this.configForm.markAllAsTouched();
+      return;
+    }
+    let payload = new FormData();
+    payload.set('action', 'Compliance_check');
+    let rawPayload: any = {
+      "__pk_list": [JSON.stringify({
+        file_type: this.data?.backup[0]?.file_type,
+        name: this.data?.backup[0]?.name,
+        device_type: this.data?.backup[0]?.device_type,
+      })],
+      module: this.configForm.value.module,
+      option: this.configForm.value.option,
+      device: this.data?.device?.name,
+    }
+    if (this.configForm.value.module === 'custom') {
+      rawPayload['custom'] = this.configForm.value.custom;
+    }
+    if (this.configForm.value.option === 'deferred') {
+      rawPayload['expire_time'] = this.configForm.value.expire_time;
+    }
+    if (this.configForm.value.option === 'loop') {
+      rawPayload['loop_time'] = this.configForm.value.loop_time * this.configForm.value.unit;
+    }
+    payload.set('options', JSON.stringify(rawPayload));
+    this._device.performDeviceConfigOperation(payload)
+      .pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result.length > 1) {
+          this._notification.showSuccess(`Device config check initiated successfully.`);
+          this.dialogRef.close(true);
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+
+  private setCustomValidation(moduleValue: string): void {
+    const customControl = this.configForm.get('custom');
+    if (customControl) { // Ensure control exists
+      if (moduleValue === 'custom') {
+        customControl.setValidators(Validators.required);
+      } else {
+        customControl.clearValidators();
+      }
+      customControl.updateValueAndValidity(); // Recalculate validation status
+    }
+  }
+
+  private setOptionValidation(optionValue: string): void {
+    const expireTimeControl = this.configForm.get('expire_time');
+    const loopTimeControl = this.configForm.get('loop_time');
+    const unitControl = this.configForm.get('unit');
+
+    if (expireTimeControl) {
+      if (optionValue === 'deferred') {
+        expireTimeControl.setValidators(Validators.required);
+      } else {
+        expireTimeControl.clearValidators();
+      }
+      expireTimeControl.updateValueAndValidity();
+    }
+
+    if (loopTimeControl && unitControl) {
+      if (optionValue === 'loop') {
+        loopTimeControl.setValidators([Validators.required, Validators.min(1)]);
+        unitControl.setValidators([Validators.required, Validators.min(1)]);
+      } else {
+        loopTimeControl.clearValidators();
+        unitControl.clearValidators();
+      }
+      loopTimeControl.updateValueAndValidity();
+      unitControl.updateValueAndValidity();
+    }
+  }
+}
+
+
+@Component({
+  selector: 'clone-config',
+  templateUrl: './clone-config.html',
+  imports: [SharedModule]
+})
+export class CloneDeviceConfigDialog implements OnInit {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<CloneDeviceConfigDialog>);
+
+  configForm: FormGroup;
+
+  virtualServices: any = [];
+
+  constructor(
+    private _device: DeviceService,
+    private _notification: NotificationService,
+    private _formBuilder: FormBuilder,
+    private _cdRef: ChangeDetectorRef,
+  ) {
+    this.configForm = this._formBuilder.group({
+      file_name: ['', Validators.required],
+      comment: [''],
+      backup_option: ['all', Validators.required],
+      vs: [''],
+    })
+  }
+
+  ngOnInit() {
+    setTimeout(() => {
+      if (this.data?.device?.device_type.toLowerCase() === 'apv' || this.data?.device?.device_type.toLowerCase() === 'vapv') {
+        this.getAPVVirtualServices();
+      }
+    })
+  }
+
+  getAPVVirtualServices() {
+    this._device.getAPVVirtualServices().pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result.VirtualService) {
+          this.virtualServices = result.VirtualService;
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+      }
+    })
+  }
+
+  onSubmit(): void {
+    if (this.configForm.invalid) {
+      console.log(this.configForm.value);
+      this.configForm.markAllAsTouched();
+      return;
+    }
+    let payload = new FormData();
+    payload.set('action', 'Clone_file');
+    let rawPayload: any = {
+      "__pk_list": [JSON.stringify({
+        file_type: this.data?.device?.file_type,
+        name: this.data?.device?.name,
+        device_type: this.data?.device.device_type,
+      })],
+      file_name: this.configForm.value.file_name,
+      option: true,
+      vs: this.configForm.value.vs,
+      comment: this.configForm.value.comment,
+    }
+    payload.set('options', JSON.stringify(rawPayload));
+    this._device.performDeviceConfigOperation(payload)
+      .pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result.length > 1) {
+          this._notification.showSuccess(`Device config clone initiated successfully.`);
+          this.dialogRef.close(true);
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+}
+
+@Component({
+  selector: 'backup-config',
+  templateUrl: './backup-config.html',
+  imports: [SharedModule]
+})
+export class BackupConfigDialog implements OnInit {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<BackupConfigDialog>);
+
+  configForm: FormGroup;
+
+  constructor(
+    private _device: DeviceService,
+    private _notification: NotificationService,
+    private _formBuilder: FormBuilder,
+    private _cdRef: ChangeDetectorRef,
+  ) {
+    this.configForm = this._formBuilder.group({
+      device: ['device', [Validators.required]],
+      devices: [['ALL']],
+      device_groups: [],
+    })
+  }
+
+  ngOnInit() {
+    console.log(this.data)
+    this.configForm.get('device')?.valueChanges.subscribe(deviceType => {
+      this.updateConditionalValidators(deviceType);
+    });
+
+    this.updateConditionalValidators(this.configForm.get('device')?.value);
+  }
+
+  onSubmit(): void {
+    if (this.configForm.invalid) {
+      console.log(this.configForm.value);
+      this.configForm.markAllAsTouched();
+      return;
+    }
+    console.log(this.configForm.value);
+    let payload = new FormData();
+    payload.set('action', 'Onekey_Backup');
+    let rawPayload: any = {
+      "__pk_list": [],
+    }
+    if (this.configForm.value.device === 'device') {
+      rawPayload['devices'] = {
+        device: this.configForm.value.devices
+      }
+    } else if (this.configForm.value.device === 'device_group') {
+      rawPayload['devices'] = {
+        group: this.configForm.value.device_groups
+      }
+    }
+    payload.set('options', JSON.stringify(rawPayload));
+    this._device.performDeviceConfigOperation(payload)
+      .pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result.length > 1) {
+          this._notification.showSuccess(`Device config check initiated successfully.`);
+          this.dialogRef.close(true);
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+
+  private updateConditionalValidators(deviceType: string): void {
+    const devicesControl = this.configForm.get('devices');
+    const deviceGroupsControl = this.configForm.get('device_groups');
+
+    if (deviceType === 'device') {
+      devicesControl?.setValidators(Validators.required);
+      deviceGroupsControl?.clearValidators();
+    } else if (deviceType === 'device_group') {
+      devicesControl?.clearValidators();
+      deviceGroupsControl?.setValidators(Validators.required);
+    } else {
+      devicesControl?.clearValidators();
+      deviceGroupsControl?.clearValidators();
+    }
+
+    devicesControl?.updateValueAndValidity();
+    deviceGroupsControl?.updateValueAndValidity();
+  }
+}
+
+
+@Component({
+  selector: 'compare-config-all',
+  templateUrl: './compare-config-all.html',
+  imports: [SharedModule]
+})
+export class CompareConfigAllDialog implements OnInit {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<CompareConfigAllDialog>);
+
+  configForm: FormGroup;
+
+  configOptions: any = [
+    {value: 'immediate', label: 'Immediate'},
+    {value: 'deferred', label: 'Deferred'},
+    {value: 'loop', label: 'Loop'},
+  ]
+
+  intervalUnits: any = [
+    {value: 1, label: 'Hour'},
+    {value: 24, label: 'Day'},
+    {value: 168, label: 'Week'},
+  ]
+
+  constructor(
+    private _device: DeviceService,
+    private _notification: NotificationService,
+    private _formBuilder: FormBuilder,
+    private _cdRef: ChangeDetectorRef,
+  ) {
+    this.configForm = this._formBuilder.group({
+      device: ['device', [Validators.required]],
+      devices: [['ALL']],
+      device_groups: [],
+      option: ['immediate', [Validators.required]],
+      custom: [''],
+      expire_time: [''],
+      loop_time: [1], // In hours
+      unit: [1],
+    })
+  }
+
+  ngOnInit() {
+    this.configForm.get('device')?.valueChanges.subscribe(deviceType => {
+      this.updateConditionalValidators(deviceType);
+    });
+
+    this.updateConditionalValidators(this.configForm.get('device')?.value);
+    this.configForm.get('option')?.valueChanges.subscribe(value => {
+      this.setOptionValidation(value);
+    });
+    this.setOptionValidation(this.configForm.get('option')?.value);
+  }
+
+  onSubmit(): void {
+    if (this.configForm.invalid) {
+      console.log(this.configForm.value);
+      this.configForm.markAllAsTouched();
+      return;
+    }
+    let payload = new FormData();
+    payload.set('action', 'Onekey_Compliance_Check');
+    let pk: any = [];
+    if (this.configForm.value.device === 'device') {
+      this.configForm.value.devices.forEach((_device: any) => {
+        if (_device !== 'ALL' && this.data.backup[_device].length > 0) {
+          pk.push(JSON.stringify({
+            name: this.data.backup[_device][0].name,
+            file_type: this.data.backup[_device][0].file_type,
+            device_type: this.data.backup[_device][0].device_type,
+            device_name: this.data.backup[_device][0].device_name,
+          }))
+        }
+      })
+    } else if (this.configForm.value.device === 'device_group') {
+      this.configForm.value.device_groups.forEach((_group: any) => {
+        this.data.deviceGroups.forEach((_dGroup: any) => {
+          if (_group === _dGroup?.group_name) {
+            _dGroup?.device_list.forEach((_device: any) => {
+              pk.push(JSON.stringify({
+                name: this.data.backup[_device?.name][0].name,
+                file_type: this.data.backup[_device?.name][0].file_type,
+                device_type: this.data.backup[_device?.name][0].device_type,
+                device_name: this.data.backup[_device?.name][0].device_name,
+              }))
+            })
+          }
+        })
+      })
+    }
+    let rawPayload: any = {
+      "__pk_list": pk,
+      option: this.configForm.value.option,
+      module: 'all',
+    }
+    if (this.configForm.value.option === 'deferred') {
+      rawPayload['expire_time'] = this.configForm.value.expire_time;
+    }
+    if (this.configForm.value.option === 'loop') {
+      rawPayload['loop_time'] = this.configForm.value.loop_time * this.configForm.value.unit;
+    }
+    payload.set('options', JSON.stringify(rawPayload));
+    this._device.performDeviceConfigOperation(payload)
+      .pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result.length > 1) {
+          this._notification.showSuccess(`Device config check initiated successfully.`);
+          this.dialogRef.close(true);
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+
+  private updateConditionalValidators(deviceType: string): void {
+    const devicesControl = this.configForm.get('devices');
+    const deviceGroupsControl = this.configForm.get('device_groups');
+
+    if (deviceType === 'device') {
+      devicesControl?.setValidators(Validators.required);
+      deviceGroupsControl?.clearValidators();
+    } else if (deviceType === 'device_group') {
+      devicesControl?.clearValidators();
+      deviceGroupsControl?.setValidators(Validators.required);
+    } else {
+      devicesControl?.clearValidators();
+      deviceGroupsControl?.clearValidators();
+    }
+
+    devicesControl?.updateValueAndValidity();
+    deviceGroupsControl?.updateValueAndValidity();
+  }
+
+  private setOptionValidation(optionValue: string): void {
+    const expireTimeControl = this.configForm.get('expire_time');
+    const loopTimeControl = this.configForm.get('loop_time');
+    const unitControl = this.configForm.get('unit');
+
+    if (expireTimeControl) {
+      if (optionValue === 'deferred') {
+        expireTimeControl.setValidators(Validators.required);
+      } else {
+        expireTimeControl.clearValidators();
+      }
+      expireTimeControl.updateValueAndValidity();
+    }
+
+    if (loopTimeControl && unitControl) {
+      if (optionValue === 'loop') {
+        loopTimeControl.setValidators([Validators.required, Validators.min(1)]);
+        unitControl.setValidators([Validators.required, Validators.min(1)]);
+      } else {
+        loopTimeControl.clearValidators();
+        unitControl.clearValidators();
+      }
+      loopTimeControl.updateValueAndValidity();
+      unitControl.updateValueAndValidity();
+    }
+  }
+}
+
+@Component({
+  selector: 'schedule-backup-config',
+  templateUrl: './schedule-backup-config.html',
+  imports: [SharedModule]
+})
+export class ScheduleBackupConfigDialog implements OnInit {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<ScheduleBackupConfigDialog>);
+
+  configForm: FormGroup;
+
+  intervalUnits: any = [
+    {value: 'minutes', label: 'Minutes'},
+    {value: 'hours', label: 'Hours'},
+    {value: 'days', label: 'Days'},
+    {value: 'weeks', label: 'Weeks'},
+  ]
+  task_name_list: any = [];
+  isScheduled: boolean = false;
+
+  constructor(
+    private _device: DeviceService,
+    private _notification: NotificationService,
+    private _formBuilder: FormBuilder,
+    private _cdRef: ChangeDetectorRef,
+  ) {
+    this.configForm = this._formBuilder.group({
+      device: ['device', [Validators.required]],
+      devices: [['ALL']],
+      device_groups: [],
+      interval: [1], // In hours
+      unit: ['minutes'],
+    })
+  }
+
+  ngOnInit() {
+    this.configForm.get('device')?.valueChanges.subscribe(deviceType => {
+      this.updateConditionalValidators(deviceType);
+    });
+
+    this.updateConditionalValidators(this.configForm.get('device')?.value);
+    setTimeout(() => {
+      this.getScheduleDeviceBackup();
+    })
+  }
+
+  getScheduleDeviceBackup() {
+    this._device.getScheduleDeviceBackup()
+      .pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result?.status && result?.data) {
+          this.configForm.patchValue({
+            devices: result?.data?.device_name,
+            interval: result?.data?.interval,
+            unit: result?.data?.unit,
+          })
+          this.task_name_list = result?.data?.task_name;
+          if (this.task_name_list.length > 0) {
+            this.isScheduled = true;
+            this.configForm.get('device')?.disable();
+            this.configForm.get('devices')?.disable();
+            this.configForm.get('device_groups')?.disable();
+            this.configForm.get('interval')?.disable();
+            this.configForm.get('unit')?.disable();
+          }
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  onSubmit(): void {
+    if (this.configForm.invalid) {
+      console.log(this.configForm.value);
+      this.configForm.markAllAsTouched();
+      return;
+    }
+    let payload = new FormData();
+    let devicesPayload: any = {};
+    payload.set('action', 'Onekey_Backup');
+    if (this.configForm.value.device === 'device') {
+      devicesPayload = {
+        "device": this.configForm.value.devices,
+      }
+    } else if (this.configForm.value.device === 'device_group') {
+      devicesPayload = {
+        "group": this.configForm.value.device_groups,
+      }
+    }
+    let rawPayload: any = {
+      "__pk_list": [],
+      devices: devicesPayload,
+      interval: this.configForm.value.interval,
+      unit: this.configForm.value.unit,
+    }
+    payload.set('options', JSON.stringify(rawPayload));
+    this._device.performDeviceConfigOperation(payload)
+      .pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result.length > 1) {
+          this._notification.showSuccess(`Device config check initiated successfully.`);
+          this.dialogRef.close(true);
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  clearScheduleDeviceBackup(): void {
+    let payload = new FormData();
+    payload.set('task_name_list', JSON.stringify(this.task_name_list));
+    this._device.clearScheduleDeviceBackup(payload)
+      .pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result.state) {
+          this._notification.showSuccess(`Device scheduled backup has been cleared successfully.`);
+          this.dialogRef.close(true);
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+
+  private updateConditionalValidators(deviceType: string): void {
+    const devicesControl = this.configForm.get('devices');
+    const deviceGroupsControl = this.configForm.get('device_groups');
+
+    if (deviceType === 'device') {
+      devicesControl?.setValidators(Validators.required);
+      deviceGroupsControl?.clearValidators();
+    } else if (deviceType === 'device_group') {
+      devicesControl?.clearValidators();
+      deviceGroupsControl?.setValidators(Validators.required);
+    } else {
+      devicesControl?.clearValidators();
+      deviceGroupsControl?.clearValidators();
+    }
+
+    devicesControl?.updateValueAndValidity();
+    deviceGroupsControl?.updateValueAndValidity();
+  }
+}
+
+@Component({
+  selector: 'compare-backup-config-version',
+  templateUrl: './compare-backup-config-version.html',
+  imports: [SharedModule]
+})
+export class CompareBackupConfigVersionDialog implements OnInit, OnDestroy {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<CompareBackupConfigVersionDialog>);
+
+  configForm: FormGroup;
+  deviceSourceConfigFiles: any = [];
+  deviceTargetConfigFiles: any = [];
+  private subscriptions = new Subscription();
+
+  constructor(
+    private _device: DeviceService,
+    private _notification: NotificationService,
+    private _formBuilder: FormBuilder,
+    private _cdRef: ChangeDetectorRef,
+  ) {
+    this.configForm = this._formBuilder.group({
+      source_device: ['', [Validators.required]],
+      source_config: ['', [Validators.required]],
+      target_type: ['device', [Validators.required]],
+      selection_type: ['device', [Validators.required]],
+      target_device: ['', [Validators.required]],
+      target_config: [''],
+      device_groups: [[]],
+    })
+  }
+
+  ngOnInit() {
+    this.subscriptions.add(
+      this.configForm.get('target_type')?.valueChanges.subscribe(targetType => {
+        this.applyDeviceGroupsValidation();
+        this.applyTargetConfigValidation(targetType);
+        this.applyTargetDeviceValidation();
+      })
+    );
+
+    this.applyDeviceGroupsValidation();
+    this.applyTargetConfigValidation(this.configForm.get('target_type')?.value);
+    this.applyTargetDeviceValidation();
+  }
+
+  onTargetTypeChange() {
+    this.configForm.patchValue({
+      target_device: this.configForm.value.target_type === 'device' ? '' : []
+    })
+  }
+
+  onSourceDeviceChange(event: any) {
+    this.deviceSourceConfigFiles = this.data.backup[this.configForm.value.source_device];
+  }
+
+  onTargetDeviceChange(event: any) {
+    this.deviceTargetConfigFiles = this.data.backup[this.configForm.value.target_device];
+  }
+
+
+  onSubmit(): void {
+    if (this.configForm.invalid) {
+      console.log(this.configForm.value);
+      this.configForm.markAllAsTouched();
+      return;
+    }
+    let payload = new FormData();
+    let devicePayload: any = {}
+    if (this.configForm.value.target_type === 'device') {
+      devicePayload = {
+        "__pk_list": [],
+        "source_device": this.configForm.value.source_device,
+        "source_config": this.configForm.value.source_config,
+        "target_type": this.configForm.value.target_type,
+        "target_device": this.configForm.value.target_device,
+        "target_config": this.configForm.value.target_config,
+      }
+    } else {
+      if (this.configForm.value.selection_type === 'device') {
+        devicePayload = {
+          "__pk_list": [],
+          "source_device": this.configForm.value.source_device,
+          "source_config": this.configForm.value.source_config,
+          "target_type": this.configForm.value.target_type,
+          "devices": {
+            device: this.configForm.value.target_device
+          },
+        }
+      } else {
+        devicePayload = {
+          "__pk_list": [],
+          "source_device": this.configForm.value.source_device,
+          "source_config": this.configForm.value.source_config,
+          "target_type": this.configForm.value.target_type,
+          "devices": {
+            group: this.configForm.value.device_groups
+          },
+        }
+      }
+    }
+    payload.set('action', 'Custom_Compliance_check');
+    payload.set('options', JSON.stringify(devicePayload));
+    this._device.performDeviceConfigOperation(payload)
+      .pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result.length > 1) {
+          this._notification.showSuccess(`Device config check initiated successfully.`);
+          this.dialogRef.close(true);
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  private applyDeviceGroupsValidation(): void {
+    const selectionType = this.configForm.get('selection_type')?.value;
+    const targetType = this.configForm.get('target_type')?.value;
+    const deviceGroupsControl = this.configForm.get('device_groups');
+
+    if (deviceGroupsControl) {
+      if (selectionType === 'batch' && targetType === 'device_groups') {
+        deviceGroupsControl.setValidators([Validators.required]);
+      } else {
+        deviceGroupsControl.clearValidators();
+      }
+      deviceGroupsControl.updateValueAndValidity();
+    }
+  }
+
+  private applyTargetConfigValidation(targetType: string): void {
+    const targetConfigControl = this.configForm.get('target_config');
+
+    if (targetConfigControl) {
+      if (targetType === 'device') {
+        targetConfigControl.setValidators([Validators.required]);
+      } else {
+        targetConfigControl.clearValidators();
+      }
+      targetConfigControl.updateValueAndValidity();
+    }
+  }
+
+  private applyTargetDeviceValidation(): void {
+    const targetType = this.configForm.get('target_type')?.value;
+    const selectionType = this.configForm.get('selection_type')?.value;
+    const targetDeviceControl = this.configForm.get('target_device');
+
+    if (targetDeviceControl) {
+      if (targetType === 'batch' && selectionType === 'device_group') {
+        targetDeviceControl.clearValidators();
+      } else {
+        targetDeviceControl.setValidators([Validators.required]);
+      }
+      targetDeviceControl.updateValueAndValidity();
+    }
+  }
+
+  // Important: Unsubscribe to prevent memory leaks
+  ngOnDestroy(): void {
+    this.subscriptions.unsubscribe();
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+}
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/schedule-backup-config.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/schedule-backup-config.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/schedule-backup-config.html	(working copy)
@@ -0,0 +1,121 @@
+<h2 mat-dialog-title>Schedule Backup Configuration</h2>
+<mat-dialog-content>
+  <form
+    (ngSubmit)="onSubmit()"
+    [formGroup]="configForm"
+  >
+    <div class="form-field-wrapper">
+      <label for="device" class="form-label">Device *</label>
+      <mat-radio-group formControlName="device">
+        <mat-radio-button value="device">Device</mat-radio-button>
+        <mat-radio-button value="device_group">Device Group</mat-radio-button>
+      </mat-radio-group>
+    </div>
+    @if (configForm.get('device')?.value === 'device') {
+      <div class="form-field-wrapper">
+        <label for="devices" class="form-label">Devices</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="devices" multiple>
+            <mat-option value="ALL">All</mat-option>
+            @for (_option of data?.devices; track _option) {
+              <mat-option [value]="_option.name">{{ _option.name }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('devices')?.invalid && configForm.get('devices')?.touched) {
+            <mat-error>
+              @if (configForm.get('devices')?.errors?.['required']) {
+                Devices is required.
+              } @else {
+                Invalid devices format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    } @else if (configForm.get('device')?.value === 'device_group') {
+      <div class="form-field-wrapper">
+        <label for="device_groups" class="form-label">Device Groups</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="device_groups" multiple>
+            @for (_option of data?.groups; track _option) {
+              <mat-option [value]="_option">{{ _option }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('device_groups')?.invalid && configForm.get('device_groups')?.touched) {
+            <mat-error>
+              @if (configForm.get('device_groups')?.errors?.['required']) {
+                Device groups is required.
+              } @else {
+                Invalid device groups format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    }
+    <div class="form-field-wrapper">
+      <label for="interval" class="form-label">Interval *</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <input
+          id="interval"
+          formControlName="interval"
+          matInput
+          placeholder="Interval"
+          type="number"
+          min="0"
+        />
+        @if (configForm.get('interval')?.invalid && configForm.get('interval')?.touched) {
+          <mat-error>
+            @if (configForm.get('interval')?.errors?.['required']) {
+              Interval is required.
+            } @else if (configForm.get('interval')?.errors) {
+              Invalid interval format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+    <div class="form-field-wrapper">
+      <label for="unit" class="form-label">Unit *</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <mat-select formControlName="unit">
+          @for (_option of intervalUnits; track _option) {
+            <mat-option [value]="_option.value">{{ _option.label }}</mat-option>
+          }
+        </mat-select>
+        @if (configForm.get('unit')?.invalid && configForm.get('unit')?.touched) {
+          <mat-error>
+            @if (configForm.get('unit')?.errors?.['required']) {
+              Unit is required.
+            } @else {
+              Invalid unit format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </div>
+  </form>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+  @if (isScheduled) {
+    <button
+      mat-raised-button
+      color="primary"
+      (click)="clearScheduleDeviceBackup()">
+      Clear Schedule
+    </button>
+  } @else {
+    <button
+      mat-raised-button
+      color="primary"
+      (click)="onSubmit()">
+      Submit
+    </button>
+  }
+</mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/show-device-config.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/show-device-config.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-config-overview/show-device-config.html	(working copy)
@@ -0,0 +1,21 @@
+<h2 mat-dialog-title>Device configuration - {{ this.data?.device?.name }}</h2>
+<mat-dialog-content>
+  <p><b>Detailed device information:</b></p>
+  <div [innerHTML]="deviceConfig | newlineToBr" class="wrapped-text"></div>
+</mat-dialog-content>
+<mat-dialog-actions>
+  <button
+    mat-button
+    color="basic"
+    (click)="onCancel()">
+    Cancel
+  </button>
+</mat-dialog-actions>
+
+<style>
+  .wrapped-text {
+    word-wrap: break-word;
+    overflow-wrap: break-word;
+  }
+
+</style>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/constants/api_urls.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/constants/api_urls.ts	(revision 2671)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/constants/api_urls.ts	(working copy)
@@ -103,4 +103,12 @@
   ACTIVATE_VL_DISCOVER_DEVICE_URL: `${PREFIX}/api/cm/device_mgmt/cm_device/DiscoverDevice/_perform?action=Activate`,
   UPDATE_VL_DISCOVER_DEVICES_URL: `${PREFIX}/cm/volume_license/set_enable_mode`,
   DELETE_VL_DISCOVER_DEVICE_URL: `${PREFIX}/api/cm/device_mgmt/cm_device/DiscoverDevice/_delete`,
+  GET_DEVICE_CONFIG_FILES_URL: `${PREFIX}/api/cm/configuration/config_file/ConfigFile/_get_list_data`,
+  CLONE_DEVICE_BACKUP_CONFIG_URL: `${PREFIX}/api/cm/configuration/config_file/ConfigFile/_perform`,
+  GET_TASK_BY_NAME_URL: `${PREFIX}/cm/get_task_by_name`,
+  DELETE_DEVICE_CONFIG_FILE_URL: `${PREFIX}/api/cm/configuration/config_file/ConfigFile/_delete`,
+  PERFORM_DEVICE_CONFIG_OPS_URL: `${PREFIX}/api/cm/configuration/config_file/ConfigFile/_perform`,
+  GET_APV_VIRTUAL_SERVICES_URL: `${PREFIX}/proxy_req_dev/rest/loadbalancing/slb/vs/VirtualService`,
+  GET_SCHEDULE_DEVICE_BACKUP_URL: `${PREFIX}/cm/configuration/device/get_schedule_backup_all`,
+  CLEAR_SCHEDULE_DEVICE_BACKUP_URL: `${PREFIX}/cm/configuration/device/clear_schedule_backup_all`,
 } as const; // Makes properties readonly
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/device-service.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/device-service.ts	(revision 2671)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/device-service.ts	(working copy)
@@ -86,4 +86,48 @@
       csrfInFormData: true
     });
   }
+
+  getDeviceConfigFiles() {
+    return this.http.get(URLS.GET_DEVICE_CONFIG_FILES_URL);
+  }
+
+  cloneDeviceBackupConfig(rawPayload: any) {
+    return this.http.post(URLS.CLONE_DEVICE_BACKUP_CONFIG_URL, rawPayload, {
+      csrf: true,
+      isFormData: true,
+      csrfInFormData: true
+    });
+  }
+
+  deleteDeviceConfigFile(rawPayload: any) {
+    return this.http.post(URLS.DELETE_DEVICE_CONFIG_FILE_URL, rawPayload, {
+      csrf: true,
+      isFormData: true,
+      csrfInFormData: true
+    });
+  }
+
+  performDeviceConfigOperation(rawPayload: any) {
+    return this.http.post(URLS.PERFORM_DEVICE_CONFIG_OPS_URL, rawPayload, {
+      csrf: true,
+      isFormData: true,
+      csrfInFormData: true
+    });
+  }
+
+  getAPVVirtualServices() {
+    return this.http.get(URLS.GET_APV_VIRTUAL_SERVICES_URL);
+  }
+
+  getScheduleDeviceBackup() {
+    return this.http.get(URLS.GET_SCHEDULE_DEVICE_BACKUP_URL);
+  }
+
+  clearScheduleDeviceBackup(rawPayload: any) {
+    return this.http.post(URLS.CLEAR_SCHEDULE_DEVICE_BACKUP_URL, rawPayload, {
+      csrf: true,
+      isFormData: true,
+      csrfInFormData: true
+    });
+  }
 }
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/system-service.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/system-service.ts	(revision 2671)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/system-service.ts	(working copy)
@@ -415,6 +415,14 @@
 
   updateUser(username: string, payload: any) {
     return this.http.post(`${URLS.UPDATE_USER_URL}/%22${username}%22`, payload, {
+      csrf: true,
+      isFormData: true,
+      csrfInFormData: true
+    })
+  }
+
+  getTaskByName(payload: any) {
+    return this.http.post(URLS.GET_TASK_BY_NAME_URL, payload, {
       csrf: true,
       isFormData: true,
       csrfInFormData: true
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/shared/shared-module.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/shared/shared-module.ts	(revision 2671)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/shared/shared-module.ts	(working copy)
@@ -25,6 +25,9 @@
   faTerminal,
   faIdBadge,
   faServer,
+  faTimeline,
+  faCodeCompare,
+  faListCheck,
 } from '@fortawesome/free-solid-svg-icons';
 import {
   faBell,
@@ -44,6 +47,10 @@
   faBuilding,
   faPlayCircle,
   faCircleStop,
+  faCopy,
+  faClone,
+  faClock,
+  faWindowRestore,
 } from '@fortawesome/free-regular-svg-icons';
 import {MatGridListModule} from '@angular/material/grid-list';
 import {MatFormFieldModule} from '@angular/material/form-field';
@@ -168,6 +175,13 @@
       faBuilding,
       faPlayCircle,
       faCircleStop,
+      faCopy,
+      faTimeline,
+      faCodeCompare,
+      faClone,
+      faListCheck,
+      faClock,
+      faWindowRestore,
     );
   }
 }
