1 import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
3 import { I18n } from '@ngx-translate/i18n-polyfill';
4 import * as _ from 'lodash';
5 import { BsModalRef, BsModalService } from 'ngx-bootstrap/modal';
7 import { RbdService } from '../../../shared/api/rbd.service';
8 import { ConfirmationModalComponent } from '../../../shared/components/confirmation-modal/confirmation-modal.component';
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 { FinishedTask } from '../../../shared/models/finished-task';
18 import { Permission } from '../../../shared/models/permissions';
19 import { DimlessBinaryPipe } from '../../../shared/pipes/dimless-binary.pipe';
20 import { DimlessPipe } from '../../../shared/pipes/dimless.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 { URLBuilderService } from '../../../shared/services/url-builder.service';
25 import { RbdParentModel } from '../rbd-form/rbd-parent.model';
26 import { RbdTrashMoveModalComponent } from '../rbd-trash-move-modal/rbd-trash-move-modal.component';
27 import { RbdModel } from './rbd-model';
29 const BASE_URL = 'block/rbd';
32 selector: 'cd-rbd-list',
33 templateUrl: './rbd-list.component.html',
34 styleUrls: ['./rbd-list.component.scss'],
37 { provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) }
40 export class RbdListComponent implements OnInit {
41 @ViewChild(TableComponent)
42 table: TableComponent;
43 @ViewChild('usageTpl')
44 usageTpl: TemplateRef<any>;
45 @ViewChild('parentTpl')
46 parentTpl: TemplateRef<any>;
48 nameTpl: TemplateRef<any>;
49 @ViewChild('flattenTpl')
50 flattenTpl: TemplateRef<any>;
52 permission: Permission;
53 tableActions: CdTableAction[];
55 columns: CdTableColumn[];
57 viewCacheStatusList: any[];
58 selection = new CdTableSelection();
63 'rbd/create': (metadata) =>
64 this.createRbdFromTask(metadata['pool_name'], metadata['image_name']),
65 'rbd/clone': (metadata) =>
66 this.createRbdFromTask(metadata['child_pool_name'], metadata['child_image_name']),
67 'rbd/copy': (metadata) =>
68 this.createRbdFromTask(metadata['dest_pool_name'], metadata['dest_image_name'])
71 private createRbdFromTask(pool: string, name: string): RbdModel {
72 const model = new RbdModel();
75 model.pool_name = pool;
80 private authStorageService: AuthStorageService,
81 private rbdService: RbdService,
82 private dimlessBinaryPipe: DimlessBinaryPipe,
83 private dimlessPipe: DimlessPipe,
84 private modalService: BsModalService,
85 private taskWrapper: TaskWrapperService,
86 private taskListService: TaskListService,
88 private urlBuilder: URLBuilderService,
89 public actionLabels: ActionLabelsI18n
91 this.permission = this.authStorageService.getPermissions().rbdImage;
92 const getImageUri = () =>
93 this.selection.first() &&
94 `${encodeURIComponent(this.selection.first().pool_name)}/${encodeURIComponent(
95 this.selection.first().name
97 const addAction: CdTableAction = {
100 routerLink: () => this.urlBuilder.getCreate(),
101 canBePrimary: (selection: CdTableSelection) => !selection.hasSingleSelection,
102 name: this.actionLabels.CREATE
104 const editAction: CdTableAction = {
105 permission: 'update',
107 routerLink: () => this.urlBuilder.getEdit(getImageUri()),
108 name: this.actionLabels.EDIT
110 const deleteAction: CdTableAction = {
111 permission: 'delete',
113 click: () => this.deleteRbdModal(),
114 name: this.actionLabels.DELETE
116 const copyAction: CdTableAction = {
117 permission: 'create',
118 canBePrimary: (selection: CdTableSelection) => selection.hasSingleSelection,
119 disable: (selection: CdTableSelection) =>
120 !selection.hasSingleSelection || selection.first().cdExecuting,
122 routerLink: () => `/block/rbd/copy/${getImageUri()}`,
123 name: this.actionLabels.COPY
125 const flattenAction: CdTableAction = {
126 permission: 'update',
127 disable: (selection: CdTableSelection) =>
128 !selection.hasSingleSelection || selection.first().cdExecuting || !selection.first().parent,
129 icon: 'fa-chain-broken',
130 click: () => this.flattenRbdModal(),
131 name: this.actionLabels.FLATTEN
133 const moveAction: CdTableAction = {
134 permission: 'delete',
136 click: () => this.trashRbdModal(),
137 name: this.actionLabels.TRASH
139 this.tableActions = [
152 name: this.i18n('Name'),
155 cellTransformation: CellTemplate.executing
158 name: this.i18n('Pool'),
163 name: this.i18n('Size'),
166 cellClass: 'text-right',
167 pipe: this.dimlessBinaryPipe
170 name: this.i18n('Objects'),
173 cellClass: 'text-right',
174 pipe: this.dimlessPipe
177 name: this.i18n('Object size'),
180 cellClass: 'text-right',
181 pipe: this.dimlessBinaryPipe
184 name: this.i18n('Provisioned'),
186 cellClass: 'text-center',
188 pipe: this.dimlessBinaryPipe
191 name: this.i18n('Total provisioned'),
192 prop: 'total_disk_usage',
193 cellClass: 'text-center',
195 pipe: this.dimlessBinaryPipe
198 name: this.i18n('Parent'),
201 cellTemplate: this.parentTpl
205 this.taskListService.init(
206 () => this.rbdService.list(),
207 (resp) => this.prepareResponse(resp),
208 (images) => (this.images = images),
209 () => this.onFetchError(),
217 this.table.reset(); // Disable loading indicator.
218 this.viewCacheStatusList = [{ status: ViewCacheStatus.ValueException }];
221 prepareResponse(resp: any[]): any[] {
223 const viewCacheStatusMap = {};
224 resp.forEach((pool) => {
225 if (_.isUndefined(viewCacheStatusMap[pool.status])) {
226 viewCacheStatusMap[pool.status] = [];
228 viewCacheStatusMap[pool.status].push(pool.pool_name);
229 images = images.concat(pool.value);
231 const viewCacheStatusList = [];
232 _.forEach(viewCacheStatusMap, (value: any, key) => {
233 viewCacheStatusList.push({
234 status: parseInt(key, 10),
236 (value.length > 1 ? 'pools ' : 'pool ') +
238 value.join('</strong>, <strong>') +
242 this.viewCacheStatusList = viewCacheStatusList;
246 itemFilter(entry, task) {
247 let pool_name_k: string;
248 let image_name_k: string;
251 pool_name_k = 'dest_pool_name';
252 image_name_k = 'dest_image_name';
255 pool_name_k = 'child_pool_name';
256 image_name_k = 'child_image_name';
259 pool_name_k = 'pool_name';
260 image_name_k = 'image_name';
264 entry.pool_name === task.metadata[pool_name_k] && entry.name === task.metadata[image_name_k]
277 ].includes(task.name);
280 updateSelection(selection: CdTableSelection) {
281 this.selection = selection;
285 const poolName = this.selection.first().pool_name;
286 const imageName = this.selection.first().name;
288 this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
290 itemDescription: 'RBD',
291 itemNames: [`${poolName}/${imageName}`],
292 submitActionObservable: () =>
293 this.taskWrapper.wrapTaskAroundCall({
294 task: new FinishedTask('rbd/delete', {
296 image_name: imageName
298 call: this.rbdService.delete(poolName, imageName)
305 const initialState = {
307 poolName: this.selection.first().pool_name,
308 imageName: this.selection.first().name
310 this.modalRef = this.modalService.show(RbdTrashMoveModalComponent, { initialState });
313 flattenRbd(poolName, imageName) {
315 .wrapTaskAroundCall({
316 task: new FinishedTask('rbd/flatten', {
318 image_name: imageName
320 call: this.rbdService.flatten(poolName, imageName)
322 .subscribe(undefined, undefined, () => {
323 this.modalRef.hide();
328 const poolName = this.selection.first().pool_name;
329 const imageName = this.selection.first().name;
330 const parent: RbdParentModel = this.selection.first().parent;
332 const initialState = {
333 titleText: 'RBD flatten',
334 buttonText: 'Flatten',
335 bodyTpl: this.flattenTpl,
337 parent: `${parent.pool_name}/${parent.image_name}@${parent.snap_name}`,
338 child: `${poolName}/${imageName}`
341 this.flattenRbd(poolName, imageName);
345 this.modalRef = this.modalService.show(ConfirmationModalComponent, { initialState });