]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/blob
5dcca32b006dd43e5e4ee42bb42c60944719e6b1
[ceph-ci.git] /
1 import { Component, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';
2 import { BehaviorSubject, forkJoin, Observable, of } from 'rxjs';
3 import { catchError, map, switchMap, tap } from 'rxjs/operators';
4 import { GatewayGroup, NvmeofService } from '~/app/shared/api/nvmeof.service';
5 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
6 import { TableComponent } from '~/app/shared/datatable/table/table.component';
7 import { CdTableAction } from '~/app/shared/models/cd-table-action';
8 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
9 import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
10 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
11 import { Permission } from '~/app/shared/models/permissions';
12 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
13 import { Icons, IconSize } from '~/app/shared/enum/icons.enum';
14 import { NvmeofGatewayGroup } from '~/app/shared/models/nvmeof';
15 import { CephServiceSpec } from '~/app/shared/models/service.interface';
16 import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
17 import { CephServiceService } from '~/app/shared/api/ceph-service.service';
18 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
19 import { DeleteConfirmationModalComponent } from '~/app/shared/components/delete-confirmation-modal/delete-confirmation-modal.component';
20 import { FinishedTask } from '~/app/shared/models/finished-task';
21 import { DeletionImpact } from '~/app/shared/enum/delete-confirmation-modal-impact.enum';
22 import { NotificationService } from '~/app/shared/services/notification.service';
23 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
24
25 @Component({
26   selector: 'cd-nvmeof-gateway-group',
27   templateUrl: './nvmeof-gateway-group.component.html',
28   styleUrls: ['./nvmeof-gateway-group.component.scss'],
29   standalone: false,
30   encapsulation: ViewEncapsulation.None
31 })
32 export class NvmeofGatewayGroupComponent implements OnInit {
33   @ViewChild(TableComponent, { static: true })
34   table: TableComponent;
35
36   @ViewChild('dateTpl', { static: true })
37   dateTpl: TemplateRef<any>;
38
39   @ViewChild('gatewayStatusTpl', { static: true })
40   gatewayStatusTpl: TemplateRef<any>;
41
42   @ViewChild('deleteTpl', { static: true })
43   deleteTpl: TemplateRef<any>;
44
45   permission: Permission;
46   tableActions: CdTableAction[];
47   columns: CdTableColumn[] = [];
48   selection: CdTableSelection = new CdTableSelection();
49   gatewayGroup$: Observable<CephServiceSpec[]>;
50   subject = new BehaviorSubject<CephServiceSpec[]>([]);
51   context: CdTableFetchDataContext;
52   gatewayGroupName: string;
53   subsystemCount: number;
54   gatewayCount: number;
55
56   icons = Icons;
57
58   iconSize = IconSize;
59
60   constructor(
61     public actionLabels: ActionLabelsI18n,
62     private authStorageService: AuthStorageService,
63     private nvmeofService: NvmeofService,
64     public modalService: ModalCdsService,
65     private cephServiceService: CephServiceService,
66     public taskWrapper: TaskWrapperService,
67     private notificationService: NotificationService
68   ) {}
69
70   ngOnInit(): void {
71     this.permission = this.authStorageService.getPermissions().nvmeof;
72
73     this.columns = [
74       {
75         name: $localize`Name`,
76         prop: 'name'
77       },
78       {
79         name: $localize`Gateways`,
80         prop: 'statusCount',
81         cellTemplate: this.gatewayStatusTpl
82       },
83       {
84         name: $localize`Subsystems`,
85         prop: 'subSystemCount'
86       },
87       {
88         name: $localize`Created on`,
89         prop: 'created',
90         cellTemplate: this.dateTpl
91       }
92     ];
93
94     const createAction: CdTableAction = {
95       permission: 'create',
96       icon: Icons.add,
97       name: this.actionLabels.CREATE,
98       canBePrimary: (selection: CdTableSelection) => !selection.hasSelection
99     };
100
101     const deleteAction: CdTableAction = {
102       permission: 'delete',
103       icon: Icons.destroy,
104       click: () => this.deleteGatewayGroupModal(),
105       name: this.actionLabels.DELETE,
106       canBePrimary: (selection: CdTableSelection) => selection.hasMultiSelection
107     };
108     this.tableActions = [createAction, deleteAction];
109     this.gatewayGroup$ = this.subject.pipe(
110       switchMap(() =>
111         this.nvmeofService.listGatewayGroups().pipe(
112           switchMap((gatewayGroups: GatewayGroup[][]) => {
113             const groups = gatewayGroups?.[0] ?? [];
114             if (groups.length === 0) {
115               return of([]);
116             }
117             return forkJoin(
118               groups.map((group: NvmeofGatewayGroup) => {
119                 const isRunning = (group.status?.running ?? 0) > 0;
120                 const subsystemsObservable = isRunning
121                   ? this.nvmeofService
122                       .listSubsystems(group.spec.group)
123                       .pipe(catchError(() => of([])))
124                   : of([]);
125
126                 return subsystemsObservable.pipe(
127                   map((subs) => ({
128                     ...group,
129                     name: group.spec?.group,
130                     statusCount: {
131                       running: group.status?.running ?? 0,
132                       error: (group.status?.size ?? 0) - (group.status?.running ?? 0)
133                     },
134                     subSystemCount: Array.isArray(subs) ? subs.length : 0,
135                     gateWayNode: group.placement?.hosts?.length ?? 0,
136                     created: group.status?.created ? new Date(group.status.created) : null
137                   }))
138                 );
139               })
140             );
141           }),
142           catchError((error) => {
143             this.context?.error?.(error);
144             return of([]);
145           })
146         )
147       )
148     );
149   }
150
151   fetchData(): void {
152     this.subject.next([]);
153   }
154
155   updateSelection(selection: CdTableSelection): void {
156     this.selection = selection;
157   }
158
159   deleteGatewayGroupModal() {
160     const selectedGroup = this.selection.first();
161     if (!selectedGroup) {
162       return;
163     }
164     const {
165       service_name: serviceName,
166       spec: { group }
167     } = selectedGroup;
168
169     const disableForm = selectedGroup.subSystemCount > 0 || !group;
170
171     this.modalService.show(DeleteConfirmationModalComponent, {
172       impact: DeletionImpact.high,
173       itemDescription: $localize`gateway group`,
174       bodyTemplate: this.deleteTpl,
175       itemNames: [selectedGroup.spec.group],
176       bodyContext: {
177         disableForm,
178         subsystemCount: selectedGroup.subSystemCount
179       },
180       submitActionObservable: () => {
181         return this.taskWrapper
182           .wrapTaskAroundCall({
183             task: new FinishedTask('nvmeof/gateway/delete', { group: selectedGroup.spec.group }),
184             call: this.cephServiceService.delete(serviceName)
185           })
186           .pipe(
187             tap(() => {
188               this.table.refreshBtn();
189             }),
190             catchError((error) => {
191               this.table.refreshBtn();
192               this.notificationService.show(
193                 NotificationType.error,
194                 $localize`${`Failed to delete gateway group ${selectedGroup.spec.group}: ${error.message}`}`
195               );
196               return of(null);
197             })
198           );
199       }
200     });
201   }
202 }