Skip to content

Commit c560da9

Browse files
feat: Add certificate delete functionality to device management UI (#2969)
- Add deleteCertificate method to DevicesService with DELETE API call - Implement delete certificate functionality in CertificatesComponent - Add delete button to certificate list with confirmation dialog - Integrate AreYouSureDialogComponent for delete confirmation - Add translation keys for delete tooltip and success/error messages - Include unit tests for deleteCertificate service method - Disable delete button for read-only certificates Resolves certificate management by allowing users to remove certificates from AMT devices through the web UI with proper confirmation flow. Signed-off-by: ShradhaGupta31 <[email protected]> Co-authored-by: Madhavi Losetty <[email protected]>
1 parent 9969fed commit c560da9

File tree

5 files changed

+103
-7
lines changed

5 files changed

+103
-7
lines changed

src/app/devices/certificates/certificates.component.html

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,22 @@
3737
{{ cert.associatedProfiles }}
3838
}
3939
</span>
40-
<button
41-
matListItemMeta
42-
mat-icon-button
43-
[matTooltip]="'certificates.download.tooltip.value' | translate"
44-
(click)="downloadCert(cert)">
45-
<mat-icon>download</mat-icon>
46-
</button>
40+
<div matListItemMeta class="flex gap-1">
41+
<button
42+
mat-icon-button
43+
[matTooltip]="'certificates.download.tooltip.value' | translate"
44+
(click)="downloadCert(cert)">
45+
<mat-icon>download</mat-icon>
46+
</button>
47+
<button
48+
mat-icon-button
49+
[matTooltip]="'certificates.delete.tooltip.value' | translate"
50+
(click)="deleteCertificate(cert)"
51+
[disabled]="isLoading() || cert.readOnlyCertificate"
52+
class="text-red-500">
53+
<mat-icon>delete</mat-icon>
54+
</button>
55+
</div>
4756
</mat-list-item>
4857
}
4958
}

src/app/devices/certificates/certificates.component.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { MatSnackBar } from '@angular/material/snack-bar'
1111
import { MatDialog } from '@angular/material/dialog'
1212
import { CertInfo } from 'src/models/models'
1313
import { AddCertDialogComponent } from './add-cert-dialog/add-cert-dialog.component'
14+
import { AreYouSureDialogComponent } from '../../shared/are-you-sure/are-you-sure.component'
1415
import { TranslateModule, TranslateService } from '@ngx-translate/core'
1516
import { MatButtonModule, MatIconButton } from '@angular/material/button'
1617
import { MatTooltip } from '@angular/material/tooltip'
@@ -132,4 +133,34 @@ export class CertificatesComponent implements OnInit {
132133
this.getCertificates()
133134
})
134135
}
136+
137+
deleteCertificate(cert: any): void {
138+
const dialogRef = this.dialog.open(AreYouSureDialogComponent)
139+
140+
dialogRef.afterClosed().subscribe((result) => {
141+
if (result === true) {
142+
this.isLoading.set(true)
143+
this.devicesService
144+
.deleteCertificate(this.deviceId(), cert.instanceID)
145+
.pipe(
146+
catchError((err) => {
147+
this.isLoading.set(false)
148+
const msg: string = this.translate.instant('certificates.errorDeletingCertificate.value')
149+
this.snackBar.open(msg, undefined, SnackbarDefaults.defaultError)
150+
return throwError(err)
151+
}),
152+
finalize(() => {
153+
this.isLoading.set(false)
154+
})
155+
)
156+
.subscribe(() => {
157+
const msg: string = this.translate.instant('certificates.deletedSuccessfully.value', {
158+
name: cert.displayName
159+
})
160+
this.snackBar.open(msg, undefined, SnackbarDefaults.defaultSuccess)
161+
this.getCertificates()
162+
})
163+
}
164+
})
165+
}
135166
}

src/app/devices/devices.service.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,41 @@ describe('DevicesService', () => {
977977
})
978978
})
979979

980+
describe('deleteCertificate', () => {
981+
it('should delete a certificate', () => {
982+
const mockResponse = { message: 'Certificate deleted successfully' }
983+
const guid = 'test-guid'
984+
const instanceId = 'Intel(r) AMT Certificate: Handle: 1'
985+
986+
service.deleteCertificate(guid, instanceId).subscribe((response) => {
987+
expect(response).toEqual(mockResponse)
988+
})
989+
990+
const req = httpMock.expectOne(
991+
`${mockEnvironment.mpsServer}/api/v1/amt/certificates/${guid}/${encodeURIComponent(instanceId)}`
992+
)
993+
expect(req.request.method).toBe('DELETE')
994+
req.flush(mockResponse)
995+
})
996+
997+
it('should handle errors when deleting certificate', () => {
998+
const mockError = { status: 400, statusText: 'Bad Request' }
999+
const guid = 'test-guid'
1000+
const instanceId = 'Intel(r) AMT Certificate: Handle: 1'
1001+
1002+
service.deleteCertificate(guid, instanceId).subscribe({
1003+
error: (error) => {
1004+
expect(error.status).toBe(400)
1005+
}
1006+
})
1007+
1008+
const req = httpMock.expectOne(
1009+
`${mockEnvironment.mpsServer}/api/v1/amt/certificates/${guid}/${encodeURIComponent(instanceId)}`
1010+
)
1011+
req.flush(null, mockError)
1012+
})
1013+
})
1014+
9801015
describe('getDisplaySelection', () => {
9811016
it('should fetch current display selection for a device', () => {
9821017
const mockResponse: DisplaySelectionResponse = {

src/app/devices/devices.service.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,15 @@ export class DevicesService {
550550
})
551551
)
552552
}
553+
deleteCertificate(guid: string, instanceId: string): Observable<any> {
554+
return this.http
555+
.delete<any>(`${environment.mpsServer}/api/v1/amt/certificates/${guid}/${encodeURIComponent(instanceId)}`)
556+
.pipe(
557+
catchError((err) => {
558+
throw err
559+
})
560+
)
561+
}
553562
getBootSources(guid: string): Observable<BootSource[]> {
554563
return this.http.get<BootSource[]>(`${environment.mpsServer}/api/v1/amt/power/bootSources/${guid}`).pipe(
555564
catchError((err) => {

src/assets/i18n/en.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,18 @@
420420
"description": "Indicates the certificate is a root certificate",
421421
"value": "Root"
422422
},
423+
"certificates.delete.tooltip": {
424+
"description": "Tooltip text for delete certificate button",
425+
"value": "Delete Certificate"
426+
},
427+
"certificates.errorDeletingCertificate": {
428+
"description": "Error message displayed when certificate deletion fails",
429+
"value": "Error deleting certificate"
430+
},
431+
"certificates.deletedSuccessfully": {
432+
"description": "Success message displayed when certificate is deleted",
433+
"value": "Certificate '{{name}}' deleted successfully"
434+
},
423435
"common.addNew": {
424436
"description": "Text for the add new button",
425437
"value": "Add New"

0 commit comments

Comments
 (0)