-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into 152438-improve-preview-loading-state
- Loading branch information
Showing
193 changed files
with
4,060 additions
and
1,391 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
src/plugins/controls/public/control_group/actions/delete_control_action.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import { | ||
lazyLoadReduxEmbeddablePackage, | ||
ReduxEmbeddablePackage, | ||
} from '@kbn/presentation-util-plugin/public'; | ||
import { ErrorEmbeddable } from '@kbn/embeddable-plugin/public'; | ||
|
||
import { ControlOutput } from '../../types'; | ||
import { ControlGroupInput } from '../types'; | ||
import { pluginServices } from '../../services'; | ||
import { DeleteControlAction } from './delete_control_action'; | ||
import { OptionsListEmbeddableInput } from '../../options_list'; | ||
import { controlGroupInputBuilder } from '../control_group_input_builder'; | ||
import { ControlGroupContainer } from '../embeddable/control_group_container'; | ||
import { OptionsListEmbeddable } from '../../options_list/embeddable/options_list_embeddable'; | ||
|
||
let container: ControlGroupContainer; | ||
let embeddable: OptionsListEmbeddable; | ||
let reduxEmbeddablePackage: ReduxEmbeddablePackage; | ||
|
||
beforeAll(async () => { | ||
reduxEmbeddablePackage = await lazyLoadReduxEmbeddablePackage(); | ||
|
||
const controlGroupInput = { chainingSystem: 'NONE', panels: {} } as ControlGroupInput; | ||
controlGroupInputBuilder.addOptionsListControl(controlGroupInput, { | ||
dataViewId: 'test-data-view', | ||
title: 'test', | ||
fieldName: 'test-field', | ||
width: 'medium', | ||
grow: false, | ||
}); | ||
container = new ControlGroupContainer(reduxEmbeddablePackage, controlGroupInput); | ||
await container.untilInitialized(); | ||
|
||
embeddable = container.getChild(container.getChildIds()[0]); | ||
}); | ||
|
||
test('Action is incompatible with Error Embeddables', async () => { | ||
const deleteControlAction = new DeleteControlAction(); | ||
const errorEmbeddable = new ErrorEmbeddable('Wow what an awful error', { id: ' 404' }); | ||
expect(await deleteControlAction.isCompatible({ embeddable: errorEmbeddable as any })).toBe( | ||
false | ||
); | ||
}); | ||
|
||
test('Execute throws an error when called with an embeddable not in a parent', async () => { | ||
const deleteControlAction = new DeleteControlAction(); | ||
const optionsListEmbeddable = new OptionsListEmbeddable( | ||
reduxEmbeddablePackage, | ||
{} as OptionsListEmbeddableInput, | ||
{} as ControlOutput | ||
); | ||
await expect(async () => { | ||
await deleteControlAction.execute({ embeddable: optionsListEmbeddable }); | ||
}).rejects.toThrow(Error); | ||
}); | ||
|
||
describe('Execute should open a confirm modal', () => { | ||
test('Canceling modal will keep control', async () => { | ||
const spyOn = jest.fn().mockResolvedValue(false); | ||
pluginServices.getServices().overlays.openConfirm = spyOn; | ||
|
||
const deleteControlAction = new DeleteControlAction(); | ||
await deleteControlAction.execute({ embeddable }); | ||
expect(spyOn).toHaveBeenCalled(); | ||
|
||
expect(container.getPanelCount()).toBe(1); | ||
}); | ||
|
||
test('Confirming modal will delete control', async () => { | ||
const spyOn = jest.fn().mockResolvedValue(true); | ||
pluginServices.getServices().overlays.openConfirm = spyOn; | ||
|
||
const deleteControlAction = new DeleteControlAction(); | ||
await deleteControlAction.execute({ embeddable }); | ||
expect(spyOn).toHaveBeenCalled(); | ||
|
||
expect(container.getPanelCount()).toBe(0); | ||
}); | ||
}); |
91 changes: 91 additions & 0 deletions
91
src/plugins/controls/public/control_group/actions/delete_control_action.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import React from 'react'; | ||
|
||
import { EuiButtonIcon, EuiToolTip } from '@elastic/eui'; | ||
import { ViewMode, isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; | ||
import { Action, IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; | ||
|
||
import { ACTION_DELETE_CONTROL } from '.'; | ||
import { pluginServices } from '../../services'; | ||
import { ControlGroupStrings } from '../control_group_strings'; | ||
import { ControlEmbeddable, DataControlInput } from '../../types'; | ||
import { isControlGroup } from '../embeddable/control_group_helpers'; | ||
|
||
export interface DeleteControlActionContext { | ||
embeddable: ControlEmbeddable<DataControlInput>; | ||
} | ||
|
||
export class DeleteControlAction implements Action<DeleteControlActionContext> { | ||
public readonly type = ACTION_DELETE_CONTROL; | ||
public readonly id = ACTION_DELETE_CONTROL; | ||
public order = 2; | ||
|
||
private openConfirm; | ||
|
||
constructor() { | ||
({ | ||
overlays: { openConfirm: this.openConfirm }, | ||
} = pluginServices.getServices()); | ||
} | ||
|
||
public readonly MenuItem = ({ context }: { context: DeleteControlActionContext }) => { | ||
return ( | ||
<EuiToolTip content={this.getDisplayName(context)}> | ||
<EuiButtonIcon | ||
data-test-subj={`control-action-${context.embeddable.id}-delete`} | ||
aria-label={this.getDisplayName(context)} | ||
iconType={this.getIconType(context)} | ||
onClick={() => this.execute(context)} | ||
color="danger" | ||
/> | ||
</EuiToolTip> | ||
); | ||
}; | ||
|
||
public getDisplayName({ embeddable }: DeleteControlActionContext) { | ||
if (!embeddable.parent || !isControlGroup(embeddable.parent)) { | ||
throw new IncompatibleActionError(); | ||
} | ||
return ControlGroupStrings.floatingActions.getRemoveButtonTitle(); | ||
} | ||
|
||
public getIconType({ embeddable }: DeleteControlActionContext) { | ||
if (!embeddable.parent || !isControlGroup(embeddable.parent)) { | ||
throw new IncompatibleActionError(); | ||
} | ||
return 'cross'; | ||
} | ||
|
||
public async isCompatible({ embeddable }: DeleteControlActionContext) { | ||
if (isErrorEmbeddable(embeddable)) return false; | ||
const controlGroup = embeddable.parent; | ||
return Boolean( | ||
controlGroup && | ||
isControlGroup(controlGroup) && | ||
controlGroup.getInput().viewMode === ViewMode.EDIT | ||
); | ||
} | ||
|
||
public async execute({ embeddable }: DeleteControlActionContext) { | ||
if (!embeddable.parent || !isControlGroup(embeddable.parent)) { | ||
throw new IncompatibleActionError(); | ||
} | ||
this.openConfirm(ControlGroupStrings.management.deleteControls.getSubtitle(), { | ||
confirmButtonText: ControlGroupStrings.management.deleteControls.getConfirm(), | ||
cancelButtonText: ControlGroupStrings.management.deleteControls.getCancel(), | ||
title: ControlGroupStrings.management.deleteControls.getDeleteTitle(), | ||
buttonColor: 'danger', | ||
}).then((confirmed) => { | ||
if (confirmed) { | ||
embeddable.parent?.removeEmbeddable(embeddable.id); | ||
} | ||
}); | ||
} | ||
} |
Oops, something went wrong.