cy.get('[data-cy=submitBtn]').click();
this.getExpandCollapseElement(newName).click();
- cy.get('.table.table-striped.table-bordered').contains('td', newSize);
+ cy.get('[data-testid=rbd-details-table]').contains('td', newSize);
}
// Selects RBD image and moves it to the trash,
values.forEach((value) => {
// iterates through list of values and
// checks if the value appears in details with the correct number attatched
- cy.contains('.table.table-striped.table-bordered', `${value[0]}\: ${value[1]}`);
+ cy.contains('[data-testid=config-details-table]', `${value[0]}\: ${value[1]}`);
});
}
}
it('should authenticate the second cluster', () => {
multiCluster.auth(url, alias, username, password);
multiCluster.existTableCell(alias);
+ multiCluster.checkConnectionStatus(alias, 'CONNECTED');
});
it('should switch to the second cluster and back to hub', () => {
+ multiCluster.checkConnectionStatus(alias, 'CONNECTED');
dashboard.navigateTo();
cy.get('[data-testid="selected-cluster"]').click();
cy.get('[data-testid="select-a-cluster"]').contains(alias).click();
});
it('should reconnect the second cluster', () => {
+ multiCluster.checkConnectionStatus(alias, 'CONNECTED');
multiCluster.reconnect(alias, password);
multiCluster.existTableCell(alias);
});
it('should edit the second cluster', () => {
+ multiCluster.checkConnectionStatus(alias, 'CONNECTED');
multiCluster.edit(alias, editedAlias);
multiCluster.existTableCell(editedAlias);
});
it('should disconnect the second cluster', () => {
+ multiCluster.checkConnectionStatus(editedAlias, 'CONNECTED');
multiCluster.disconnect(editedAlias);
multiCluster.existTableCell(editedAlias, false);
});
export class MultiClusterPageHelper extends PageHelper {
pages = pages;
+ columnIndex = {
+ alias: 2,
+ connection: 3
+ };
+
auth(url: string, alias: string, username: string, password: string) {
cy.contains('button', 'Connect').click();
cy.get('cd-multi-cluster-form').should('exist');
});
cy.wait(WAIT_TIMER);
}
+
+ checkConnectionStatus(alias: string, expectedStatus = 'CONNECTED', shouldReload = true) {
+ let aliasIndex = this.columnIndex.alias;
+ let statusIndex = this.columnIndex.connection;
+ if (shouldReload) {
+ cy.reload(true, { log: true, timeout: 5 * 1000 });
+ }
+
+ this.getTableCell(aliasIndex, alias)
+ .parent()
+ .find(`[cdstabledata]:nth-child(${statusIndex}) .badge`)
+ .should(($ele) => {
+ const status = $ele.toArray().map((v) => v.innerText);
+ expect(status).to.include(expectedStatus);
+ });
+ }
}
* Grabs striped tables
*/
getStatusTables() {
- return cy.get('.table.table-striped');
+ return cy.get(
+ '.cds--data-table--sort.cds--data-table--no-border.cds--data-table.cds--data-table--md'
+ );
}
filterTable(name: string, option: string) {
this.getExpandCollapseElement(name).click();
// check its details table for edited owner field
- cy.get('.table.table-striped.table-bordered').first().as('bucketDataTable');
+ cy.get('[data-testid="rgw-bucket-details"]').first().as('bucketDataTable');
// Check versioning enabled:
cy.get('@bucketDataTable').find('tr').its(0).find('td').last().as('versioningValueCell');
this.getExpandCollapseElement(name).click();
// Check versioning enabled:
- cy.get('.table.table-striped.table-bordered').first().as('bucketDataTable');
+ cy.get('[data-testid="rgw-bucket-details"]').first().as('bucketDataTable');
cy.get('@bucketDataTable').find('tr').its(0).find('td').last().as('versioningValueCell');
cy.get('@versioningValueCell').should('have.text', this.versioningStateEnabled);
import { NvmeofSubsystemInitiator } from '~/app/shared/models/nvmeof';
import { Permission } from '~/app/shared/models/permissions';
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
-import { ModalService } from '~/app/shared/services/modal.service';
+import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
const BASE_URL = 'block/nvmeof/subsystems';
public actionLabels: ActionLabelsI18n,
private authStorageService: AuthStorageService,
private nvmeofService: NvmeofService,
- private modalService: ModalService,
+ private modalService: ModalCdsService,
private router: Router,
private taskWrapper: TaskWrapperService
) {
import { NvmeofListener } from '~/app/shared/models/nvmeof';
import { Permission } from '~/app/shared/models/permissions';
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
-import { ModalService } from '~/app/shared/services/modal.service';
+import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
const BASE_URL = 'block/nvmeof/subsystems';
constructor(
public actionLabels: ActionLabelsI18n,
- private modalService: ModalService,
+ private modalService: ModalCdsService,
private authStorageService: AuthStorageService,
private taskWrapper: TaskWrapperService,
private nvmeofService: NvmeofService,
import { IopsPipe } from '~/app/shared/pipes/iops.pipe';
import { MbpersecondPipe } from '~/app/shared/pipes/mbpersecond.pipe';
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
-import { ModalService } from '~/app/shared/services/modal.service';
+import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
const BASE_URL = 'block/nvmeof/subsystems';
constructor(
public actionLabels: ActionLabelsI18n,
private router: Router,
- private modalService: ModalService,
+ private modalService: ModalCdsService,
private authStorageService: AuthStorageService,
private taskWrapper: TaskWrapperService,
private nvmeofService: NvmeofService,
<a ngbNavLink
i18n>Details</a>
<ng-template ngbNavContent>
- <table class="table table-striped table-bordered">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="rbd-details-table">
<tbody>
- <tr>
+ <tr cdstablerow>
<td i18n
- class="bold w-25">Name</td>
+ class="bold w-25"
+ cdstabledata>Name</td>
<td class="w-75">{{ selection.name }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
- class="bold">Pool</td>
+ class="bold"
+ cdstabledata>Pool</td>
<td>{{ selection.pool_name }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Data Pool</td>
<td>{{ selection.data_pool | empty }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Created</td>
<td>{{ selection.timestamp | cdDate }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Size</td>
<td>{{ selection.size | dimlessBinary }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Objects</td>
<td>{{ selection.num_objs | dimless }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Object size</td>
<td>{{ selection.obj_size | dimlessBinary }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Features</td>
<td>
</span>
</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Provisioned</td>
<td>
</span>
</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Total provisioned</td>
<td>
</span>
</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Striping unit</td>
<td>{{ selection.stripe_unit | dimlessBinary }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Striping count</td>
<td>{{ selection.stripe_count }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Parent</td>
<td>
<span *ngIf="!selection.parent">-</span>
</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Block name prefix</td>
<td>{{ selection.block_name_prefix }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Order</td>
<td>{{ selection.order }}</td>
</tr>
- <tr>
+ <tr cdstablerow>
<td i18n
class="bold">Format Version</td>
<td>{{ selection.image_format }}</td>
<ng-template #mirroringTpl
let-value="data.value"
let-row="data.row">
- <span *ngIf="value.length === 3; else probb"
+ <span *ngIf="value?.length === 3; else probb"
class="badge badge-info">{{ value[0] }}</span>
- <span *ngIf="value.length === 3"
+ <span *ngIf="value?.length === 3"
class="badge badge-info">{{ value[1] }}</span>
- <span *ngIf="row.primary === true"
+ <span *ngIf="row?.primary === true"
class="badge badge-info"
i18n>primary</span>
- <span *ngIf="row.primary === false"
+ <span *ngIf="row?.primary === false"
class="badge badge-info"
i18n>secondary</span>
<ng-template #probb>
images: any;
columns: CdTableColumn[];
retries: number;
- tableStatus = new TableStatus('light');
+ tableStatus = new TableStatus('ghost');
selection = new CdTableSelection();
icons = Icons;
count = 0;
<ng-container *ngIf="selection">
- <table class="table table-striped table-bordered">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="config-details-table">
<tbody>
<tr>
<td i18n
<fieldset>
<legend class="cd-header"
i18n>Cluster Resources</legend>
- <table class="table table-striped">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
<tr>
<td i18n
class="bold">Hosts</td>
<fieldset>
<legend class="cd-header"
i18n>Status</legend>
- <table class="table table-striped"
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
*ngIf="mon_status">
<tbody>
<tr>
(setExpandedRow)="setExpandedRow($event)"
[maxLimit]="25"
(updateSelection)="updateSelection($event)">
- <div class="table-actions">
- <cd-table-actions [permission]="permissions.user"
- [selection]="selection"
- class="btn-group"
- id="cluster-actions"
- [tableActions]="tableActions">
- </cd-table-actions>
- </div>
- <cd-multi-cluster-details cdTableDetail
+ <cd-table-actions [permission]="permissions.user"
+ [selection]="selection"
+ class="table-actions"
+ id="cluster-actions"
+ [tableActions]="tableActions">
+ </cd-table-actions>
+ <cd-multi-cluster-details *cdTableDetail
[permissions]="permissions"
[selection]="expandedRow">
</cd-multi-cluster-details>
})
]
],
- group: [null, Validators.required],
+ group: [
+ null,
+ CdValidators.requiredIf({
+ service_type: 'nvmeof'
+ })
+ ],
// RGW
rgw_frontend_port: [null, [CdValidators.number(false)]],
realm_name: [null],
i18n>Details</a>
<ng-template ngbNavContent>
- <table class="table table-striped table-bordered">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="rgw-bucket-details">
<tbody>
<tr>
<td i18n
<!-- Bucket quota -->
<div>
<legend i18n>Bucket quota</legend>
- <table class="table table-striped table-bordered">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="rgw-bucket-quota-details">
<tbody>
<tr>
<td i18n
<!-- Locking -->
<legend i18n>Locking</legend>
- <table class="table table-striped table-bordered">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md"
+ data-testid="rgw-bucket-locking-details">
<tbody>
<tr>
<td i18n
<!-- Tags -->
<ng-container *ngIf="(selection.tagset | keyvalue)?.length">
<legend i18n>Tags</legend>
- <table class="table table-striped table-bordered">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
<tbody>
<tr *ngFor="let tag of selection.tagset | keyvalue">
<td i18n
i18n>Policies</a>
<ng-template ngbNavContent>
<div class="table-scroller">
- <table class="table table-striped table-bordered">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
<tbody>
<tr>
<td i18n
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { AbstractControl, Validators } from '@angular/forms';
-import { Router } from '@angular/router';
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
import _ from 'lodash';
import { CdValidators } from '~/app/shared/forms/cd-validators';
import { NotificationService } from '~/app/shared/services/notification.service';
import { rgwBucketEncryptionModel } from '../models/rgw-bucket-encryption';
+import { TableComponent } from '~/app/shared/datatable/table/table.component';
@Component({
selector: 'cd-rgw-config-modal',
allEncryptionConfigValues: any = [];
editing = false;
action: string;
+ table: TableComponent;
constructor(
private formBuilder: CdFormBuilder,
public activeModal: NgbActiveModal,
- private router: Router,
public actionLabels: ActionLabelsI18n,
private rgwBucketService: RgwBucketService,
private notificationService: NotificationService
},
complete: () => {
this.activeModal.close();
- this.router.routeReuseStrategy.shouldReuseRoute = () => false;
- this.router.onSameUrlNavigation = 'reload';
- this.router.navigate([this.router.url]);
+ this.table?.refreshBtn();
}
});
}
<cd-table #table
[data]="encryptionConfigValues"
[columns]="columns"
+ (fetchData)="fetchData()"
identifier="unique_id"
[forceIdentifier]="true"
[hasDetails]="true"
-import { Component, EventEmitter, OnInit, Output } from '@angular/core';
+import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core';
import { NgbActiveModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
import _ from 'lodash';
import { ModalService } from '~/app/shared/services/modal.service';
import { RgwConfigModalComponent } from '../rgw-config-modal/rgw-config-modal.component';
import { rgwBucketEncryptionModel } from '../models/rgw-bucket-encryption';
+import { TableComponent } from '~/app/shared/datatable/table/table.component';
@Component({
selector: 'cd-rgw-configuration-page',
})
export class RgwConfigurationPageComponent extends ListWithDetails implements OnInit {
readonly vaultAddress = /^((https?:\/\/)|(www.))(?:([a-zA-Z]+)|(\d+\.\d+.\d+.\d+)):\d{4}$/;
+ @ViewChild(TableComponent)
+ table: TableComponent;
kmsProviders: string[];
}
];
- this.rgwBucketService.getEncryptionConfig().subscribe((data: any) => {
- this.allEncryptionValues = data;
- const allowedBackends = rgwBucketEncryptionModel.kmsProviders;
-
- const kmsBackends = this.getBackend(data, 'SSE_KMS');
- const s3Backends = this.getBackend(data, 'SSE_S3');
-
- const allKmsBackendsPresent = this.areAllAllowedBackendsPresent(allowedBackends, kmsBackends);
- const allS3BackendsPresent = this.areAllAllowedBackendsPresent(allowedBackends, s3Backends);
-
- this.disableCreate = allKmsBackendsPresent && allS3BackendsPresent;
- this.encryptionConfigValues = Object.values(data).flat();
- });
-
this.excludeProps = this.columns.map((column) => column.prop);
this.excludeProps.push('unique_id');
}
const initialState = {
action: 'edit',
editing: true,
- selectedEncryptionConfigValues: this.selection.first()
+ selectedEncryptionConfigValues: this.selection.first(),
+ table: this.table
};
this.bsModalRef = this.modalService.show(RgwConfigModalComponent, initialState, {
size: 'lg'
setExpandedRow(expandedRow: any) {
super.setExpandedRow(expandedRow);
}
+
+ fetchData() {
+ this.rgwBucketService.getEncryptionConfig().subscribe((data: any) => {
+ this.allEncryptionValues = data;
+ const allowedBackends = rgwBucketEncryptionModel.kmsProviders;
+
+ const kmsBackends = this.getBackend(data, 'SSE_KMS');
+ const s3Backends = this.getBackend(data, 'SSE_S3');
+
+ const allKmsBackendsPresent = this.areAllAllowedBackendsPresent(allowedBackends, kmsBackends);
+ const allS3BackendsPresent = this.areAllAllowedBackendsPresent(allowedBackends, s3Backends);
+
+ this.disableCreate = allKmsBackendsPresent && allS3BackendsPresent;
+ this.encryptionConfigValues = Object.values(data).flat();
+ });
+ }
}
<cd-table-actions class="btn-group mb-4 me-2"
[permission]="permission"
[selection]="selection"
- [tableActions]="createTableActions">
+ [tableActions]="createTableActions"
+ [primaryDropDown]="true">
</cd-table-actions>
</span>
<ng-template #migrateAndReplicationActionTpl>
*ngIf="metadata">
<legend>{{ metadataTitle }}</legend>
<div>
- <cd-table-key-value *cdTableDetail
- [data]="metadata">
+ <cd-table-key-value [data]="metadata">
</cd-table-key-value>
</div>
</div>
<div *ngIf="user">
<div *ngIf="keys.length">
<legend i18n>Keys</legend>
- <div>
- <cd-table [data]="keys"
- [columns]="keysColumns"
- columnMode="flex"
- selectionType="multi"
- forceIdentifier="true"
- (updateSelection)="updateKeysSelection($event)">
- <div class="table-actions">
- <div class="btn-group"
- dropdown>
- <button type="button"
- class="btn btn-accent"
- [disabled]="!keysSelection.hasSingleSelection"
- (click)="showKeyModal()">
- <i [ngClass]="[icons.show]"></i>
- <ng-container i18n>Show</ng-container>
- </button>
- </div>
- </div>
- </cd-table>
- </div>
+ <cd-table [data]="keys"
+ [columns]="keysColumns"
+ columnMode="flex"
+ selectionType="single"
+ forceIdentifier="true"
+ (updateSelection)="updateKeysSelection($event)">
+ <cd-table-actions class="table-actions"
+ [permission]="{read: true}"
+ [selection]="selection"
+ [tableActions]="tableAction"></cd-table-actions>
+ </cd-table>
</div>
<legend i18n>Details</legend>
- <table class="table table-striped table-bordered">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
<tbody>
<tr>
<td i18n
<!-- User quota -->
<div *ngIf="user.user_quota">
<legend i18n>User quota</legend>
- <table class="table table-striped table-bordered">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
<tbody>
<tr>
<td i18n
<!-- Bucket quota -->
<div *ngIf="user.bucket_quota">
<legend i18n>Bucket quota</legend>
- <table class="table table-striped table-bordered">
+ <table class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
<tbody>
<tr>
<td i18n
fixture.detectChanges();
const detailsTab = fixture.debugElement.nativeElement.querySelectorAll(
- '.table.table-striped.table-bordered tr td'
+ '.cds--data-table--sort.cds--data-table--no-border tr td'
);
expect(detailsTab[10].textContent).toEqual('System user');
expect(detailsTab[11].textContent).toEqual('Yes');
fixture.detectChanges();
const detailsTab = fixture.debugElement.nativeElement.querySelectorAll(
- '.table.table-striped.table-bordered tr td'
+ '.cds--data-table--sort.cds--data-table--no-border tr td'
);
expect(detailsTab[14].textContent).toEqual('MFAs(Id)');
expect(detailsTab[15].textContent).toEqual('testMFA1, testMFA2');
import { RgwUserSwiftKey } from '../models/rgw-user-swift-key';
import { RgwUserS3KeyModalComponent } from '../rgw-user-s3-key-modal/rgw-user-s3-key-modal.component';
import { RgwUserSwiftKeyModalComponent } from '../rgw-user-swift-key-modal/rgw-user-swift-key-modal.component';
+import { CdTableAction } from '~/app/shared/models/cd-table-action';
+import { Permissions } from '~/app/shared/models/permissions';
@Component({
selector: 'cd-rgw-user-details',
keys: any = [];
keysColumns: CdTableColumn[] = [];
keysSelection: CdTableSelection = new CdTableSelection();
+ tableAction: CdTableAction[] = [];
+ permissions: Permissions;
icons = Icons;
}
ngOnChanges() {
+ this.tableAction = [
+ {
+ name: $localize`Show`,
+ permission: 'read',
+ click: () => this.showKeyModal(),
+ icon: Icons.show
+ }
+ ];
+
if (this.selection) {
this.user = this.selection;
this.staleTimeout = window.setTimeout(() => {
this.ngZone.run(() => {
this.tableStatus = new TableStatus(
- 'warning',
+ 'secondary',
$localize`The user list data might be stale. If needed, you can manually reload it.`
);
});
it('should create an instance', () => {
const ts = new TableStatusViewCache();
expect(ts).toBeTruthy();
- expect(ts).toEqual({ msg: '', type: 'light' });
+ expect(ts).toEqual({ msg: '', type: 'ghost' });
});
it('should create a ValueStale instance', () => {
let ts = new TableStatusViewCache(ViewCacheStatus.ValueStale);
- expect(ts).toEqual({ type: 'warning', msg: 'Displaying previously cached data.' });
+ expect(ts).toEqual({ type: 'secondary', msg: 'Displaying previously cached data.' });
ts = new TableStatusViewCache(ViewCacheStatus.ValueStale, 'foo bar');
- expect(ts).toEqual({ type: 'warning', msg: 'Displaying previously cached data for foo bar.' });
+ expect(ts).toEqual({
+ type: 'secondary',
+ msg: 'Displaying previously cached data for foo bar.'
+ });
});
it('should create a ValueNone instance', () => {
let ts = new TableStatusViewCache(ViewCacheStatus.ValueNone);
- expect(ts).toEqual({ type: 'info', msg: 'Retrieving data. Please wait...' });
+ expect(ts).toEqual({ type: 'primary', msg: 'Retrieving data. Please wait...' });
ts = new TableStatusViewCache(ViewCacheStatus.ValueNone, 'foo bar');
- expect(ts).toEqual({ type: 'info', msg: 'Retrieving data for foo bar. Please wait...' });
+ expect(ts).toEqual({ type: 'primary', msg: 'Retrieving data for foo bar. Please wait...' });
});
it('should create a ValueException instance', () => {
switch (status) {
case ViewCacheStatus.ValueOk:
- this.type = 'light';
+ this.type = 'ghost';
this.msg = '';
break;
case ViewCacheStatus.ValueNone:
- this.type = 'info';
+ this.type = 'primary';
this.msg =
(statusFor ? $localize`Retrieving data for ${statusFor}.` : $localize`Retrieving data.`) +
' ' +
$localize`Please wait...`;
break;
case ViewCacheStatus.ValueStale:
- this.type = 'warning';
+ this.type = 'secondary';
this.msg = statusFor
? $localize`Displaying previously cached data for ${statusFor}.`
: $localize`Displaying previously cached data.`;
it('should create an instance', () => {
const ts = new TableStatus();
expect(ts).toBeTruthy();
- expect(ts).toEqual({ msg: '', type: 'light' });
+ expect(ts).toEqual({ msg: '', type: 'ghost' });
});
it('should create with parameters', () => {
export class TableStatus {
- constructor(public type: 'info' | 'warning' | 'danger' | 'light' = 'light', public msg = '') {}
+ constructor(
+ public type: 'primary' | 'secondary' | 'danger' | 'ghost' = 'ghost',
+ public msg = ''
+ ) {}
}
</div>
<ng-container *ngIf="expandedRow && meta.detail_columns.length > 0">
<table *cdTableDetail
- class="table table-striped table-bordered">
+ class="cds--data-table--sort cds--data-table--no-border cds--data-table cds--data-table--md">
<tbody>
<tr *ngFor="let column of meta.detail_columns">
<td i18n
cdsIcon="add"
size="16"></svg>
</button>
+ <ng-container *ngIf="primaryDropDown">
+ <button class="primary-dropdown-btn"
+ [attr.aria-label]="dropDownOnly"
+ [offset]="{ x: -210, y: 65 }"
+ [cdsOverflowMenu]="overflowMenuTpl"
+ data-testid="table-action-btn">
+ <svg class="cds--btn__icon"
+ cdsIcon="caret--down"
+ size="16"></svg>
+ </button>
+ <ng-template #overflowMenuTpl>
+ <ng-container *ngFor="let action of dropDownActions">
+ <cds-overflow-menu-option *ngIf="currentAction !== action"
+ class="{{ toClassName(action) }}"
+ title="{{ useDisableDesc(action) }}"
+ (click)="useClickAction(action)"
+ [routerLink]="useRouterLink(action)"
+ [preserveFragment]="action.preserveFragment ? '' : null"
+ [disabled]="disableSelectionAction(action)"
+ [attr.aria-label]="action.name"
+ data-testid="table-action-option-btn"
+ i18n>
+ {{ action.name }}
+ </cds-overflow-menu-option>
+ </ng-container>
+ </ng-template>
+ </ng-container>
</ng-container>
+<ng-template #caret>
+ <button [cdsButton]="currentAction.buttonKind"
+ class="caret-btn">
+ <svg class="cds--btn__icon"
+ cdsIcon="caret--down"
+ size="16"></svg>
+ </button>
+</ng-template>
<ng-template #dropDownOnlyTpl>
<cds-overflow-menu [customTrigger]="customTrigger"
::ng-deep .cds--toolbar-content .cds--overflow-menu {
inline-size: auto !important;
}
+
+.primary-dropdown-btn {
+ align-items: center;
+ background-color: vv.$primary;
+ border: 0;
+ display: flex;
+ fill: vv.$white;
+ height: 3rem;
+ justify-content: center;
+ width: 3rem;
+}
// This disables the main action button.
@Input()
dropDownOnly?: string;
+ @Input()
+ primaryDropDown = false;
currentAction?: CdTableAction;
// Array with all visible actions
</ng-container>
<!-- end column filters -->
<!-- refresh button -->
- <button cdsButton="ghost"
+ <cds-icon-button
+ [kind]="status.type"
[disabled]="!fetchData?.observers?.length"
(click)="refreshBtn()"
- title="Refresh"
+ [title]="status.msg"
[description]="status.msg"
i18n-title
i18n-description
<svg cdsIcon="renew"
size="16"
[ngClass]="{ 'cds--toolbar-action__icon': true, 'reload': loadingIndicator }"></svg>
- </button>
+ </cds-icon-button>
<!-- end refresh button -->
<!-- show hide columns -->
<button cdsButton="ghost"
(deselectRow)="onDeselect($event)"
(deselectAll)="onDeselectAll($event)">
<tbody>
- <tr cdstablerow>
- <td *ngIf="!rows?.length && !loadingIndicator"
- class="no-data"
+ <tr cdstablerow
+ *ngIf="!rows?.length && !loadingIndicator">
+ <td class="no-data"
cdstabledata
- [attr.colspan]="visibleColumns.length + 1">
+ [attr.colspan]="selectionType === 'single' ? visibleColumns.length + 1 : visibleColumns.length + 2">
<span class="d-flex justify-content-center align-items-center"
i18n>No data to display</span>
</td>
</tr>
- <tr cdstablerow>
- <td *ngIf="loadingIndicator"
- class="no-data"
+ <tr cdstablerow
+ *ngIf="loadingIndicator">
+ <td class="no-data"
cdstabledata
[attr.colspan]="visibleColumns.length + 1">
<span class="d-flex justify-content-center align-items-center"