From: Stephan Müller Date: Mon, 4 Jun 2018 14:27:16 +0000 (+0200) Subject: mgr/dashboard: Executing messages for tasks X-Git-Tag: v14.0.1~1110^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=refs%2Fpull%2F22014%2Fhead;p=ceph.git mgr/dashboard: Executing messages for tasks Signed-off-by: Stephan Müller --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.spec.ts index b2d3d0e06678c..5b1c8680a3e0a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.spec.ts @@ -3,6 +3,8 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PopoverModule } from 'ngx-bootstrap'; +import { ExecutingTask } from '../../../shared/models/executing-task'; +import { FinishedTask } from '../../../shared/models/finished-task'; import { SharedModule } from '../../../shared/shared.module'; import { configureTestBed } from '../../../shared/unit-test-helper'; import { TaskManagerComponent } from './task-manager.component'; @@ -10,6 +12,10 @@ import { TaskManagerComponent } from './task-manager.component'; describe('TaskManagerComponent', () => { let component: TaskManagerComponent; let fixture: ComponentFixture; + const tasks = { + executing: [], + finished: [] + }; configureTestBed({ imports: [SharedModule, PopoverModule.forRoot(), HttpClientTestingModule], @@ -20,9 +26,54 @@ describe('TaskManagerComponent', () => { fixture = TestBed.createComponent(TaskManagerComponent); component = fixture.componentInstance; fixture.detectChanges(); + tasks.executing = [ + new ExecutingTask('rbd/delete', { + pool_name: 'somePool', + image_name: 'someImage' + }) + ]; + tasks.finished = [ + new FinishedTask('rbd/copy', { + dest_pool_name: 'somePool', + dest_image_name: 'someImage' + }), + new FinishedTask('rbd/clone', { + child_pool_name: 'somePool', + child_image_name: 'someImage' + }) + ]; + tasks.finished[1].success = false; + tasks.finished[1].exception = { code: 17 }; }); it('should create', () => { expect(component).toBeTruthy(); }); + + it('should get executing message for task', () => { + component._handleTasks(tasks.executing, []); + expect(component.executingTasks.length).toBe(1); + expect(component.executingTasks[0].description).toBe('Deleting RBD \'somePool/someImage\''); + }); + + it('should get finished message for task', () => { + component._handleTasks([], tasks.finished); + expect(component.finishedTasks.length).toBe(2); + expect(component.finishedTasks[0].description).toBe('Copy RBD \'somePool/someImage\''); + expect(component.finishedTasks[0].errorMessage).toBe(undefined); + expect(component.finishedTasks[1].description).toBe('Clone RBD \'somePool/someImage\''); + expect(component.finishedTasks[1].errorMessage).toBe( + 'Name \'somePool/someImage\' is already in use.' + ); + }); + + it('should get an empty hour glass with only finished tasks', () => { + component._setIcon(0); + expect(component.icon).toBe('fa-hourglass-o'); + }); + + it('should get a nearly empty hour glass with executing tasks', () => { + component._setIcon(10); + expect(component.icon).toBe('fa-hourglass-start'); + }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.ts index d9770b18a3d56..0c07f881c4db1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/task-manager/task-manager.component.ts @@ -11,38 +11,40 @@ import { TaskManagerMessageService } from '../../../shared/services/task-manager styleUrls: ['./task-manager.component.scss'] }) export class TaskManagerComponent implements OnInit { - - executingTasks: Array = []; - finishedTasks: Array = []; + executingTasks: ExecutingTask[] = []; + finishedTasks: FinishedTask[] = []; icon = 'fa-hourglass-o'; - constructor(private summaryService: SummaryService, - private taskManagerMessageService: TaskManagerMessageService) { - } + constructor( + private summaryService: SummaryService, + private taskMessageManager: TaskManagerMessageService + ) {} ngOnInit() { - const icons = ['fa-hourglass-o', 'fa-hourglass-start', 'fa-hourglass-half', 'fa-hourglass-end']; - let iconIndex = 0; this.summaryService.summaryData$.subscribe((data: any) => { - this.executingTasks = data.executing_tasks; - this.finishedTasks = data.finished_tasks; - for (const excutingTask of this.executingTasks) { - excutingTask.description = this.taskManagerMessageService.getDescription(excutingTask); - } - for (const finishedTask of this.finishedTasks) { - finishedTask.description = this.taskManagerMessageService.getDescription(finishedTask); - if (finishedTask.success === false) { - finishedTask.errorMessage = this.taskManagerMessageService.getErrorMessage(finishedTask); - } - } - if (this.executingTasks.length > 0) { - iconIndex = (iconIndex + 1) % icons.length; - } else { - iconIndex = 0; - } - this.icon = icons[iconIndex]; + this._handleTasks(data.executing_tasks, data.finished_tasks); + this._setIcon(data.executing_tasks.length); }); } + _handleTasks(executingTasks: ExecutingTask[], finishedTasks: FinishedTask[]) { + for (const excutingTask of executingTasks) { + excutingTask.description = this.taskMessageManager.getRunningMessage(excutingTask); + } + for (const finishedTask of finishedTasks) { + finishedTask.description = this.taskMessageManager.getDescription(finishedTask); + if (finishedTask.success === false) { + finishedTask.errorMessage = this.taskMessageManager.getErrorMessage(finishedTask); + } + } + this.executingTasks = executingTasks; + this.finishedTasks = finishedTasks; + } + + _setIcon(executingTasks: number) { + const iconSuffix = ['o', 'start', 'half', 'end']; // TODO: Use all suffixes + const iconIndex = executingTasks > 0 ? 1 : 0; + this.icon = 'fa-hourglass-' + iconSuffix[iconIndex]; + } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-manager-message.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-manager-message.service.spec.ts index 5dade8f70bc07..1c3e4ad42eafc 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-manager-message.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-manager-message.service.spec.ts @@ -28,6 +28,25 @@ describe('TaskManagerMessageService', () => { expect(message).toBe('Unknown Task'); }); + it('should get default running message', () => { + finishedTask.metadata = {}; + let message = service.getRunningMessage(finishedTask); + expect(message).toBe('Executing unknown task'); + finishedTask.metadata = { component: 'rbd' }; + message = service.getRunningMessage(finishedTask); + expect(message).toBe('Executing RBD'); + }); + + it('should get custom running message', () => { + finishedTask.name = 'rbd/create'; + finishedTask.metadata = { + pool_name: 'somePool', + image_name: 'someImage' + }; + const message = service.getRunningMessage(finishedTask); + expect(message).toBe('Creating RBD \'somePool/someImage\''); + }); + it('should getErrorMessage', () => { finishedTask.exception = _.assign(new TaskException(), { code: 1 @@ -46,6 +65,7 @@ describe('TaskManagerMessageService', () => { expect(value.descr({})).toBeTruthy(); expect(value.success({})).toBeTruthy(); expect(value.error({})).toBeTruthy(); + expect(value.running({})).toBeTruthy(); }); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-manager-message.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-manager-message.service.ts index e7d034bc90407..9f32645a24c07 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-manager-message.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-manager-message.service.ts @@ -7,15 +7,18 @@ import { ServicesModule } from './services.module'; class TaskManagerMessage { descr: (metadata) => string; + running: (metadata) => string; success: (metadata) => string; error: (metadata) => object; constructor( descr: (metadata) => string, + running: (metadata) => string, success: (metadata) => string, error: (metadata) => object ) { this.descr = descr; + this.running = running; this.success = success; this.error = error; } @@ -28,30 +31,31 @@ export class TaskManagerMessageService { messages = { 'rbd/create': new TaskManagerMessage( (metadata) => `Create RBD '${metadata.pool_name}/${metadata.image_name}'`, - (metadata) => `RBD '${metadata.pool_name}/${metadata.image_name}' - has been created successfully`, + (metadata) => `Creating RBD '${metadata.pool_name}/${metadata.image_name}'`, + (metadata) => + `RBD '${metadata.pool_name}/${metadata.image_name}' has been created successfully`, (metadata) => { return { - '17': `Name '${metadata.pool_name}/${metadata.image_name}' is already - in use.` + '17': `Name '${metadata.pool_name}/${metadata.image_name}' is already in use.` }; } ), 'rbd/edit': new TaskManagerMessage( (metadata) => `Update RBD '${metadata.pool_name}/${metadata.image_name}'`, - (metadata) => `RBD '${metadata.pool_name}/${metadata.image_name}' - has been updated successfully`, + (metadata) => `Updating RBD '${metadata.pool_name}/${metadata.image_name}'`, + (metadata) => + `RBD '${metadata.pool_name}/${metadata.image_name}' has been updated successfully`, (metadata) => { return { - '17': `Name '${metadata.pool_name}/${metadata.name}' is already - in use.` + '17': `Name '${metadata.pool_name}/${metadata.name}' is already in use.` }; } ), 'rbd/delete': new TaskManagerMessage( (metadata) => `Delete RBD '${metadata.pool_name}/${metadata.image_name}'`, - (metadata) => `RBD '${metadata.pool_name}/${metadata.image_name}' - has been deleted successfully`, + (metadata) => `Deleting RBD '${metadata.pool_name}/${metadata.image_name}'`, + (metadata) => + `RBD '${metadata.pool_name}/${metadata.image_name}' has been deleted successfully`, (metadata) => { return { '39': `RBD image contains snapshots.` @@ -60,31 +64,36 @@ export class TaskManagerMessageService { ), 'rbd/clone': new TaskManagerMessage( (metadata) => `Clone RBD '${metadata.child_pool_name}/${metadata.child_image_name}'`, - (metadata) => `RBD '${metadata.child_pool_name}/${metadata.child_image_name}' - has been cloned successfully`, + (metadata) => `Cloning RBD '${metadata.child_pool_name}/${metadata.child_image_name}'`, + (metadata) => + `RBD '${metadata.child_pool_name}/${ + metadata.child_image_name + }' has been cloned successfully`, (metadata) => { return { - '17': `Name '${metadata.child_pool_name}/${metadata.child_image_name}' is already - in use.`, + '17': `Name '${metadata.child_pool_name}/${ + metadata.child_image_name + }' is already in use.`, '22': `Snapshot must be protected.` }; } ), 'rbd/copy': new TaskManagerMessage( (metadata) => `Copy RBD '${metadata.dest_pool_name}/${metadata.dest_image_name}'`, - (metadata) => `RBD '${metadata.dest_pool_name}/${metadata.dest_image_name}' - has been copied successfully`, + (metadata) => `Copying RBD '${metadata.dest_pool_name}/${metadata.dest_image_name}'`, + (metadata) => + `RBD '${metadata.dest_pool_name}/${metadata.dest_image_name}' has been copied successfully`, (metadata) => { return { - '17': `Name '${metadata.dest_pool_name}/${metadata.dest_image_name}' is already - in use.` + '17': `Name '${metadata.dest_pool_name}/${metadata.dest_image_name}' is already in use.` }; } ), 'rbd/flatten': new TaskManagerMessage( (metadata) => `Flatten RBD '${metadata.pool_name}/${metadata.image_name}'`, - (metadata) => `RBD '${metadata.pool_name}/${metadata.image_name}' - has been flattened successfully`, + (metadata) => `Flattening RBD '${metadata.pool_name}/${metadata.image_name}'`, + (metadata) => + `RBD '${metadata.pool_name}/${metadata.image_name}' has been flattened successfully`, () => { return {}; } @@ -93,6 +102,9 @@ export class TaskManagerMessageService { (metadata) => `Create snapshot ` + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}'`, + (metadata) => + `Creating snapshot ` + + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}'`, (metadata) => `Snapshot ` + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}' ` + @@ -107,6 +119,9 @@ export class TaskManagerMessageService { (metadata) => `Update snapshot ` + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}'`, + (metadata) => + `Updating snapshot ` + + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}'`, (metadata) => `Snapshot ` + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}' ` + @@ -121,6 +136,9 @@ export class TaskManagerMessageService { (metadata) => `Delete snapshot ` + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}'`, + (metadata) => + `Deleting snapshot ` + + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}'`, (metadata) => `Snapshot ` + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}' ` + @@ -135,6 +153,9 @@ export class TaskManagerMessageService { (metadata) => `Rollback snapshot ` + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}'`, + (metadata) => + `Rolling back snapshot ` + + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}'`, (metadata) => `Snapshot ` + `'${metadata.pool_name}/${metadata.image_name}@${metadata.snapshot_name}' ` + @@ -149,6 +170,11 @@ export class TaskManagerMessageService { (metadata) => { return Components[metadata.component] || metadata.component || 'Unknown Task'; }, + (metadata) => { + return ( + 'Executing ' + (Components[metadata.component] || metadata.component || 'unknown task') + ); + }, (metadata) => 'Task executed successfully', () => { return {}; @@ -174,4 +200,9 @@ export class TaskManagerMessageService { const taskManagerMessage = this.messages[task.name] || this.defaultMessage; return taskManagerMessage.descr(task.metadata); } + + getRunningMessage(task: Task) { + const taskManagerMessage = this.messages[task.name] || this.defaultMessage; + return taskManagerMessage.running(task.metadata); + } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-wrapper.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-wrapper.service.ts index ae227c5c83bf4..ff346968a6856 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-wrapper.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/services/task-wrapper.service.ts @@ -56,7 +56,7 @@ export class TaskWrapperService { _handleExecutingTasks(task: FinishedTask, tasks?: ExecutingTask[]) { this.notificationService.show( NotificationType.info, - task.name + ' in progress...', + this.taskManagerMessageService.getRunningMessage(task), this.taskManagerMessageService.getDescription(task) ); const executingTask = new ExecutingTask(task.name, task.metadata);