]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
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 { BsModalRef, BsModalService } from 'ngx-bootstrap/modal'; | |
6 | ||
7 | import { PoolService } from '../../../shared/api/pool.service'; | |
8 | import { CriticalConfirmationModalComponent } from '../../../shared/components/critical-confirmation-modal/critical-confirmation-modal.component'; | |
9 | import { ActionLabelsI18n, URLVerbs } from '../../../shared/constants/app.constants'; | |
10 | import { TableComponent } from '../../../shared/datatable/table/table.component'; | |
11 | import { CellTemplate } from '../../../shared/enum/cell-template.enum'; | |
12 | import { ViewCacheStatus } from '../../../shared/enum/view-cache-status.enum'; | |
13 | import { CdTableAction } from '../../../shared/models/cd-table-action'; | |
14 | import { CdTableColumn } from '../../../shared/models/cd-table-column'; | |
15 | import { CdTableSelection } from '../../../shared/models/cd-table-selection'; | |
16 | import { ExecutingTask } from '../../../shared/models/executing-task'; | |
17 | import { FinishedTask } from '../../../shared/models/finished-task'; | |
18 | import { Permissions } from '../../../shared/models/permissions'; | |
19 | import { DimlessPipe } from '../../../shared/pipes/dimless.pipe'; | |
20 | import { AuthStorageService } from '../../../shared/services/auth-storage.service'; | |
21 | import { TaskListService } from '../../../shared/services/task-list.service'; | |
22 | import { TaskWrapperService } from '../../../shared/services/task-wrapper.service'; | |
23 | import { URLBuilderService } from '../../../shared/services/url-builder.service'; | |
24 | import { PgCategoryService } from '../../shared/pg-category.service'; | |
25 | import { Pool } from '../pool'; | |
26 | ||
27 | const BASE_URL = 'pool'; | |
28 | ||
29 | @Component({ | |
30 | selector: 'cd-pool-list', | |
31 | templateUrl: './pool-list.component.html', | |
32 | providers: [ | |
33 | TaskListService, | |
34 | { provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) } | |
35 | ], | |
36 | styleUrls: ['./pool-list.component.scss'] | |
37 | }) | |
38 | export class PoolListComponent implements OnInit { | |
39 | @ViewChild(TableComponent) | |
40 | table: TableComponent; | |
41 | @ViewChild('poolUsageTpl') | |
42 | poolUsageTpl: TemplateRef<any>; | |
43 | ||
44 | @ViewChild('poolConfigurationSourceTpl') | |
45 | poolConfigurationSourceTpl: TemplateRef<any>; | |
46 | ||
47 | pools: Pool[] = []; | |
48 | columns: CdTableColumn[]; | |
49 | selection = new CdTableSelection(); | |
50 | modalRef: BsModalRef; | |
51 | executingTasks: ExecutingTask[] = []; | |
52 | permissions: Permissions; | |
53 | tableActions: CdTableAction[]; | |
54 | viewCacheStatusList: any[]; | |
55 | selectionCacheTiers: any[] = []; | |
56 | ||
57 | constructor( | |
58 | private poolService: PoolService, | |
59 | private taskWrapper: TaskWrapperService, | |
60 | private authStorageService: AuthStorageService, | |
61 | private taskListService: TaskListService, | |
62 | private modalService: BsModalService, | |
63 | private i18n: I18n, | |
64 | private pgCategoryService: PgCategoryService, | |
65 | private dimlessPipe: DimlessPipe, | |
66 | private urlBuilder: URLBuilderService, | |
67 | public actionLabels: ActionLabelsI18n | |
68 | ) { | |
69 | this.permissions = this.authStorageService.getPermissions(); | |
70 | this.tableActions = [ | |
71 | { | |
72 | permission: 'create', | |
73 | icon: 'fa-plus', | |
74 | routerLink: () => this.urlBuilder.getCreate(), | |
75 | name: this.actionLabels.CREATE | |
76 | }, | |
77 | { | |
78 | permission: 'update', | |
79 | icon: 'fa-pencil', | |
80 | routerLink: () => | |
81 | this.urlBuilder.getEdit(encodeURIComponent(this.selection.first().pool_name)), | |
82 | name: this.actionLabels.EDIT | |
83 | }, | |
84 | { | |
85 | permission: 'delete', | |
86 | icon: 'fa-trash-o', | |
87 | click: () => this.deletePoolModal(), | |
88 | name: this.actionLabels.DELETE | |
89 | } | |
90 | ]; | |
91 | } | |
92 | ||
93 | ngOnInit() { | |
94 | this.columns = [ | |
95 | { | |
96 | prop: 'pool_name', | |
97 | name: this.i18n('Name'), | |
98 | flexGrow: 4, | |
99 | cellTransformation: CellTemplate.executing | |
100 | }, | |
101 | { | |
102 | prop: 'type', | |
103 | name: this.i18n('Type'), | |
104 | flexGrow: 2 | |
105 | }, | |
106 | { | |
107 | prop: 'application_metadata', | |
108 | name: this.i18n('Applications'), | |
109 | flexGrow: 2 | |
110 | }, | |
111 | { | |
112 | prop: 'pg_status', | |
113 | name: this.i18n('PG Status'), | |
114 | flexGrow: 3, | |
115 | cellClass: ({ row, column, value }): any => { | |
116 | return this.getPgStatusCellClass(row, column, value); | |
117 | } | |
118 | }, | |
119 | { | |
120 | prop: 'size', | |
121 | name: this.i18n('Replica Size'), | |
122 | flexGrow: 1, | |
123 | cellClass: 'text-right' | |
124 | }, | |
125 | { | |
126 | prop: 'last_change', | |
127 | name: this.i18n('Last Change'), | |
128 | flexGrow: 1, | |
129 | cellClass: 'text-right' | |
130 | }, | |
131 | { | |
132 | prop: 'erasure_code_profile', | |
133 | name: this.i18n('Erasure Coded Profile'), | |
134 | flexGrow: 2 | |
135 | }, | |
136 | { | |
137 | prop: 'crush_rule', | |
138 | name: this.i18n('Crush Ruleset'), | |
139 | flexGrow: 3 | |
140 | }, | |
141 | { name: this.i18n('Usage'), cellTemplate: this.poolUsageTpl, flexGrow: 3 }, | |
142 | { | |
143 | prop: 'stats.rd_bytes.series', | |
144 | name: this.i18n('Read bytes'), | |
145 | cellTransformation: CellTemplate.sparkline, | |
146 | flexGrow: 3 | |
147 | }, | |
148 | { | |
149 | prop: 'stats.wr_bytes.series', | |
150 | name: this.i18n('Write bytes'), | |
151 | cellTransformation: CellTemplate.sparkline, | |
152 | flexGrow: 3 | |
153 | }, | |
154 | { | |
155 | prop: 'stats.rd.rate', | |
156 | name: this.i18n('Read ops'), | |
157 | flexGrow: 1, | |
158 | pipe: this.dimlessPipe, | |
159 | cellTransformation: CellTemplate.perSecond | |
160 | }, | |
161 | { | |
162 | prop: 'stats.wr.rate', | |
163 | name: this.i18n('Write ops'), | |
164 | flexGrow: 1, | |
165 | pipe: this.dimlessPipe, | |
166 | cellTransformation: CellTemplate.perSecond | |
167 | } | |
168 | ]; | |
169 | ||
170 | this.taskListService.init( | |
171 | () => this.poolService.getList(), | |
172 | undefined, | |
173 | (pools) => (this.pools = this.transformPoolsData(pools)), | |
174 | () => { | |
175 | this.table.reset(); // Disable loading indicator. | |
176 | this.viewCacheStatusList = [{ status: ViewCacheStatus.ValueException }]; | |
177 | }, | |
178 | (task) => task.name.startsWith(`${BASE_URL}/`), | |
179 | (pool, task) => task.metadata['pool_name'] === pool.pool_name, | |
180 | { default: (task: ExecutingTask) => new Pool(task.metadata['pool_name']) } | |
181 | ); | |
182 | } | |
183 | ||
184 | updateSelection(selection: CdTableSelection) { | |
185 | this.selection = selection; | |
186 | this.getSelectionTiers(); | |
187 | } | |
188 | ||
189 | deletePoolModal() { | |
190 | const name = this.selection.first().pool_name; | |
191 | this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, { | |
192 | initialState: { | |
193 | itemDescription: 'Pool', | |
194 | submitActionObservable: () => | |
195 | this.taskWrapper.wrapTaskAroundCall({ | |
196 | task: new FinishedTask(`${BASE_URL}/${URLVerbs.DELETE}`, { pool_name: name }), | |
197 | call: this.poolService.delete(name) | |
198 | }) | |
199 | } | |
200 | }); | |
201 | } | |
202 | ||
203 | getPgStatusCellClass(_row, _column, value): object { | |
204 | return { | |
205 | 'text-right': true, | |
206 | [`pg-${this.pgCategoryService.getTypeByStates(value)}`]: true | |
207 | }; | |
208 | } | |
209 | ||
210 | transformPoolsData(pools: any) { | |
211 | const requiredStats = ['bytes_used', 'max_avail', 'rd_bytes', 'wr_bytes', 'rd', 'wr']; | |
212 | const emptyStat = { latest: 0, rate: 0, series: [] }; | |
213 | ||
214 | _.forEach(pools, (pool: Pool) => { | |
215 | pool['pg_status'] = this.transformPgStatus(pool['pg_status']); | |
216 | const stats = {}; | |
217 | _.forEach(requiredStats, (stat) => { | |
218 | stats[stat] = pool.stats && pool.stats[stat] ? pool.stats[stat] : emptyStat; | |
219 | }); | |
220 | pool['stats'] = stats; | |
221 | ||
222 | ['rd_bytes', 'wr_bytes'].forEach((stat) => { | |
223 | pool.stats[stat].series = pool.stats[stat].series.map((point) => point[1]); | |
224 | }); | |
225 | pool.cdIsBinary = true; | |
226 | }); | |
227 | ||
228 | return pools; | |
229 | } | |
230 | ||
231 | transformPgStatus(pgStatus: any): string { | |
232 | const strings = []; | |
233 | _.forEach(pgStatus, (count, state) => { | |
234 | strings.push(`${count} ${state}`); | |
235 | }); | |
236 | ||
237 | return strings.join(', '); | |
238 | } | |
239 | ||
240 | getPoolDetails(pool: object) { | |
241 | return _.omit(pool, ['cdExecuting', 'cdIsBinary']); | |
242 | } | |
243 | ||
244 | getSelectionTiers() { | |
245 | const cacheTierIds = this.selection.hasSingleSelection ? this.selection.first()['tiers'] : []; | |
246 | this.selectionCacheTiers = this.pools.filter((pool) => cacheTierIds.includes(pool.pool)); | |
247 | } | |
248 | } |