]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-bucket-list/rgw-bucket-list.component.ts
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / rgw / rgw-bucket-list / rgw-bucket-list.component.ts
1 import { Component, NgZone, OnInit, TemplateRef, ViewChild } from '@angular/core';
2
3 import _ from 'lodash';
4 import { forkJoin as observableForkJoin, Observable, Subscriber } from 'rxjs';
5
6 import { RgwBucketService } from '~/app/shared/api/rgw-bucket.service';
7 import { ListWithDetails } from '~/app/shared/classes/list-with-details.class';
8 import { TableStatus } from '~/app/shared/classes/table-status';
9 import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
10 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
11 import { TableComponent } from '~/app/shared/datatable/table/table.component';
12 import { Icons } from '~/app/shared/enum/icons.enum';
13 import { CdTableAction } from '~/app/shared/models/cd-table-action';
14 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
15 import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
16 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
17 import { Permission } from '~/app/shared/models/permissions';
18 import { DimlessBinaryPipe } from '~/app/shared/pipes/dimless-binary.pipe';
19 import { DimlessPipe } from '~/app/shared/pipes/dimless.pipe';
20 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
21 import { ModalService } from '~/app/shared/services/modal.service';
22 import { URLBuilderService } from '~/app/shared/services/url-builder.service';
23
24 const BASE_URL = 'rgw/bucket';
25
26 @Component({
27 selector: 'cd-rgw-bucket-list',
28 templateUrl: './rgw-bucket-list.component.html',
29 styleUrls: ['./rgw-bucket-list.component.scss'],
30 providers: [{ provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) }]
31 })
32 export class RgwBucketListComponent extends ListWithDetails implements OnInit {
33 @ViewChild(TableComponent, { static: true })
34 table: TableComponent;
35 @ViewChild('bucketSizeTpl', { static: true })
36 bucketSizeTpl: TemplateRef<any>;
37 @ViewChild('bucketObjectTpl', { static: true })
38 bucketObjectTpl: TemplateRef<any>;
39
40 permission: Permission;
41 tableActions: CdTableAction[];
42 columns: CdTableColumn[] = [];
43 buckets: object[] = [];
44 selection: CdTableSelection = new CdTableSelection();
45 tableStatus = new TableStatus();
46 staleTimeout: number;
47
48 constructor(
49 private authStorageService: AuthStorageService,
50 private dimlessBinaryPipe: DimlessBinaryPipe,
51 private dimlessPipe: DimlessPipe,
52 private rgwBucketService: RgwBucketService,
53 private modalService: ModalService,
54 private urlBuilder: URLBuilderService,
55 public actionLabels: ActionLabelsI18n,
56 private ngZone: NgZone
57 ) {
58 super();
59 }
60
61 ngOnInit() {
62 this.permission = this.authStorageService.getPermissions().rgw;
63 this.columns = [
64 {
65 name: $localize`Name`,
66 prop: 'bid',
67 flexGrow: 2
68 },
69 {
70 name: $localize`Owner`,
71 prop: 'owner',
72 flexGrow: 2.5
73 },
74 {
75 name: $localize`Used Capacity`,
76 prop: 'bucket_size',
77 flexGrow: 0.6,
78 pipe: this.dimlessBinaryPipe
79 },
80 {
81 name: $localize`Capacity Limit %`,
82 prop: 'size_usage',
83 cellTemplate: this.bucketSizeTpl,
84 flexGrow: 0.8
85 },
86 {
87 name: $localize`Objects`,
88 prop: 'num_objects',
89 flexGrow: 0.6,
90 pipe: this.dimlessPipe
91 },
92 {
93 name: $localize`Object Limit %`,
94 prop: 'object_usage',
95 cellTemplate: this.bucketObjectTpl,
96 flexGrow: 0.8
97 }
98 ];
99 const getBucketUri = () =>
100 this.selection.first() && `${encodeURIComponent(this.selection.first().bid)}`;
101 const addAction: CdTableAction = {
102 permission: 'create',
103 icon: Icons.add,
104 routerLink: () => this.urlBuilder.getCreate(),
105 name: this.actionLabels.CREATE,
106 canBePrimary: (selection: CdTableSelection) => !selection.hasSelection
107 };
108 const editAction: CdTableAction = {
109 permission: 'update',
110 icon: Icons.edit,
111 routerLink: () => this.urlBuilder.getEdit(getBucketUri()),
112 name: this.actionLabels.EDIT
113 };
114 const deleteAction: CdTableAction = {
115 permission: 'delete',
116 icon: Icons.destroy,
117 click: () => this.deleteAction(),
118 disable: () => !this.selection.hasSelection,
119 name: this.actionLabels.DELETE,
120 canBePrimary: (selection: CdTableSelection) => selection.hasMultiSelection
121 };
122 this.tableActions = [addAction, editAction, deleteAction];
123 this.timeConditionReached();
124 }
125
126 transformBucketData() {
127 _.forEach(this.buckets, (bucketKey) => {
128 const usageList = bucketKey['usage'];
129 const maxBucketSize = bucketKey['bucket_quota']['max_size'];
130 const maxBucketObjects = bucketKey['bucket_quota']['max_objects'];
131 let totalBucketSize = 0;
132 let numOfObjects = 0;
133 _.forEach(usageList, (usageKey) => {
134 totalBucketSize = totalBucketSize + usageKey.size_actual;
135 numOfObjects = numOfObjects + usageKey.num_objects;
136 });
137 bucketKey['bucket_size'] = totalBucketSize;
138 bucketKey['num_objects'] = numOfObjects;
139 bucketKey['size_usage'] = maxBucketSize > 0 ? totalBucketSize / maxBucketSize : undefined;
140 bucketKey['object_usage'] =
141 maxBucketObjects > 0 ? numOfObjects / maxBucketObjects : undefined;
142 });
143 }
144
145 timeConditionReached() {
146 clearTimeout(this.staleTimeout);
147 this.ngZone.runOutsideAngular(() => {
148 this.staleTimeout = window.setTimeout(() => {
149 this.ngZone.run(() => {
150 this.tableStatus = new TableStatus(
151 'warning',
152 $localize`The bucket list data might be stale. If needed, you can manually reload it.`
153 );
154 });
155 }, 10000);
156 });
157 }
158
159 getBucketList(context: CdTableFetchDataContext) {
160 this.tableStatus = new TableStatus();
161 this.timeConditionReached();
162 this.rgwBucketService.list().subscribe(
163 (resp: object[]) => {
164 this.buckets = resp;
165 this.transformBucketData();
166 },
167 () => {
168 context.error();
169 }
170 );
171 }
172
173 updateSelection(selection: CdTableSelection) {
174 this.selection = selection;
175 }
176
177 deleteAction() {
178 this.modalService.show(CriticalConfirmationModalComponent, {
179 itemDescription: this.selection.hasSingleSelection ? $localize`bucket` : $localize`buckets`,
180 itemNames: this.selection.selected.map((bucket: any) => bucket['bid']),
181 submitActionObservable: () => {
182 return new Observable((observer: Subscriber<any>) => {
183 // Delete all selected data table rows.
184 observableForkJoin(
185 this.selection.selected.map((bucket: any) => {
186 return this.rgwBucketService.delete(bucket.bid);
187 })
188 ).subscribe({
189 error: (error) => {
190 // Forward the error to the observer.
191 observer.error(error);
192 // Reload the data table content because some deletions might
193 // have been executed successfully in the meanwhile.
194 this.table.refreshBtn();
195 },
196 complete: () => {
197 // Notify the observer that we are done.
198 observer.complete();
199 // Reload the data table content.
200 this.table.refreshBtn();
201 }
202 });
203 });
204 }
205 });
206 }
207 }