]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-list/rbd-trash-list.component.ts
import ceph 14.2.5
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / block / rbd-trash-list / rbd-trash-list.component.ts
1 import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
2
3 import { I18n } from '@ngx-translate/i18n-polyfill';
4 import * as _ from 'lodash';
5 import * as moment from 'moment';
6 import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
7
8 import { RbdService } from '../../../shared/api/rbd.service';
9 import { CriticalConfirmationModalComponent } from '../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
10 import { ActionLabelsI18n } from '../../../shared/constants/app.constants';
11 import { TableComponent } from '../../../shared/datatable/table/table.component';
12 import { CellTemplate } from '../../../shared/enum/cell-template.enum';
13 import { ViewCacheStatus } from '../../../shared/enum/view-cache-status.enum';
14 import { CdTableAction } from '../../../shared/models/cd-table-action';
15 import { CdTableColumn } from '../../../shared/models/cd-table-column';
16 import { CdTableSelection } from '../../../shared/models/cd-table-selection';
17 import { ExecutingTask } from '../../../shared/models/executing-task';
18 import { FinishedTask } from '../../../shared/models/finished-task';
19 import { Permission } from '../../../shared/models/permissions';
20 import { CdDatePipe } from '../../../shared/pipes/cd-date.pipe';
21 import { AuthStorageService } from '../../../shared/services/auth-storage.service';
22 import { TaskListService } from '../../../shared/services/task-list.service';
23 import { TaskWrapperService } from '../../../shared/services/task-wrapper.service';
24 import { RbdTrashPurgeModalComponent } from '../rbd-trash-purge-modal/rbd-trash-purge-modal.component';
25 import { RbdTrashRestoreModalComponent } from '../rbd-trash-restore-modal/rbd-trash-restore-modal.component';
26
27 @Component({
28 selector: 'cd-rbd-trash-list',
29 templateUrl: './rbd-trash-list.component.html',
30 styleUrls: ['./rbd-trash-list.component.scss'],
31 providers: [TaskListService]
32 })
33 export class RbdTrashListComponent implements OnInit {
34 @ViewChild(TableComponent)
35 table: TableComponent;
36 @ViewChild('expiresTpl')
37 expiresTpl: TemplateRef<any>;
38 @ViewChild('deleteTpl')
39 deleteTpl: TemplateRef<any>;
40
41 columns: CdTableColumn[];
42 executingTasks: ExecutingTask[] = [];
43 images: any;
44 modalRef: BsModalRef;
45 permission: Permission;
46 retries: number;
47 selection = new CdTableSelection();
48 tableActions: CdTableAction[];
49 viewCacheStatusList: any[];
50
51 constructor(
52 private authStorageService: AuthStorageService,
53 private rbdService: RbdService,
54 private modalService: BsModalService,
55 private cdDatePipe: CdDatePipe,
56 private taskListService: TaskListService,
57 private taskWrapper: TaskWrapperService,
58 private i18n: I18n,
59 public actionLabels: ActionLabelsI18n
60 ) {
61 this.permission = this.authStorageService.getPermissions().rbdImage;
62
63 const restoreAction: CdTableAction = {
64 permission: 'update',
65 icon: 'fa-undo',
66 click: () => this.restoreModal(),
67 name: this.actionLabels.RESTORE
68 };
69 const deleteAction: CdTableAction = {
70 permission: 'delete',
71 icon: 'fa-times',
72 click: () => this.deleteModal(),
73 name: this.actionLabels.DELETE
74 };
75 this.tableActions = [restoreAction, deleteAction];
76 }
77
78 ngOnInit() {
79 this.columns = [
80 {
81 name: this.i18n('ID'),
82 prop: 'id',
83 flexGrow: 1,
84 cellTransformation: CellTemplate.executing
85 },
86 {
87 name: this.i18n('Name'),
88 prop: 'name',
89 flexGrow: 1
90 },
91 {
92 name: this.i18n('Pool'),
93 prop: 'pool_name',
94 flexGrow: 1
95 },
96 {
97 name: this.i18n('Status'),
98 prop: 'deferment_end_time',
99 flexGrow: 1,
100 cellTemplate: this.expiresTpl
101 },
102 {
103 name: this.i18n('Deleted At'),
104 prop: 'deletion_time',
105 flexGrow: 1,
106 pipe: this.cdDatePipe
107 }
108 ];
109
110 this.taskListService.init(
111 () => this.rbdService.listTrash(),
112 (resp) => this.prepareResponse(resp),
113 (images) => (this.images = images),
114 () => this.onFetchError(),
115 this.taskFilter,
116 this.itemFilter,
117 undefined
118 );
119 }
120
121 prepareResponse(resp: any[]): any[] {
122 let images = [];
123 const viewCacheStatusMap = {};
124 resp.forEach((pool) => {
125 if (_.isUndefined(viewCacheStatusMap[pool.status])) {
126 viewCacheStatusMap[pool.status] = [];
127 }
128 viewCacheStatusMap[pool.status].push(pool.pool_name);
129 images = images.concat(pool.value);
130 });
131
132 const viewCacheStatusList = [];
133 _.forEach(viewCacheStatusMap, (value: any, key) => {
134 viewCacheStatusList.push({
135 status: parseInt(key, 10),
136 statusFor:
137 (value.length > 1 ? 'pools ' : 'pool ') +
138 '<strong>' +
139 value.join('</strong>, <strong>') +
140 '</strong>'
141 });
142 });
143 this.viewCacheStatusList = viewCacheStatusList;
144 images.forEach((image) => {
145 image.cdIsExpired = moment().isAfter(image.deferment_end_time);
146 });
147 return images;
148 }
149
150 onFetchError() {
151 this.table.reset(); // Disable loading indicator.
152 this.viewCacheStatusList = [{ status: ViewCacheStatus.ValueException }];
153 }
154
155 itemFilter(entry, task) {
156 return entry.id === task.metadata['image_id'];
157 }
158
159 taskFilter(task) {
160 return ['rbd/trash/remove', 'rbd/trash/restore'].includes(task.name);
161 }
162
163 updateSelection(selection: CdTableSelection) {
164 this.selection = selection;
165 }
166
167 restoreModal() {
168 const initialState = {
169 metaType: 'RBD',
170 poolName: this.selection.first().pool_name,
171 imageName: this.selection.first().name,
172 imageId: this.selection.first().id
173 };
174
175 this.modalRef = this.modalService.show(RbdTrashRestoreModalComponent, { initialState });
176 }
177
178 deleteModal() {
179 const poolName = this.selection.first().pool_name;
180 const imageName = this.selection.first().name;
181 const imageId = this.selection.first().id;
182 const expiresAt = this.selection.first().deferment_end_time;
183
184 this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
185 initialState: {
186 itemDescription: 'RBD',
187 itemNames: [`${poolName}/${imageName}`],
188 bodyTemplate: this.deleteTpl,
189 bodyContext: { $implicit: expiresAt },
190 submitActionObservable: () =>
191 this.taskWrapper.wrapTaskAroundCall({
192 task: new FinishedTask('rbd/trash/remove', {
193 pool_name: poolName,
194 image_id: imageId,
195 image_name: imageName
196 }),
197 call: this.rbdService.removeTrash(poolName, imageId, imageName, true)
198 })
199 }
200 });
201 }
202
203 isExpired(expiresAt): boolean {
204 return moment().isAfter(expiresAt);
205 }
206
207 purgeModal() {
208 this.modalService.show(RbdTrashPurgeModalComponent);
209 }
210 }