Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Embeddable Rebuild] [Controls] Draft of apply on reset #41

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,8 @@ export const ReactControlExample = ({
<EuiFlexItem grow={false}>
<EuiButtonEmpty
isDisabled={!controlGroupApi}
onClick={() => {
controlGroupApi?.resetUnsavedChanges();
onClick={async () => {
if (controlGroupApi) await controlGroupApi.asyncResetUnsavedChanges();
}}
>
Reset
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@ import {
} from '@kbn/presentation-containers';
import {
apiPublishesUnsavedChanges,
PublishesUnsavedChanges,
PublishesAsyncUnsavedChanges,
StateComparators,
} from '@kbn/presentation-publishing';
import { combineLatest, map } from 'rxjs';
import { ControlsInOrder, getControlsInOrder } from './init_controls_manager';
import { ControlGroupRuntimeState, ControlPanelsState } from './types';
import { DataControlApi } from '../data_controls/types';

export type ControlGroupComparatorState = Pick<
ControlGroupRuntimeState,
Expand All @@ -35,6 +36,7 @@ export type ControlGroupComparatorState = Pick<
export function initializeControlGroupUnsavedChanges(
children$: PresentationContainer['children$'],
comparators: StateComparators<ControlGroupComparatorState>,
applySelections: () => void,
snapshotControlsRuntimeState: () => ControlPanelsState,
parentApi: unknown,
lastSavedRuntimeState: ControlGroupRuntimeState
Expand Down Expand Up @@ -68,12 +70,20 @@ export function initializeControlGroupUnsavedChanges(
return Object.keys(unsavedChanges).length ? unsavedChanges : undefined;
})
),
resetUnsavedChanges: () => {
asyncResetUnsavedChanges: async () => {
controlGroupUnsavedChanges.api.resetUnsavedChanges();
const filtersReadyPromises: Array<Promise<void>> = [];
Object.values(children$.value).forEach((controlApi) => {
if (apiPublishesUnsavedChanges(controlApi)) controlApi.resetUnsavedChanges();
if ((controlApi as DataControlApi).untilFiltersReady) {
filtersReadyPromises.push((controlApi as DataControlApi).untilFiltersReady());
}
});
if (!comparators.autoApplySelections[0].getValue()) {
await Promise.all(filtersReadyPromises);
applySelections();
}
},
} as PublishesUnsavedChanges<ControlGroupRuntimeState>,
} as PublishesAsyncUnsavedChanges<ControlGroupRuntimeState>,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export const getControlGroupEmbeddableFactory = (services: {
],
labelPosition: [labelPosition$, (next: ControlStyle) => labelPosition$.next(next)],
},
selectionsManager.applySelections,
controlsManager.snapshotControlsRuntimeState,
parentApi,
lastSavedRuntimeState
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import {
import {
HasEditCapabilities,
HasParentApi,
PublishesAsyncUnsavedChanges,
PublishesDataLoading,
PublishesFilters,
PublishesTimeslice,
PublishesUnifiedSearch,
PublishesUnsavedChanges,
PublishingSubject,
} from '@kbn/presentation-publishing';
import { PublishesDataViews } from '@kbn/presentation-publishing/interfaces/publishes_data_views';
Expand Down Expand Up @@ -55,7 +55,7 @@ export type ControlGroupApi = PresentationContainer &
HasSerializedChildState<ControlPanelState> &
HasEditCapabilities &
PublishesDataLoading &
PublishesUnsavedChanges &
PublishesAsyncUnsavedChanges &
PublishesControlGroupDisplaySettings &
PublishesTimeslice &
Partial<HasParentApi<PublishesUnifiedSearch> & HasSaveNotification> & {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import { isEqual } from 'lodash';
import { BehaviorSubject, combineLatest, first, switchMap } from 'rxjs';
import { BehaviorSubject, combineLatest, filter, first, switchMap, tap } from 'rxjs';

import { CoreStart } from '@kbn/core-lifecycle-browser';
import { DataView, DATA_VIEW_SAVED_OBJECT_TYPE } from '@kbn/data-views-plugin/common';
Expand Down Expand Up @@ -39,7 +39,6 @@ export const initializeDataControl = <EditorState extends object = {}>(
comparators: StateComparators<DefaultDataControlState>;
stateManager: ControlStateManager<DefaultDataControlState>;
serialize: () => SerializedPanelState<DefaultControlState>;
untilFiltersInitialized: () => Promise<void>;
} => {
const defaultControl = initializeDefaultControlApi(state);

Expand All @@ -49,6 +48,7 @@ export const initializeDataControl = <EditorState extends object = {}>(
const fieldName = new BehaviorSubject<string>(state.fieldName);
const dataViews = new BehaviorSubject<DataView[] | undefined>(undefined);
const filters$ = new BehaviorSubject<Filter[] | undefined>(undefined);
const filtersReady$ = new BehaviorSubject<boolean>(false);

const stateManager: ControlStateManager<DefaultDataControlState> = {
...defaultControl.stateManager,
Expand All @@ -65,6 +65,10 @@ export const initializeDataControl = <EditorState extends object = {}>(

const dataViewIdSubscription = dataViewId
.pipe(
tap(() => {
// need to fetch new data view before filters are ready to be published
filtersReady$.next(false);
}),
switchMap(async (currentDataViewId) => {
let dataView: DataView | undefined;
try {
Expand Down Expand Up @@ -153,17 +157,37 @@ export const initializeDataControl = <EditorState extends object = {}>(
});
};

/** When the filter outputs **for the first time**, set `filtersReady` to `true` */
let filtersInitialized = false;
combineLatest([defaultControl.api.blockingError, filters$])
.pipe(
first(([blockingError, filters]) => blockingError !== undefined || (filters?.length ?? 0) > 0)
)
.subscribe(() => {
filtersReady$.next(true);
filtersInitialized = true;
});

const api: ControlApiInitialization<DataControlApi> = {
...defaultControl.api,
panelTitle,
defaultPanelTitle,
dataViews,
onEdit,
filters$,
filtersReady$,
setOutputFilter: (newFilter: Filter | undefined) => {
filters$.next(newFilter ? [newFilter] : undefined);
if (filtersInitialized) filtersReady$.next(true);
},
isEditingEnabled: () => true,
untilFiltersReady: async () => {
return new Promise((resolve) => {
filtersReady$.pipe(first((filtersReady) => filtersReady)).subscribe((ready) => {
resolve();
});
});
},
};

return {
Expand Down Expand Up @@ -196,19 +220,5 @@ export const initializeDataControl = <EditorState extends object = {}>(
],
};
},
untilFiltersInitialized: async () => {
return new Promise((resolve) => {
combineLatest([defaultControl.api.blockingError, filters$])
.pipe(
first(
([blockingError, filters]) =>
blockingError !== undefined || (filters?.length ?? 0) > 0
)
)
.subscribe(() => {
resolve();
});
});
},
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export const getRangesliderControlFactory = (
});

if (initialState.value !== undefined) {
await dataControl.untilFiltersInitialized();
await dataControl.api.untilFiltersReady();
}

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export const getSearchControlFactory = ({
});

if (initialState.searchString?.length) {
await dataControl.untilFiltersInitialized();
await dataControl.api.untilFiltersReady();
}

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ import {
PublishesFilters,
PublishesPanelTitle,
} from '@kbn/presentation-publishing';
import { BehaviorSubject } from 'rxjs';
import { ControlFactory, DefaultControlApi, DefaultControlState } from '../types';

export type DataControlApi = DefaultControlApi &
Omit<PublishesPanelTitle, 'hidePanelTitle'> & // control titles cannot be hidden
HasEditCapabilities &
PublishesDataViews &
PublishesFilters & {
filtersReady$: BehaviorSubject<boolean>;
untilFiltersReady: () => Promise<void>;
setOutputFilter: (filter: Filter | undefined) => void; // a control should only ever output a **single** filter
};

Expand Down
1 change: 1 addition & 0 deletions packages/presentation/presentation_publishing/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export {
export {
apiPublishesUnsavedChanges,
type PublishesUnsavedChanges,
type PublishesAsyncUnsavedChanges,
} from './interfaces/publishes_unsaved_changes';
export {
apiPublishesViewMode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@ export interface PublishesUnsavedChanges<Runtime extends object = object> {
resetUnsavedChanges: () => void;
}

export const apiPublishesUnsavedChanges = (api: unknown): api is PublishesUnsavedChanges => {
export interface PublishesAsyncUnsavedChanges<Runtime extends object = object>
extends Pick<PublishesUnsavedChanges<Runtime>, 'unsavedChanges'> {
asyncResetUnsavedChanges: () => Promise<void>;
}

export const apiPublishesUnsavedChanges = (
api: unknown
): api is PublishesUnsavedChanges | PublishesAsyncUnsavedChanges => {
return Boolean(
api &&
(api as PublishesUnsavedChanges).unsavedChanges &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,6 @@ export interface ReactEmbeddableFactory<
* Last saved runtime state. Different from initialRuntimeState in that it does not contain previous sessions's unsaved changes
* Compare with initialRuntimeState to flag unsaved changes on load
*/
lastSavedRuntimeState: RuntimeState,
lastSavedRuntimeState: RuntimeState
) => Promise<{ Component: React.FC<{}>; api: Api }>;
}
Loading