From 887aaf8d862d22bba39d350cb05bf3734b54a352 Mon Sep 17 00:00:00 2001 From: Tiago Melo Date: Fri, 24 Jul 2020 15:59:35 +0000 Subject: [PATCH] mgr/dashboard: Merge disable and disableDesc Fixes: https://tracker.ceph.com/issues/46750 Signed-off-by: Tiago Melo (cherry picked from commit 2f1c977ec6d8a25b4e5cf7ce7f3155eac69761a6) Conflicts: src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.ts src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-namespace-list/rbd-namespace-list.component.ts src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-actions.model.ts src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.ts src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/mgr-modules/mgr-module-list/mgr-module-list.component.ts src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts - `$localize` calls are not available in Angular 8. They are replaced with i18n. - Optional chaining syntax is not supported in typescript 3.5.3. Statements with optional chaining are re-coded. --- .../iscsi-target-list.component.spec.ts | 12 ++--- .../iscsi-target-list.component.ts | 16 +++---- .../block/rbd-list/rbd-list.component.spec.ts | 2 +- .../ceph/block/rbd-list/rbd-list.component.ts | 17 +++---- .../rbd-namespace-list.component.ts | 9 ++-- .../rbd-snapshot-actions.model.ts | 18 +++---- .../cluster/hosts/hosts.component.spec.ts | 16 +++---- .../app/ceph/cluster/hosts/hosts.component.ts | 47 ++++++++++--------- .../mgr-module-list.component.ts | 14 ++---- .../pool-list/pool-list.component.spec.ts | 8 +++- .../pool/pool-list/pool-list.component.ts | 19 ++++---- .../table-actions.component.spec.ts | 6 +-- .../table-actions/table-actions.component.ts | 7 ++- .../src/app/shared/models/cd-table-action.ts | 16 +++---- 14 files changed, 104 insertions(+), 103 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts index 16ff57abd231..a9b4a8f07b91 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.spec.ts @@ -195,8 +195,7 @@ describe('IscsiTargetListComponent', () => { id: '-1' } ]; - expect(action.disable(undefined)).toBeTruthy(); - expect(action.disableDesc(undefined)).toBe('Unavailable gateway(s)'); + expect(action.disable(undefined)).toBe('Unavailable gateway(s)'); }); it('should be enabled if active sessions', () => { @@ -209,7 +208,6 @@ describe('IscsiTargetListComponent', () => { } ]; expect(action.disable(undefined)).toBeFalsy(); - expect(action.disableDesc(undefined)).toBeUndefined(); }); it('should be enabled if no active sessions', () => { @@ -222,7 +220,6 @@ describe('IscsiTargetListComponent', () => { } ]; expect(action.disable(undefined)).toBeFalsy(); - expect(action.disableDesc(undefined)).toBeUndefined(); }); }); @@ -237,8 +234,7 @@ describe('IscsiTargetListComponent', () => { id: '-1' } ]; - expect(action.disable(undefined)).toBeTruthy(); - expect(action.disableDesc(undefined)).toBe('Unavailable gateway(s)'); + expect(action.disable(undefined)).toBe('Unavailable gateway(s)'); }); it('should be disabled if active sessions', () => { @@ -250,8 +246,7 @@ describe('IscsiTargetListComponent', () => { } } ]; - expect(action.disable(undefined)).toBeTruthy(); - expect(action.disableDesc(undefined)).toBe('Target has active sessions'); + expect(action.disable(undefined)).toBe('Target has active sessions'); }); it('should be enabled if no active sessions', () => { @@ -264,7 +259,6 @@ describe('IscsiTargetListComponent', () => { } ]; expect(action.disable(undefined)).toBeFalsy(); - expect(action.disableDesc(undefined)).toBeUndefined(); }); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.ts index 15e4341e81e8..09bc4d288d10 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/iscsi-target-list/iscsi-target-list.component.ts @@ -82,16 +82,14 @@ export class IscsiTargetListComponent extends ListWithDetails implements OnInit, icon: Icons.edit, routerLink: () => `/block/iscsi/targets/edit/${this.selection.first().target_iqn}`, name: this.actionLabels.EDIT, - disable: () => !this.selection.first() || !_.isUndefined(this.getEditDisableDesc()), - disableDesc: () => this.getEditDisableDesc() + disable: () => this.getEditDisableDesc() }, { permission: 'delete', icon: Icons.destroy, click: () => this.deleteIscsiTargetModal(), name: this.actionLabels.DELETE, - disable: () => !this.selection.first() || !_.isUndefined(this.getDeleteDisableDesc()), - disableDesc: () => this.getDeleteDisableDesc() + disable: () => this.getDeleteDisableDesc() } ]; } @@ -156,8 +154,9 @@ export class IscsiTargetListComponent extends ListWithDetails implements OnInit, } } - getEditDisableDesc(): string | undefined { + getEditDisableDesc(): string | boolean { const first = this.selection.first(); + if (first && first.cdExecuting) { return first.cdExecuting; } @@ -165,11 +164,12 @@ export class IscsiTargetListComponent extends ListWithDetails implements OnInit, return this.i18n('Unavailable gateway(s)'); } - return undefined; + return !first; } - getDeleteDisableDesc(): string | undefined { + getDeleteDisableDesc(): string | boolean { const first = this.selection.first(); + if (first && first.cdExecuting) { return first.cdExecuting; } @@ -180,7 +180,7 @@ export class IscsiTargetListComponent extends ListWithDetails implements OnInit, return this.i18n('Target has active sessions'); } - return undefined; + return !first; } prepareResponse(resp: any): any[] { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts index f9ad4cf7cb74..87f8e78f994f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.spec.ts @@ -138,7 +138,7 @@ describe('RbdListComponent', () => { } ] }); - expect(component.getDeleteDisableDesc()).toBe( + expect(component.getDeleteDisableDesc(component.selection)).toBe( 'This RBD has cloned snapshots. Please delete related RBDs before deleting this RBD.' ); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts index 18c95ec1e236..da53bb3fd549 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts @@ -138,11 +138,7 @@ export class RbdListComponent extends ListWithDetails implements OnInit { icon: Icons.destroy, click: () => this.deleteRbdModal(), name: this.actionLabels.DELETE, - disable: (selection: CdTableSelection) => - !this.selection.first() || - !this.selection.hasSingleSelection || - this.hasClonedSnapshots(selection.first()), - disableDesc: () => this.getDeleteDisableDesc() + disable: (selection: CdTableSelection) => this.getDeleteDisableDesc(selection) }; const copyAction: CdTableAction = { permission: 'create', @@ -430,14 +426,19 @@ export class RbdListComponent extends ListWithDetails implements OnInit { }, []); } - getDeleteDisableDesc(): string { - const first = this.selection.first(); + getDeleteDisableDesc(selection: CdTableSelection): string | boolean { + const first = selection.first(); + if (first && this.hasClonedSnapshots(first)) { return this.i18n( 'This RBD has cloned snapshots. Please delete related RBDs before deleting this RBD.' ); } - return ''; + return ( + !selection.first() || + !selection.hasSingleSelection || + this.hasClonedSnapshots(selection.first()) + ); } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-namespace-list/rbd-namespace-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-namespace-list/rbd-namespace-list.component.ts index 80b0945f65d5..82038162c78e 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-namespace-list/rbd-namespace-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-namespace-list/rbd-namespace-list.component.ts @@ -55,8 +55,7 @@ export class RbdNamespaceListComponent implements OnInit { icon: Icons.destroy, click: () => this.deleteModal(), name: this.actionLabels.DELETE, - disable: () => !this.selection.first() || !_.isUndefined(this.getDeleteDisableDesc()), - disableDesc: () => this.getDeleteDisableDesc() + disable: () => this.getDeleteDisableDesc() }; this.tableActions = [createAction, deleteAction]; } @@ -153,14 +152,14 @@ export class RbdNamespaceListComponent implements OnInit { }); } - getDeleteDisableDesc(): string | undefined { + getDeleteDisableDesc(): string | boolean { const first = this.selection.first(); if (first) { if (first.num_images > 0) { return this.i18n('Namespace contains images'); } + return false; } - - return undefined; + return true; } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-actions.model.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-actions.model.ts index 3086a1a5a2ac..f2ac418ac85a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-actions.model.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-snapshot-list/rbd-snapshot-actions.model.ts @@ -49,11 +49,7 @@ export class RbdSnapshotActionsModel { this.clone = { permission: 'create', canBePrimary: (selection: CdTableSelection) => selection.hasSingleSelection, - disable: (selection: CdTableSelection) => - !selection.hasSingleSelection || - selection.first().cdExecuting || - !_.isUndefined(this.getCloneDisableDesc(featuresName)), - disableDesc: () => this.getCloneDisableDesc(featuresName), + disable: (selection: CdTableSelection) => this.getCloneDisableDesc(selection, featuresName), icon: Icons.clone, name: actionLabels.CLONE }; @@ -92,11 +88,15 @@ export class RbdSnapshotActionsModel { ]; } - getCloneDisableDesc(featuresName: string[]): string | undefined { - if (!featuresName.includes('layering')) { - return this.i18n('Parent image must support Layering'); + getCloneDisableDesc(selection: CdTableSelection, featuresName: string[]): boolean | string { + if (selection && selection.hasSingleSelection && !selection.first().cdExecuting) { + if (!_.includes(featuresName, 'layering')) { + return this.i18n('Parent image must support Layering'); + } + + return false; } - return undefined; + return true; } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.spec.ts index 695898c25ae5..7efb4ed9bb95 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.spec.ts @@ -116,12 +116,12 @@ describe('HostsComponent', () => { ); }); - it('should disable button and return undefined (no selection)', () => { + it('should disable button and return true (no selection)', () => { expect(tableAction.disable(component.selection)).toBeTruthy(); - expect(component.getEditDisableDesc(component.selection)).toBeUndefined(); + expect(component.getEditDisableDesc(component.selection)).toBeTruthy(); }); - it('should enable button and return undefined (managed by Orchestrator)', () => { + it('should enable button and return false (managed by Orchestrator)', () => { component.selection.add({ sources: { ceph: false, @@ -129,7 +129,7 @@ describe('HostsComponent', () => { } }); expect(tableAction.disable(component.selection)).toBeFalsy(); - expect(component.getEditDisableDesc(component.selection)).toBeUndefined(); + expect(component.getEditDisableDesc(component.selection)).toBeFalsy(); }); }); @@ -152,11 +152,11 @@ describe('HostsComponent', () => { ); }); - it('should return undefined (no selection)', () => { - expect(component.getDeleteDisableDesc(component.selection)).toBeUndefined(); + it('should return true (no selection)', () => { + expect(component.getDeleteDisableDesc(component.selection)).toBeTruthy(); }); - it('should return undefined (managed by Orchestrator)', () => { + it('should return false (managed by Orchestrator)', () => { component.selection.add({ sources: { ceph: false, @@ -169,7 +169,7 @@ describe('HostsComponent', () => { orchestrator: true } }); - expect(component.getDeleteDisableDesc(component.selection)).toBeUndefined(); + expect(component.getDeleteDisableDesc(component.selection)).toBeFalsy(); }); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.ts index 52414bdf3ef0..ff97846943c2 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/hosts/hosts.component.ts @@ -92,9 +92,7 @@ export class HostsComponent extends ListWithDetails implements OnInit { () => this.editAction() ); }, - disable: (selection: CdTableSelection) => - !selection.hasSingleSelection || !selection.first().sources.orchestrator, - disableDesc: this.getEditDisableDesc.bind(this) + disable: this.getEditDisableDesc.bind(this) }, { name: this.actionLabels.DELETE, @@ -107,10 +105,7 @@ export class HostsComponent extends ListWithDetails implements OnInit { () => this.deleteAction() ); }, - disable: (selection: CdTableSelection) => - !selection.hasSelection || - !selection.selected.every((selected) => selected.sources.orchestrator), - disableDesc: this.getDeleteDisableDesc.bind(this) + disable: this.getDeleteDisableDesc.bind(this) } ]; } @@ -192,13 +187,18 @@ export class HostsComponent extends ListWithDetails implements OnInit { }); } - getEditDisableDesc(selection: CdTableSelection): string | undefined { - if (selection && selection.hasSingleSelection && !selection.first().sources.orchestrator) { - return this.i18n( - 'Host editing is disabled because the selected host is not managed by Orchestrator.' - ); + getEditDisableDesc(selection: CdTableSelection): boolean | string { + if (selection && selection.hasSingleSelection) { + if (!selection.first().sources.orchestrator) { + return this.i18n( + 'Host editing is disabled because the selected host is not managed by Orchestrator.' + ); + } + + return false; } - return undefined; + + return true; } deleteAction() { @@ -217,17 +217,18 @@ export class HostsComponent extends ListWithDetails implements OnInit { }); } - getDeleteDisableDesc(selection: CdTableSelection): string | undefined { - if ( - selection && - selection.hasSelection && - !selection.selected.every((selected) => selected.sources.orchestrator) - ) { - return this.i18n( - 'Host deletion is disabled because a selected host is not managed by Orchestrator.' - ); + getDeleteDisableDesc(selection: CdTableSelection): boolean | string { + if (selection && selection.hasSelection) { + if (!selection.selected.every((selected) => selected.sources.orchestrator)) { + return this.i18n( + 'Host deletion is disabled because a selected host is not managed by Orchestrator.' + ); + } + + return false; } - return undefined; + + return true; } getHosts(context: CdTableFetchDataContext) { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/mgr-modules/mgr-module-list/mgr-module-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/mgr-modules/mgr-module-list/mgr-module-list.component.ts index ea9214a6deb7..9c8fcf09e5ee 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/mgr-modules/mgr-module-list/mgr-module-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/mgr-modules/mgr-module-list/mgr-module-list.component.ts @@ -90,8 +90,7 @@ export class MgrModuleListComponent extends ListWithDetails { name: this.i18n('Disable'), permission: 'update', click: () => this.updateModuleState(), - disable: () => this.isTableActionDisabled('disabled'), - disableDesc: () => this.getTableActionDisabledDesc(), + disable: () => this.getTableActionDisabledDesc(), icon: Icons.stop } ]; @@ -141,15 +140,12 @@ export class MgrModuleListComponent extends ListWithDetails { } } - getTableActionDisabledDesc(): string | undefined { - if (this.selection.hasSelection) { - const selected = this.selection.first(); - if (selected.always_on) { - return this.i18n('This Manager module is always on.'); - } + getTableActionDisabledDesc(): string | boolean { + if (this.selection && this.selection.first().always_on) { + return this.i18n('This Manager module is always on.'); } - return undefined; + return this.isTableActionDisabled('disabled'); } /** diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts index 165ed7f34e83..31e5ca8cbc76 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.spec.ts @@ -479,6 +479,10 @@ describe('PoolListComponent', () => { }); describe('getDisableDesc', () => { + beforeEach(() => { + component.selection.selected = [{ pool_name: 'foo' }]; + }); + it('should return message if mon_allow_pool_delete flag is set to false', () => { component.monAllowPoolDelete = false; expect(component.getDisableDesc()).toBe( @@ -486,9 +490,9 @@ describe('PoolListComponent', () => { ); }); - it('should return undefined if mon_allow_pool_delete flag is set to true', () => { + it('should return false if mon_allow_pool_delete flag is set to true', () => { component.monAllowPoolDelete = true; - expect(component.getDisableDesc()).toBeUndefined(); + expect(component.getDisableDesc()).toBeFalsy(); }); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts index 93958f1b5339..2f35cf8a97f8 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/pool/pool-list/pool-list.component.ts @@ -93,8 +93,7 @@ export class PoolListComponent extends ListWithDetails implements OnInit { icon: Icons.destroy, click: () => this.deletePoolModal(), name: this.actionLabels.DELETE, - disable: () => !this.selection.first() || !this.monAllowPoolDelete, - disableDesc: () => this.getDisableDesc() + disable: this.getDisableDesc.bind(this) } ]; @@ -294,14 +293,18 @@ export class PoolListComponent extends ListWithDetails implements OnInit { } } - getDisableDesc(): string | undefined { - if (!this.monAllowPoolDelete) { - return this.i18n( - 'Pool deletion is disabled by the mon_allow_pool_delete configuration setting.' - ); + getDisableDesc(): boolean | string { + if (this.selection && this.selection.hasSelection) { + if (!this.monAllowPoolDelete) { + return this.i18n( + 'Pool deletion is disabled by the mon_allow_pool_delete configuration setting.' + ); + } + + return false; } - return undefined; + return true; } setExpandedRow(expandedRow: any) { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.spec.ts index 2593a59b2bea..e7b2b73ee6a5 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.spec.ts @@ -163,12 +163,12 @@ describe('TableActionsComponent', () => { }); describe('useDisableDesc', () => { - it('should return a description if disableDesc is set for action', () => { + it('should return a description if disable method returns a string', () => { const deleteWithDescAction: CdTableAction = { permission: 'delete', icon: 'fa-times', canBePrimary: (selection: CdTableSelection) => selection.hasSelection, - disableDesc: () => { + disable: () => { return 'Delete action disabled description'; }, name: 'DeleteDesc' @@ -179,7 +179,7 @@ describe('TableActionsComponent', () => { ); }); - it('should return no description if disableDesc is not set for action', () => { + it('should return no description if disable does not return string', () => { expect(component.useDisableDesc(deleteAction)).toBeUndefined(); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.ts index 334f5563eeb5..baf5761510fc 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-actions/table-actions.component.ts @@ -148,6 +148,11 @@ export class TableActionsComponent implements OnInit { } useDisableDesc(action: CdTableAction) { - return action.disableDesc && action.disableDesc(this.selection); + if (action.disable) { + const result = action.disable(this.selection); + return _.isString(result) ? result : undefined; + } + + return undefined; } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/cd-table-action.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/cd-table-action.ts index 9af10625ae65..70f06e506c36 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/cd-table-action.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/cd-table-action.ts @@ -19,17 +19,15 @@ export class CdTableAction { // The font awesome icon that will be used icon: string; - // You can define the condition to disable the action. - // By default all 'update' and 'delete' actions will only be enabled - // if one selection is made and no task is running on the selected item. - disable?: (_: CdTableSelection) => boolean; - /** + * You can define the condition to disable the action. + * By default all 'update' and 'delete' actions will only be enabled + * if one selection is made and no task is running on the selected item.` + * * In some cases you might want to give the user a hint why a button is - * disabled. The specified message will be shown to the user as a button - * tooltip. - */ - disableDesc?: (_: CdTableSelection) => string | undefined; + * disabled. This is achieved by returning a string. + * */ + disable?: (_: CdTableSelection) => boolean | string; /** * Defines if the button can become 'primary' (displayed as button and not -- 2.47.3