Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/apply-configuration.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/apply-configuration.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/apply-configuration.html	(working copy)
@@ -0,0 +1,120 @@
+<h2 mat-dialog-title>Apply Configuration</h2>
+<mat-dialog-content>
+  <p>
+    The cloned files contain IP addresses, and applying the configuration might alter the device addresses, potentially
+    leading to data discrepancies. Please ensure that you apply the configuration to the correct device(s).
+  </p>
+  <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>
+            @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">
+            @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>
+    }
+    <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-cloned-files/compare-clone-config.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/compare-clone-config.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/compare-clone-config.html	(working copy)
@@ -0,0 +1,155 @@
+<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>
+    <div class="form-field-wrapper">
+      <label for="device" class="form-label">Devices *</label>
+      <mat-form-field appearance="outline" subscriptSizing="dynamic">
+        <mat-select formControlName="device">
+          @for (_option of data?.devices; track _option) {
+            <mat-option [value]="_option.name">{{ _option.name }}</mat-option>
+          }
+        </mat-select>
+        @if (configForm.get('device')?.invalid && configForm.get('device')?.touched) {
+          <mat-error>
+            @if (configForm.get('device')?.errors?.['required']) {
+              Device is required.
+            } @else {
+              Invalid device format.
+            }
+          </mat-error>
+        }
+      </mat-form-field>
+    </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-cloned-files/device-cloned-files.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/device-cloned-files.html	(revision 2673)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/device-cloned-files.html	(working copy)
@@ -1 +1,61 @@
-<p>device-cloned-files works!</p>
+<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>Configuration Filename</th>
+      <td mat-cell *matCellDef="let element">
+        <a class="details-page-link" (click)="editDeviceConfiguration(element)">{{ element.name }}</a>
+      </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="deviceType">
+      <th mat-header-cell *matHeaderCellDef>Device Type</th>
+      <td mat-cell *matCellDef="let element"> {{ element.device_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="cloneSource">
+      <th mat-header-cell *matHeaderCellDef>Clone Source</th>
+      <td mat-cell *matCellDef="let element">{{ element.modify_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 configuration"
+                   (click)="cloneConfiguration(element)"></fa-icon>
+          <fa-icon [icon]="['fas', 'code-compare']" size="lg" matTooltip="Compare configuration"
+                   (click)="compareConfiguration(element)"></fa-icon>
+          <fa-icon [icon]="['fas', 'gears']" size="lg" matTooltip="Apply configuration"
+                   (click)="applyConfiguration(element)"></fa-icon>
+          <fa-icon [icon]="['fas', 'list-check']" size="lg" matTooltip="Task for this configuration"
+                   (click)="showTaskConfiguration(element)"></fa-icon>
+          <fa-icon [icon]="['far', 'trash-can']" size="lg" class="delete-icon" matTooltip="Delete configuration"
+                   (click)="deleteConfiguration(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-cloned-files/device-cloned-files.scss
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/device-cloned-files.scss	(revision 2673)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/device-cloned-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-cloned-files/device-cloned-files.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/device-cloned-files.ts	(revision 2673)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/device-cloned-files.ts	(working copy)
@@ -1,11 +1,642 @@
-import { Component } from '@angular/core';
+import {AfterViewInit, ChangeDetectorRef, Component, inject, OnDestroy, OnInit, ViewChild} from '@angular/core';
+import {SharedModule} from '../../../shared/shared-module';
+import {NotificationService} from '../../../services/notification';
+import {DeviceService} from '../../../services/device-service';
+import {MatTableDataSource} from '@angular/material/table';
+import {MatPaginator} from '@angular/material/paginator';
+import {MAT_DIALOG_DATA, MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material/dialog';
+import {take} from 'rxjs/operators';
+import {Confirmation} from '../../../services/confirmation';
+import {CloneConfigDialog, ShowTasksByNameDialog} from '../device-backup-files/device-backup-files';
+import {FormBuilder, FormGroup, Validators} from '@angular/forms';
+import {Subscription} from 'rxjs';
 
 @Component({
   selector: 'app-device-cloned-files',
-  imports: [],
+  imports: [
+    SharedModule
+  ],
   templateUrl: './device-cloned-files.html',
   styleUrl: './device-cloned-files.scss'
 })
-export class DeviceClonedFiles {
+export class DeviceClonedFiles implements OnInit, AfterViewInit {
 
+  totalRecords: number = 0;
+  dataSource: MatTableDataSource<any> = new MatTableDataSource();
+  deviceColumns: string[] = ['serial', 'deviceName', 'fileType', 'deviceType', 'createTime', 'cloneSource', 'comment', 'action'];
+  @ViewChild(MatPaginator) paginator!: MatPaginator;
+
+  dialog = inject(MatDialog);
+  dialogConfig = new MatDialogConfig();
+
+  devices: any = [];
+  groups: any = [];
+  deviceGroups: any = [];
+  groupedDevices: any = {};
+
+  constructor(
+    private _notification: NotificationService,
+    private _device: DeviceService,
+    private _cdRef: ChangeDetectorRef,
+    private _confirmation: Confirmation,
+  ) {
+  }
+
+  ngAfterViewInit(): void {
+    this.dataSource.paginator = this.paginator;
+    this._cdRef.detectChanges();
+  }
+
+  ngOnInit(): void {
+    setTimeout(() => {
+      this.getDeviceConfigFiles();
+      this.getAMPDevicesList();
+    })
+  }
+
+  getAMPDevicesList() {
+    this.devices = [];
+    this._device.getAMPDevicesList().pipe(take(1)).subscribe({
+      next: (result: any) => {
+        if (result && result.length > 0) {
+          this.devices = result;
+        }
+        this.groupDevicesByType();
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  groupDevicesByType(): void {
+    this.groupedDevices = this.devices.reduce((acc: any, device: any) => {
+      const type = device.type;
+      if (!acc[type]) {
+        acc[type] = [];
+      }
+      acc[type].push(device);
+      return acc;
+    }, {});
+  }
+
+  getDeviceConfigFiles() {
+    this.dataSource.data = [];
+    this.totalRecords = 0;
+    this._device.getDeviceConfigFiles().pipe(take(1)).subscribe({
+      next: (result: any) => {
+        let cloneFiles: any = [];
+        if (result.length > 0) {
+          result.forEach((item: any) => {
+            if (item.file_type === 'system' || item.file_type === 'vs') {
+              cloneFiles.push(item);
+            }
+          })
+        }
+        this.dataSource.data = cloneFiles;
+        this.dataSource.paginator = this.paginator;
+        this.totalRecords = this.dataSource.data.length;
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  getGlobalSerial(index: number): number {
+    if (this.paginator) {
+      return this.paginator.pageIndex * this.paginator.pageSize + index + 1;
+    }
+    return index + 1;
+  }
+
+  editDeviceConfiguration(_device: any) {
+    this.dialogConfig.data = {
+      config: _device,
+    };
+    const dialogRef = this.dialog.open(EditConfigurationDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe(() => {
+    })
+  }
+
+  cloneConfiguration(_device: any) {
+    this.dialogConfig.data = {
+      config: _device,
+    };
+    const dialogRef = this.dialog.open(CloneConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe(() => {
+    })
+  }
+
+  compareConfiguration(_device: any) {
+    this.dialogConfig.width = '60%';
+    this.dialogConfig.data = {
+      device: _device,
+      devices: this.groupedDevices[_device?.device_type],
+    }
+    const dialogRef = this.dialog.open(CompareCloneConfigDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  applyConfiguration(_device: any) {
+    this.dialogConfig.width = '60%';
+    this.dialogConfig.data = {
+      device: _device,
+      devices: this.groupedDevices[_device?.device_type],
+      groups: this.groups
+    }
+    const dialogRef = this.dialog.open(ApplyConfigurationDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  showTaskConfiguration(_device: any) {
+    this.dialogConfig.data = {
+      config: _device,
+    };
+    const dialogRef = this.dialog.open(ShowTasksByNameDialog, this.dialogConfig);
+    dialogRef.afterClosed().subscribe((result: boolean) => {
+    })
+  }
+
+  deleteConfiguration(_device: any) {
+    let confirmMsg = `Are you sure you want to delete the configuration file - ${_device?.name}"?`
+    this._confirmation.openConfirmDialog({
+      title: `Delete 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: _device?.file_type,
+          name: _device?.name
+        }));
+        this._device.deleteDeviceConfigFile(rawPayload)
+          .pipe(take(1))
+          .subscribe({
+            next: (result: any) => {
+              this.getDeviceConfigFiles();
+            },
+            error: (err: any) => {
+              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: 'compare-clone-config',
+  templateUrl: './compare-clone-config.html',
+  imports: [SharedModule]
+})
+export class CompareCloneConfigDialog implements OnInit {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<CompareCloneConfigDialog>);
+
+  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]],
+      device: ['', [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?.device?.file_type,
+        name: this.data?.device?.name,
+        device_type: this.data?.device?.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: 'apply-configuration',
+  templateUrl: './apply-configuration.html',
+  imports: [SharedModule]
+})
+export class ApplyConfigurationDialog implements OnInit, OnDestroy {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<ApplyConfigurationDialog>);
+  configForm: FormGroup;
+  configOptions: any = [
+    {value: 'immediate', label: 'Immediate'},
+    {value: 'deferred', label: 'Deferred'},
+  ]
+  private subscriptions: Subscription = new Subscription();
+
+  constructor(
+    private _device: DeviceService,
+    private _notification: NotificationService,
+    private _formBuilder: FormBuilder,
+    private _cdRef: ChangeDetectorRef,
+  ) {
+    this.configForm = this._formBuilder.group({
+      device: ['device', [Validators.required]],
+      enable_backup: [false, [Validators.required]],
+      devices: [''],
+      device_groups: [''],
+      option: ['immediate', [Validators.required]],
+      custom: [''],
+      expire_time: [''],
+    })
+  }
+
+  ngOnInit() {
+    this.subscriptions.add(
+      this.configForm.get('device')?.valueChanges.subscribe(deviceType => {
+        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') {
+          deviceGroupsControl?.setValidators([Validators.required]);
+          devicesControl?.clearValidators();
+        } else {
+          devicesControl?.clearValidators();
+          deviceGroupsControl?.clearValidators();
+        }
+        devicesControl?.updateValueAndValidity();
+        deviceGroupsControl?.updateValueAndValidity();
+      })
+    );
+
+    this.subscriptions.add(
+      this.configForm.get('option')?.valueChanges.subscribe(optionValue => {
+        const expireTimeControl = this.configForm.get('expire_time');
+
+        if (optionValue === 'deferred') {
+          expireTimeControl?.setValidators([Validators.required]);
+        } else {
+          expireTimeControl?.clearValidators();
+        }
+        expireTimeControl?.updateValueAndValidity();
+      })
+    );
+    this.configForm.get('device')?.updateValueAndValidity();
+    this.configForm.get('option')?.updateValueAndValidity();
+  }
+
+  onSubmit(): void {
+    if (this.configForm.invalid) {
+      console.log(this.configForm.value);
+      this.configForm.markAllAsTouched();
+      return;
+    }
+    let payload = new FormData();
+    payload.set('action', 'Init_device');
+    let rawPayload: any = {
+      "__pk_list": [
+        JSON.stringify({
+          file_type: this.data.device?.file_type,
+          name: this.data.device?.name,
+        })
+      ],
+      option: this.configForm.value.option,
+      backup: this.configForm.value.enable_backup,
+    }
+    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
+      }
+    }
+    if (this.configForm.value.option === 'deferred') {
+      rawPayload['expire_time'] = this.configForm.value.expire_time;
+    }
+    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(`Apply configuration initiated successfully.`);
+          this.dialogRef.close(true);
+        }
+        this._cdRef.detectChanges();
+      },
+      error: error => {
+        this._notification.showError(`Error: ${error?.message}`);
+        this._cdRef.detectChanges();
+      }
+    })
+  }
+
+  ngOnDestroy(): void {
+    this.subscriptions.unsubscribe();
+  }
+
+  onCancel(): void {
+    this.dialogRef.close(false);
+  }
+}
+
+@Component({
+  selector: 'edit-configuration',
+  templateUrl: './edit-configuration.html',
+  imports: [SharedModule]
+})
+export class EditConfigurationDialog implements OnInit, OnDestroy {
+
+  readonly data = inject(MAT_DIALOG_DATA);
+  readonly dialogRef = inject(MatDialogRef<EditConfigurationDialog>);
+  configForm: FormGroup;
+  deviceType: any = '';
+  aGOptions: any = [];
+  configOptions: any = [
+    {value: 'immediate', label: 'Immediate'},
+    {value: 'deferred', label: 'Deferred'},
+  ]
+  private subscriptions: Subscription = new Subscription();
+
+  constructor(
+    private _device: DeviceService,
+    private _notification: NotificationService,
+    private _formBuilder: FormBuilder,
+    private _cdRef: ChangeDetectorRef,
+  ) {
+    this.configForm = this._formBuilder.group({
+      aGOption: [''],
+      device_config: ['', [Validators.required]],
+    })
+  }
+
+  ngOnInit() {
+    setTimeout(() => {
+      this.deviceType = this.data?.config?.device_type?.toLowerCase();
+      if (this.data?.config?.device_type.toLowerCase() === 'vapv' ||
+        this.data?.config?.device_type.toLowerCase() === 'apv' ||
+        this.data?.config?.device_type.toLowerCase() === 'vasf' ||
+        this.data?.config?.device_type.toLowerCase() === 'asf') {
+        this.getConfig();
+      } else if (this.data?.config?.device_type.toLowerCase() === 'vxag' || this.data?.config?.device_type.toLowerCase() === 'ag') {
+        this.getAGConfigAssociatedVsites();
+        const agOptionControl = this.configForm.get('aGOption');
+        agOptionControl?.clearValidators();
+        if (this.deviceType === 'ag' || this.deviceType === 'vxag') {
+          agOptionControl?.setValidators([Validators.required]);
+        }
+        agOptionControl?.updateValueAndValidity();
+      }
+    });
+  }
+
+  getConfig() {
+    this._device.getDeviceConfigByConfigFileName(this.data?.config?.name)
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          if (result && result.length > 0) {
+            this.configForm.patchValue({
+              device_config: result[1],
+            })
+          }
+          this._cdRef.detectChanges();
+        },
+        error: (error: { message: string; }) => {
+          console.log(error);
+          this._notification.showError(error.message);
+          this._cdRef.detectChanges();
+        }
+      })
+  }
+
+  getAGConfigAssociatedVsites() {
+    this.aGOptions = []
+    let payload = new FormData();
+    payload.set('initial_filter', JSON.stringify({name: this.data?.config?.name.split('.')[0]}));
+    this._device.getAGConfigAssociatedVsites(payload)
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          if (result && result.length > 0) {
+            this.aGOptions = result;
+          }
+          this._cdRef.detectChanges();
+        },
+        error: (error: { message: string; }) => {
+          console.log(error);
+          this._notification.showError(error.message);
+          this._cdRef.detectChanges();
+        }
+      })
+  }
+
+  onSelectionChange() {
+    this.configForm.patchValue({
+      device_config: '',
+    })
+    let configName: string = this.data?.config?.name.split('.')[0];
+    this._device.getAGVSiteConfig(configName, this.configForm.value.aGOption)
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          if (result && result.length > 0 && result[0]) {
+            this.configForm.patchValue({
+              device_config: result[1],
+            })
+          } else {
+            this._notification.showError(result[1] || 'Failed to get the device configuration.');
+          }
+          this._cdRef.detectChanges();
+        },
+        error: (error: { message: string; }) => {
+          console.log(error);
+          this._notification.showError(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 filename: string = this.data?.config?.name;
+    payload.set('data', JSON.stringify({
+      config_content: this.configForm.value.device_config,
+    }));
+    if (this.deviceType === 'ag' || this.deviceType === 'vxag') {
+      filename = filename.split('.')[0];
+      this._device.updateAGVSiteConfig(filename, this.configForm.value.aGOption, payload)
+        .pipe(take(1)).subscribe({
+        next: (result: any) => {
+          if (result) {
+            this._notification.showSuccess(`The configuration has been updated successfully.`);
+            this.dialogRef.close(true);
+          }
+          this._cdRef.detectChanges();
+        },
+        error: error => {
+          this._notification.showError(`Error: ${error?.message}`);
+          this._cdRef.detectChanges();
+        }
+      })
+    } else {
+      this._device.updateDeviceConfigByConfigFileName(filename, payload)
+        .pipe(take(1)).subscribe({
+        next: (result: any) => {
+          if (result) {
+            this._notification.showSuccess(`The configuration has been updated successfully.`);
+            this.dialogRef.close(true);
+          }
+          this._cdRef.detectChanges();
+        },
+        error: error => {
+          this._notification.showError(`Error: ${error?.message}`);
+          this._cdRef.detectChanges();
+        }
+      })
+    }
+  }
+
+  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-cloned-files/edit-configuration.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/edit-configuration.html	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/device-cloned-files/edit-configuration.html	(working copy)
@@ -0,0 +1,56 @@
+<h2 mat-dialog-title>Edit Configuration</h2>
+<mat-dialog-content>
+  <form
+    (ngSubmit)="onSubmit()"
+    [formGroup]="configForm"
+  >
+    @if (deviceType === 'ag' || deviceType === 'vxag') {
+      <div class="form-field-wrapper">
+        <label for="aGOption" class="form-label">Select Virtual Site *</label>
+        <mat-form-field appearance="outline" subscriptSizing="dynamic">
+          <mat-select formControlName="aGOption" (selectionChange)="onSelectionChange()">
+            <mat-option value="global">global</mat-option>
+            @for (_option of aGOptions; track _option) {
+              <mat-option [value]="_option.vsite_name">{{ _option.vsite_name }}</mat-option>
+            }
+          </mat-select>
+          @if (configForm.get('aGOption')?.invalid && configForm.get('aGOption')?.touched) {
+            <mat-error>
+              @if (configForm.get('aGOption')?.errors?.['required']) {
+                Virtual site is required.
+              } @else {
+                Invalid virtual site format.
+              }
+            </mat-error>
+          }
+        </mat-form-field>
+      </div>
+    }
+    <div class="form-field-wrapper">
+      <textarea matInput formControlName="device_config" cols="80" rows="45"></textarea>
+      @if (configForm.get('device_config')?.invalid && configForm.get('device_config')?.touched) {
+        <mat-error>
+          @if (configForm.get('device_config')?.errors?.['required']) {
+            Device configuration is required.
+          } @else {
+            Invalid device configuration format.
+          }
+        </mat-error>
+      }
+    </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.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 2673)
+++ /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)
@@ -587,7 +587,6 @@
       this.configForm.markAllAsTouched();
       return;
     }
-    console.log(this.configForm.value);
     let payload = new FormData();
     payload.set('action', 'Onekey_Backup');
     let rawPayload: any = {
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 2673)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/constants/api_urls.ts	(working copy)
@@ -111,4 +111,9 @@
   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`,
+  GET_DEVICE_CONFIG_BY_CONFIG_FILE_NAME_URL: `${PREFIX}/cm/configuration/configuration_file/get_config/system`,
+  UPDATE_DEVICE_CONFIG_BY_CONFIG_FILE_NAME_URL: `${PREFIX}cm/configuration/configuration_file/save_config/system`,
+  GET_AG_CONFIG_ASSOCIATED_VSITE_URL: `${PREFIX}/api/cm/configuration/config_file/TarFile/_get_asso_list_data`,
+  GET_AG_VSITE_CA_CONFIG_URL: `${PREFIX}/cm/configuration/configuration_file/get_config/system`,
+  UPDATE_AG_VSITE_CA_CONFIG_URL: `${PREFIX}/cm/configuration/configuration_file/save_config/system`,
 } 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 2673)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/device-service.ts	(working copy)
@@ -134,4 +134,49 @@
   getAMPDevicesList() {
     return this.http.get(URLS.GET_AMP_DEVICES_LIST_URL);
   }
+
+  getDeviceConfigByConfigFileName(filename: any) {
+    return this.http.get(`${URLS.GET_DEVICE_CONFIG_BY_CONFIG_FILE_NAME_URL}/${filename}`);
+  }
+
+  getAGConfigAssociatedVsites(rawPayload: any) {
+    return this.http.post(URLS.GET_AG_CONFIG_ASSOCIATED_VSITE_URL, rawPayload, {
+      csrf: true,
+      isFormData: true,
+      csrfInFormData: true
+    });
+  }
+
+  getAGVSiteConfig(configName: string, vsite: any = 'global') {
+    let finalURL: any = `${URLS.GET_AG_VSITE_CA_CONFIG_URL}/${configName}/ca.conf`;
+    if (vsite !== 'global') {
+      finalURL =  `${URLS.GET_AG_VSITE_CA_CONFIG_URL}/${configName}/vsites/${vsite}/ca.conf.${vsite}`;
+    }
+    return this.http.post(finalURL, null, {
+      csrf: true,
+      isFormData: true,
+      csrfInFormData: true
+    });
+  }
+
+  updateDeviceConfigByConfigFileName(filename: string, rawPayload: any) {
+    return this.http.post(`${URLS.UPDATE_DEVICE_CONFIG_BY_CONFIG_FILE_NAME_URL}/${filename}`, rawPayload, {
+      csrf: true,
+      isFormData: true,
+      csrfInFormData: true
+    });
+  }
+
+  updateAGVSiteConfig(configName: string, vsite: any = 'global', rawPayload: any) {
+    let finalURL: any = `${URLS.UPDATE_AG_VSITE_CA_CONFIG_URL}/${configName}/ca.conf`;
+    if (vsite !== 'global') {
+      finalURL =  `${URLS.UPDATE_AG_VSITE_CA_CONFIG_URL}/${configName}/vsites/${vsite}/ca.conf.${vsite}`;
+    }
+    return this.http.post(finalURL, rawPayload, {
+      csrf: true,
+      isFormData: true,
+      csrfInFormData: true
+    });
+  }
+
 }
