Skip to content

Commit

Permalink
Draft of apply on reset - types still angry
Browse files Browse the repository at this point in the history
  • Loading branch information
Heenawter committed Jul 31, 2024
1 parent 1807a35 commit 2dc2e0d
Show file tree
Hide file tree
Showing 11 changed files with 59 additions and 27 deletions.
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 }>;
}

0 comments on commit 2dc2e0d

Please sign in to comment.