cy.get('#size').type(size);
// Click the create button and wait for image to be made
- cy.contains('button', 'Create RBD').click();
+ cy.get('[data-cy=submitBtn]').click();
this.getFirstTableCell(name).should('exist');
}
cy.get('#name').clear().type(newName);
cy.get('#size').clear().type(newSize); // click the size box and send new size
- cy.contains('button', 'Edit RBD').click();
+ cy.get('[data-cy=submitBtn]').click();
this.getExpandCollapseElement(newName).click();
cy.get('.table.table-striped.table-bordered').contains('td', newSize);
cy.get('.table-actions button.dropdown-toggle').first().click();
cy.get('button.move-to-trash').click();
- cy.contains('button', 'Move Image').should('be.visible').click();
+ cy.get('[data-cy=submitBtn]').should('be.visible').click();
// Clicks trash tab
cy.contains('.nav-link', 'Trash').click();
cy.get('cd-modal #name').clear().type(newName);
}
- cy.contains('button', 'Restore Image').click();
+ cy.get('[data-cy=submitBtn]').click();
// clicks images tab
cy.contains('.nav-link', 'Images').click();
this.selectOption('poolName', pool);
cy.get('#poolName').should('have.class', 'ng-valid'); // check if pool is selected
}
- cy.get('#purgeFormButton').click();
+ cy.get('[data-cy=submitBtn]').click();
// Wait for image to delete and check it is not present
this.getFirstTableCell(name).should('not.exist');
cy.get(`#${i}`).clear();
}
// Clicks save button and checks that values are not present for the selected config
- cy.contains('button', 'Save').click();
+ cy.get('[data-cy=submitBtn]').click();
// Enter config setting name into filter box
this.seachTable(name);
// Clicks save button then waits until the desired config is visible, clicks it,
// then checks that each desired value appears with the desired number
- cy.contains('button', 'Save').click();
+ cy.get('[data-cy=submitBtn]').click();
// Enter config setting name into filter box
this.seachTable(name);
cy.get('#description').type(description);
// Click the create button and wait for role to be made
- cy.contains('button', 'Create Role').click();
+ cy.get('[data-cy=submitBtn]').click();
cy.get('.breadcrumb-item.active').should('not.have.text', 'Create');
this.getFirstTableCell(name).should('exist');
cy.get('#description').clear().type(description);
// Click the edit button and check new values are present in table
- cy.contains('button', 'Edit Role').click();
+ cy.get('[data-cy=submitBtn]').click();
cy.get('.breadcrumb-item.active').should('not.have.text', 'Edit');
this.getFirstTableCell(name).should('exist');
cy.get('#email').type(email);
// Click the create button and wait for user to be made
- cy.contains('button', 'Create User').click();
+ cy.get('[data-cy=submitBtn]').click();
this.getFirstTableCell(username).should('exist');
}
cy.get('#email').clear().type(email);
// Click the edit button and check new values are present in table
- const editButton = cy.contains('button', 'Edit User');
+ const editButton = cy.get('[data-cy=submitBtn]');
editButton.click();
this.getFirstTableCell(email).should('exist');
this.getFirstTableCell(name).should('exist');
</div>
<div class="modal-footer">
- <cd-submit-button (submitAction)="submitAction()"
- [form]="discoveryForm"
- *ngIf="hasPermission"
- i18n>Submit</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="submitAction()"
+ [form]="discoveryForm"
+ [showSubmit]="hasPermission"
+ [submitText]="actionLabels.SUBMIT"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { IscsiService } from '~/app/shared/api/iscsi.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import { CdValidators } from '~/app/shared/forms/cd-validators';
constructor(
private authStorageService: AuthStorageService,
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private iscsiService: IscsiService,
private notificationService: NotificationService
) {
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button (submitAction)="submit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="targetForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
</div>
<div class="modal-footer">
- <cd-submit-button i18n
- [form]="settingsForm"
- (submitAction)="save()">Confirm</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="save()"
+ [form]="settingsForm"
+ [submitText]="actionLabels.UPDATE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import _ from 'lodash';
import { IscsiService } from '~/app/shared/api/iscsi.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
@Component({
settingsForm: CdFormGroup;
- constructor(public activeModal: NgbActiveModal, public iscsiService: IscsiService) {}
+ constructor(
+ public activeModal: NgbActiveModal,
+ public iscsiService: IscsiService,
+ public actionLabels: ActionLabelsI18n
+ ) {}
ngOnInit() {
const fg: Record<string, FormControl> = {
</div>
<div class="modal-footer">
- <cd-submit-button i18n
- [form]="settingsForm"
- (submitAction)="save()">Confirm</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="save()"
+ [form]="settingsForm"
+ [submitText]="actionLabels.UPDATE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import _ from 'lodash';
import { IscsiService } from '~/app/shared/api/iscsi.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
@Component({
settingsForm: CdFormGroup;
- constructor(public activeModal: NgbActiveModal, public iscsiService: IscsiService) {}
+ constructor(
+ public activeModal: NgbActiveModal,
+ public iscsiService: IscsiService,
+ public actionLabels: ActionLabelsI18n
+ ) {}
ngOnInit() {
const fg: Record<string, FormControl> = {};
</div>
<div class="modal-footer">
- <cd-submit-button i18n
- [form]="importBootstrapForm"
- (submitAction)="import()">Import</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Close"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="import()"
+ [form]="importBootstrapForm"
+ [submitText]="actionLabels.SUBMIT"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { Pool } from '~/app/ceph/pool/pool';
import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import { FinishedTask } from '~/app/shared/models/finished-task';
import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
constructor(
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private rbdMirroringService: RbdMirroringService,
private taskWrapper: TaskWrapperService
) {
</div>
<div class="modal-footer">
- <cd-submit-button i18n
- [form]="editSiteNameForm"
- (submitAction)="update()">Update</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="update()"
+ [form]="editSiteNameForm"
+ [submitText]="actionLabels.UPDATE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import { FinishedTask } from '~/app/shared/models/finished-task';
import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
constructor(
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private rbdMirroringService: RbdMirroringService,
private taskWrapper: TaskWrapperService
) {
</div>
<div class="modal-footer">
- <cd-submit-button i18n
- [form]="editModeForm"
- (submitAction)="update()">Update</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="update()"
+ [form]="editModeForm"
+ [submitText]="actionLabels.UPDATE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { Subscription } from 'rxjs';
import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import { FinishedTask } from '~/app/shared/models/finished-task';
import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
constructor(
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private rbdMirroringService: RbdMirroringService,
private taskWrapper: TaskWrapperService
) {
</div>
<div class="modal-footer">
- <cd-submit-button i18n
- [form]="editPeerForm"
- (submitAction)="update()">Submit</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="update()"
+ [form]="editPeerForm"
+ [submitText]="actionLabels.SUBMIT"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { RbdMirroringService } from '~/app/shared/api/rbd-mirroring.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import { FinishedTask } from '~/app/shared/models/finished-task';
import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
constructor(
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private rbdMirroringService: RbdMirroringService,
private taskWrapper: TaskWrapperService
) {
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button (submitAction)="submit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="formDir"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
</div>
<div class="modal-footer">
- <cd-submit-button [form]="namespaceForm"
- (submitAction)="submit()"
- i18n>Create Namespace</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Close"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="namespaceForm"
+ [submitText]="actionLabels.CREATE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { Pool } from '~/app/ceph/pool/pool';
import { PoolService } from '~/app/shared/api/pool.service';
import { RbdService } from '~/app/shared/api/rbd.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import { FinishedTask } from '~/app/shared/models/finished-task';
constructor(
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private authStorageService: AuthStorageService,
private notificationService: NotificationService,
private poolService: PoolService,
</div>
<div class="modal-footer">
- <cd-submit-button [form]="snapshotForm"
- i18n="form action button|Example: Create rbdSnapshot@@formActionButton"
- (submitAction)="submit()">{{ action | titlecase }}
- {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Close"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="snapshotForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
</div>
</form>
</ng-container>
</div>
<div class="modal-footer">
- <cd-submit-button i18n
- [form]="moveForm"
- (submitAction)="moveImage()">Move Image</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="moveImage()"
+ [form]="moveForm"
+ [submitText]="actionLabels.MOVE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import moment from 'moment';
import { RbdService } from '~/app/shared/api/rbd.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import { CdValidators } from '~/app/shared/forms/cd-validators';
constructor(
private rbdService: RbdService,
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private fb: CdFormBuilder,
private taskWrapper: TaskWrapperService
) {
</div>
<div class="modal-footer">
- <cd-submit-button id="purgeFormButton"
- [form]="purgeForm"
- (submitAction)="purge()"
- i18n>Purge Trash</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="purge()"
+ [form]="purgeForm"
+ [submitText]="actionLabels.PURGE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { Pool } from '~/app/ceph/pool/pool';
import { PoolService } from '~/app/shared/api/pool.service';
import { RbdService } from '~/app/shared/api/rbd.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import { FinishedTask } from '~/app/shared/models/finished-task';
private authStorageService: AuthStorageService,
private rbdService: RbdService,
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private fb: CdFormBuilder,
private poolService: PoolService,
private taskWrapper: TaskWrapperService
</div>
<div class="modal-footer">
- <cd-submit-button [form]="restoreForm"
- (submitAction)="restore()"
- i18n>Restore Image</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="restore()"
+ [form]="restoreForm"
+ [submitText]="actionLabels.RESTORE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { RbdService } from '~/app/shared/api/rbd.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import { ExecutingTask } from '~/app/shared/models/executing-task';
constructor(
private rbdService: RbdService,
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private fb: CdFormBuilder,
private taskWrapper: TaskWrapperService
) {}
</div>
<!-- Footer -->
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button [form]="formDir"
- (submitAction)="submit()">
- <span i18n>Save</span>
- </cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="configForm"
+ [submitText]="actionLabels.UPDATE"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
import { ConfigurationService } from '~/app/shared/api/configuration.service';
import { ConfigFormModel } from '~/app/shared/components/config-option/config-option.model';
import { ConfigOptionTypes } from '~/app/shared/components/config-option/config-option.types';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
import { CdForm } from '~/app/shared/forms/cd-form';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
availSections = ['global', 'mon', 'mgr', 'osd', 'mds', 'client'];
constructor(
+ public actionLabels: ActionLabelsI18n,
private route: ActivatedRoute,
private router: Router,
private configService: ConfigurationService,
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button [form]="formDir"
- i18n="form action button|Example: Create Pool@@formActionButton"
- (submitAction)="submit()">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="hostForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
</div>
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button (submitAction)="onSubmit()"
- [form]="mgrModuleForm">
- <ng-container i18n>Update</ng-container>
- </cd-submit-button>
- <button type="button"
- class="btn btn-light"
- routerLink="/mgr-modules"
- i18n>Back</button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="mgrModuleForm"
+ [submitText]="actionLabels.UPDATE"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
import { forkJoin as observableForkJoin } from 'rxjs';
import { MgrModuleService } from '~/app/shared/api/mgr-module.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
import { CdForm } from '~/app/shared/forms/cd-form';
import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
moduleOptions: any[] = [];
constructor(
+ public actionLabels: ActionLabelsI18n,
private route: ActivatedRoute,
private router: Router,
private formBuilder: CdFormBuilder,
<pre>{{ driveGroups | json}}</pre>
</div>
<div class="modal-footer">
- <cd-submit-button (submitAction)="onSubmit()"
- [form]="formGroup">{{ action | titlecase }}</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"></cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="formGroup"
+ [submitText]="action | titlecase"></cd-form-button-panel>
</div>
</form>
</ng-container>
</div>
</div>
<div class="modal-footer">
- <cd-submit-button (submitAction)="onSubmit()"
- [form]="formGroup"
- [disabled]="!canSubmit || filteredDevices.length === 0">{{ action | titlecase }}</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"></cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="formGroup"
+ [disabled]="!canSubmit || filteredDevices.length === 0"
+ [submitText]="action | titlecase"></cd-form-button-panel>
</div>
</form>
</ng-container>
const expectSubmitButton = (enabled: boolean) => {
const nativeElement = fixture.debugElement.nativeElement;
- const button = nativeElement.querySelector('.modal-footer button');
+ const button = nativeElement.querySelector('.modal-footer .tc_submitButton');
expect(button.disabled).toBe(!enabled);
};
class="btn btn-light"
(click)="resetSelection()"
i18n>Restore previous selection</button>
- <cd-submit-button *ngIf="permissions.osd.update"
- (submitAction)="submitAction()"
- [form]="osdFlagsForm"
- i18n>Submit</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="submitAction()"
+ [form]="osdFlagsForm"
+ [showSubmit]="permissions.osd.update"
+ [submitText]="actionLabels.UPDATE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import _ from 'lodash';
import { OsdService } from '~/app/shared/api/osd.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
import { Flag } from '~/app/shared/models/flag';
import { Permissions } from '~/app/shared/models/permissions';
constructor(
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private authStorageService: AuthStorageService,
private osdService: OsdService,
private notificationService: NotificationService
</div>
<div class="modal-footer">
- <cd-submit-button *ngIf="permissions.osd.update"
- (submitAction)="submitAction()"
- [form]="osdFlagsForm"
- i18n>Submit</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="submitAction()"
+ [form]="osdFlagsForm"
+ [showSubmit]="permissions.osd.update"
+ [submitText]="actionLabels.UPDATE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import _ from 'lodash';
import { OsdService } from '~/app/shared/api/osd.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
import { Permissions } from '~/app/shared/models/permissions';
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
constructor(
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private authStorageService: AuthStorageService,
private osdService: OsdService,
private notificationService: NotificationService
</fieldset>
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button #previewButton
- (submitAction)="submit()"
- i18n
- [form]="formDir"
- [disabled]="dataDeviceSelectionGroups.devices.length === 0">Preview</cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="form"
+ [disabled]="dataDeviceSelectionGroups.devices.length === 0"
+ [submitText]="actionLabels.PREVIEW"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
];
const expectPreviewButton = (enabled: boolean) => {
- const debugElement = fixtureHelper.getElementByCss('.card-footer button');
+ const debugElement = fixtureHelper.getElementByCss('.tc_submitButton');
expect(debugElement.nativeElement.disabled).toBe(!enabled);
};
</div>
</div>
<div class="modal-footer">
- <cd-submit-button *ngIf="permissions.configOpt.update"
- (submitAction)="submitAction()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="osdPgScrubForm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()">
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="submitAction()"
+ [form]="osdPgScrubForm"
+ [showSubmit]="permissions.configOpt.update"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)">
+ </cd-form-button-panel>
</div>
</form>
</ng-container>
</div>
</div>
<div class="modal-footer">
- <cd-submit-button *ngIf="permissions.configOpt.update"
- (submitAction)="submitAction()"
- [form]="osdRecvSpeedForm"
- i18n>Submit</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="submitAction()"
+ [form]="osdRecvSpeedForm"
+ [submitText]="actionLabels.UPDATE"
+ [showSubmit]="permissions.configOpt.update"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { ConfigurationService } from '~/app/shared/api/configuration.service';
import { OsdService } from '~/app/shared/api/osd.service';
import { ConfigOptionTypes } from '~/app/shared/components/config-option/config-option.types';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import { Permissions } from '~/app/shared/models/permissions';
constructor(
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private authStorageService: AuthStorageService,
private configService: ConfigurationService,
private notificationService: NotificationService,
</div>
<div class="modal-footer">
- <cd-submit-button (submitAction)="reweight()"
- [form]="reweightForm"
- [disabled]="reweightForm.invalid"
- i18n>Reweight</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="reweight()"
+ [form]="reweightForm"
+ [submitText]="actionLabels.REWEIGHT"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
SubmitButtonComponent,
BackButtonComponent
],
+ schemas: [NO_ERRORS_SCHEMA],
providers: [OsdService, NgbActiveModal, CdFormBuilder]
});
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import { OsdService } from '~/app/shared/api/osd.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
reweightForm: CdFormGroup;
constructor(
+ public actionLabels: ActionLabelsI18n,
public activeModal: NgbActiveModal,
private osdService: OsdService,
private fb: CdFormBuilder
</div>
<div class="modal-footer">
- <cd-submit-button (submitAction)="scrub()"
- [form]="scrubForm"
- i18n>Submit</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="scrub()"
+ [form]="scrubForm"
+ [submitText]="actionLabels.UPDATE"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { forkJoin } from 'rxjs';
import { OsdService } from '~/app/shared/api/osd.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
import { JoinPipe } from '~/app/shared/pipes/join.pipe';
import { NotificationService } from '~/app/shared/services/notification.service';
constructor(
public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n,
private osdService: OsdService,
private notificationService: NotificationService,
private joinPipe: JoinPipe
<div class="card-footer">
<div class="text-right">
- <cd-submit-button (submitAction)="submit()"
- [form]="formDir"
- i18n="@@formTitle">
- {{ action | titlecase }} {{ resource | upperFirst }}
- </cd-submit-button>
- <cd-back-button></cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="form"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
</div>
</div>
</div>
</div>
<div class="modal-footer">
- <cd-submit-button (submitAction)="onSubmit()"
- [form]="form">
- <span i18n>{editMode, select, true {Edit} other {Add}}</span>
- </cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Close"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="form"
+ [submitText]="getMode()"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { merge, Observable, Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, filter, map } from 'rxjs/operators';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
import {
constructor(
private formBuilder: CdFormBuilder,
private silenceMatcher: PrometheusSilenceMatcherService,
- public activeModal: NgbActiveModal
+ public activeModal: NgbActiveModal,
+ public actionLabels: ActionLabelsI18n
) {
this.createForm();
this.subscribeToChanges();
);
}
+ getMode() {
+ return this.editMode ? this.actionLabels.EDIT : this.actionLabels.ADD;
+ }
+
preFillControls(matcher: AlertmanagerSilenceMatcher) {
this.form.setValue(matcher);
}
<div class="card-footer">
<div class="text-right">
- <cd-submit-button (submitAction)="onSubmit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="serviceForm">{{ action | titlecase }} {{ resource | upperFirst }}
- </cd-submit-button>
- <cd-back-button></cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="serviceForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
</div>
</div>
</div>
<button type="button"
class="btn btn-light"
(click)="next()">
- <ng-container i18n>Next</ng-container>
+ <ng-container i18n>{{ actionLabels.NEXT }}</ng-container>
</button>
</div>
</div>
</div>
<div class="card-footer">
<div class="button-group text-right">
- <cd-submit-button (submitAction)="onSubmit()"
- [form]="previewForm">
- <ng-container i18n>Save</ng-container>
- </cd-submit-button>
- <button type="button"
- class="btn btn-light"
- (click)="back()"
- i18n>Back</button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ (backActionEvent)="back()"
+ [form]="previewForm"
+ [submitText]="actionLabels.UPDATE"
+ [cancelText]="actionLabels.BACK"></cd-form-button-panel>
</div>
</div>
</div>
import { MgrModuleService } from '~/app/shared/api/mgr-module.service';
import { TelemetryService } from '~/app/shared/api/telemetry.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
import { CdForm } from '~/app/shared/forms/cd-form';
import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
step = 1;
constructor(
+ public actionLabels: ActionLabelsI18n,
private formBuilder: CdFormBuilder,
private mgrModuleService: MgrModuleService,
private notificationService: NotificationService,
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button
- (submitAction)="submitAction()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="submitAction()"
+ [form]="nfsForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
</div>
<div class="modal-footer">
- <cd-submit-button (submitAction)="onSubmit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="frm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"></cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="form"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
</div>
</form>
</ng-container>
</div>
<div class="modal-footer">
- <cd-submit-button (submitAction)="onSubmit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="frm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"></cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="form"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
</div>
</form>
</ng-container>
</div>
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button [form]="formDir"
- i18n="form action button|Example: Create Pool@@formActionButton"
- (submitAction)="submit()">{{ action | titlecase }} {{ resource | upperFirst }}
- </cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="form"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button (submitAction)="submit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="bucketForm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="bucketForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
</div>
<div class="modal-footer">
- <cd-submit-button (submitAction)="onSubmit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="formGroup">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"></cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="formGroup"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
</div>
</form>
</ng-container>
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button (submitAction)="onSubmit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="userForm">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="userForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
</div>
<div class="modal-footer">
- <cd-submit-button *ngIf="!viewing"
- (submitAction)="onSubmit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="formGroup">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"></cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="formGroup"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ [showSubmit]="!viewing"></cd-form-button-panel>
</div>
</form>
</ng-container>
<cd-modal [modalRef]="bsModalRef">
<ng-container i18n="form title|Example: Create Pool@@formTitle"
class="modal-title">{{ action | titlecase }} {{ resource | upperFirst }}</ng-container>
-
<ng-container class="modal-content">
<form #frm="ngForm"
[formGroup]="formGroup"
</div>
<div class="modal-footer">
- <cd-submit-button (submitAction)="onSubmit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="formGroup">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button (backAction)="bsModalRef.close()"></cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="formGroup"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
</div>
</form>
</ng-container>
*ngIf="userForm.showError('confirmnewpassword', frm, 'match')"
i18n>Password confirmation doesn't match the new password.</span>
</div>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ (backActionEvent)="onCancel()"
+ [form]="userForm"
+ [disabled]="userForm.invalid"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</form>
- <div class="form-footer">
- <cd-submit-button class="full-width"
- btnClass="btn-block"
- (submitAction)="onSubmit()"
- [form]="userForm"
- [disabled]="userForm.invalid"
- i18n="form action button|Example: Create Pool@@formActionButton">
- {{ action | titlecase }} {{ resource | upperFirst }}
- </cd-submit-button>
- <button class="btn btn-light"
- (click)="onCancel()">
- <ng-container i18n>Cancel</ng-container>
- </button>
- </div>
</div>
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button (submitAction)="submit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="roleForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
</div>
<div class="card-footer">
- <div class="text-right">
- <cd-submit-button (submitAction)="submit()"
- i18n="form action button|Example: Create Pool@@formActionButton"
- [form]="formDir">{{ action | titlecase }} {{ resource | upperFirst }}</cd-submit-button>
- <cd-back-button></cd-back-button>
- </div>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="userForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
</div>
<div class="card-footer">
- <cd-submit-button (submitAction)="onSubmit()"
- [form]="userForm"
- class="float-right"
- i18n="form action button|Example: Create Pool@@formActionButton">
- {{ action | titlecase }} {{ resource | upperFirst }}
- </cd-submit-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit()"
+ [form]="userForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
+ wrappingClass="text-right"></cd-form-button-panel>
</div>
</div>
</form>
import { DateTimePickerComponent } from './date-time-picker/date-time-picker.component';
import { DocComponent } from './doc/doc.component';
import { DownloadButtonComponent } from './download-button/download-button.component';
+import { FormButtonPanelComponent } from './form-button-panel/form-button-panel.component';
import { FormModalComponent } from './form-modal/form-modal.component';
import { GrafanaComponent } from './grafana/grafana.component';
import { HelperComponent } from './helper/helper.component';
OrchestratorDocPanelComponent,
DateTimePickerComponent,
DocComponent,
- DownloadButtonComponent
+ DownloadButtonComponent,
+ FormButtonPanelComponent
],
providers: [],
exports: [
OrchestratorDocPanelComponent,
DateTimePickerComponent,
DocComponent,
- DownloadButtonComponent
+ DownloadButtonComponent,
+ FormButtonPanelComponent
]
})
export class ComponentsModule {}
</p>
</div>
<div class="modal-footer">
- <cd-submit-button [form]="confirmationForm"
- (submitAction)="onSubmit(confirmationForm.value)">
- {{ buttonText }}
- </cd-submit-button>
- <cd-back-button (backAction)="boundCancel()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmit(confirmationForm.value)"
+ (backActionEvent)="boundCancel()"
+ [form]="confirmationForm"
+ [submitText]="buttonText"></cd-form-button-panel>
</div>
</form>
</ng-container>
import { Component, NgModule, NO_ERRORS_SCHEMA, TemplateRef, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
-import { By } from '@angular/platform-browser';
import { RouterTestingModule } from '@angular/router/testing';
import { NgbActiveModal, NgbModalModule, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import { ModalService } from '~/app/shared/services/modal.service';
import { configureTestBed, FixtureHelper } from '~/testing/unit-test-helper';
import { BackButtonComponent } from '../back-button/back-button.component';
+import { FormButtonPanelComponent } from '../form-button-panel/form-button-panel.component';
import { ModalComponent } from '../modal/modal.component';
import { SubmitButtonComponent } from '../submit-button/submit-button.component';
import { ConfirmationModalComponent } from './confirmation-modal.component';
BackButtonComponent,
MockComponent,
ModalComponent,
- SubmitButtonComponent
+ SubmitButtonComponent,
+ FormButtonPanelComponent
],
schemas: [NO_ERRORS_SCHEMA],
imports: [ReactiveFormsModule, MockModule, RouterTestingModule, NgbModalModule],
- providers: [NgbActiveModal, SubmitButtonComponent]
+ providers: [NgbActiveModal, SubmitButtonComponent, FormButtonPanelComponent]
});
beforeEach(() => {
it('should use the correct submit action', () => {
// In order to ignore the `ElementRef` usage of `SubmitButtonComponent`
- spyOn(
- fixture.debugElement.query(By.directive(SubmitButtonComponent)).componentInstance,
- 'focusButton'
- );
+ spyOn(fh.getElementByCss('.tc_submitButton').componentInstance, 'focusButton');
fh.clickElement('.tc_submitButton');
expect(component.onSubmit).toHaveBeenCalledTimes(1);
expect(component.activeModal.close).toHaveBeenCalledTimes(0);
</div>
</div>
<div class="modal-footer">
- <cd-submit-button #submitButton
- [form]="deletionForm"
- (submitAction)="callSubmitAction()">
- <ng-container *ngTemplateOutlet="deletionHeading"></ng-container>
- </cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"
- name="Cancel"
- i18n-name>
- </cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="callSubmitAction()"
+ [form]="deletionForm"
+ [submitText]="(actionDescription | titlecase) + ' ' + itemDescription"></cd-form-button-panel>
</div>
</form>
</ng-container>
--- /dev/null
+<div [class]="wrappingClass">
+ <cd-back-button class="m-2"
+ (backAction)="backAction()"
+ [name]="cancelText"></cd-back-button>
+ <cd-submit-button *ngIf="showSubmit"
+ (submitAction)="submitAction()"
+ [disabled]="disabled"
+ [form]="form"
+ data-cy="submitBtn">{{ submitText }}</cd-submit-button>
+</div>
--- /dev/null
+import { NO_ERRORS_SCHEMA } from '@angular/core';
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { configureTestBed } from '~/testing/unit-test-helper';
+import { FormButtonPanelComponent } from './form-button-panel.component';
+
+describe('FormButtonPanelComponent', () => {
+ let component: FormButtonPanelComponent;
+ let fixture: ComponentFixture<FormButtonPanelComponent>;
+
+ configureTestBed({
+ declarations: [FormButtonPanelComponent],
+ schemas: [NO_ERRORS_SCHEMA]
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FormButtonPanelComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+import { Location } from '@angular/common';
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { FormGroup, NgForm } from '@angular/forms';
+
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
+import { ModalService } from '~/app/shared/services/modal.service';
+
+@Component({
+ selector: 'cd-form-button-panel',
+ templateUrl: './form-button-panel.component.html',
+ styleUrls: ['./form-button-panel.component.scss']
+})
+export class FormButtonPanelComponent {
+ @Output()
+ submitActionEvent = new EventEmitter();
+ @Output()
+ backActionEvent = new EventEmitter();
+
+ @Input()
+ form: FormGroup | NgForm;
+ @Input()
+ showSubmit = true;
+ @Input()
+ wrappingClass = '';
+ @Input()
+ btnClass = '';
+ @Input()
+ submitText: string = this.actionLabels.CREATE;
+ @Input()
+ cancelText: string = this.actionLabels.CANCEL;
+ @Input()
+ disabled = false;
+
+ constructor(
+ private location: Location,
+ private actionLabels: ActionLabelsI18n,
+ private modalService: ModalService
+ ) {}
+
+ submitAction() {
+ this.submitActionEvent.emit();
+ }
+
+ backAction() {
+ if (this.backActionEvent.observers.length === 0) {
+ if (this.modalService.hasOpenModals()) {
+ this.modalService.dismissAll();
+ } else {
+ this.location.back();
+ }
+ } else {
+ this.backActionEvent.emit();
+ }
+ }
+}
</ng-container>
</div>
<div class="modal-footer">
- <cd-submit-button [form]="formGroup"
- (submitAction)="onSubmitForm(formGroup.value)">
- {{ submitButtonText }}
- </cd-submit-button>
- <cd-back-button (backAction)="activeModal.close()"></cd-back-button>
+ <cd-form-button-panel (submitActionEvent)="onSubmitForm(formGroup.value)"
+ [form]="formGroup"
+ [submitText]="submitButtonText"></cd-form-button-panel>
</div>
</form>
</ng-container>