diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b4b38325..905316437 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Job Manager Change Log +## v1.2.2 Release Notes + +### Added 'Abort Job' button to Job Details page. + ## v1.2.1 Release Notes ### Added logic to avoid 500 error on Job Details page when a task does not have a start time. diff --git a/ui/src/app/job-details/job-details.component.spec.ts b/ui/src/app/job-details/job-details.component.spec.ts index 787c22cb1..88b0c7c12 100644 --- a/ui/src/app/job-details/job-details.component.spec.ts +++ b/ui/src/app/job-details/job-details.component.spec.ts @@ -49,7 +49,6 @@ describe('JobDetailsComponent', () => { let fixture: ComponentFixture; let router: Router; let fakeJobService: FakeJobManagerService; - let snackBar: MatSnackBar; const jobId = '123'; function testJob(): JobMetadataResponse { @@ -65,7 +64,7 @@ describe('JobDetailsComponent', () => { beforeEach(async(() => { fakeJobService = new FakeJobManagerService([testJob()]); let fakeCapabilitiesService: FakeCapabilitiesService = new FakeCapabilitiesService({}); - let authService = new AuthService(null, fakeCapabilitiesService, null, snackBar); + let authService = new AuthService(null, fakeCapabilitiesService, null, null); let settingsService: SettingsService = new SettingsService(authService, fakeCapabilitiesService, localStorage); TestBed.configureTestingModule({ @@ -115,6 +114,7 @@ describe('JobDetailsComponent', () => { {provide: SettingsService, useValue: settingsService}, {provide: CapabilitiesService, useValue: fakeCapabilitiesService}, {provide: AuthService, useValue: authService}, + {provide: MatSnackBar}, JobDetailsResolver ], }).compileComponents(); diff --git a/ui/src/app/job-details/panels/panels.component.css b/ui/src/app/job-details/panels/panels.component.css index af2091367..386f666f4 100644 --- a/ui/src/app/job-details/panels/panels.component.css +++ b/ui/src/app/job-details/panels/panels.component.css @@ -26,6 +26,13 @@ p { height: 2.25rem; } +button.mat-raised-button { + background-color: #74AE43; + color: #fff; + font-weight: 500; + text-transform: uppercase; +} + .job-id { margin-bottom: 0.5rem; } diff --git a/ui/src/app/job-details/panels/panels.component.html b/ui/src/app/job-details/panels/panels.component.html index dab470220..1b780261e 100644 --- a/ui/src/app/job-details/panels/panels.component.html +++ b/ui/src/app/job-details/panels/panels.component.html @@ -18,6 +18,7 @@ +

ID: {{ job.id }}

diff --git a/ui/src/app/job-details/panels/panels.component.spec.ts b/ui/src/app/job-details/panels/panels.component.spec.ts index c0e2a48a3..7d3b57cf1 100644 --- a/ui/src/app/job-details/panels/panels.component.spec.ts +++ b/ui/src/app/job-details/panels/panels.component.spec.ts @@ -7,6 +7,7 @@ import { MatCardModule, MatGridListModule, MatMenuModule, + MatSnackBar, MatTabsModule, MatTableModule } from '@angular/material'; @@ -17,6 +18,8 @@ import {JobMetadataResponse} from '../../shared/model/JobMetadataResponse'; import {JobPanelsComponent} from './panels.component'; import {JobFailuresTableComponent} from "../common/failures-table/failures-table.component"; import {JobDebugIconsComponent} from "../common/debug-icons/debug-icons.component"; +import {JobManagerService} from "../../core/job-manager.service"; +import {FakeJobManagerService} from "../../testing/fake-job-manager.service"; describe('JobPanelsComponent', () => { @@ -43,6 +46,7 @@ describe('JobPanelsComponent', () => { statusDetail: 'success', } }; + let fakeJobService = new FakeJobManagerService([minimalJob, completeJob]); beforeEach(async(() => { TestBed.configureTestingModule({ @@ -64,6 +68,10 @@ describe('JobPanelsComponent', () => { MatTableModule, SharedModule ], + providers: [ + {provide: JobManagerService, useValue: fakeJobService}, + {provide: MatSnackBar}, + ] }).compileComponents(); })); diff --git a/ui/src/app/job-details/panels/panels.component.ts b/ui/src/app/job-details/panels/panels.component.ts index 9fbc0e6e4..fd27516b3 100644 --- a/ui/src/app/job-details/panels/panels.component.ts +++ b/ui/src/app/job-details/panels/panels.component.ts @@ -12,6 +12,9 @@ import {JobStatus} from '../../shared/model/JobStatus'; import {JobFailuresTableComponent} from "../common/failures-table/failures-table.component"; import {JobStatusIcon} from "../../shared/common"; import {DisplayField} from "../../shared/model/DisplayField"; +import {JobManagerService} from "../../core/job-manager.service"; +import {MatSnackBar} from "@angular/material"; +import {ErrorMessageFormatterPipe} from "../../shared/pipes/error-message-formatter.pipe"; @Component({ selector: 'jm-panels', @@ -38,6 +41,10 @@ export class JobPanelsComponent implements OnInit { numTasks: number = 0; public readonly numOfErrorsToShow = 4; + constructor( + private readonly snackBar: MatSnackBar, + private readonly jobManagerService: JobManagerService) { } + ngOnInit() { this.setUpExtensions(); if (this.job.labels) { @@ -115,4 +122,22 @@ export class JobPanelsComponent implements OnInit { getStatusIcon(status: JobStatus): string { return JobStatusIcon[status]; } + + abortJob() { + this.jobManagerService.abortJob(this.job.id) + .then(() => { + window.location.reload(); + }) + .catch((error) => this.handleError(error)); + } + + canAbort(): boolean { + return !this.hasParent() && (this.job.status == JobStatus.Submitted || this.job.status == JobStatus.Running); + } + + handleError(error: any) { + this.snackBar.open( + new ErrorMessageFormatterPipe().transform(error), + 'Dismiss'); + } }