]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
641d25a8dc29cce78a140e811c4c917141640a76
[ceph.git] /
1 <cd-modal [pageURL]="pageURL"
2           [modalRef]="activeModal">
3   <span class="modal-title"
4         i18n>{{ action | titlecase }} {{ resource | upperFirst }}</span>
5   <ng-container class="modal-content">
6     <form #frm="ngForm"
7           [formGroup]="serviceForm"
8           novalidate>
9       <div class="modal-body">
10         <cd-alert-panel *ngIf="serviceForm.controls.service_type.value === 'rgw' && showRealmCreationForm"
11                         type="info"
12                         spacingClass="mb-3"
13                         i18n>
14           <a class="text-decoration-underline"
15              (click)="createMultisiteSetup()">
16              Click here</a> to create a new Realm/Zone Group/Zone
17         </cd-alert-panel>
18
19         <cd-alert-panel *ngIf="serviceForm.controls.service_type.value === 'oauth2-proxy'"
20                         type="info"
21                         spacingClass="mb-3"
22                         i18n>
23           Authentication must be enabled in an active `mgtm-gateway` service to enable Single Sign-On(SSO) with `oauth2-proxy`
24         </cd-alert-panel>
25         <cd-alert-panel *ngIf="serviceForm.controls.service_type.value === 'mgmt-gateway'"
26                         type="info"
27                         spacingClass="mb-3"
28                         i18n>
29           With an active mgmt-gateway service, the dashboard will continue to be served on {{currentURL}}:{{port}} and all other services will be accessible from {{currentURL}}:{{port}}/service_name
30         </cd-alert-panel>
31
32         <!-- Service type -->
33         <div class="form-group row">
34           <label class="cd-col-form-label required"
35                  for="service_type"
36                  i18n>Type</label>
37           <div class="cd-col-form-input">
38             <select id="service_type"
39                     name="service_type"
40                     class="form-select"
41                     formControlName="service_type"
42                     (change)="onServiceTypeChange($event.target.value)">
43               <option i18n
44                       [ngValue]="null">-- Select a service type --</option>
45               <option *ngFor="let serviceType of serviceTypes"
46                       [value]="serviceType">
47                 {{ serviceType }}
48               </option>
49             </select>
50             <span class="invalid-feedback"
51                   *ngIf="serviceForm.showError('service_type', frm, 'required')"
52                   i18n>This field is required.</span>
53           </div>
54         </div>
55
56         <!-- backend_service -->
57         <div *ngIf="serviceForm.controls.service_type.value === 'ingress'"
58              class="form-group row">
59           <label i18n
60                  class="cd-col-form-label"
61                  [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
62                  for="backend_service">Backend Service</label>
63           <div class="cd-col-form-input">
64             <select id="backend_service"
65                     name="backend_service"
66                     class="form-select"
67                     formControlName="backend_service"
68                     (change)="prePopulateId()">
69               <option *ngIf="services === null"
70                       [ngValue]="null"
71                       i18n>Loading...</option>
72               <option *ngIf="services !== null && services.length === 0"
73                       [ngValue]="null"
74                       i18n>-- No service available --</option>
75               <option *ngIf="services !== null && services.length > 0"
76                       [ngValue]="null"
77                       i18n>-- Select an existing service --</option>
78               <option *ngFor="let service of services"
79                       [value]="service.service_name">{{ service.service_name }}</option>
80             </select>
81             <span class="invalid-feedback"
82                   *ngIf="serviceForm.showError('backend_service', frm, 'required')"
83                   i18n>This field is required.</span>
84           </div>
85         </div>
86
87         <!-- NVMe/TCP -->
88         <!-- Block Pool -->
89         <div class="form-group row"
90              *ngIf="serviceForm.controls.service_type.value === 'nvmeof'">
91           <label i18n
92                  class="cd-col-form-label required"
93                  for="pool">Block Pool</label>
94           <div class="cd-col-form-input">
95             <select id="pool"
96                     name="pool"
97                     class="form-select"
98                     formControlName="pool"
99                     (change)="onBlockPoolChange()">
100               <option *ngIf="rbdPools === null"
101                       [ngValue]="null"
102                       i18n>Loading...</option>
103               <option *ngIf="rbdPools && rbdPools.length === 0"
104                       [ngValue]="null"
105                       i18n>-- No block pools available --</option>
106               <option *ngIf="rbdPools && rbdPools.length > 0"
107                       [ngValue]="null"
108                       i18n>-- Select a pool --</option>
109               <option *ngFor="let pool of rbdPools"
110                       [value]="pool.pool_name">{{ pool.pool_name }}</option>
111             </select>
112             <cd-help-text i18n>
113               An RBD application-enabled pool in which the gateway configuration can be managed.
114             </cd-help-text>
115             <span class="invalid-feedback"
116                   *ngIf="serviceForm.showError('pool', frm, 'required')"
117                   i18n>This field is required.</span>
118           </div>
119         </div>
120
121         <!-- Group Name -->
122         <div class="form-group row"
123              *ngIf="serviceForm.controls.service_type.value === 'nvmeof'">
124           <label class="cd-col-form-label required"
125                  for="group">
126             <span i18n>Group Name</span>
127           </label>
128           <div class="cd-col-form-input">
129             <div class="input-group">
130               <input id="group"
131                      class="form-control"
132                      type="text"
133                      formControlName="group"
134                      (change)="onNvmeofGroupChange($event.target.value)">
135             </div>
136             <cd-help-text i18n>
137               The name of the gateway group.
138             </cd-help-text>
139             <span class="invalid-feedback"
140                   *ngIf="serviceForm.showError('service_id', frm, 'required')"
141                   i18n>This field is required.</span>
142           </div>
143         </div>
144
145         <!-- Service id -->
146         <div class="form-group row"
147              *ngIf="serviceForm.controls.service_type.value !== 'snmp-gateway'">
148           <label class="cd-col-form-label"
149                  [ngClass]="{'required': ['mds', 'rgw', 'nfs', 'iscsi', 'nvmeof', 'smb', 'ingress'].includes(serviceForm.controls.service_type.value)}"
150                  for="service_id">
151             <span i18n>Service Name</span>
152           </label>
153           <div class="cd-col-form-input">
154             <div class="input-group">
155               <span class="input-group-text"
156                     *ngIf="serviceForm.controls.service_type.value && ['mds', 'rgw', 'nfs', 'iscsi', 'nvmeof', 'smb', 'ingress'].includes(serviceForm.controls.service_type.value)"
157                     for="userId"
158                     i18n>{{serviceForm.controls.service_type.value}}.
159               </span>
160               <input id="service_id"
161                      class="form-control"
162                      type="text"
163                      formControlName="service_id">
164             </div>
165             <span class="invalid-feedback"
166                   *ngIf="serviceForm.showError('service_id', frm, 'required')"
167                   i18n>This field is required.</span>
168             <span class="invalid-feedback"
169                   *ngIf="serviceForm.showError('service_id', frm, 'uniqueName')"
170                   i18n>This service id is already in use.</span>
171             <span class="invalid-feedback"
172                   *ngIf="serviceForm.showError('service_id', frm, 'mdsPattern')"
173                   i18n>MDS service id must start with a letter and contain alphanumeric characters or '.', '-', and '_'</span>
174           </div>
175         </div>
176
177         <div class="form-group row"
178              *ngIf="serviceForm.controls.service_type.value === 'rgw'">
179           <label class="cd-col-form-label"
180                  for="realm_name"
181                  i18n>Realm</label>
182           <div class="cd-col-form-input">
183             <select class="form-select"
184                     id="realm_name"
185                     formControlName="realm_name"
186                     name="realm_name"
187                     [attr.disabled]="realmList.length === 0  || editing ? true : null">
188             <option *ngIf="realmList.length === 0"
189                     i18n
190                     selected>-- No realm available --</option>
191             <option *ngFor="let realm of realmList"
192                     [value]="realm.name">
193                   {{ realm.name }}
194             </option>
195             </select>
196           </div>
197         </div>
198
199         <div class="form-group row"
200              *ngIf="serviceForm.controls.service_type.value === 'rgw'">
201           <label class="cd-col-form-label"
202                  for="zonegroup_name"
203                  i18n>Zone Group</label>
204           <div class="cd-col-form-input">
205             <select class="form-select"
206                     id="zonegroup_name"
207                     formControlName="zonegroup_name"
208                     name="zonegroup_name"
209                     [attr.disabled]="zonegroupList.length === 0  || editing ? true : null">
210               <option *ngFor="let zonegroup of zonegroupList"
211                       [value]="zonegroup.name">
212               {{ zonegroup.name }}
213               </option>
214             </select>
215           </div>
216         </div>
217
218         <div class="form-group row"
219              *ngIf="serviceForm.controls.service_type.value === 'rgw'">
220           <label class="cd-col-form-label"
221                  for="zone_name"
222                  i18n>Zone</label>
223           <div class="cd-col-form-input">
224             <select class="form-select"
225                     id="zone_name"
226                     formControlName="zone_name"
227                     name="zone_name"
228                     [attr.disabled]="zoneList.length === 0  || editing ? true : null">
229               <option *ngFor="let zone of zoneList"
230                       [value]="zone.name">
231               {{ zone.name }}
232               </option>
233             </select>
234           </div>
235         </div>
236
237         <!-- unmanaged -->
238         <div class="form-group row">
239           <div class="cd-col-form-offset">
240             <div class="custom-control custom-checkbox">
241               <input class="custom-control-input"
242                      id="unmanaged"
243                      type="checkbox"
244                      formControlName="unmanaged">
245               <label class="custom-control-label m-0"
246                      for="unmanaged"
247                      i18n>Unmanaged</label>
248               <cd-help-text i18n>If Unmanaged is selected, the orchestrator will not stop or stop any daemons associated with this service. Placement and all other properties will be ignored.</cd-help-text>
249             </div>
250           </div>
251         </div>
252
253         <!-- Placement -->
254         <div *ngIf="!serviceForm.controls.unmanaged.value"
255              class="form-group row">
256           <label class="cd-col-form-label"
257                  for="placement"
258                  i18n>Placement</label>
259           <div class="cd-col-form-input">
260             <select id="placement"
261                     class="form-select"
262                     formControlName="placement"
263                     (change)="onPlacementChange($event.target.value)">
264               <option i18n
265                       value="hosts">Hosts</option>
266               <option i18n
267                       value="label">Label</option>
268             </select>
269           </div>
270         </div>
271
272         <!-- Label -->
273         <div *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.placement.value === 'label'"
274              class="form-group row">
275           <label i18n
276                  class="cd-col-form-label"
277                  for="label">Label</label>
278           <div class="cd-col-form-input">
279             <input id="label"
280                    class="form-control"
281                    type="text"
282                    formControlName="label"
283                    [ngbTypeahead]="searchLabels"
284                    (focus)="labelFocus.next($any($event).target.value)"
285                    (click)="labelClick.next($any($event).target.value)">
286             <span class="invalid-feedback"
287                   *ngIf="serviceForm.showError('label', frm, 'required')"
288                   i18n>This field is required.</span>
289           </div>
290         </div>
291
292         <!-- Hosts -->
293         <div *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.placement.value === 'hosts'"
294              class="form-group row">
295           <label class="cd-col-form-label"
296                  for="hosts"
297                  i18n>Hosts</label>
298           <div class="cd-col-form-input">
299             <cd-select-badges id="hosts"
300                               [data]="serviceForm.controls.hosts.value"
301                               [options]="hosts.options"
302                               [messages]="hosts.messages">
303             </cd-select-badges>
304           </div>
305         </div>
306
307         <!-- Count -->
308         <div *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value !== 'nvmeof'"
309              class="form-group row">
310           <label class="cd-col-form-label"
311                  for="count">
312             <span i18n>Count</span>
313           </label>
314           <div class="cd-col-form-input">
315             <input id="count"
316                    class="form-control"
317                    type="number"
318                    formControlName="count"
319                    min="1">
320             <cd-help-text i18n>Number of deamons that will be deployed</cd-help-text>
321             <span class="invalid-feedback"
322                   *ngIf="serviceForm.showError('count', frm, 'min')"
323                   i18n>The value must be at least 1.</span>
324             <span class="invalid-feedback"
325                   *ngIf="serviceForm.showError('count', frm, 'pattern')"
326                   i18n>The entered value needs to be a number.</span>
327           </div>
328         </div>
329
330         <!-- RGW -->
331         <ng-container *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value === 'rgw'">
332           <!-- rgw_frontend_port -->
333           <div class="form-group row">
334             <label i18n
335                    class="cd-col-form-label"
336                    for="rgw_frontend_port">Port</label>
337             <div class="cd-col-form-input">
338               <input id="rgw_frontend_port"
339                      class="form-control"
340                      type="number"
341                      formControlName="rgw_frontend_port"
342                      min="1"
343                      max="65535">
344               <span class="invalid-feedback"
345                     *ngIf="serviceForm.showError('rgw_frontend_port', frm, 'pattern')"
346                     i18n>The entered value needs to be a number.</span>
347               <span class="invalid-feedback"
348                     *ngIf="serviceForm.showError('rgw_frontend_port', frm, 'min')"
349                     i18n>The value must be at least 1.</span>
350               <span class="invalid-feedback"
351                     *ngIf="serviceForm.showError('rgw_frontend_port', frm, 'max')"
352                     i18n>The value cannot exceed 65535.</span>
353             </div>
354           </div>
355         </ng-container>
356
357         <!-- iSCSI -->
358         <!-- pool -->
359         <div class="form-group row"
360              *ngIf="serviceForm.controls.service_type.value === 'iscsi'">
361           <label i18n
362                  class="cd-col-form-label required"
363                  for="pool">Pool</label>
364           <div class="cd-col-form-input">
365             <select id="pool"
366                     name="pool"
367                     class="form-select"
368                     formControlName="pool">
369               <option *ngIf="pools === null"
370                       [ngValue]="null"
371                       i18n>Loading...</option>
372               <option *ngIf="pools && pools.length === 0"
373                       [ngValue]="null"
374                       i18n>-- No pools available --</option>
375               <option *ngIf="pools && pools.length > 0"
376                       [ngValue]="null"
377                       i18n>-- Select a pool --</option>
378               <option *ngFor="let pool of pools"
379                       [value]="pool.pool_name">{{ pool.pool_name }}</option>
380             </select>
381             <span class="invalid-feedback"
382                   *ngIf="serviceForm.showError('pool', frm, 'required')"
383                   i18n>This field is required.</span>
384           </div>
385         </div>
386
387         <!-- fields in iSCSI which are hidden when unmanaged is true -->
388         <ng-container *ngIf="!serviceForm.controls.unmanaged.value && serviceForm.controls.service_type.value === 'iscsi'">
389           <!-- trusted_ip_list -->
390           <div class="form-group row">
391             <label class="cd-col-form-label"
392                    for="trusted_ip_list">
393               <span i18n>Trusted IPs</span>
394               <cd-helper>
395                 <span i18n>Comma separated list of IP addresses.</span>
396                 <br>
397                 <span i18n>Please add the <b>Ceph Manager</b> IP addresses here, otherwise the iSCSI gateways can't be reached.</span>
398               </cd-helper>
399             </label>
400             <div class="cd-col-form-input">
401               <input id="trusted_ip_list"
402                      class="form-control"
403                      type="text"
404                      formControlName="trusted_ip_list">
405             </div>
406           </div>
407
408           <!-- api_port -->
409           <div class="form-group row">
410             <label i18n
411                    class="cd-col-form-label"
412                    for="api_port">Port</label>
413             <div class="cd-col-form-input">
414               <input id="api_port"
415                      class="form-control"
416                      type="number"
417                      formControlName="api_port"
418                      min="1"
419                      max="65535">
420               <span class="invalid-feedback"
421                     *ngIf="serviceForm.showError('api_port', frm, 'pattern')"
422                     i18n>The entered value needs to be a number.</span>
423               <span class="invalid-feedback"
424                     *ngIf="serviceForm.showError('api_port', frm, 'min')"
425                     i18n>The value must be at least 1.</span>
426               <span class="invalid-feedback"
427                     *ngIf="serviceForm.showError('api_port', frm, 'max')"
428                     i18n>The value cannot exceed 65535.</span>
429             </div>
430           </div>
431
432           <!-- api_user -->
433           <div class="form-group row">
434             <label i18n
435                    class="cd-col-form-label"
436                    [ngClass]="{'required': ['iscsi'].includes(serviceForm.controls.service_type.value)}"
437                    for="api_user">User</label>
438             <div class="cd-col-form-input">
439               <input id="api_user"
440                      class="form-control"
441                      type="text"
442                      formControlName="api_user">
443               <span class="invalid-feedback"
444                     *ngIf="serviceForm.showError('api_user', frm, 'required')"
445                     i18n>This field is required.</span>
446             </div>
447           </div>
448
449           <!-- api_password -->
450           <div class="form-group row">
451             <label i18n
452                    class="cd-col-form-label"
453                    [ngClass]="{'required': ['iscsi'].includes(serviceForm.controls.service_type.value)}"
454                    for="api_password">Password</label>
455             <div class="cd-col-form-input">
456               <div class="input-group">
457                 <input id="api_password"
458                        class="form-control"
459                        type="password"
460                        autocomplete="new-password"
461                        formControlName="api_password">
462                 <button type="button"
463                         class="btn btn-light"
464                         cdPasswordButton="api_password">
465                 </button>
466                 <cd-copy-2-clipboard-button source="api_password">
467                 </cd-copy-2-clipboard-button>
468                 <span class="invalid-feedback"
469                       *ngIf="serviceForm.showError('api_password', frm, 'required')"
470                       i18n>This field is required.</span>
471               </div>
472             </div>
473           </div>
474         </ng-container>
475
476         <!-- smb -->
477         <ng-container *ngIf="serviceForm.controls.service_type.value === 'smb'">
478           <div class="form-group row">
479             <label class="cd-col-form-label required"
480                    for="cluster_id"
481                    i18n>
482               Cluster id
483               <cd-helper>
484                 <span>A short name identifying the SMB “cluster”. In this case a cluster is simply a management unit of one or more Samba services sharing a common configuration,
485                    and may not provide actual clustering or availability mechanisms.</span>
486               </cd-helper>
487             </label>
488             <div class="cd-col-form-input">
489               <input id="cluster_id"
490                      class="form-control"
491                      type="text"
492                      formControlName="cluster_id"
493                      placeholder="foo"
494                      i18n-placeholder>
495               <span class="invalid-feedback"
496                     *ngIf="serviceForm.showError('cluster_id', frm, 'required')"
497                     i18n>This field is required.</span>
498             </div>
499           </div>
500
501           <div class="form-group row">
502             <label class="cd-col-form-label required"
503                    for="config_uri">
504               <span i18n>Config URI</span>
505               <cd-helper i18n>
506                 Configuration source that should be loaded by the samba-container as the primary configuration file.
507               </cd-helper>
508             </label>
509             <div class="cd-col-form-input">
510               <input id="config_uri"
511                      class="form-control"
512                      type="text"
513                      formControlName="config_uri"
514                      placeholder="rados://.smb/foo/scc.toml"
515                      i18n-placeholder>
516               <span class="invalid-feedback"
517                     *ngIf="serviceForm.showError('config_uri', frm, 'required')"
518                     i18n>This field is required.</span>
519               <span class="invalid-feedback"
520                     *ngIf="serviceForm.showError('config_uri', frm, 'configUriPattern')"
521                     i18n>The value must start with either 'http:', 'https:', 'rados:' or 'rados:mon-config-key:'</span>
522             </div>
523           </div>
524
525           <div class="form-group row"
526                formGroupName="features">
527             <label class="cd-col-form-label"
528                    for="features"
529                    i18n>Features
530               <cd-helper>
531                 <span>Pre-defined terms enabling specific deployment characteristics.</span>
532               </cd-helper>
533             </label>
534             <div class="cd-col-form-input">
535               <div class="custom-control custom-checkbox"
536                    *ngFor="let feature of smbFeaturesList">
537                 <input class="custom-control-input"
538                        type="checkbox"
539                        name="{{feature}}"
540                        id="{{feature}}"
541                        formControlName="{{feature}}">
542                 <label class="custom-control-label"
543                        for="{{feature}}"
544                        i18n>{{feature}}
545                 </label>
546               </div>
547             </div>
548           </div>
549
550           <div class="form-group row">
551             <label class="cd-col-form-label"
552                    for="custom_dns">
553               <span i18n>Custom DNS</span>
554               <cd-helper i18n>
555                 <span>Comma separated list of DNSs.</span>
556                 <br>
557                 <span>A list of IP addresses that will be used as the DNS servers for a Samba container.</span>
558               </cd-helper>
559             </label>
560             <div class="cd-col-form-input">
561               <input id="custom_dns"
562                      class="form-control"
563                      type="text"
564                      formControlName="custom_dns"
565                      placeholder="192.168.76.204"
566                      i18n-placeholder>
567             </div>
568           </div>
569
570           <div class="form-group row">
571             <label class="cd-col-form-label"
572                    for="join_sources">
573               <span i18n>Join sources</span>
574               <cd-helper i18n>
575                 <span>Comma separated list of URIs.</span>
576                 <br>
577                 <span>A list of values that will be used to identify where authentication data that will be used to perform domain joins are located.</span>
578               </cd-helper>
579             </label>
580             <div class="cd-col-form-input">
581               <input id="join_sources"
582                      class="form-control"
583                      type="text"
584                      formControlName="join_sources"
585                      placeholder="rados:mon-config-key:smb/config/foo/join1.json"
586                      i18n-placeholder>
587             </div>
588           </div>
589
590           <div class="form-group row">
591             <label class="cd-col-form-label"
592                    for="user_sources">
593               <span i18n>User sources</span>
594               <cd-helper i18n>
595                 <span>Comma separated list of URIs.</span>
596                 <br>
597                 <span>A list of pseudo-uris containing data the samba-container can use to create users (and/or
598                   groups). A ceph based samba container may typically use a rados uri
599                   or a mon config-key store uri </span>
600               </cd-helper>
601             </label>
602             <div class="cd-col-form-input">
603               <input id="user_sources"
604                      class="form-control"
605                      type="text"
606                      formControlName="user_sources"
607                      placeholder="rados:mon-config-key:smb/config/foo/join2.json"
608                      i18n-placeholder>
609             </div>
610           </div>
611
612           <div class="form-group row">
613             <label class="cd-col-form-label"
614                    for="include_ceph_users">
615               <span i18n>Ceph users</span>
616               <cd-helper i18n>
617                 <span>Comma separated list of Ceph users.</span>
618                 <br>
619                 <span>A list of cephx user names that the Samba Containers may use.</span>
620               </cd-helper>
621             </label>
622             <div class="cd-col-form-input">
623               <input id="include_ceph_users"
624                      class="form-control"
625                      type="text"
626                      formControlName="include_ceph_users"
627                      placeholder="client.smb.fs.cluster.foo"
628                      i18n-placeholder>
629             </div>
630           </div>
631
632         </ng-container>
633
634         <!-- Ingress -->
635         <ng-container *ngIf="serviceForm.controls.service_type.value === 'ingress'">
636           <!-- virtual_ip -->
637           <div class="form-group row">
638             <label class="cd-col-form-label"
639                    [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
640                    for="virtual_ip">
641               <span i18n>Virtual IP</span>
642               <cd-helper>
643                 <span i18n>The virtual IP address and subnet (in CIDR notation) where the ingress service will be available.</span>
644               </cd-helper>
645             </label>
646             <div class="cd-col-form-input">
647               <input id="virtual_ip"
648                      class="form-control"
649                      type="text"
650                      formControlName="virtual_ip">
651               <span class="invalid-feedback"
652                     *ngIf="serviceForm.showError('virtual_ip', frm, 'required')"
653                     i18n>This field is required.</span>
654             </div>
655           </div>
656
657           <!-- frontend_port -->
658           <div class="form-group row">
659             <label class="cd-col-form-label"
660                    [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
661                    for="frontend_port">
662               <span i18n>Frontend Port</span>
663               <cd-helper>
664                 <span i18n>The port used to access the ingress service.</span>
665               </cd-helper>
666             </label>
667             <div class="cd-col-form-input">
668               <input id="frontend_port"
669                      class="form-control"
670                      type="number"
671                      formControlName="frontend_port"
672                      min="1"
673                      max="65535">
674               <span class="invalid-feedback"
675                     *ngIf="serviceForm.showError('frontend_port', frm, 'pattern')"
676                     i18n>The entered value needs to be a number.</span>
677               <span class="invalid-feedback"
678                     *ngIf="serviceForm.showError('frontend_port', frm, 'min')"
679                     i18n>The value must be at least 1.</span>
680               <span class="invalid-feedback"
681                     *ngIf="serviceForm.showError('frontend_port', frm, 'max')"
682                     i18n>The value cannot exceed 65535.</span>
683               <span class="invalid-feedback"
684                     *ngIf="serviceForm.showError('frontend_port', frm, 'required')"
685                     i18n>This field is required.</span>
686             </div>
687           </div>
688
689           <!-- monitor_port -->
690           <div class="form-group row">
691             <label class="cd-col-form-label"
692                    [ngClass]="{'required': ['ingress'].includes(serviceForm.controls.service_type.value)}"
693                    for="monitor_port">
694               <span i18n>Monitor Port</span>
695               <cd-helper>
696                 <span i18n>The port used by haproxy for load balancer status.</span>
697               </cd-helper>
698             </label>
699             <div class="cd-col-form-input">
700               <input id="monitor_port"
701                      class="form-control"
702                      type="number"
703                      formControlName="monitor_port"
704                      min="1"
705                      max="65535">
706               <span class="invalid-feedback"
707                     *ngIf="serviceForm.showError('monitor_port', frm, 'pattern')"
708                     i18n>The entered value needs to be a number.</span>
709               <span class="invalid-feedback"
710                     *ngIf="serviceForm.showError('monitor_port', frm, 'min')"
711                     i18n>The value must be at least 1.</span>
712               <span class="invalid-feedback"
713                     *ngIf="serviceForm.showError('monitor_port', frm, 'max')"
714                     i18n>The value cannot exceed 65535.</span>
715               <span class="invalid-feedback"
716                     *ngIf="serviceForm.showError('monitor_port', frm, 'required')"
717                     i18n>This field is required.</span>
718             </div>
719           </div>
720           <!-- virtual_interface_networks -->
721           <div class="form-group row"
722                *ngIf="!serviceForm.controls.unmanaged.value">
723             <label class="cd-col-form-label"
724                    for="virtual_interface_networks">
725               <span i18n>CIDR Networks</span>
726               <cd-helper>
727                 <span i18n>A list of networks to identify which network interface to use for the virtual IP address.</span>
728               </cd-helper>
729             </label>
730             <div class="cd-col-form-input">
731               <input id="virtual_interface_networks"
732                      class="form-control"
733                      type="text"
734                      formControlName="virtual_interface_networks">
735             </div>
736           </div>
737         </ng-container>
738
739         <!-- SNMP-Gateway -->
740         <ng-container *ngIf="serviceForm.controls.service_type.value === 'snmp-gateway'">
741           <!-- snmp-version -->
742           <div class="form-group row">
743             <label class="cd-col-form-label required"
744                    for="snmp_version"
745                    i18n>Version</label>
746             <div class="cd-col-form-input">
747               <select id="snmp_version"
748                       name="snmp_version"
749                       class="form-select"
750                       formControlName="snmp_version"
751                       (change)="clearValidations()">
752                 <option i18n
753                         [ngValue]="null">-- Select SNMP version --</option>
754                 <option *ngFor="let snmpVersion of ['V2c', 'V3']"
755                         [value]="snmpVersion">{{ snmpVersion }}</option>
756               </select>
757               <span class="invalid-feedback"
758                     *ngIf="serviceForm.showError('snmp_version', frm, 'required')"
759                     i18n>This field is required.</span>
760             </div>
761           </div>
762           <!-- Destination -->
763           <div class="form-group row">
764             <label class="cd-col-form-label required"
765                    for="snmp_destination">
766               <span i18n>Destination</span>
767               <cd-helper>
768                 <span i18n>Must be of the format hostname:port.</span>
769               </cd-helper>
770             </label>
771             <div class="cd-col-form-input">
772               <input id="snmp_destination"
773                      class="form-control"
774                      type="text"
775                      formControlName="snmp_destination">
776               <span class="invalid-feedback"
777                     *ngIf="serviceForm.showError('snmp_destination', frm, 'required')"
778                     i18n>This field is required.</span>
779               <span class="invalid-feedback"
780                     *ngIf="serviceForm.showError('snmp_destination', frm, 'snmpDestinationPattern')"
781                     i18n>The value does not match the pattern: <strong>hostname:port</strong></span>
782             </div>
783           </div>
784           <!-- Engine id for snmp V3 -->
785           <div class="form-group row"
786                *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
787             <label class="cd-col-form-label required"
788                    for="engine_id">
789               <span i18n>Engine Id</span>
790               <cd-helper>
791                 <span i18n>Unique identifier for the device (in hex).</span>
792               </cd-helper>
793             </label>
794             <div class="cd-col-form-input">
795               <input id="engine_id"
796                      class="form-control"
797                      type="text"
798                      formControlName="engine_id">
799               <span class="invalid-feedback"
800                     *ngIf="serviceForm.showError('engine_id', frm, 'required')"
801                     i18n>This field is required.</span>
802               <span class="invalid-feedback"
803                     *ngIf="serviceForm.showError('engine_id', frm, 'snmpEngineIdPattern')"
804                     i18n>The value does not match the pattern: <strong>Must be in hexadecimal and length must be multiple of 2 with min value = 10 amd max value = 64.</strong></span>
805             </div>
806           </div>
807           <!-- Auth protocol for snmp V3 -->
808           <div class="form-group row"
809                *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
810             <label class="cd-col-form-label required"
811                    for="auth_protocol"
812                    i18n>Auth Protocol</label>
813             <div class="cd-col-form-input">
814               <select id="auth_protocol"
815                       name="auth_protocol"
816                       class="form-select"
817                       formControlName="auth_protocol">
818                 <option i18n
819                         [ngValue]="null">-- Select auth protocol --</option>
820                 <option *ngFor="let authProtocol of ['SHA', 'MD5']"
821                         [value]="authProtocol">
822                   {{ authProtocol }}
823                 </option>
824               </select>
825               <span class="invalid-feedback"
826                     *ngIf="serviceForm.showError('auth_protocol', frm, 'required')"
827                     i18n>This field is required.</span>
828             </div>
829           </div>
830           <!-- Privacy protocol for snmp V3 -->
831           <div class="form-group row"
832                *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
833             <label class="cd-col-form-label"
834                    for="privacy_protocol"
835                    i18n>Privacy Protocol</label>
836             <div class="cd-col-form-input">
837               <select id="privacy_protocol"
838                       name="privacy_protocol"
839                       class="form-select"
840                       formControlName="privacy_protocol">
841                 <option i18n
842                         [ngValue]="null">-- Select privacy protocol --</option>
843                 <option *ngFor="let privacyProtocol of ['DES', 'AES']"
844                         [value]="privacyProtocol">
845                   {{ privacyProtocol }}
846                 </option>
847               </select>
848             </div>
849           </div>
850           <!-- Credentials -->
851           <fieldset>
852             <legend i18n>Credentials</legend>
853             <!-- snmp v2c snmp_community -->
854             <div class="form-group row"
855                  *ngIf="serviceForm.controls.snmp_version.value === 'V2c'">
856               <label class="cd-col-form-label required"
857                      for="snmp_community">
858                 <span i18n>SNMP Community</span>
859               </label>
860               <div class="cd-col-form-input">
861                 <input id="snmp_community"
862                        class="form-control"
863                        type="text"
864                        formControlName="snmp_community">
865                 <span class="invalid-feedback"
866                       *ngIf="serviceForm.showError('snmp_community', frm, 'required')"
867                       i18n>This field is required.</span>
868               </div>
869             </div>
870             <!-- snmp v3 auth username -->
871             <div class="form-group row"
872                  *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
873               <label class="cd-col-form-label required"
874                      for="snmp_v3_auth_username">
875                 <span i18n>Username</span>
876               </label>
877               <div class="cd-col-form-input">
878                 <input id="snmp_v3_auth_username"
879                        class="form-control"
880                        type="text"
881                        formControlName="snmp_v3_auth_username">
882                 <span class="invalid-feedback"
883                       *ngIf="serviceForm.showError('snmp_v3_auth_username', frm, 'required')"
884                       i18n>This field is required.</span>
885               </div>
886             </div>
887             <!-- snmp v3 auth password -->
888             <div class="form-group row"
889                  *ngIf="serviceForm.controls.snmp_version.value === 'V3'">
890               <label class="cd-col-form-label required"
891                      for="snmp_v3_auth_password">
892                 <span i18n>Password</span>
893               </label>
894               <div class="cd-col-form-input">
895                 <input id="snmp_v3_auth_password"
896                        class="form-control"
897                        type="password"
898                        formControlName="snmp_v3_auth_password">
899                 <span class="invalid-feedback"
900                       *ngIf="serviceForm.showError('snmp_v3_auth_password', frm, 'required')"
901                       i18n>This field is required.</span>
902               </div>
903             </div>
904             <!-- snmp v3 priv password -->
905             <div class="form-group row"
906                  *ngIf="serviceForm.controls.snmp_version.value === 'V3' && serviceForm.controls.privacy_protocol.value !== null && serviceForm.controls.privacy_protocol.value !== undefined">
907               <label class="cd-col-form-label required"
908                      for="snmp_v3_priv_password">
909                 <span i18n>Encryption</span>
910               </label>
911               <div class="cd-col-form-input">
912                 <input id="snmp_v3_priv_password"
913                        class="form-control"
914                        type="password"
915                        formControlName="snmp_v3_priv_password">
916                 <span class="invalid-feedback"
917                       *ngIf="serviceForm.showError('snmp_v3_priv_password', frm, 'required')"
918                       i18n>This field is required.</span>
919               </div>
920             </div>
921           </fieldset>
922         </ng-container>
923
924         <!-- oauth2-proxy -->
925         <ng-container *ngIf="serviceForm.controls.service_type.value === 'oauth2-proxy'">
926           <!-- provider_display_name -->
927           <div class="form-group row">
928             <label class="cd-col-form-label required"
929                    for="provider_display_name">
930               <span i18n>Provider display name</span>
931             </label>
932             <div class="cd-col-form-input">
933               <input id="provider_display_name"
934                      class="form-control"
935                      type="text"
936                      formControlName="provider_display_name"
937                      placeholder="My OIDC Provider"
938                      i18n-placeholder>
939               <cd-help-text i18n>The display name for the identity provider (IdP) in the UI.</cd-help-text>
940               <span class="invalid-feedback"
941                     *ngIf="serviceForm.showError('provider_display_name', frm, 'required')"
942                     i18n>This field is required.</span>
943             </div>
944           </div>
945           <!-- client_id -->
946           <div class="form-group row">
947             <label class="cd-col-form-label required"
948                    for="client_id">
949               <span i18n>Client ID</span>
950             </label>
951             <div class="cd-col-form-input">
952               <input id="client_id"
953                      class="form-control"
954                      type="text"
955                      formControlName="client_id"
956                      placeholder="oauth2-client">
957               <cd-help-text i18n>The client ID for authenticating with the IdP.</cd-help-text>
958               <span class="invalid-feedback"
959                     *ngIf="serviceForm.showError('client_id', frm, 'required')"
960                     i18n>This field is required.</span>
961             </div>
962           </div>
963           <!-- client_secret -->
964           <div class="form-group row">
965             <label class="cd-col-form-label required"
966                    for="client_secret">
967               <span i18n>Client secret</span>
968             </label>
969             <div class="cd-col-form-input">
970               <div class="input-group">
971                 <input id="client_secret"
972                        class="form-control"
973                        type="password"
974                        formControlName="client_secret">
975                 <span class="input-group-append">
976                   <button type="button"
977                           class="btn btn-light"
978                           cdPasswordButton="client_secret">
979                   </button>
980                   <cd-copy-2-clipboard-button source="client_secret">
981                   </cd-copy-2-clipboard-button>
982                 </span>
983               </div>
984               <cd-help-text i18n>The client secret for authenticating with the IdP.</cd-help-text>
985               <span class="invalid-feedback"
986                     *ngIf="serviceForm.showError('client_secret', frm, 'required')"
987                     i18n>This field is required.</span>
988             </div>
989           </div>
990           <!-- oidc_issuer_url -->
991           <div class="form-group row">
992             <label class="cd-col-form-label required"
993                    for="oidc_issuer_url">
994               <span i18n>OIDC Issuer URL</span>
995             </label>
996             <div class="cd-col-form-input">
997               <input id="oidc_issuer_url"
998                      class="form-control"
999                      type="text"
1000                      formControlName="oidc_issuer_url"
1001                      placeholder="https://<IdPs-domain>/realms/<realm-name>">
1002               <cd-help-text i18n>The URL of the OpenID Connect (OIDC) issuer.</cd-help-text>
1003               <span class="invalid-feedback"
1004                     *ngIf="serviceForm.showError('oidc_issuer_url', frm, 'required')"
1005                     i18n>This field is required.</span>
1006               <span class="invalid-feedback"
1007                     *ngIf="serviceForm.showError('oidc_issuer_url', frm, 'validUrl')"
1008                     i18n>Invalid url.</span>
1009             </div>
1010           </div>
1011           <!-- https_address -->
1012           <div class="form-group row">
1013             <label class="cd-col-form-label"
1014                    for="https_address">
1015               <span i18n>Https address</span>
1016             </label>
1017             <div class="cd-col-form-input">
1018               <input id="https_address"
1019                      class="form-control"
1020                      type="text"
1021                      formControlName="https_address"
1022                      placeholder="0.0.0.0:4180">
1023               <cd-help-text i18n>The address for HTTPS connections as [IP|Hostname]:port.</cd-help-text>
1024               <span class="invalid-feedback"
1025                     *ngIf="serviceForm.showError('https_address', frm, 'invalidAddress')"
1026                     i18n>Format must be [IP|Hostname]:port and the port between 0 and 65535</span>
1027             </div>
1028           </div>
1029           <!-- redirect_url -->
1030           <div class="form-group row">
1031             <label class="cd-col-form-label"
1032                    for="redirect_url">
1033               <span i18n>Redirect URL</span>
1034             </label>
1035             <div class="cd-col-form-input">
1036               <input id="redirect_url"
1037                      class="form-control"
1038                      type="text"
1039                      formControlName="redirect_url"
1040                      placeholder="https://<IP|Hostname>:4180/oauth2/callback">
1041               <cd-help-text i18n>The URL the oauth2-proxy service will redirect to after a successful login.</cd-help-text>
1042             </div>
1043           </div>
1044           <!-- Allowlist_domains -->
1045           <div class="form-group row">
1046             <label class="cd-col-form-label"
1047                    for="allowlist_domains">
1048               <span i18n>Allowlist domains</span>
1049             </label>
1050             <div class="cd-col-form-input">
1051               <input id="allowlist_domains"
1052                      class="form-control"
1053                      type="text"
1054                      formControlName="allowlist_domains"
1055                      placeholder="domain1.com,192.168.100.1:8080">
1056               <cd-help-text i18n>Comma separated list of domains to be allowed to redirect to, used for login or logout.</cd-help-text>
1057             </div>
1058           </div>
1059         </ng-container>
1060
1061         <ng-container *ngIf="!serviceForm.controls.unmanaged.value && ['mgmt-gateway'].includes(serviceForm.controls.service_type.value)">
1062           <!-- port -->
1063           <div class="form-group row">
1064             <label i18n
1065                    class="cd-col-form-label"
1066                    for="port">Port</label>
1067             <div class="cd-col-form-input">
1068               <input id="port"
1069                      class="form-control"
1070                      type="number"
1071                      formControlName="port"
1072                      min="1"
1073                      max="65535">
1074               <span class="invalid-feedback"
1075                     *ngIf="serviceForm.showError('port', frm, 'pattern')"
1076                     i18n>The entered value needs to be a number.</span>
1077               <span class="invalid-feedback"
1078                     *ngIf="serviceForm.showError('port', frm, 'min')"
1079                     i18n>The value must be at least 1.</span>
1080               <span class="invalid-feedback"
1081                     *ngIf="serviceForm.showError('port', frm, 'max')"
1082                     i18n>The value cannot exceed 65535.</span>
1083             </div>
1084           </div>
1085           <!-- enable_auth -->
1086           <div class="form-item">
1087             <fieldset>
1088               <label class="cds--label"
1089                      for="pools"
1090                      i18n>Authentication</label>
1091                 <cds-checkbox i18n-label
1092                               id="enable_auth"
1093                               name="enable_auth"
1094                               formControlName="enable_auth">
1095                 Enable
1096                 <cd-help-text i18n>
1097                   Allows to enable authentication through an external Identity Provider (IdP) using Single Sign-On (SSO)
1098                 </cd-help-text>
1099               </cds-checkbox>
1100             </fieldset>
1101           </div>
1102           <!-- ssl_protocols -->
1103           <div class="form-item">
1104             <cds-combo-box type="multi"
1105                            label="SSL protocols"
1106                            selectionFeedback="top-after-reopen"
1107                            for="ssl_protocols"
1108                            name="ssl_protocols"
1109                            formControlName="ssl_protocols"
1110                            id="ssl_protocols"
1111                            placeholder="Select protocols..."
1112                            [appendInline]="true"
1113                            [items]="sslProtocolsItems"
1114                            i18n-placeholder
1115                            i18n>
1116               <cds-dropdown-list></cds-dropdown-list>
1117             </cds-combo-box>
1118           </div>
1119           <!-- ssl_ciphers -->
1120           <div class="form-group row">
1121           <label class="cd-col-form-label"
1122                  for="ssl_ciphers">
1123             <span i18n>SSL ciphers</span>
1124           </label>
1125           <div class="cd-col-form-input">
1126             <div class="input-group">
1127               <input id="ssl_ciphers"
1128                      class="form-control"
1129                      type="text"
1130                      formControlName="ssl_ciphers"
1131                      placeholder="ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256">
1132             </div>
1133             <cd-help-text i18n>Default cipher list used: <a href="https://ssl-config.mozilla.org/#server=nginx"
1134                                                             target="_blank">https://ssl-config.mozilla.org/#server=nginx</a></cd-help-text>
1135             <span class="invalid-feedback"
1136                   *ngIf="serviceForm.showError('ssl_ciphers', frm, 'invalidPattern')"
1137                   i18n>Invalid cipher suite. Each cipher must be separated by '-' and each cipher suite must be separated by ':'</span>
1138           </div>
1139         </div>
1140         </ng-container>
1141         <!-- RGW, Ingress, iSCSI, Oauth2-proxy & mgmt-gateway -->
1142         <ng-container *ngIf="!serviceForm.controls.unmanaged.value && ['rgw', 'iscsi', 'ingress', 'oauth2-proxy', 'mgmt-gateway'].includes(serviceForm.controls.service_type.value)">
1143           <!-- ssl -->
1144           <ng-container *ngIf="!['mgmt-gateway'].includes(serviceForm.controls.service_type.value)">
1145             <div class="form-group row">
1146               <div class="cd-col-form-offset">
1147                 <div class="custom-control custom-checkbox">
1148                   <input class="custom-control-input"
1149                          id="ssl"
1150                          type="checkbox"
1151                          formControlName="ssl">
1152                   <label class="custom-control-label"
1153                          for="ssl"
1154                          i18n>SSL</label>
1155                 </div>
1156               </div>
1157             </div>
1158           </ng-container>
1159           <!-- ssl_cert -->
1160           <div *ngIf="serviceForm.controls.ssl.value || ['mgmt-gateway'].includes(serviceForm.controls.service_type.value)"
1161                class="form-group row">
1162             <label class="cd-col-form-label"
1163                    for="ssl_cert">
1164               <span i18n>Certificate</span>
1165               <cd-helper i18n>The SSL certificate in PEM format.</cd-helper>
1166             </label>
1167             <div class="cd-col-form-input">
1168               <textarea id="ssl_cert"
1169                         class="form-control resize-vertical text-monospace text-pre"
1170                         formControlName="ssl_cert"
1171                         rows="5">
1172               </textarea>
1173               <input type="file"
1174                      (change)="fileUpload($event.target.files, 'ssl_cert')">
1175               <span class="invalid-feedback"
1176                     *ngIf="serviceForm.showError('ssl_cert', frm, 'required')"
1177                     i18n>This field is required.</span>
1178               <span class="invalid-feedback"
1179                     *ngIf="serviceForm.showError('ssl_cert', frm, 'pattern')"
1180                     i18n>Invalid SSL certificate.</span>
1181             </div>
1182           </div>
1183
1184           <!-- ssl_key -->
1185           <div *ngIf="(serviceForm.controls.ssl.value && !(['rgw', 'ingress'].includes(serviceForm.controls.service_type.value))) || ['mgmt-gateway'].includes(serviceForm.controls.service_type.value)"
1186                class="form-group row">
1187             <label class="cd-col-form-label"
1188                    for="ssl_key">
1189               <span i18n>Private key</span>
1190               <cd-helper i18n>The SSL private key in PEM format.</cd-helper>
1191             </label>
1192             <div class="cd-col-form-input">
1193               <textarea id="ssl_key"
1194                         class="form-control resize-vertical text-monospace text-pre"
1195                         formControlName="ssl_key"
1196                         rows="5">
1197               </textarea>
1198               <input type="file"
1199                      (change)="fileUpload($event.target.files,'ssl_key')">
1200               <span class="invalid-feedback"
1201                     *ngIf="serviceForm.showError('ssl_key', frm, 'required')"
1202                     i18n>This field is required.</span>
1203               <span class="invalid-feedback"
1204                     *ngIf="serviceForm.showError('ssl_key', frm, 'pattern')"
1205                     i18n>Invalid SSL private key.</span>
1206             </div>
1207           </div>
1208         </ng-container>
1209         <!-- Grafana -->
1210         <ng-container *ngIf="serviceForm.controls.service_type.value === 'grafana'">
1211           <div class="form-group row">
1212             <label class="cd-col-form-label"
1213                    for="grafana_port">
1214               <span i18n>Grafana Port</span>
1215               <cd-helper>
1216                 <span i18n>The default port used by grafana.</span>
1217               </cd-helper>
1218             </label>
1219             <div class="cd-col-form-input">
1220               <input id="grafana_port"
1221                      class="form-control"
1222                      type="number"
1223                      formControlName="grafana_port"
1224                      min="1"
1225                      max="65535">
1226               <span class="invalid-feedback"
1227                     *ngIf="serviceForm.showError('grafana_port', frm, 'pattern')"
1228                     i18n>The entered value needs to be a number.</span>
1229               <span class="invalid-feedback"
1230                     *ngIf="serviceForm.showError('grafana_port', frm, 'min')"
1231                     i18n>The value must be at least 1.</span>
1232               <span class="invalid-feedback"
1233                     *ngIf="serviceForm.showError('grafana_port', frm, 'max')"
1234                     i18n>The value cannot exceed 65535.</span>
1235               <span class="invalid-feedback"
1236                     *ngIf="serviceForm.showError('grafana_port', frm, 'required')"
1237                     i18n>This field is required.</span>
1238             </div>
1239           </div>
1240
1241           <div class="form-group row">
1242             <label i18n
1243                    class="cd-col-form-label"
1244                    for="grafana_admin_password">
1245               <span>Grafana Password</span>
1246               <cd-helper>The password of the default Grafana Admin. Set once on first-run.</cd-helper>
1247             </label>
1248             <div class="cd-col-form-input">
1249               <div class="input-group">
1250                 <input id="grafana_admin_password"
1251                        class="form-control"
1252                        type="password"
1253                        autocomplete="new-password"
1254                        [attr.disabled]="editing ? true:null"
1255                        formControlName="grafana_admin_password">
1256                 <span class="input-group-append">
1257                   <button type="button"
1258                           class="btn btn-light"
1259                           cdPasswordButton="grafana_admin_password">
1260                   </button>
1261                   <cd-copy-2-clipboard-button source="grafana_admin_password">
1262                   </cd-copy-2-clipboard-button>
1263                 </span>
1264               </div>
1265             </div>
1266           </div>
1267         </ng-container>
1268
1269       <cd-alert-panel *ngIf="serviceForm.controls.service_type.value === 'mgmt-gateway' && showMgmtGatewayMessage"
1270                       type="warning"
1271                       spacingClass="mb-3"
1272                       i18n>
1273         Modifying the default settings could lead to a weaker security configuration
1274       </cd-alert-panel>
1275       </div>
1276
1277       <div class="modal-footer">
1278         <div class="text-right">
1279           <cd-form-button-panel (submitActionEvent)="onSubmit()"
1280                                 [form]="serviceForm"
1281                                 [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
1282         </div>
1283       </div>
1284     </form>
1285   </ng-container>
1286 </cd-modal>