]>
Commit | Line | Data |
---|---|---|
9f95a23c | 1 | import { Component, Input, OnChanges, OnInit, ViewChild } from '@angular/core'; |
9f95a23c | 2 | |
adb31ebb TL |
3 | import { delay, finalize } from 'rxjs/operators'; |
4 | ||
f67539c2 TL |
5 | import { CephServiceService } from '~/app/shared/api/ceph-service.service'; |
6 | import { OrchestratorService } from '~/app/shared/api/orchestrator.service'; | |
7 | import { ListWithDetails } from '~/app/shared/classes/list-with-details.class'; | |
8 | import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component'; | |
9 | import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants'; | |
10 | import { TableComponent } from '~/app/shared/datatable/table/table.component'; | |
11 | import { CellTemplate } from '~/app/shared/enum/cell-template.enum'; | |
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 { FinishedTask } from '~/app/shared/models/finished-task'; | |
18 | import { OrchestratorFeature } from '~/app/shared/models/orchestrator.enum'; | |
19 | import { OrchestratorStatus } from '~/app/shared/models/orchestrator.interface'; | |
20 | import { Permissions } from '~/app/shared/models/permissions'; | |
21 | import { CephServiceSpec } from '~/app/shared/models/service.interface'; | |
22 | import { RelativeDatePipe } from '~/app/shared/pipes/relative-date.pipe'; | |
23 | import { AuthStorageService } from '~/app/shared/services/auth-storage.service'; | |
24 | import { ModalService } from '~/app/shared/services/modal.service'; | |
25 | import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service'; | |
26 | import { URLBuilderService } from '~/app/shared/services/url-builder.service'; | |
adb31ebb TL |
27 | import { PlacementPipe } from './placement.pipe'; |
28 | ||
29 | const BASE_URL = 'services'; | |
9f95a23c TL |
30 | |
31 | @Component({ | |
32 | selector: 'cd-services', | |
33 | templateUrl: './services.component.html', | |
adb31ebb TL |
34 | styleUrls: ['./services.component.scss'], |
35 | providers: [{ provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) }] | |
9f95a23c | 36 | }) |
e306af50 | 37 | export class ServicesComponent extends ListWithDetails implements OnChanges, OnInit { |
f67539c2 | 38 | @ViewChild(TableComponent, { static: true }) |
9f95a23c TL |
39 | table: TableComponent; |
40 | ||
41 | @Input() hostname: string; | |
42 | ||
43 | // Do not display these columns | |
44 | @Input() hiddenColumns: string[] = []; | |
45 | ||
46 | permissions: Permissions; | |
adb31ebb | 47 | tableActions: CdTableAction[]; |
f67539c2 | 48 | showDocPanel = false; |
9f95a23c | 49 | |
f67539c2 TL |
50 | orchStatus: OrchestratorStatus; |
51 | actionOrchFeatures = { | |
52 | create: [OrchestratorFeature.SERVICE_CREATE], | |
53 | delete: [OrchestratorFeature.SERVICE_DELETE] | |
54 | }; | |
9f95a23c TL |
55 | |
56 | columns: Array<CdTableColumn> = []; | |
1911f103 | 57 | services: Array<CephServiceSpec> = []; |
9f95a23c | 58 | isLoadingServices = false; |
adb31ebb | 59 | selection: CdTableSelection = new CdTableSelection(); |
9f95a23c TL |
60 | |
61 | constructor( | |
adb31ebb | 62 | private actionLabels: ActionLabelsI18n, |
9f95a23c | 63 | private authStorageService: AuthStorageService, |
f67539c2 | 64 | private modalService: ModalService, |
9f95a23c | 65 | private orchService: OrchestratorService, |
adb31ebb | 66 | private cephServiceService: CephServiceService, |
f67539c2 | 67 | private relativeDatePipe: RelativeDatePipe, |
adb31ebb TL |
68 | private taskWrapperService: TaskWrapperService, |
69 | private urlBuilder: URLBuilderService | |
9f95a23c | 70 | ) { |
e306af50 | 71 | super(); |
9f95a23c | 72 | this.permissions = this.authStorageService.getPermissions(); |
adb31ebb TL |
73 | this.tableActions = [ |
74 | { | |
75 | permission: 'create', | |
76 | icon: Icons.add, | |
77 | routerLink: () => this.urlBuilder.getCreate(), | |
78 | name: this.actionLabels.CREATE, | |
f67539c2 TL |
79 | canBePrimary: (selection: CdTableSelection) => !selection.hasSelection, |
80 | disable: (selection: CdTableSelection) => this.getDisable('create', selection) | |
adb31ebb TL |
81 | }, |
82 | { | |
83 | permission: 'delete', | |
84 | icon: Icons.destroy, | |
85 | click: () => this.deleteAction(), | |
f67539c2 TL |
86 | name: this.actionLabels.DELETE, |
87 | disable: (selection: CdTableSelection) => this.getDisable('delete', selection) | |
adb31ebb TL |
88 | } |
89 | ]; | |
9f95a23c TL |
90 | } |
91 | ||
92 | ngOnInit() { | |
93 | const columns = [ | |
94 | { | |
f67539c2 | 95 | name: $localize`Service`, |
9f95a23c TL |
96 | prop: 'service_name', |
97 | flexGrow: 1 | |
98 | }, | |
99 | { | |
f67539c2 | 100 | name: $localize`Container image name`, |
1911f103 | 101 | prop: 'status.container_image_name', |
9f95a23c TL |
102 | flexGrow: 3 |
103 | }, | |
104 | { | |
f67539c2 | 105 | name: $localize`Container image ID`, |
1911f103 TL |
106 | prop: 'status.container_image_id', |
107 | flexGrow: 3, | |
108 | cellTransformation: CellTemplate.truncate, | |
109 | customTemplateConfig: { | |
110 | length: 12 | |
111 | } | |
9f95a23c | 112 | }, |
adb31ebb | 113 | { |
f67539c2 | 114 | name: $localize`Placement`, |
adb31ebb | 115 | prop: '', |
f67539c2 | 116 | pipe: new PlacementPipe(), |
adb31ebb TL |
117 | flexGrow: 1 |
118 | }, | |
9f95a23c | 119 | { |
f67539c2 | 120 | name: $localize`Running`, |
1911f103 | 121 | prop: 'status.running', |
adb31ebb | 122 | flexGrow: 1 |
9f95a23c TL |
123 | }, |
124 | { | |
f67539c2 | 125 | name: $localize`Size`, |
1911f103 | 126 | prop: 'status.size', |
9f95a23c TL |
127 | flexGrow: 1 |
128 | }, | |
129 | { | |
f67539c2 | 130 | name: $localize`Last Refreshed`, |
1911f103 | 131 | prop: 'status.last_refresh', |
f67539c2 | 132 | pipe: this.relativeDatePipe, |
9f95a23c TL |
133 | flexGrow: 1 |
134 | } | |
135 | ]; | |
136 | ||
137 | this.columns = columns.filter((col: any) => { | |
138 | return !this.hiddenColumns.includes(col.prop); | |
139 | }); | |
140 | ||
f67539c2 TL |
141 | this.orchService.status().subscribe((status: OrchestratorStatus) => { |
142 | this.orchStatus = status; | |
adb31ebb | 143 | this.showDocPanel = !status.available; |
9f95a23c TL |
144 | }); |
145 | } | |
146 | ||
147 | ngOnChanges() { | |
f67539c2 | 148 | if (this.orchStatus?.available) { |
9f95a23c TL |
149 | this.services = []; |
150 | this.table.reloadData(); | |
151 | } | |
152 | } | |
153 | ||
f67539c2 TL |
154 | getDisable(action: 'create' | 'delete', selection: CdTableSelection): boolean | string { |
155 | if (action === 'delete') { | |
156 | if (!selection?.hasSingleSelection) { | |
157 | return true; | |
158 | } | |
159 | } | |
160 | return this.orchService.getTableActionDisableDesc( | |
161 | this.orchStatus, | |
162 | this.actionOrchFeatures[action] | |
163 | ); | |
164 | } | |
165 | ||
9f95a23c TL |
166 | getServices(context: CdTableFetchDataContext) { |
167 | if (this.isLoadingServices) { | |
168 | return; | |
169 | } | |
170 | this.isLoadingServices = true; | |
171 | this.cephServiceService.list().subscribe( | |
1911f103 | 172 | (services: CephServiceSpec[]) => { |
9f95a23c TL |
173 | this.services = services; |
174 | this.isLoadingServices = false; | |
175 | }, | |
176 | () => { | |
177 | this.isLoadingServices = false; | |
178 | this.services = []; | |
179 | context.error(); | |
180 | } | |
181 | ); | |
182 | } | |
adb31ebb TL |
183 | |
184 | updateSelection(selection: CdTableSelection) { | |
185 | this.selection = selection; | |
186 | } | |
187 | ||
188 | deleteAction() { | |
189 | const service = this.selection.first(); | |
f67539c2 TL |
190 | this.modalService.show(CriticalConfirmationModalComponent, { |
191 | itemDescription: $localize`Service`, | |
192 | itemNames: [service.service_name], | |
193 | actionDescription: 'delete', | |
194 | submitActionObservable: () => | |
195 | this.taskWrapperService | |
196 | .wrapTaskAroundCall({ | |
197 | task: new FinishedTask(`service/${URLVerbs.DELETE}`, { | |
198 | service_name: service.service_name | |
199 | }), | |
200 | call: this.cephServiceService.delete(service.service_name) | |
201 | }) | |
202 | .pipe( | |
203 | // Delay closing the dialog, otherwise the datatable still | |
204 | // shows the deleted service after forcing a reload. | |
205 | // Showing the dialog while delaying is done to increase | |
206 | // the user experience. | |
207 | delay(2000), | |
208 | finalize(() => { | |
209 | // Force reloading the data table content because it is | |
210 | // auto-reloaded only every 60s. | |
211 | this.table.refreshBtn(); | |
adb31ebb | 212 | }) |
f67539c2 | 213 | ) |
adb31ebb TL |
214 | }); |
215 | } | |
9f95a23c | 216 | } |