summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts')
-rw-r--r--src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts225
1 files changed, 225 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts
new file mode 100644
index 000000000..43fe42b99
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts
@@ -0,0 +1,225 @@
+import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
+
+import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
+import _ from 'lodash';
+import moment from 'moment';
+
+import { RbdService } from '~/app/shared/api/rbd.service';
+import { TableStatusViewCache } from '~/app/shared/classes/table-status-view-cache';
+import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
+import { TableComponent } from '~/app/shared/datatable/table/table.component';
+import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
+import { Icons } from '~/app/shared/enum/icons.enum';
+import { ViewCacheStatus } from '~/app/shared/enum/view-cache-status.enum';
+import { CdTableAction } from '~/app/shared/models/cd-table-action';
+import { CdTableColumn } from '~/app/shared/models/cd-table-column';
+import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
+import { ExecutingTask } from '~/app/shared/models/executing-task';
+import { FinishedTask } from '~/app/shared/models/finished-task';
+import { ImageSpec } from '~/app/shared/models/image-spec';
+import { Permission } from '~/app/shared/models/permissions';
+import { Task } from '~/app/shared/models/task';
+import { CdDatePipe } from '~/app/shared/pipes/cd-date.pipe';
+import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
+import { ModalService } from '~/app/shared/services/modal.service';
+import { TaskListService } from '~/app/shared/services/task-list.service';
+import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
+import { RbdTrashPurgeModalComponent } from '../rbd-trash-purge-modal/rbd-trash-purge-modal.component';
+import { RbdTrashRestoreModalComponent } from '../rbd-trash-restore-modal/rbd-trash-restore-modal.component';
+
+@Component({
+ selector: 'cd-rbd-trash-list',
+ templateUrl: './rbd-trash-list.component.html',
+ styleUrls: ['./rbd-trash-list.component.scss'],
+ providers: [TaskListService]
+})
+export class RbdTrashListComponent implements OnInit {
+ @ViewChild(TableComponent, { static: true })
+ table: TableComponent;
+ @ViewChild('expiresTpl', { static: true })
+ expiresTpl: TemplateRef<any>;
+ @ViewChild('deleteTpl', { static: true })
+ deleteTpl: TemplateRef<any>;
+
+ icons = Icons;
+
+ columns: CdTableColumn[];
+ executingTasks: ExecutingTask[] = [];
+ images: any;
+ modalRef: NgbModalRef;
+ permission: Permission;
+ retries: number;
+ selection = new CdTableSelection();
+ tableActions: CdTableAction[];
+ tableStatus = new TableStatusViewCache();
+ disablePurgeBtn = true;
+
+ constructor(
+ private authStorageService: AuthStorageService,
+ private rbdService: RbdService,
+ private modalService: ModalService,
+ private cdDatePipe: CdDatePipe,
+ public taskListService: TaskListService,
+ private taskWrapper: TaskWrapperService,
+ public actionLabels: ActionLabelsI18n
+ ) {
+ this.permission = this.authStorageService.getPermissions().rbdImage;
+ const restoreAction: CdTableAction = {
+ permission: 'update',
+ icon: Icons.undo,
+ click: () => this.restoreModal(),
+ name: this.actionLabels.RESTORE
+ };
+ const deleteAction: CdTableAction = {
+ permission: 'delete',
+ icon: Icons.destroy,
+ click: () => this.deleteModal(),
+ name: this.actionLabels.DELETE
+ };
+ this.tableActions = [restoreAction, deleteAction];
+ }
+
+ ngOnInit() {
+ this.columns = [
+ {
+ name: $localize`ID`,
+ prop: 'id',
+ flexGrow: 1,
+ cellTransformation: CellTemplate.executing
+ },
+ {
+ name: $localize`Name`,
+ prop: 'name',
+ flexGrow: 1
+ },
+ {
+ name: $localize`Pool`,
+ prop: 'pool_name',
+ flexGrow: 1
+ },
+ {
+ name: $localize`Namespace`,
+ prop: 'namespace',
+ flexGrow: 1
+ },
+ {
+ name: $localize`Status`,
+ prop: 'deferment_end_time',
+ flexGrow: 1,
+ cellTemplate: this.expiresTpl
+ },
+ {
+ name: $localize`Deleted At`,
+ prop: 'deletion_time',
+ flexGrow: 1,
+ pipe: this.cdDatePipe
+ }
+ ];
+
+ const itemFilter = (entry: any, task: Task) => {
+ const imageSpec = new ImageSpec(entry.pool_name, entry.namespace, entry.id);
+ return imageSpec.toString() === task.metadata['image_id_spec'];
+ };
+
+ const taskFilter = (task: Task) => {
+ return ['rbd/trash/remove', 'rbd/trash/restore'].includes(task.name);
+ };
+
+ this.taskListService.init(
+ () => this.rbdService.listTrash(),
+ (resp) => this.prepareResponse(resp),
+ (images) => (this.images = images),
+ () => this.onFetchError(),
+ taskFilter,
+ itemFilter,
+ undefined
+ );
+ }
+
+ prepareResponse(resp: any[]): any[] {
+ let images: any[] = [];
+ const viewCacheStatusMap = {};
+
+ resp.forEach((pool: Record<string, any>) => {
+ if (_.isUndefined(viewCacheStatusMap[pool.status])) {
+ viewCacheStatusMap[pool.status] = [];
+ }
+ viewCacheStatusMap[pool.status].push(pool.pool_name);
+ images = images.concat(pool.value);
+ this.disablePurgeBtn = !images.length;
+ });
+
+ let status: number;
+ if (viewCacheStatusMap[3]) {
+ status = 3;
+ } else if (viewCacheStatusMap[1]) {
+ status = 1;
+ } else if (viewCacheStatusMap[2]) {
+ status = 2;
+ }
+
+ if (status) {
+ const statusFor =
+ (viewCacheStatusMap[status].length > 1 ? 'pools ' : 'pool ') +
+ viewCacheStatusMap[status].join();
+
+ this.tableStatus = new TableStatusViewCache(status, statusFor);
+ } else {
+ this.tableStatus = new TableStatusViewCache();
+ }
+
+ images.forEach((image) => {
+ image.cdIsExpired = moment().isAfter(image.deferment_end_time);
+ });
+
+ return images;
+ }
+
+ onFetchError() {
+ this.table.reset(); // Disable loading indicator.
+ this.tableStatus = new TableStatusViewCache(ViewCacheStatus.ValueException);
+ }
+
+ updateSelection(selection: CdTableSelection) {
+ this.selection = selection;
+ }
+
+ restoreModal() {
+ const initialState = {
+ poolName: this.selection.first().pool_name,
+ namespace: this.selection.first().namespace,
+ imageName: this.selection.first().name,
+ imageId: this.selection.first().id
+ };
+
+ this.modalRef = this.modalService.show(RbdTrashRestoreModalComponent, initialState);
+ }
+
+ deleteModal() {
+ const poolName = this.selection.first().pool_name;
+ const namespace = this.selection.first().namespace;
+ const imageId = this.selection.first().id;
+ const expiresAt = this.selection.first().deferment_end_time;
+ const isExpired = moment().isAfter(expiresAt);
+ const imageIdSpec = new ImageSpec(poolName, namespace, imageId);
+
+ this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
+ itemDescription: 'RBD',
+ itemNames: [imageIdSpec],
+ bodyTemplate: this.deleteTpl,
+ bodyContext: { expiresAt, isExpired },
+ submitActionObservable: () =>
+ this.taskWrapper.wrapTaskAroundCall({
+ task: new FinishedTask('rbd/trash/remove', {
+ image_id_spec: imageIdSpec.toString()
+ }),
+ call: this.rbdService.removeTrash(imageIdSpec, true)
+ })
+ });
+ }
+
+ purgeModal() {
+ this.modalService.show(RbdTrashPurgeModalComponent);
+ }
+}