diff --git a/src/platform/packages/shared/presentation/presentation_containers/interfaces/unsaved_changes/initialize_unsaved_changes.ts b/src/platform/packages/shared/presentation/presentation_containers/interfaces/unsaved_changes/initialize_unsaved_changes.ts index 1038ef8c9c889..af3be9f653119 100644 --- a/src/platform/packages/shared/presentation/presentation_containers/interfaces/unsaved_changes/initialize_unsaved_changes.ts +++ b/src/platform/packages/shared/presentation/presentation_containers/interfaces/unsaved_changes/initialize_unsaved_changes.ts @@ -16,9 +16,9 @@ import { } from '@kbn/presentation-publishing'; import { MaybePromise } from '@kbn/utility-types'; import { Observable, combineLatestWith, debounceTime, map, of } from 'rxjs'; +import { isEqual, sortBy } from 'lodash'; import { apiHasLastSavedChildState } from '../last_saved_child_state'; import { PresentationContainer } from '../presentation_container'; - const UNSAVED_CHANGES_DEBOUNCE = 100; export const initializeUnsavedChanges = ({ @@ -29,6 +29,7 @@ export const initializeUnsavedChanges = ({ defaultState, serializeState, anyStateChange$, + checkRefEquality, }: { uuid: string; parentApi: unknown; @@ -37,6 +38,7 @@ export const initializeUnsavedChanges = ({ getComparators: () => StateComparators; defaultState?: Partial; onReset: (lastSavedPanelState?: SerializedPanelState) => MaybePromise; + checkRefEquality?: boolean; }): PublishesUnsavedChanges => { if (!apiHasLastSavedChildState(parentApi)) { return { @@ -46,16 +48,25 @@ export const initializeUnsavedChanges = ({ } const hasUnsavedChanges$ = anyStateChange$.pipe( - combineLatestWith( - parentApi.lastSavedStateForChild$(uuid).pipe(map((panelState) => panelState?.rawState)) - ), + combineLatestWith(parentApi.lastSavedStateForChild$(uuid)), debounceTime(UNSAVED_CHANGES_DEBOUNCE), map(([, lastSavedState]) => { - const currentState = serializeState().rawState; + const currentState = serializeState(); + + // check ref equality + if (checkRefEquality) { + const lastSavedRefs = sortBy(lastSavedState?.references ?? [], 'id'); + const currentRefs = sortBy(currentState?.references ?? [], 'id'); + const equalRefs = isEqual(lastSavedRefs, currentRefs); + + if (!equalRefs) return true; + } + + // check state equality return !areComparatorsEqual( getComparators(), - lastSavedState, - currentState, + lastSavedState?.rawState, + currentState.rawState, defaultState, (key: string) => { const childApi = (parentApi as Partial).children$?.getValue()[ diff --git a/src/platform/plugins/shared/dashboard/public/dashboard_api/get_dashboard_api.ts b/src/platform/plugins/shared/dashboard/public/dashboard_api/get_dashboard_api.ts index 2aaebe1f2f568..fb32970c265a9 100644 --- a/src/platform/plugins/shared/dashboard/public/dashboard_api/get_dashboard_api.ts +++ b/src/platform/plugins/shared/dashboard/public/dashboard_api/get_dashboard_api.ts @@ -174,6 +174,7 @@ export function getDashboardApi({ } if (saveResult) { + references$.next(saveResult.references); unsavedChangesManager.internalApi.onSave(saveResult.savedState); const settings = settingsManager.api.getSettings(); settingsManager.api.setSettings({ @@ -185,8 +186,6 @@ export function getDashboardApi({ title: saveResult.savedState.title, }); savedObjectId$.next(saveResult.id); - - references$.next(saveResult.references); } return saveResult; @@ -203,8 +202,8 @@ export function getDashboardApi({ }); if (saveResult?.error) return; - unsavedChangesManager.internalApi.onSave(dashboardState); references$.next(saveResult.references); + unsavedChangesManager.internalApi.onSave(dashboardState); return; }, diff --git a/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx b/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx index 4642cca35f810..61fc6fb21827f 100644 --- a/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/platform/plugins/shared/visualizations/public/embeddable/visualize_embeddable.tsx @@ -177,6 +177,7 @@ export const getVisualizeEmbeddableFactory: (deps: { serializeState: () => { return serializeVisualizeEmbeddable(savedObjectId$.getValue(), linkedToLibrary); }, + checkRefEquality: true, anyStateChange$: merge( ...(dynamicActionsManager ? [dynamicActionsManager.anyStateChange$] : []), savedObjectId$, diff --git a/src/platform/test/functional/fixtures/kbn_archiver/dashboard/current/kibana.json b/src/platform/test/functional/fixtures/kbn_archiver/dashboard/current/kibana.json index e453c2ba30311..65411f092c3c7 100644 --- a/src/platform/test/functional/fixtures/kbn_archiver/dashboard/current/kibana.json +++ b/src/platform/test/functional/fixtures/kbn_archiver/dashboard/current/kibana.json @@ -3198,6 +3198,11 @@ "type": "visualization", "id": "50643b60-3dd3-11e8-b2b9-5d5dc1715159" }, + { + "name":"ffc13252-56b4-4e3f-847e-61373fa0be86:kibanaSavedObjectMeta.searchSourceJSON.index", + "type":"index-pattern", + "id":"a0f483a0-3dc9-11e8-8660-4d65aa086b3c" + }, { "name": "controlGroup_41827e70-5285-4d44-8375-4c498449b9a7:optionsListControlDataView", "type": "index-pattern", @@ -3317,4 +3322,4 @@ "managed": false, "coreMigrationVersion": "8.8.0", "typeMigrationVersion": "10.2.0" -} \ No newline at end of file +}