From e18448e416ef6286bde60ca2dc2d620d309a254d Mon Sep 17 00:00:00 2001 From: heenawter Date: Wed, 8 Dec 2021 11:26:40 -0700 Subject: [PATCH 1/7] Added special case to panel comparison. --- .../application/lib/diff_dashboard_state.ts | 41 +++++++++++++++---- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts b/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts index 3f6f9f0966c9ca..4c93d6312c022f 100644 --- a/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts +++ b/src/plugins/dashboard/public/application/lib/diff_dashboard_state.ts @@ -9,6 +9,7 @@ import _ from 'lodash'; import { DashboardPanelState } from '..'; import { esFilters, Filter } from '../../services/data'; +import { EmbeddableInput } from '../../services/embeddable'; import { DashboardContainerInput, DashboardOptions, @@ -56,12 +57,12 @@ export const diffDashboardState = ( }; const optionsAreEqual = (optionsA: DashboardOptions, optionsB: DashboardOptions): boolean => { - const optionKeys = [...Object.keys(optionsA), ...Object.keys(optionsB)]; + const optionKeys = [ + ...(Object.keys(optionsA) as Array), + ...(Object.keys(optionsB) as Array), + ]; for (const key of optionKeys) { - if ( - Boolean((optionsA as unknown as { [key: string]: boolean })[key]) !== - Boolean((optionsB as unknown as { [key: string]: boolean })[key]) - ) { + if (Boolean(optionsA[key]) !== Boolean(optionsB[key])) { return false; } } @@ -82,16 +83,40 @@ const panelsAreEqual = (panelsA: DashboardPanelMap, panelsB: DashboardPanelMap): const panelCommonDiff = commonDiff( panelsA[id] as unknown as DashboardDiffCommon, panelsB[id] as unknown as DashboardDiffCommon, - ['panelRefName'] + ['panelRefName', 'explicitInput'] ); - if (Object.keys(panelCommonDiff).length > 0) { + if ( + Object.keys(panelCommonDiff).length > 0 || + !explicitInputIsEqual(panelsA[id].explicitInput, panelsB[id].explicitInput) + ) { return false; } } - return true; }; +/** + * Need to compare properties of explicitInput *directly* in order to handle special comparisons for 'title' + * and 'hidePanelTitles.' For example, if some object 'obj1' has 'obj1[title] = undefined' and some other + * object `obj2' simply does not have the key `title,' we want obj1 to still equal obj2 - in normal comparisons + * without this special case, `obj1 != obj2.' + * @param originalInput + * @param newInput + */ +const explicitInputIsEqual = ( + originalInput: EmbeddableInput, + newInput: EmbeddableInput +): boolean => { + const diffs = commonDiff(originalInput, newInput, [ + 'hidePanelTitles', + 'title', + ]); + const hidePanelsAreEqual = + Boolean(originalInput.hidePanelTitles) === Boolean(newInput.hidePanelTitles); + const titlesAreEqual = originalInput.title === newInput.title; + return Object.keys(diffs).length === 0 && hidePanelsAreEqual && titlesAreEqual; +}; + const commonDiffFilters = ( originalObj: DashboardDiffCommonFilters, newObj: DashboardDiffCommonFilters, From 7781d60def6ba2af6168924b842d043343085f06 Mon Sep 17 00:00:00 2001 From: heenawter Date: Wed, 8 Dec 2021 11:27:28 -0700 Subject: [PATCH 2/7] Fixed panel title behaviour when linking/unlinking to/from the library. --- .../application/actions/unlink_from_library_action.tsx | 7 ++++++- .../public/lib/attribute_service/attribute_service.tsx | 5 +++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx b/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx index 814f68a400981e..68a5950269517e 100644 --- a/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx +++ b/src/plugins/dashboard/public/application/actions/unlink_from_library_action.tsx @@ -70,19 +70,24 @@ export class UnlinkFromLibraryAction implements Action = { type: embeddable.type, - explicitInput: { ...newInput }, + explicitInput: { ...newInput, title: embeddable.getTitle() }, }; + // since by value visualizations should not have default titles, unlinking a visualization should remove + // the library title from the attributes. + _.unset(newPanel, 'explicitInput.attributes.title'); dashboard.replacePanel(panelToReplace, newPanel, true); const title = dashboardUnlinkFromLibraryAction.getSuccessMessage( embeddable.getTitle() ? `'${embeddable.getTitle()}'` : '' ); + this.deps.toasts.addSuccess({ title, 'data-test-subj': 'unlinkPanelSuccess', diff --git a/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx b/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx index 9a575a9446a011..b443ab2f2090a6 100644 --- a/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx +++ b/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx @@ -169,8 +169,9 @@ export class AttributeService< // Remove unneeded attributes from the original input. const newInput = omit(input, ATTRIBUTE_SERVICE_KEY); - // Combine input and wrapped input to preserve any passed in explicit Input. - resolve({ ...newInput, ...wrappedInput }); + // Combine input and wrapped input to preserve any passed in explicit Input while ensuring that the + // library title ovewrites the original title + resolve({ ...newInput, ...wrappedInput, title: newAttributes.title }); return { id: wrappedInput.savedObjectId }; } catch (error) { reject(error); From 2a475ff085d169d408174a1b40f513447fa3a743 Mon Sep 17 00:00:00 2001 From: heenawter Date: Wed, 8 Dec 2021 11:27:50 -0700 Subject: [PATCH 3/7] Added panel title test suite. --- .../lib/panel/panel_header/panel_header.tsx | 38 ++-- .../functional/page_objects/dashboard_page.ts | 21 +++ .../services/common/test_subjects.ts | 3 +- .../test/functional/apps/dashboard/index.ts | 1 + .../functional/apps/dashboard/panel_titles.ts | 162 ++++++++++++++++++ 5 files changed, 206 insertions(+), 19 deletions(-) create mode 100644 x-pack/test/functional/apps/dashboard/panel_titles.ts diff --git a/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx b/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx index 742a2d19099418..75a33b0e7336b3 100644 --- a/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx +++ b/src/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsx @@ -153,7 +153,7 @@ export function PanelHeader({ if (!showPanelBar) { return ( -
+
-

- {getAriaLabel()} - {renderTitle()} - {renderBadges(badges, embeddable)} -

- {renderNotifications(notifications, embeddable)} - - + +
+

+ {getAriaLabel()} + {renderTitle()} + {renderBadges(badges, embeddable)} +

+ {renderNotifications(notifications, embeddable)} + +
+
); } diff --git a/test/functional/page_objects/dashboard_page.ts b/test/functional/page_objects/dashboard_page.ts index 77ea098c76878b..c3f88d20369af1 100644 --- a/test/functional/page_objects/dashboard_page.ts +++ b/test/functional/page_objects/dashboard_page.ts @@ -534,6 +534,27 @@ export class DashboardPageObject extends FtrService { return await Promise.all(titleObjects.map(async (title) => await title.getVisibleText())); } + // returns an array of Boolean values - true if the panel title is visible in view mode, false if it is not + public async getVisibilityOfPanelTitles() { + this.log.debug('in getVisibilityOfPanels'); + // only works if the dashboard is in view mode + const inViewMode = await this.getIsInViewMode(); + if (!inViewMode) { + await this.clickCancelOutOfEditMode(); + } + const visibilities: boolean[] = []; + const titleObjects = await this.testSubjects.findAll('dashboardPanelTitle__wrapper'); + for (const titleObject of titleObjects) { + const exists = !(await titleObject.elementHasClass('embPanel__header--floater')); + visibilities.push(exists); + } + // return to edit mode if a switch to view mode above was necessary + if (!inViewMode) { + await this.switchToEditMode(); + } + return visibilities; + } + public async getPanelDimensions() { const panels = await this.find.allByCssSelector('.react-grid-item'); // These are gridster-defined elements and classes return await Promise.all( diff --git a/test/functional/services/common/test_subjects.ts b/test/functional/services/common/test_subjects.ts index 09c54af7b8811c..ef63c15b0bf481 100644 --- a/test/functional/services/common/test_subjects.ts +++ b/test/functional/services/common/test_subjects.ts @@ -206,7 +206,8 @@ export class TestSubjects extends FtrService { // call clearValue() and type() on the element that is focused after // clicking on the testSubject const input = await this.findService.activeElement(); - if (clearWithKeyboard === true) { + // if `text` is explicitely set to the empty string, then call clearValueWithKeyboard() rather than clearValue() + if (clearWithKeyboard === true || text === '') { await input.clearValueWithKeyboard(); } else { await input.clearValue(); diff --git a/x-pack/test/functional/apps/dashboard/index.ts b/x-pack/test/functional/apps/dashboard/index.ts index be817faeaa6c49..4aa379ac19dc72 100644 --- a/x-pack/test/functional/apps/dashboard/index.ts +++ b/x-pack/test/functional/apps/dashboard/index.ts @@ -20,6 +20,7 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./dashboard_tagging')); loadTestFile(require.resolve('./dashboard_lens_by_value')); loadTestFile(require.resolve('./dashboard_maps_by_value')); + loadTestFile(require.resolve('./panel_titles')); loadTestFile(require.resolve('./migration_smoke_tests/lens_migration_smoke_test')); loadTestFile(require.resolve('./migration_smoke_tests/controls_migration_smoke_test')); diff --git a/x-pack/test/functional/apps/dashboard/panel_titles.ts b/x-pack/test/functional/apps/dashboard/panel_titles.ts new file mode 100644 index 00000000000000..be83542858aaf2 --- /dev/null +++ b/x-pack/test/functional/apps/dashboard/panel_titles.ts @@ -0,0 +1,162 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const testSubjects = getService('testSubjects'); + const retry = getService('retry'); + const dashboardPanelActions = getService('dashboardPanelActions'); + const PageObjects = getPageObjects([ + 'common', + 'dashboard', + 'visualize', + 'visEditor', + 'timePicker', + 'lens', + ]); + + const DASHBOARD_NAME = 'Panel Title Test'; + const EMPTY_TITLE = '[No Title]'; + const NEW_CUSTOM_TITLE = 'Test Custom Title'; + const LIBRARY_TITLE_FOR_EMPTY_TESTS = 'Library Title for Empty String'; + + describe('panel titles', () => { + const clearUnsavedChanges = async () => { + await retry.try(async () => { + // avoid flaky test by surrounding in retry + await testSubjects.existOrFail('dashboardUnsavedChangesBadge'); + await PageObjects.dashboard.clickQuickSave(); + await testSubjects.missingOrFail('dashboardUnsavedChangesBadge'); + }); + }; + + before(async () => { + await esArchiver.load('test/functional/fixtures/es_archiver/dashboard/current/kibana'); + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); + await kibanaServer.importExport.load( + 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json' + ); + await PageObjects.common.navigateToApp('dashboard'); + await PageObjects.dashboard.preserveCrossAppState(); + await PageObjects.dashboard.clickNewDashboard(); + await PageObjects.dashboard.saveDashboard(DASHBOARD_NAME); + }); + + it('new panel by value has empty title', async () => { + await PageObjects.lens.createAndAddLensFromDashboard({}); + const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; + expect(newPanelTitle).to.equal(EMPTY_TITLE); + }); + + it('saving new panel with blank title clears "unsaved changes" badge', async () => { + await dashboardPanelActions.setCustomPanelTitle(''); + await clearUnsavedChanges(); + }); + + it('custom title causes unsaved changes and saving clears it', async () => { + await dashboardPanelActions.setCustomPanelTitle(NEW_CUSTOM_TITLE); + const panelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; + expect(panelTitle).to.equal(NEW_CUSTOM_TITLE); + await clearUnsavedChanges(); + }); + + it('resetting title on a by reference panel sets it to the library title', async () => { + const BY_REFERENCE_TITLE = 'Reset Title - By Reference'; + await dashboardPanelActions.saveToLibrary(BY_REFERENCE_TITLE); + await dashboardPanelActions.setCustomPanelTitle('This should go away'); + + await dashboardPanelActions.resetCustomPanelTitle(); + const resetPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; + expect(resetPanelTitle).to.equal(BY_REFERENCE_TITLE); + + // unlink so that panel goes back to by value for next tests + await dashboardPanelActions.unlinkFromLibary(); + }); + + it('resetting title on a by value panel sets it to the empty string', async () => { + const BY_VALUE_TITLE = 'Reset Title - By Value'; + await dashboardPanelActions.setCustomPanelTitle(BY_VALUE_TITLE); + + await dashboardPanelActions.resetCustomPanelTitle(); + const panelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; + expect(panelTitle).to.equal(EMPTY_TITLE); + await clearUnsavedChanges(); + }); + + it('blank titles are hidden in view mode', async () => { + await PageObjects.dashboard.clickCancelOutOfEditMode(); + + const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; + expect(titleVisibility).to.be(false); + }); + + it('custom titles are visible in view mode', async () => { + await PageObjects.dashboard.switchToEditMode(); + await dashboardPanelActions.setCustomPanelTitle(NEW_CUSTOM_TITLE); + await PageObjects.dashboard.clickQuickSave(); + await PageObjects.dashboard.clickCancelOutOfEditMode(); + + const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; + expect(titleVisibility).to.be(true); + }); + + it('hiding an individual panel title hides it in view mode', async () => { + await PageObjects.dashboard.switchToEditMode(); + await dashboardPanelActions.toggleHidePanelTitle(); + await PageObjects.dashboard.clickQuickSave(); + await PageObjects.dashboard.clickCancelOutOfEditMode(); + + const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; + expect(titleVisibility).to.be(false); + + // undo the previous hide panel toggle (i.e. make the panel visible) to prepare for next tests + await PageObjects.dashboard.switchToEditMode(); + await dashboardPanelActions.toggleHidePanelTitle(); + await PageObjects.dashboard.clickQuickSave(); + }); + + it('linking a by value panel with a custom title to the library will overwrite the custom title with the library title', async () => { + // note that the panel already has a custom title from the previous tests + const BY_REFERENCE_TITLE = 'Test Custom Title on Link'; + + await PageObjects.dashboard.switchToEditMode(); + await dashboardPanelActions.saveToLibrary(BY_REFERENCE_TITLE); + await retry.try(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(BY_REFERENCE_TITLE); + }); + }); + + it('unlinking a by reference panel with a custom title will keep the current title', async () => { + await dashboardPanelActions.setCustomPanelTitle(NEW_CUSTOM_TITLE); + await dashboardPanelActions.unlinkFromLibary(); + const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; + expect(newPanelTitle).to.equal(NEW_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.setCustomPanelTitle(''); + await dashboardPanelActions.saveToLibrary(LIBRARY_TITLE_FOR_EMPTY_TESTS); + await retry.try(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); + }); + }); + + it('unlinking a by reference panel without a custom title will keep the library title', async () => { + await dashboardPanelActions.unlinkFromLibary(); + const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; + expect(newPanelTitle).to.equal(LIBRARY_TITLE_FOR_EMPTY_TESTS); + }); + }); +} From 84afa07fb750d53a58db56f4161bfc005c12eaeb Mon Sep 17 00:00:00 2001 From: heenawter Date: Thu, 9 Dec 2021 13:41:46 -0700 Subject: [PATCH 4/7] Made the injection of the 'savedSearchId' key conditional on if it is defined when unlinking. --- src/plugins/visualizations/public/vis.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/visualizations/public/vis.ts b/src/plugins/visualizations/public/vis.ts index ad5c0705d75394..fd9bb434a7cf0c 100644 --- a/src/plugins/visualizations/public/vis.ts +++ b/src/plugins/visualizations/public/vis.ts @@ -200,7 +200,7 @@ export class Vis { data: { aggs: aggs as any, searchSource: this.data.searchSource ? this.data.searchSource.getSerializedFields() : {}, - savedSearchId: this.data.savedSearchId, + ...(this.data.savedSearchId ? { savedSearchId: this.data.savedSearchId } : {}), }, }; } From 4ee8a49af36fc1269e11d74e69aff482f4a02efa Mon Sep 17 00:00:00 2001 From: heenawter Date: Mon, 13 Dec 2021 14:17:52 -0700 Subject: [PATCH 5/7] Adjusted use of 'setValue()' based on feedback from @dmlemeshko --- test/functional/services/common/test_subjects.ts | 3 +-- test/functional/services/dashboard/panel_actions.ts | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/functional/services/common/test_subjects.ts b/test/functional/services/common/test_subjects.ts index ef63c15b0bf481..09c54af7b8811c 100644 --- a/test/functional/services/common/test_subjects.ts +++ b/test/functional/services/common/test_subjects.ts @@ -206,8 +206,7 @@ export class TestSubjects extends FtrService { // call clearValue() and type() on the element that is focused after // clicking on the testSubject const input = await this.findService.activeElement(); - // if `text` is explicitely set to the empty string, then call clearValueWithKeyboard() rather than clearValue() - if (clearWithKeyboard === true || text === '') { + if (clearWithKeyboard === true) { await input.clearValueWithKeyboard(); } else { await input.clearValue(); diff --git a/test/functional/services/dashboard/panel_actions.ts b/test/functional/services/dashboard/panel_actions.ts index 4340f16492a7c2..c7e786f4b123a4 100644 --- a/test/functional/services/dashboard/panel_actions.ts +++ b/test/functional/services/dashboard/panel_actions.ts @@ -316,7 +316,9 @@ export class DashboardPanelActionsService extends FtrService { } else { await this.customizePanel(); } - await this.testSubjects.setValue('customEmbeddablePanelTitleInput', customTitle); + await this.testSubjects.setValue('customEmbeddablePanelTitleInput', customTitle, { + clearWithKeyboard: customTitle === '', // if clearing the title using the empty string as the new value, 'clearWithKeyboard' must be true; otherwise, false + }); await this.testSubjects.click('saveNewTitleButton'); } From 77c622fff2089d3b8029d3feeb0043b2a918924a Mon Sep 17 00:00:00 2001 From: heenawter Date: Mon, 13 Dec 2021 15:31:13 -0700 Subject: [PATCH 6/7] Refractor test suite. --- .../functional/apps/dashboard/panel_titles.ts | 188 +++++++++--------- 1 file changed, 92 insertions(+), 96 deletions(-) diff --git a/x-pack/test/functional/apps/dashboard/panel_titles.ts b/x-pack/test/functional/apps/dashboard/panel_titles.ts index be83542858aaf2..7cca12b4ee4370 100644 --- a/x-pack/test/functional/apps/dashboard/panel_titles.ts +++ b/x-pack/test/functional/apps/dashboard/panel_titles.ts @@ -24,20 +24,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ]); const DASHBOARD_NAME = 'Panel Title Test'; + const CUSTOM_TITLE = 'Test Custom Title'; const EMPTY_TITLE = '[No Title]'; - const NEW_CUSTOM_TITLE = 'Test Custom Title'; - const LIBRARY_TITLE_FOR_EMPTY_TESTS = 'Library Title for Empty String'; + 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', () => { - const clearUnsavedChanges = async () => { - await retry.try(async () => { - // avoid flaky test by surrounding in retry - await testSubjects.existOrFail('dashboardUnsavedChangesBadge'); - await PageObjects.dashboard.clickQuickSave(); - await testSubjects.missingOrFail('dashboardUnsavedChangesBadge'); - }); - }; - before(async () => { await esArchiver.load('test/functional/fixtures/es_archiver/dashboard/current/kibana'); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/logstash_functional'); @@ -50,113 +42,117 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.saveDashboard(DASHBOARD_NAME); }); - it('new panel by value has empty title', async () => { - await PageObjects.lens.createAndAddLensFromDashboard({}); - const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; - expect(newPanelTitle).to.equal(EMPTY_TITLE); - }); + describe('panel titles - by value', () => { + const clearUnsavedChanges = async () => { + await retry.try(async () => { + // avoid flaky test by surrounding in retry + await testSubjects.existOrFail('dashboardUnsavedChangesBadge'); + await PageObjects.dashboard.clickQuickSave(); + await testSubjects.missingOrFail('dashboardUnsavedChangesBadge'); + }); + }; + + it('new panel by value has empty title', async () => { + await PageObjects.lens.createAndAddLensFromDashboard({}); + const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; + expect(newPanelTitle).to.equal(EMPTY_TITLE); + }); - it('saving new panel with blank title clears "unsaved changes" badge', async () => { - await dashboardPanelActions.setCustomPanelTitle(''); - await clearUnsavedChanges(); - }); + it('saving new panel with blank title clears "unsaved changes" badge', async () => { + await dashboardPanelActions.setCustomPanelTitle(''); + await clearUnsavedChanges(); + }); - it('custom title causes unsaved changes and saving clears it', async () => { - await dashboardPanelActions.setCustomPanelTitle(NEW_CUSTOM_TITLE); - const panelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; - expect(panelTitle).to.equal(NEW_CUSTOM_TITLE); - await clearUnsavedChanges(); - }); + it('custom title causes unsaved changes and saving clears it', async () => { + await dashboardPanelActions.setCustomPanelTitle(CUSTOM_TITLE); + const panelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; + expect(panelTitle).to.equal(CUSTOM_TITLE); + await clearUnsavedChanges(); + }); - it('resetting title on a by reference panel sets it to the library title', async () => { - const BY_REFERENCE_TITLE = 'Reset Title - By Reference'; - await dashboardPanelActions.saveToLibrary(BY_REFERENCE_TITLE); - await dashboardPanelActions.setCustomPanelTitle('This should go away'); + it('resetting title on a by value panel sets it to the empty string', async () => { + const BY_VALUE_TITLE = 'Reset Title - By Value'; + await dashboardPanelActions.setCustomPanelTitle(BY_VALUE_TITLE); - await dashboardPanelActions.resetCustomPanelTitle(); - const resetPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; - expect(resetPanelTitle).to.equal(BY_REFERENCE_TITLE); + await dashboardPanelActions.resetCustomPanelTitle(); + const panelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; + expect(panelTitle).to.equal(EMPTY_TITLE); + await clearUnsavedChanges(); + }); - // unlink so that panel goes back to by value for next tests - await dashboardPanelActions.unlinkFromLibary(); - }); + it('blank titles are hidden in view mode', async () => { + await PageObjects.dashboard.clickCancelOutOfEditMode(); - it('resetting title on a by value panel sets it to the empty string', async () => { - const BY_VALUE_TITLE = 'Reset Title - By Value'; - await dashboardPanelActions.setCustomPanelTitle(BY_VALUE_TITLE); + const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; + expect(titleVisibility).to.be(false); + }); - await dashboardPanelActions.resetCustomPanelTitle(); - const panelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; - expect(panelTitle).to.equal(EMPTY_TITLE); - await clearUnsavedChanges(); - }); + it('custom titles are visible in view mode', async () => { + await PageObjects.dashboard.switchToEditMode(); + await dashboardPanelActions.setCustomPanelTitle(CUSTOM_TITLE); + await PageObjects.dashboard.clickQuickSave(); + await PageObjects.dashboard.clickCancelOutOfEditMode(); - it('blank titles are hidden in view mode', async () => { - await PageObjects.dashboard.clickCancelOutOfEditMode(); + const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; + expect(titleVisibility).to.be(true); + }); - const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; - expect(titleVisibility).to.be(false); - }); + it('hiding an individual panel title hides it in view mode', async () => { + await PageObjects.dashboard.switchToEditMode(); + await dashboardPanelActions.toggleHidePanelTitle(); + await PageObjects.dashboard.clickQuickSave(); + await PageObjects.dashboard.clickCancelOutOfEditMode(); - it('custom titles are visible in view mode', async () => { - await PageObjects.dashboard.switchToEditMode(); - await dashboardPanelActions.setCustomPanelTitle(NEW_CUSTOM_TITLE); - await PageObjects.dashboard.clickQuickSave(); - await PageObjects.dashboard.clickCancelOutOfEditMode(); + const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; + expect(titleVisibility).to.be(false); - const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; - expect(titleVisibility).to.be(true); + // undo the previous hide panel toggle (i.e. make the panel visible) to keep state consistent + await PageObjects.dashboard.switchToEditMode(); + await dashboardPanelActions.toggleHidePanelTitle(); + await PageObjects.dashboard.clickQuickSave(); + }); }); - it('hiding an individual panel title hides it in view mode', async () => { - await PageObjects.dashboard.switchToEditMode(); - await dashboardPanelActions.toggleHidePanelTitle(); - await PageObjects.dashboard.clickQuickSave(); - await PageObjects.dashboard.clickCancelOutOfEditMode(); - - const titleVisibility = (await PageObjects.dashboard.getVisibilityOfPanelTitles())[0]; - expect(titleVisibility).to.be(false); - - // undo the previous hide panel toggle (i.e. make the panel visible) to prepare for next tests - await PageObjects.dashboard.switchToEditMode(); - await dashboardPanelActions.toggleHidePanelTitle(); - await PageObjects.dashboard.clickQuickSave(); - }); + describe('panel titles - by reference', () => { + 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.setCustomPanelTitle(CUSTOM_TITLE); + await dashboardPanelActions.saveToLibrary(LIBRARY_TITLE_FOR_CUSTOM_TESTS); + await retry.try(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); + }); + }); - it('linking a by value panel with a custom title to the library will overwrite the custom title with the library title', async () => { - // note that the panel already has a custom title from the previous tests - const BY_REFERENCE_TITLE = 'Test Custom Title on Link'; + it('resetting title on a by reference panel sets it to the library title', async () => { + await dashboardPanelActions.setCustomPanelTitle('This should go away'); + await dashboardPanelActions.resetCustomPanelTitle(); + const resetPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; + expect(resetPanelTitle).to.equal(LIBRARY_TITLE_FOR_CUSTOM_TESTS); + }); - await PageObjects.dashboard.switchToEditMode(); - await dashboardPanelActions.saveToLibrary(BY_REFERENCE_TITLE); - await retry.try(async () => { - // need to surround in 'retry' due to delays in HTML updates causing the title read to be behind + it('unlinking a by reference panel with a custom title will keep the current title', async () => { + await dashboardPanelActions.setCustomPanelTitle(CUSTOM_TITLE); + await dashboardPanelActions.unlinkFromLibary(); const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; - expect(newPanelTitle).to.equal(BY_REFERENCE_TITLE); + expect(newPanelTitle).to.equal(CUSTOM_TITLE); }); - }); - it('unlinking a by reference panel with a custom title will keep the current title', async () => { - await dashboardPanelActions.setCustomPanelTitle(NEW_CUSTOM_TITLE); - await dashboardPanelActions.unlinkFromLibary(); - const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; - expect(newPanelTitle).to.equal(NEW_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.setCustomPanelTitle(''); + await dashboardPanelActions.saveToLibrary(LIBRARY_TITLE_FOR_EMPTY_TESTS); + await retry.try(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); + }); + }); - 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.setCustomPanelTitle(''); - await dashboardPanelActions.saveToLibrary(LIBRARY_TITLE_FOR_EMPTY_TESTS); - await retry.try(async () => { - // need to surround in 'retry' due to delays in HTML updates causing the title read to be behind + it('unlinking a by reference panel without a custom title will keep the library title', async () => { + await dashboardPanelActions.unlinkFromLibary(); const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; expect(newPanelTitle).to.equal(LIBRARY_TITLE_FOR_EMPTY_TESTS); }); }); - - it('unlinking a by reference panel without a custom title will keep the library title', async () => { - await dashboardPanelActions.unlinkFromLibary(); - const newPanelTitle = (await PageObjects.dashboard.getPanelTitles())[0]; - expect(newPanelTitle).to.equal(LIBRARY_TITLE_FOR_EMPTY_TESTS); - }); }); } From 12bae8bc22fda6bdbb03fe9a7cf31c9613896c47 Mon Sep 17 00:00:00 2001 From: heenawter Date: Tue, 14 Dec 2021 16:22:36 -0700 Subject: [PATCH 7/7] Improved code for removal of title on library link. --- .../lib/attribute_service/attribute_service.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx b/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx index 92ec81e56925b1..749b968f633bd3 100644 --- a/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx +++ b/src/plugins/embeddable/public/lib/attribute_service/attribute_service.tsx @@ -168,13 +168,12 @@ export class AttributeService< newAttributes, true )) as unknown as RefType; + // Remove unneeded attributes from the original input. Note that the original panel title + // is removed in favour of the new attributes title + const newInput = omit(input, [ATTRIBUTE_SERVICE_KEY, 'title']); - // Remove unneeded attributes from the original input. - const newInput = omit(input, ATTRIBUTE_SERVICE_KEY); - - // Combine input and wrapped input to preserve any passed in explicit Input while ensuring that the - // library title ovewrites the original title - resolve({ ...newInput, ...wrappedInput, title: newAttributes.title }); + // Combine input and wrapped input to preserve any passed in explicit Input + resolve({ ...newInput, ...wrappedInput }); return { id: wrappedInput.savedObjectId }; } catch (error) { reject(error);