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