mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Fix reset
UX for panel title
and description
(#182986)
## Summary Updates to the panel title flyout behavior to be more strict about changes to the title, including... - Input defaults to the actual title when empty (`""`), no longer fills with default viz `title`/`description`. - Uses the default title/description when the value is `undefined`, such that the value has never been set. - Adds a clear button to the `title` input. - `Reset` wording replaced with `Reset to default`, for `title` and `description`. - Only shows reset if there is a `default` non-empty `title`/`description` to reset to, applies mostly to by-value viz. - Changes the inspect panel `title` to always match the panel `title` and show `"[No Title]"` when empty.
This commit is contained in:
parent
5346e0ddcd
commit
382ee2d076
22 changed files with 294 additions and 153 deletions
|
@ -109,6 +109,7 @@ export {
|
|||
export {
|
||||
apiPublishesPanelDescription,
|
||||
apiPublishesWritablePanelDescription,
|
||||
getPanelDescription,
|
||||
type PublishesPanelDescription,
|
||||
type PublishesWritablePanelDescription,
|
||||
} from './interfaces/titles/publishes_panel_description';
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 { BehaviorSubject } from 'rxjs';
|
||||
import { getPanelDescription } from './publishes_panel_description';
|
||||
|
||||
describe('getPanelDescription', () => {
|
||||
test('should return default description when description is undefined', () => {
|
||||
const api = {
|
||||
panelDescription: new BehaviorSubject<string | undefined>(undefined),
|
||||
defaultPanelDescription: new BehaviorSubject<string | undefined>('default description'),
|
||||
};
|
||||
expect(getPanelDescription(api)).toBe('default description');
|
||||
});
|
||||
|
||||
test('should return empty description when description is empty string', () => {
|
||||
const api = {
|
||||
panelDescription: new BehaviorSubject<string | undefined>(''),
|
||||
defaultPanelDescription: new BehaviorSubject<string | undefined>('default description'),
|
||||
};
|
||||
expect(getPanelDescription(api)).toBe('');
|
||||
});
|
||||
|
||||
test('should return description when description is provided', () => {
|
||||
const api = {
|
||||
panelDescription: new BehaviorSubject<string | undefined>('custom description'),
|
||||
defaultPanelDescription: new BehaviorSubject<string | undefined>('default description'),
|
||||
};
|
||||
expect(getPanelDescription(api)).toBe('custom description');
|
||||
});
|
||||
});
|
|
@ -13,6 +13,10 @@ export interface PublishesPanelDescription {
|
|||
defaultPanelDescription?: PublishingSubject<string | undefined>;
|
||||
}
|
||||
|
||||
export function getPanelDescription(api: Partial<PublishesPanelDescription>): string | undefined {
|
||||
return api.panelDescription?.value ?? api.defaultPanelDescription?.value;
|
||||
}
|
||||
|
||||
export type PublishesWritablePanelDescription = PublishesPanelDescription & {
|
||||
setPanelDescription: (newTitle: string | undefined) => void;
|
||||
};
|
||||
|
|
|
@ -18,12 +18,12 @@ describe('getPanelTitle', () => {
|
|||
expect(getPanelTitle(api)).toBe('default title');
|
||||
});
|
||||
|
||||
test('should return default title when title is empty string', () => {
|
||||
test('should return empty title when title is empty string', () => {
|
||||
const api = {
|
||||
panelTitle: new BehaviorSubject<string | undefined>(''),
|
||||
defaultPanelTitle: new BehaviorSubject<string | undefined>('default title'),
|
||||
};
|
||||
expect(getPanelTitle(api)).toBe('default title');
|
||||
expect(getPanelTitle(api)).toBe('');
|
||||
});
|
||||
|
||||
test('should return title when title is provided', () => {
|
||||
|
|
|
@ -15,7 +15,7 @@ export interface PublishesPanelTitle {
|
|||
}
|
||||
|
||||
export function getPanelTitle(api: Partial<PublishesPanelTitle>): string | undefined {
|
||||
return api.panelTitle?.value || api.defaultPanelTitle?.value;
|
||||
return api.panelTitle?.value ?? api.defaultPanelTitle?.value;
|
||||
}
|
||||
|
||||
export type PublishesWritablePanelTitle = PublishesPanelTitle & {
|
||||
|
|
|
@ -19,19 +19,17 @@ import { CustomizePanelEditor } from './customize_panel_editor';
|
|||
|
||||
describe('customize panel editor', () => {
|
||||
let api: CustomizePanelActionApi;
|
||||
let setTitle: (title: string | undefined) => void;
|
||||
let setTitle: (title?: string) => void;
|
||||
let setViewMode: (viewMode: ViewMode) => void;
|
||||
let setDescription: (description: string | undefined) => void;
|
||||
let setDescription: (description?: string) => void;
|
||||
|
||||
beforeEach(() => {
|
||||
const titleSubject = new BehaviorSubject<string | undefined>(undefined);
|
||||
setTitle = jest.fn().mockImplementation((title) => titleSubject.next(title));
|
||||
setTitle = jest.fn((title) => titleSubject.next(title));
|
||||
const descriptionSubject = new BehaviorSubject<string | undefined>(undefined);
|
||||
setDescription = jest
|
||||
.fn()
|
||||
.mockImplementation((description) => descriptionSubject.next(description));
|
||||
setDescription = jest.fn((description) => descriptionSubject.next(description));
|
||||
const viewMode = new BehaviorSubject<ViewMode>('edit');
|
||||
setViewMode = jest.fn().mockImplementation((nextViewMode) => viewMode.next(nextViewMode));
|
||||
setViewMode = jest.fn((nextViewMode) => viewMode.next(nextViewMode));
|
||||
|
||||
api = {
|
||||
viewMode,
|
||||
|
@ -75,27 +73,44 @@ describe('customize panel editor', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('Sets panel title on apply', () => {
|
||||
it('should set panel title on apply', () => {
|
||||
renderPanelEditor();
|
||||
userEvent.type(screen.getByTestId('customEmbeddablePanelTitleInput'), 'New title');
|
||||
userEvent.click(screen.getByTestId('saveCustomizePanelButton'));
|
||||
expect(setTitle).toBeCalledWith('New title');
|
||||
});
|
||||
|
||||
it('should use default title when title is undefined', () => {
|
||||
api.defaultPanelTitle = new BehaviorSubject<string | undefined>('Default title');
|
||||
setTitle(undefined);
|
||||
renderPanelEditor();
|
||||
const titleInput = screen.getByTestId('customEmbeddablePanelTitleInput');
|
||||
expect(titleInput).toHaveValue('Default title');
|
||||
});
|
||||
|
||||
it('should use title even when empty string', () => {
|
||||
api.defaultPanelTitle = new BehaviorSubject<string | undefined>('Default title');
|
||||
setTitle('');
|
||||
renderPanelEditor();
|
||||
const titleInput = screen.getByTestId('customEmbeddablePanelTitleInput');
|
||||
expect(titleInput).toHaveValue('');
|
||||
});
|
||||
|
||||
it('Resets panel title to default when reset button is pressed', () => {
|
||||
api.defaultPanelTitle = new BehaviorSubject<string | undefined>('Default title');
|
||||
setTitle('Initial title');
|
||||
renderPanelEditor();
|
||||
userEvent.type(screen.getByTestId('customEmbeddablePanelTitleInput'), 'New title');
|
||||
userEvent.click(screen.getByTestId('resetCustomEmbeddablePanelTitleButton'));
|
||||
expect(screen.getByTestId('customEmbeddablePanelTitleInput')).toHaveValue('Default title');
|
||||
});
|
||||
|
||||
it('Reset panel title to undefined on apply', () => {
|
||||
setTitle('very cool title');
|
||||
it('should hide title reset when no default exists', () => {
|
||||
api.defaultPanelTitle = new BehaviorSubject<string | undefined>(undefined);
|
||||
setTitle('Initial title');
|
||||
renderPanelEditor();
|
||||
userEvent.click(screen.getByTestId('resetCustomEmbeddablePanelTitleButton'));
|
||||
userEvent.click(screen.getByTestId('saveCustomizePanelButton'));
|
||||
expect(setTitle).toBeCalledWith(undefined);
|
||||
userEvent.type(screen.getByTestId('customEmbeddablePanelTitleInput'), 'New title');
|
||||
expect(screen.queryByTestId('resetCustomEmbeddablePanelTitleButton')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('title input receives focus when `focusOnTitle` is `true`', async () => {
|
||||
|
@ -128,7 +143,7 @@ describe('customize panel editor', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('Sets panel description on apply', () => {
|
||||
it('should set panel description on apply', () => {
|
||||
renderPanelEditor();
|
||||
userEvent.type(
|
||||
screen.getByTestId('customEmbeddablePanelDescriptionInput'),
|
||||
|
@ -138,22 +153,47 @@ describe('customize panel editor', () => {
|
|||
expect(setDescription).toBeCalledWith('New description');
|
||||
});
|
||||
|
||||
it('Resets panel desription to default when reset button is pressed', () => {
|
||||
it('should use default description when description is undefined', () => {
|
||||
api.defaultPanelDescription = new BehaviorSubject<string | undefined>('Default description');
|
||||
setDescription(undefined);
|
||||
renderPanelEditor();
|
||||
userEvent.type(screen.getByTestId('customEmbeddablePanelDescriptionInput'), 'New desription');
|
||||
const descriptionInput = screen.getByTestId('customEmbeddablePanelDescriptionInput');
|
||||
expect(descriptionInput).toHaveValue('Default description');
|
||||
});
|
||||
|
||||
it('should use description even when empty string', () => {
|
||||
api.defaultPanelDescription = new BehaviorSubject<string | undefined>('Default description');
|
||||
setDescription('');
|
||||
renderPanelEditor();
|
||||
const descriptionInput = screen.getByTestId('customEmbeddablePanelDescriptionInput');
|
||||
expect(descriptionInput).toHaveValue('');
|
||||
});
|
||||
|
||||
it('Resets panel description to default when reset button is pressed', () => {
|
||||
api.defaultPanelDescription = new BehaviorSubject<string | undefined>('Default description');
|
||||
setDescription('Initial description');
|
||||
renderPanelEditor();
|
||||
userEvent.type(
|
||||
screen.getByTestId('customEmbeddablePanelDescriptionInput'),
|
||||
'New description'
|
||||
);
|
||||
userEvent.click(screen.getByTestId('resetCustomEmbeddablePanelDescriptionButton'));
|
||||
expect(screen.getByTestId('customEmbeddablePanelDescriptionInput')).toHaveValue(
|
||||
'Default description'
|
||||
);
|
||||
});
|
||||
|
||||
it('Reset panel description to undefined on apply', () => {
|
||||
setDescription('very cool description');
|
||||
it('should hide description reset when no default exists', () => {
|
||||
api.defaultPanelDescription = new BehaviorSubject<string | undefined>(undefined);
|
||||
setDescription('Initial description');
|
||||
renderPanelEditor();
|
||||
userEvent.click(screen.getByTestId('resetCustomEmbeddablePanelDescriptionButton'));
|
||||
userEvent.click(screen.getByTestId('saveCustomizePanelButton'));
|
||||
expect(setDescription).toBeCalledWith(undefined);
|
||||
userEvent.type(
|
||||
screen.getByTestId('customEmbeddablePanelDescriptionInput'),
|
||||
'New description'
|
||||
);
|
||||
expect(
|
||||
screen.queryByTestId('resetCustomEmbeddablePanelDescriptionButton')
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import {
|
|||
apiPublishesTimeRange,
|
||||
apiPublishesUnifiedSearch,
|
||||
getInheritedViewMode,
|
||||
getPanelDescription,
|
||||
getPanelTitle,
|
||||
PublishesUnifiedSearch,
|
||||
} from '@kbn/presentation-publishing';
|
||||
|
@ -62,10 +63,8 @@ export const CustomizePanelEditor = ({
|
|||
*/
|
||||
const editMode = getInheritedViewMode(api) === 'edit';
|
||||
const [hideTitle, setHideTitle] = useState(api.hidePanelTitle?.value);
|
||||
const [panelDescription, setPanelDescription] = useState(
|
||||
api.panelDescription?.value ?? api.defaultPanelDescription?.value
|
||||
);
|
||||
const [panelTitle, setPanelTitle] = useState(getPanelTitle(api));
|
||||
const [panelDescription, setPanelDescription] = useState(getPanelDescription(api));
|
||||
const [timeRange, setTimeRange] = useState(
|
||||
api.timeRange$?.value ?? api.parentApi?.timeRange$?.value
|
||||
);
|
||||
|
@ -121,7 +120,6 @@ export const CustomizePanelEditor = ({
|
|||
<EuiSwitch
|
||||
checked={!hideTitle}
|
||||
data-test-subj="customEmbeddablePanelHideTitleSwitch"
|
||||
disabled={!editMode}
|
||||
id="hideTitle"
|
||||
label={
|
||||
<FormattedMessage
|
||||
|
@ -140,23 +138,25 @@ export const CustomizePanelEditor = ({
|
|||
/>
|
||||
}
|
||||
labelAppend={
|
||||
<EuiButtonEmpty
|
||||
size="xs"
|
||||
data-test-subj="resetCustomEmbeddablePanelTitleButton"
|
||||
onClick={() => setPanelTitle(api.defaultPanelTitle?.value)}
|
||||
disabled={hideTitle || !editMode || api?.defaultPanelTitle?.value === panelTitle}
|
||||
aria-label={i18n.translate(
|
||||
'presentationPanel.action.customizePanel.flyout.optionsMenuForm.resetCustomTitleButtonAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Reset title',
|
||||
}
|
||||
)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="presentationPanel.action.customizePanel.flyout.optionsMenuForm.resetCustomTitleButtonLabel"
|
||||
defaultMessage="Reset"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
api?.defaultPanelTitle?.value && (
|
||||
<EuiButtonEmpty
|
||||
size="xs"
|
||||
data-test-subj="resetCustomEmbeddablePanelTitleButton"
|
||||
onClick={() => setPanelTitle(api.defaultPanelTitle?.value)}
|
||||
disabled={hideTitle || panelTitle === api?.defaultPanelTitle?.value}
|
||||
aria-label={i18n.translate(
|
||||
'presentationPanel.action.customizePanel.flyout.optionsMenuForm.resetCustomTitleButtonAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Reset title to default',
|
||||
}
|
||||
)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="presentationPanel.action.customizePanel.flyout.optionsMenuForm.resetCustomTitleButtonLabel"
|
||||
defaultMessage="Reset to default"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
)
|
||||
}
|
||||
>
|
||||
<EuiFieldText
|
||||
|
@ -166,7 +166,7 @@ export const CustomizePanelEditor = ({
|
|||
data-test-subj="customEmbeddablePanelTitleInput"
|
||||
name="title"
|
||||
type="text"
|
||||
disabled={hideTitle || !editMode}
|
||||
disabled={hideTitle}
|
||||
value={panelTitle ?? ''}
|
||||
onChange={(e) => setPanelTitle(e.target.value)}
|
||||
aria-label={i18n.translate(
|
||||
|
@ -185,23 +185,25 @@ export const CustomizePanelEditor = ({
|
|||
/>
|
||||
}
|
||||
labelAppend={
|
||||
<EuiButtonEmpty
|
||||
size="xs"
|
||||
data-test-subj="resetCustomEmbeddablePanelDescriptionButton"
|
||||
onClick={() => setPanelDescription(api.defaultPanelDescription?.value)}
|
||||
disabled={!editMode || api.defaultPanelDescription?.value === panelDescription}
|
||||
aria-label={i18n.translate(
|
||||
'presentationPanel.action.customizePanel.flyout.optionsMenuForm.resetCustomDescriptionButtonAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Reset description',
|
||||
}
|
||||
)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="presentationPanel.action.customizePanel.modal.optionsMenuForm.resetCustomDescriptionButtonLabel"
|
||||
defaultMessage="Reset"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
api.defaultPanelDescription?.value && (
|
||||
<EuiButtonEmpty
|
||||
size="xs"
|
||||
data-test-subj="resetCustomEmbeddablePanelDescriptionButton"
|
||||
onClick={() => setPanelDescription(api.defaultPanelDescription?.value)}
|
||||
disabled={api.defaultPanelDescription?.value === panelDescription}
|
||||
aria-label={i18n.translate(
|
||||
'presentationPanel.action.customizePanel.flyout.optionsMenuForm.resetCustomDescriptionButtonAriaLabel',
|
||||
{
|
||||
defaultMessage: 'Reset description to default',
|
||||
}
|
||||
)}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="presentationPanel.action.customizePanel.modal.optionsMenuForm.resetCustomDescriptionButtonLabel"
|
||||
defaultMessage="Reset to default"
|
||||
/>
|
||||
</EuiButtonEmpty>
|
||||
)
|
||||
}
|
||||
>
|
||||
<EuiTextArea
|
||||
|
|
|
@ -59,7 +59,7 @@ export class InspectPanelAction implements Action<EmbeddableApiContext> {
|
|||
const panelTitle =
|
||||
getPanelTitle(embeddable) ||
|
||||
i18n.translate('presentationPanel.action.inspectPanel.untitledEmbeddableFilename', {
|
||||
defaultMessage: 'untitled',
|
||||
defaultMessage: '[No Title]',
|
||||
});
|
||||
const session = inspector.open(adapters, {
|
||||
title: panelTitle,
|
||||
|
|
|
@ -79,7 +79,7 @@ exports[`SavedObjectSaveModal should render matching snapshot 1`] = `
|
|||
labelType="label"
|
||||
>
|
||||
<EuiTextArea
|
||||
data-test-subj="viewDescription"
|
||||
data-test-subj="savedObjectDescription"
|
||||
fullWidth={true}
|
||||
onChange={[Function]}
|
||||
value=""
|
||||
|
@ -203,7 +203,7 @@ exports[`SavedObjectSaveModal should render matching snapshot when custom isVali
|
|||
labelType="label"
|
||||
>
|
||||
<EuiTextArea
|
||||
data-test-subj="viewDescription"
|
||||
data-test-subj="savedObjectDescription"
|
||||
fullWidth={true}
|
||||
onChange={[Function]}
|
||||
value=""
|
||||
|
@ -327,7 +327,7 @@ exports[`SavedObjectSaveModal should render matching snapshot when custom isVali
|
|||
labelType="label"
|
||||
>
|
||||
<EuiTextArea
|
||||
data-test-subj="viewDescription"
|
||||
data-test-subj="savedObjectDescription"
|
||||
fullWidth={true}
|
||||
onChange={[Function]}
|
||||
value=""
|
||||
|
@ -455,7 +455,7 @@ exports[`SavedObjectSaveModal should render matching snapshot when given options
|
|||
labelType="label"
|
||||
>
|
||||
<EuiTextArea
|
||||
data-test-subj="viewDescription"
|
||||
data-test-subj="savedObjectDescription"
|
||||
fullWidth={true}
|
||||
onChange={[Function]}
|
||||
value=""
|
||||
|
|
|
@ -214,7 +214,7 @@ export class SavedObjectSaveModal extends React.Component<Props, SaveModalState>
|
|||
>
|
||||
<EuiTextArea
|
||||
fullWidth
|
||||
data-test-subj="viewDescription"
|
||||
data-test-subj="savedObjectDescription"
|
||||
value={this.state.visualizationDescription}
|
||||
onChange={this.onDescriptionChange}
|
||||
/>
|
||||
|
|
|
@ -41,7 +41,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await dashboardAddPanel.closeAddPanel();
|
||||
|
||||
const originalPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:heatmap');
|
||||
await panelActions.legacyUnlinkFromLibary(originalPanel);
|
||||
await panelActions.legacyUnlinkFromLibrary(originalPanel);
|
||||
await testSubjects.existOrFail('unlinkPanelSuccess');
|
||||
|
||||
const updatedPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:heatmap');
|
||||
|
|
|
@ -589,7 +589,7 @@ export class DashboardPageObject extends FtrService {
|
|||
public async getPanelTitles() {
|
||||
this.log.debug('in getPanelTitles');
|
||||
const titleObjects = await this.find.allByCssSelector(
|
||||
'[data-test-subj=embeddablePanelTitleInner] .embPanel__titleText'
|
||||
'[data-test-subj="embeddablePanelTitleInner"] .embPanel__titleText'
|
||||
);
|
||||
return await Promise.all(titleObjects.map(async (title) => await title.getVisibleText()));
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ interface SaveModalArgs {
|
|||
dashboardId?: string;
|
||||
saveAsNew?: boolean;
|
||||
redirectToOrigin?: boolean;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
type DashboardPickerOption =
|
||||
|
@ -65,13 +66,27 @@ export class TimeToVisualizePageObject extends FtrService {
|
|||
|
||||
public async setSaveModalValues(
|
||||
vizName: string,
|
||||
{ saveAsNew, redirectToOrigin, addToDashboard, dashboardId, saveToLibrary }: SaveModalArgs = {}
|
||||
{
|
||||
saveAsNew,
|
||||
redirectToOrigin,
|
||||
addToDashboard,
|
||||
dashboardId,
|
||||
saveToLibrary,
|
||||
description,
|
||||
}: SaveModalArgs = {}
|
||||
) {
|
||||
await this.testSubjects.setValue('savedObjectTitle', vizName, {
|
||||
typeCharByChar: true,
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
|
||||
if (description !== undefined) {
|
||||
await this.testSubjects.setValue('savedObjectDescription', description, {
|
||||
typeCharByChar: true,
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
}
|
||||
|
||||
const hasSaveAsNew = await this.testSubjects.exists('saveAsNewCheckbox');
|
||||
if (hasSaveAsNew && saveAsNew !== undefined) {
|
||||
const state = saveAsNew ? 'check' : 'uncheck';
|
||||
|
|
|
@ -447,7 +447,7 @@ export class VisualizePageObject extends FtrService {
|
|||
await this.testSubjects.setValue('savedObjectTitle', vizName);
|
||||
|
||||
if (description) {
|
||||
await this.testSubjects.setValue('viewDescription', description);
|
||||
await this.testSubjects.setValue('savedObjectDescription', description);
|
||||
}
|
||||
|
||||
const saveAsNewCheckboxExists = await this.testSubjects.exists('saveAsNewCheckbox');
|
||||
|
|
|
@ -91,7 +91,16 @@ export class DashboardPanelActionsService extends FtrService {
|
|||
await this.clickContextMenuMoreItem();
|
||||
}
|
||||
|
||||
private async navigateToEditorFromFlyout() {
|
||||
async clickContextMenuItem(itemSelector: string, parent?: WebElementWrapper) {
|
||||
await this.openContextMenu(parent);
|
||||
const exists = await this.testSubjects.exists(itemSelector);
|
||||
if (!exists) {
|
||||
await this.clickContextMenuMoreItem();
|
||||
}
|
||||
await this.testSubjects.click(itemSelector);
|
||||
}
|
||||
|
||||
async navigateToEditorFromFlyout() {
|
||||
await this.testSubjects.clickWhenNotDisabledWithoutRetry(INLINE_EDIT_PANEL_DATA_TEST_SUBJ);
|
||||
await this.header.waitUntilLoadingHasFinished();
|
||||
await this.testSubjects.click(EDIT_IN_LENS_EDITOR_DATA_TEST_SUBJ);
|
||||
|
@ -113,7 +122,8 @@ export class DashboardPanelActionsService extends FtrService {
|
|||
await this.common.waitForTopNavToBeVisible();
|
||||
}
|
||||
|
||||
/** The dashboard/canvas panels can be either edited on their editor or inline.
|
||||
/**
|
||||
* The dashboard/canvas panels can be either edited on their editor or inline.
|
||||
* The inline editing panels allow the navigation to the editor after the flyout opens
|
||||
*/
|
||||
async clickEdit() {
|
||||
|
@ -135,7 +145,8 @@ export class DashboardPanelActionsService extends FtrService {
|
|||
await this.common.waitForTopNavToBeVisible();
|
||||
}
|
||||
|
||||
/** The dashboard/canvas panels can be either edited on their editor or inline.
|
||||
/**
|
||||
* The dashboard/canvas panels can be either edited on their editor or inline.
|
||||
* The inline editing panels allow the navigation to the editor after the flyout opens
|
||||
*/
|
||||
async editPanelByTitle(title?: string) {
|
||||
|
@ -253,35 +264,20 @@ export class DashboardPanelActionsService extends FtrService {
|
|||
}
|
||||
|
||||
async openInspector(parent?: WebElementWrapper) {
|
||||
await this.openContextMenu(parent);
|
||||
const exists = await this.testSubjects.exists(OPEN_INSPECTOR_TEST_SUBJ);
|
||||
if (!exists) {
|
||||
await this.clickContextMenuMoreItem();
|
||||
}
|
||||
await this.testSubjects.click(OPEN_INSPECTOR_TEST_SUBJ);
|
||||
await this.clickContextMenuItem(OPEN_INSPECTOR_TEST_SUBJ, parent);
|
||||
}
|
||||
|
||||
async legacyUnlinkFromLibary(parent?: WebElementWrapper) {
|
||||
async legacyUnlinkFromLibrary(parent?: WebElementWrapper) {
|
||||
this.log.debug('legacyUnlinkFromLibrary');
|
||||
await this.openContextMenu(parent);
|
||||
const exists = await this.testSubjects.exists(LEGACY_UNLINK_FROM_LIBRARY_TEST_SUBJ);
|
||||
if (!exists) {
|
||||
await this.clickContextMenuMoreItem();
|
||||
}
|
||||
await this.testSubjects.click(LEGACY_UNLINK_FROM_LIBRARY_TEST_SUBJ);
|
||||
await this.clickContextMenuItem(LEGACY_UNLINK_FROM_LIBRARY_TEST_SUBJ, parent);
|
||||
await this.testSubjects.waitForDeleted(
|
||||
'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION'
|
||||
);
|
||||
}
|
||||
|
||||
async unlinkFromLibary(parent?: WebElementWrapper) {
|
||||
async unlinkFromLibrary(parent?: WebElementWrapper) {
|
||||
this.log.debug('unlinkFromLibrary');
|
||||
await this.openContextMenu(parent);
|
||||
const exists = await this.testSubjects.exists(UNLINK_FROM_LIBRARY_TEST_SUBJ);
|
||||
if (!exists) {
|
||||
await this.clickContextMenuMoreItem();
|
||||
}
|
||||
await this.testSubjects.click(UNLINK_FROM_LIBRARY_TEST_SUBJ);
|
||||
await this.clickContextMenuItem(UNLINK_FROM_LIBRARY_TEST_SUBJ, parent);
|
||||
await this.testSubjects.waitForDeleted(
|
||||
'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION'
|
||||
);
|
||||
|
@ -289,12 +285,7 @@ export class DashboardPanelActionsService extends FtrService {
|
|||
|
||||
async legacySaveToLibrary(newTitle: string, parent?: WebElementWrapper) {
|
||||
this.log.debug('legacySaveToLibrary');
|
||||
await this.openContextMenu(parent);
|
||||
const exists = await this.testSubjects.exists(LEGACY_SAVE_TO_LIBRARY_TEST_SUBJ);
|
||||
if (!exists) {
|
||||
await this.clickContextMenuMoreItem();
|
||||
}
|
||||
await this.testSubjects.click(LEGACY_SAVE_TO_LIBRARY_TEST_SUBJ);
|
||||
await this.clickContextMenuItem(LEGACY_SAVE_TO_LIBRARY_TEST_SUBJ, parent);
|
||||
await this.testSubjects.setValue('savedObjectTitle', newTitle, {
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
|
@ -308,12 +299,7 @@ export class DashboardPanelActionsService extends FtrService {
|
|||
|
||||
async saveToLibrary(newTitle: string, parent?: WebElementWrapper) {
|
||||
this.log.debug('saveToLibrary');
|
||||
await this.openContextMenu(parent);
|
||||
const exists = await this.testSubjects.exists(SAVE_TO_LIBRARY_TEST_SUBJ);
|
||||
if (!exists) {
|
||||
await this.clickContextMenuMoreItem();
|
||||
}
|
||||
await this.testSubjects.click(SAVE_TO_LIBRARY_TEST_SUBJ);
|
||||
await this.clickContextMenuItem(SAVE_TO_LIBRARY_TEST_SUBJ, parent);
|
||||
await this.testSubjects.setValue('savedObjectTitle', newTitle, {
|
||||
clearWithKeyboard: true,
|
||||
});
|
||||
|
|
|
@ -124,6 +124,11 @@ export function DashboardCustomizePanelProvider({ getService, getPageObject }: F
|
|||
await testSubjects.click('customEmbeddablePanelHideTitleSwitch');
|
||||
}
|
||||
|
||||
public async getCustomPanelTitle() {
|
||||
log.debug('getCustomPanelTitle');
|
||||
return (await testSubjects.find('customEmbeddablePanelTitleInput')).getAttribute('value');
|
||||
}
|
||||
|
||||
public async setCustomPanelTitle(customTitle: string) {
|
||||
log.debug('setCustomPanelTitle');
|
||||
await testSubjects.setValue('customEmbeddablePanelTitleInput', customTitle, {
|
||||
|
@ -136,6 +141,13 @@ export function DashboardCustomizePanelProvider({ getService, getPageObject }: F
|
|||
await testSubjects.click('resetCustomEmbeddablePanelTitleButton');
|
||||
}
|
||||
|
||||
public async getCustomPanelDescription() {
|
||||
log.debug('getCustomPanelDescription');
|
||||
return (await testSubjects.find('customEmbeddablePanelDescriptionInput')).getAttribute(
|
||||
'value'
|
||||
);
|
||||
}
|
||||
|
||||
public async setCustomPanelDescription(customDescription: string) {
|
||||
log.debug('setCustomPanelDescription');
|
||||
await testSubjects.setValue('customEmbeddablePanelDescriptionInput', customDescription, {
|
||||
|
|
|
@ -94,7 +94,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
panels[0]
|
||||
)
|
||||
).to.be(true);
|
||||
await dashboardPanelActions.legacyUnlinkFromLibary(panels[0]);
|
||||
await dashboardPanelActions.legacyUnlinkFromLibrary(panels[0]);
|
||||
await testSubjects.existOrFail('unlinkPanelSuccess');
|
||||
panels = await testSubjects.findAll('embeddablePanel');
|
||||
expect(panels.length).to.be(1);
|
||||
|
|
|
@ -14,6 +14,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
const retry = getService('retry');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
const dashboardCustomizePanel = getService('dashboardCustomizePanel');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects([
|
||||
'common',
|
||||
'dashboard',
|
||||
|
@ -23,11 +24,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
'lens',
|
||||
]);
|
||||
|
||||
const DASHBOARD_NAME = 'Panel Title Test';
|
||||
const CUSTOM_TITLE = 'Test Custom Title';
|
||||
const EMPTY_TITLE = '[No Title]';
|
||||
const LIBRARY_TITLE_FOR_CUSTOM_TESTS = 'Library Title for Custom Title Tests';
|
||||
const LIBRARY_TITLE_FOR_EMPTY_TESTS = 'Library Title for Empty Title Tests';
|
||||
|
||||
describe('panel titles', () => {
|
||||
before(async () => {
|
||||
|
@ -39,13 +36,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.dashboard.navigateToApp();
|
||||
await PageObjects.dashboard.preserveCrossAppState();
|
||||
await PageObjects.dashboard.clickNewDashboard();
|
||||
await PageObjects.dashboard.saveDashboard(DASHBOARD_NAME);
|
||||
await PageObjects.dashboard.saveDashboard('Panel Title Test');
|
||||
await PageObjects.lens.createAndAddLensFromDashboard({});
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
// close any open flyouts to prevent dirty state between tests
|
||||
if (await testSubjects.exists('euiFlyoutCloseButton')) {
|
||||
await testSubjects.click('euiFlyoutCloseButton');
|
||||
}
|
||||
});
|
||||
|
||||
describe('by value', () => {
|
||||
it('new panel by value has empty title', async () => {
|
||||
await PageObjects.lens.createAndAddLensFromDashboard({});
|
||||
const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0];
|
||||
const [newPanelTitle] = await PageObjects.dashboard.getPanelTitles();
|
||||
expect(newPanelTitle).to.equal(EMPTY_TITLE);
|
||||
});
|
||||
|
||||
|
@ -58,78 +62,115 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
it('custom title causes unsaved changes and saving clears it', async () => {
|
||||
await dashboardPanelActions.customizePanel();
|
||||
await dashboardCustomizePanel.setCustomPanelTitle(CUSTOM_TITLE);
|
||||
await dashboardCustomizePanel.setCustomPanelTitle('Custom title');
|
||||
await dashboardCustomizePanel.clickSaveButton();
|
||||
const panelTitle = (await PageObjects.dashboard.getPanelTitles())[0];
|
||||
expect(panelTitle).to.equal(CUSTOM_TITLE);
|
||||
const [panelTitle] = await PageObjects.dashboard.getPanelTitles();
|
||||
expect(panelTitle).to.equal('Custom title');
|
||||
await PageObjects.dashboard.clearUnsavedChanges();
|
||||
});
|
||||
|
||||
it('resetting title on a by value panel sets it to the empty string', async () => {
|
||||
const BY_VALUE_TITLE = 'Reset Title - By Value';
|
||||
it('reset title should be hidden on a by value panel', async () => {
|
||||
await dashboardPanelActions.customizePanel();
|
||||
await dashboardCustomizePanel.setCustomPanelTitle(BY_VALUE_TITLE);
|
||||
await dashboardCustomizePanel.setCustomPanelTitle('Some title');
|
||||
await dashboardCustomizePanel.clickSaveButton();
|
||||
await dashboardPanelActions.customizePanel();
|
||||
expect(await testSubjects.exists('resetCustomEmbeddablePanelTitleButton')).to.be(false);
|
||||
});
|
||||
|
||||
it('reset description should be hidden on a by value panel', async () => {
|
||||
await dashboardPanelActions.customizePanel();
|
||||
await dashboardCustomizePanel.resetCustomPanelTitle();
|
||||
await dashboardCustomizePanel.setCustomPanelDescription('Some description');
|
||||
await dashboardCustomizePanel.clickSaveButton();
|
||||
const panelTitle = (await PageObjects.dashboard.getPanelTitles())[0];
|
||||
expect(panelTitle).to.equal(EMPTY_TITLE);
|
||||
await PageObjects.dashboard.clearUnsavedChanges();
|
||||
await dashboardPanelActions.customizePanel();
|
||||
expect(await testSubjects.exists('resetCustomEmbeddablePanelDescriptionButton')).to.be(
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('by reference', () => {
|
||||
describe('nick by reference', () => {
|
||||
const VIS_LIBRARY_DESCRIPTION = 'Vis library description';
|
||||
|
||||
let count = 0;
|
||||
const getVisTitle = (increment = false) =>
|
||||
`Vis Library Title - ${increment ? ++count : count}`;
|
||||
|
||||
it('linking a by value panel with a custom title to the library will overwrite the custom title with the library title', async () => {
|
||||
await dashboardPanelActions.customizePanel();
|
||||
await dashboardCustomizePanel.setCustomPanelTitle(CUSTOM_TITLE);
|
||||
await dashboardCustomizePanel.setCustomPanelTitle('Custom title');
|
||||
await dashboardCustomizePanel.clickSaveButton();
|
||||
await dashboardPanelActions.legacySaveToLibrary(LIBRARY_TITLE_FOR_CUSTOM_TESTS);
|
||||
await retry.try(async () => {
|
||||
await dashboardPanelActions.legacySaveToLibrary(getVisTitle(true));
|
||||
await retry.tryForTime(500, async () => {
|
||||
// need to surround in 'retry' due to delays in HTML updates causing the title read to be behind
|
||||
const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0];
|
||||
expect(newPanelTitle).to.equal(LIBRARY_TITLE_FOR_CUSTOM_TESTS);
|
||||
const [newPanelTitle] = await PageObjects.dashboard.getPanelTitles();
|
||||
expect(newPanelTitle).to.equal(getVisTitle());
|
||||
});
|
||||
});
|
||||
|
||||
it('resetting title on a by reference panel sets it to the library title', async () => {
|
||||
await dashboardPanelActions.customizePanel();
|
||||
await dashboardCustomizePanel.setCustomPanelTitle('This should go away');
|
||||
await dashboardCustomizePanel.setCustomPanelTitle('Custom Title');
|
||||
await dashboardCustomizePanel.clickSaveButton();
|
||||
|
||||
await dashboardPanelActions.customizePanel();
|
||||
await dashboardCustomizePanel.resetCustomPanelTitle();
|
||||
await dashboardCustomizePanel.clickSaveButton();
|
||||
const resetPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0];
|
||||
expect(resetPanelTitle).to.equal(LIBRARY_TITLE_FOR_CUSTOM_TESTS);
|
||||
await dashboardPanelActions.customizePanel();
|
||||
expect(await dashboardCustomizePanel.getCustomPanelTitle()).to.equal(getVisTitle());
|
||||
});
|
||||
|
||||
it('resetting description on a by reference panel sets it to the library title', async () => {
|
||||
await dashboardPanelActions.openContextMenu();
|
||||
await dashboardPanelActions.navigateToEditorFromFlyout();
|
||||
// legacySaveToLibrary UI cannot set description
|
||||
await PageObjects.lens.save(
|
||||
getVisTitle(true),
|
||||
false,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
VIS_LIBRARY_DESCRIPTION
|
||||
);
|
||||
|
||||
await dashboardPanelActions.customizePanel();
|
||||
await dashboardCustomizePanel.setCustomPanelDescription('Custom description');
|
||||
await dashboardCustomizePanel.clickSaveButton();
|
||||
|
||||
await dashboardPanelActions.customizePanel();
|
||||
await dashboardCustomizePanel.resetCustomPanelDescription();
|
||||
await dashboardCustomizePanel.clickSaveButton();
|
||||
|
||||
await dashboardPanelActions.customizePanel();
|
||||
expect(await dashboardCustomizePanel.getCustomPanelDescription()).to.equal(
|
||||
VIS_LIBRARY_DESCRIPTION
|
||||
);
|
||||
});
|
||||
|
||||
it('unlinking a by reference panel with a custom title will keep the current title', async () => {
|
||||
await dashboardPanelActions.customizePanel();
|
||||
await dashboardCustomizePanel.setCustomPanelTitle(CUSTOM_TITLE);
|
||||
await dashboardCustomizePanel.setCustomPanelTitle('Custom title');
|
||||
await dashboardCustomizePanel.clickSaveButton();
|
||||
await dashboardPanelActions.legacyUnlinkFromLibary();
|
||||
const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0];
|
||||
expect(newPanelTitle).to.equal(CUSTOM_TITLE);
|
||||
await dashboardPanelActions.legacyUnlinkFromLibrary();
|
||||
const [newPanelTitle] = await PageObjects.dashboard.getPanelTitles();
|
||||
expect(newPanelTitle).to.equal('Custom title');
|
||||
});
|
||||
|
||||
it("linking a by value panel with a blank title to the library will set the panel's title to the library title", async () => {
|
||||
await dashboardPanelActions.customizePanel();
|
||||
await dashboardCustomizePanel.setCustomPanelTitle('');
|
||||
await dashboardCustomizePanel.clickSaveButton();
|
||||
await dashboardPanelActions.legacySaveToLibrary(LIBRARY_TITLE_FOR_EMPTY_TESTS);
|
||||
await retry.try(async () => {
|
||||
await dashboardPanelActions.legacySaveToLibrary(getVisTitle(true));
|
||||
await retry.tryForTime(500, async () => {
|
||||
// need to surround in 'retry' due to delays in HTML updates causing the title read to be behind
|
||||
const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0];
|
||||
expect(newPanelTitle).to.equal(LIBRARY_TITLE_FOR_EMPTY_TESTS);
|
||||
const [newPanelTitle] = await PageObjects.dashboard.getPanelTitles();
|
||||
expect(newPanelTitle).to.equal(getVisTitle());
|
||||
});
|
||||
});
|
||||
|
||||
it('unlinking a by reference panel without a custom title will keep the library title', async () => {
|
||||
await dashboardPanelActions.legacyUnlinkFromLibary();
|
||||
const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0];
|
||||
expect(newPanelTitle).to.equal(LIBRARY_TITLE_FOR_EMPTY_TESTS);
|
||||
await dashboardPanelActions.legacyUnlinkFromLibrary();
|
||||
const [newPanelTitle] = await PageObjects.dashboard.getPanelTitles();
|
||||
expect(newPanelTitle).to.equal(getVisTitle());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -242,7 +242,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await dashboardAddPanel.closeAddPanel();
|
||||
|
||||
const originalPanel = await testSubjects.find('embeddablePanelHeading-lnsPieVis');
|
||||
await panelActions.legacyUnlinkFromLibary(originalPanel);
|
||||
await panelActions.legacyUnlinkFromLibrary(originalPanel);
|
||||
await testSubjects.existOrFail('unlinkPanelSuccess');
|
||||
|
||||
const updatedPanel = await testSubjects.find('embeddablePanelHeading-lnsPieVis');
|
||||
|
|
|
@ -59,7 +59,7 @@ export default function ({ getPageObjects, getService }) {
|
|||
|
||||
it('unlink map panel from embeddable library', async () => {
|
||||
const originalPanel = await testSubjects.find('embeddablePanelHeading-embeddablelibrarymap');
|
||||
await dashboardPanelActions.unlinkFromLibary(originalPanel);
|
||||
await dashboardPanelActions.unlinkFromLibrary(originalPanel);
|
||||
await testSubjects.existOrFail('unlinkPanelSuccess');
|
||||
|
||||
const updatedPanel = await testSubjects.find('embeddablePanelHeading-embeddablelibrarymap');
|
||||
|
|
|
@ -746,7 +746,8 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
|
|||
redirectToOrigin?: boolean,
|
||||
saveToLibrary?: boolean,
|
||||
addToDashboard?: 'new' | 'existing' | null,
|
||||
dashboardId?: string
|
||||
dashboardId?: string,
|
||||
description?: string
|
||||
) {
|
||||
await PageObjects.timeToVisualize.setSaveModalValues(title, {
|
||||
saveAsNew,
|
||||
|
@ -754,6 +755,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
|
|||
addToDashboard: addToDashboard ? addToDashboard : null,
|
||||
dashboardId,
|
||||
saveToLibrary,
|
||||
description,
|
||||
});
|
||||
|
||||
await testSubjects.click('confirmSaveSavedObjectButton');
|
||||
|
@ -774,7 +776,8 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
|
|||
redirectToOrigin?: boolean,
|
||||
saveToLibrary?: boolean,
|
||||
addToDashboard?: 'new' | 'existing' | null,
|
||||
dashboardId?: string
|
||||
dashboardId?: string,
|
||||
description?: string
|
||||
) {
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await testSubjects.click('lnsApp_saveButton');
|
||||
|
@ -785,7 +788,8 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont
|
|||
redirectToOrigin,
|
||||
saveToLibrary,
|
||||
addToDashboard,
|
||||
dashboardId
|
||||
dashboardId,
|
||||
description
|
||||
);
|
||||
},
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
|
||||
// Convert to by-value
|
||||
const byRefPanel = await testSubjects.find('embeddablePanelHeading-' + lensTitle);
|
||||
await dashboardPanelActions.legacyUnlinkFromLibary(byRefPanel);
|
||||
await dashboardPanelActions.legacyUnlinkFromLibrary(byRefPanel);
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
const byValueSessionId = await dashboardPanelActions.getSearchSessionIdByTitle(lensTitle);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue