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

[Lens] allow user to disable auto apply #125158

Merged
Show file tree
Hide file tree
Changes from 76 commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
ba8b5a5
Auto-apply toggle switch + reducers
drewdaemon Feb 4, 2022
0968920
add apply changes button
drewdaemon Feb 4, 2022
7bb60c6
kinda sorta workin!
drewdaemon Feb 4, 2022
4c942d9
auto apply applies working changes
drewdaemon Feb 7, 2022
c5dd500
record applied datasource layers in frame public API
drewdaemon Feb 9, 2022
49069af
Save setting to localstorage
drewdaemon Feb 9, 2022
36a67e2
hide suggestions until changes applied
drewdaemon Feb 10, 2022
569f82a
rename applyWorkingState -> applyChanges
drewdaemon Feb 10, 2022
0d450d9
apply suggestions when clicked
drewdaemon Feb 11, 2022
6e6f127
apply state changes due to data panel load immediately
drewdaemon Feb 11, 2022
1add31a
consolidate applied state logic
drewdaemon Feb 11, 2022
322b1d3
keep flyout open when apply changes
drewdaemon Feb 11, 2022
976242e
generalizing exclusion mechanism
drewdaemon Feb 11, 2022
009dee3
only update extent when it changes meaningfully
drewdaemon Feb 11, 2022
3288e42
Merge branch 'main' of github.com:elastic/kibana into 74490/disable-a…
drewdaemon Feb 11, 2022
1e96ab0
add reducer tests
drewdaemon Feb 11, 2022
aab38f1
test selectors
drewdaemon Feb 14, 2022
3980e08
data-panel test (not working yet)
drewdaemon Feb 14, 2022
14ba2be
test that datasource applies changes immediately
drewdaemon Feb 14, 2022
026737c
test DataPanelWrapper's setState function
drewdaemon Feb 14, 2022
4811574
Test suggestion panel apply changes prompt
drewdaemon Feb 14, 2022
dcbc4f7
Move controls to toolbar
drewdaemon Feb 14, 2022
8dd20fe
some UI tweaks
drewdaemon Feb 14, 2022
dbcb18f
fix disabling auto apply from localstorage for new vis
drewdaemon Feb 14, 2022
13b0599
correcting workspace panel regression
drewdaemon Feb 14, 2022
a91bd24
make button smaller to conserve space
drewdaemon Feb 15, 2022
25f22c4
test that workspace panel uses applied state
drewdaemon Feb 15, 2022
f2fb7f3
Merge branch 'main' of github.com:elastic/kibana into 74490/disable-a…
drewdaemon Feb 15, 2022
cf1f3e4
test auto-apply controls
drewdaemon Feb 15, 2022
62be81d
Merge branch 'main' into 74490/disable-auto-apply-duplicate-state-str…
kibanamachine Feb 15, 2022
e3c6416
some small tweaks
drewdaemon Feb 15, 2022
89391c0
Merge branch '74490/disable-auto-apply-duplicate-state-strategy' of g…
drewdaemon Feb 15, 2022
294d8e5
prevent suggestions not from suggestions panel from being applied imm…
drewdaemon Feb 15, 2022
371962c
reinstate apply label
drewdaemon Feb 16, 2022
126ad53
update some types
drewdaemon Feb 16, 2022
4b3169b
preserve auto-apply controls for fullscreen datasource
drewdaemon Feb 16, 2022
d9053e6
some updates to the controls
drewdaemon Feb 16, 2022
88e2be1
fix ui in fullscreen mode
drewdaemon Feb 16, 2022
7a55fd6
fix excluded click target check
drewdaemon Feb 17, 2022
ff02fd2
stop changing visualization type from changing workspace panel contents
drewdaemon Feb 17, 2022
12f2e81
Merge branch 'main' into 74490/disable-auto-apply-duplicate-state-str…
kibanamachine Feb 17, 2022
7f18f65
apply changes on save
drewdaemon Feb 17, 2022
271a0b1
Merge branch '74490/disable-auto-apply-duplicate-state-strategy' of g…
drewdaemon Feb 17, 2022
bfd4303
correct test title
drewdaemon Feb 17, 2022
730a608
move apply-changes-on-save to avoid race condition
drewdaemon Feb 17, 2022
d269777
Merge branch 'main' into 74490/disable-auto-apply-duplicate-state-str…
kibanamachine Feb 22, 2022
a65d0e2
isolate expression generation
drewdaemon Feb 22, 2022
f7d88e7
factoring some validation into own function
drewdaemon Feb 22, 2022
fb47b75
select active datasource inside getBuildExpressionArgs
drewdaemon Feb 22, 2022
3d06710
assert saveability against unapplied state
drewdaemon Feb 22, 2022
e4f9b4a
Merge branch '74490/disable-auto-apply-duplicate-state-strategy' of g…
drewdaemon Feb 22, 2022
25a70dd
add functional tests for auto-apply in full-screen and page refresh
drewdaemon Feb 23, 2022
a69b9fd
functional test: apply changes
drewdaemon Feb 23, 2022
77fd88f
test applying through suggestions
drewdaemon Feb 24, 2022
96d77a6
passing working state to workspace panel wrapper
drewdaemon Feb 24, 2022
7e4c955
caching expression strategy
drewdaemon Feb 24, 2022
59d1ece
apply-changes counter
drewdaemon Feb 24, 2022
ff5465e
move initial render flag to local state
drewdaemon Feb 24, 2022
638fd5c
fix expression check
drewdaemon Feb 24, 2022
923bf57
refine workspace panel state usage
drewdaemon Feb 24, 2022
6d8b1d3
unskip auto-apply test
drewdaemon Feb 25, 2022
806b6d7
remove missing dependency
drewdaemon Feb 25, 2022
a21de00
allow null expression as initial render (empty workspace)
drewdaemon Feb 25, 2022
cf332d6
add empty workspace test
drewdaemon Feb 25, 2022
93f444a
Merge branch 'main' into 74490/disable-auto-apply-duplicate-state-str…
kibanamachine Feb 25, 2022
1d762e1
base saveability on working changes
drewdaemon Feb 25, 2022
4c39e45
mark changes as applied when auto-apply is enabled
drewdaemon Feb 26, 2022
3fb4390
update selectors test
drewdaemon Feb 26, 2022
eada3fe
encapsulate apply-changes trigger
drewdaemon Feb 26, 2022
ababa8e
update unit tests
drewdaemon Feb 26, 2022
25b520b
Add telemetry
drewdaemon Feb 28, 2022
c676959
Merge branch '74490/disable-auto-apply-duplicate-state-strategy' of g…
drewdaemon Feb 28, 2022
1031b2a
Merge pull request #4 from andrewctate/74490/disable-auto-apply-toggl…
drewdaemon Feb 28, 2022
73eb511
Merge branch 'main' of github.com:elastic/kibana into 74490/disable-a…
drewdaemon Feb 28, 2022
acbd930
fix typo in telemetry configs
drewdaemon Feb 28, 2022
d966510
fix typings
drewdaemon Feb 28, 2022
b540de4
remove unused variable
drewdaemon Mar 1, 2022
8a850f0
useRef for expressionToRender
drewdaemon Mar 1, 2022
fba80cb
stop context middleware from updating time range when user has unappl…
drewdaemon Mar 1, 2022
d6ba1db
update context-update behavior when auto-apply disabled
drewdaemon Mar 1, 2022
a5493e6
fix typings
drewdaemon Mar 1, 2022
6a58a86
wrapping changesApplied signal in useEffect
drewdaemon Mar 1, 2022
9b0e750
using ref for marking initial render complete
drewdaemon Mar 1, 2022
41d8e8e
handle expressionToRender in an effect hook
drewdaemon Mar 2, 2022
80f9f1e
fix typings
drewdaemon Mar 2, 2022
be329a3
Merge branch 'main' into 74490/disable-auto-apply-duplicate-state-str…
kibanamachine Mar 2, 2022
381ec60
allow falsy value for axis title
drewdaemon Mar 3, 2022
74a3dbd
Merge branch '74490/disable-auto-apply-duplicate-state-strategy' of g…
drewdaemon Mar 3, 2022
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
14 changes: 13 additions & 1 deletion x-pack/plugins/lens/public/app_plugin/app.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import { SavedObjectReference } from '../../../../../src/core/types';
import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public';
import moment from 'moment';

import { setState, LensAppState } from '../state_management/index';
import { setState, LensAppState, selectTriggerApplyChanges } from '../state_management/index';
jest.mock('../editor_frame_service/editor_frame/expression_helpers');
jest.mock('src/core/public');
jest.mock('../persistence/saved_objects_utils/check_for_duplicate_title', () => ({
Expand Down Expand Up @@ -635,6 +635,18 @@ describe('Lens App', () => {
);
});

it('applies all changes on-save', async () => {
const { lensStore } = await save({
initialSavedObjectId: undefined,
newCopyOnSave: false,
newTitle: 'hello there',
preloadedState: {
applyChangesCounter: 0,
},
});
expect(lensStore.getState().lens.applyChangesCounter).toBe(1);
});

it('adds to the recently accessed list on save', async () => {
const { services } = await save({
initialSavedObjectId: undefined,
Expand Down
3 changes: 3 additions & 0 deletions x-pack/plugins/lens/public/app_plugin/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Document } from '../persistence/saved_object_store';

import {
setState,
applyChanges,
useLensSelector,
useLensDispatch,
LensAppState,
Expand Down Expand Up @@ -270,6 +271,7 @@ export function App({

const runSave = useCallback(
(saveProps: SaveProps, options: { saveToLibrary: boolean }) => {
dispatch(applyChanges());
return runSaveLensVisualization(
{
lastKnownDoc,
Expand Down Expand Up @@ -310,6 +312,7 @@ export function App({
redirectTo,
lensAppServices,
dispatchSetState,
dispatch,
setIsSaveModalVisible,
]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,26 @@ import {

import { i18n } from '@kbn/i18n';

/**
* The dimension container is set up to close when it detects a click outside it.
* Use this CSS class to exclude particular elements from this behavior.
*/
export const DONT_CLOSE_DIMENSION_CONTAINER_ON_CLICK_CLASS =
'lensDontCloseDimensionContainerOnClick';

function fromExcludedClickTarget(event: Event) {
for (
let node: HTMLElement | null = event.target as HTMLElement;
node !== null;
node = node!.parentElement
) {
if (node.classList!.contains(DONT_CLOSE_DIMENSION_CONTAINER_ON_CLICK_CLASS)) {
return true;
}
}
return false;
}

export function DimensionContainer({
isOpen,
groupLabel,
Expand Down Expand Up @@ -77,8 +97,8 @@ export function DimensionContainer({
<EuiFocusTrap disabled={!focusTrapIsEnabled} clickOutsideDisables={true}>
<EuiWindowEvent event="keydown" handler={closeOnEscape} />
<EuiOutsideClickDetector
onOutsideClick={() => {
if (isFullscreen) {
onOutsideClick={(event) => {
if (isFullscreen || fromExcludedClickTarget(event)) {
return;
}
closeFlyout();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* 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 React from 'react';
import { DataPanelWrapper } from './data_panel_wrapper';
import { Datasource, DatasourceDataPanelProps } from '../../types';
import { DragDropIdentifier } from '../../drag_drop';
import { UiActionsStart } from 'src/plugins/ui_actions/public';
import { mockStoreDeps, mountWithProvider } from '../../mocks';
import { disableAutoApply } from '../../state_management/lens_slice';
import { selectTriggerApplyChanges } from '../../state_management';

describe('Data Panel Wrapper', () => {
describe('Datasource data panel properties', () => {
let datasourceDataPanelProps: DatasourceDataPanelProps;
let lensStore: Awaited<ReturnType<typeof mountWithProvider>>['lensStore'];
beforeEach(async () => {
const renderDataPanel = jest.fn();

const datasourceMap = {
activeDatasource: {
renderDataPanel,
} as unknown as Datasource,
};

const mountResult = await mountWithProvider(
<DataPanelWrapper
datasourceMap={datasourceMap}
showNoDataPopover={() => {}}
core={{} as DatasourceDataPanelProps['core']}
dropOntoWorkspace={(field: DragDropIdentifier) => {}}
hasSuggestionForField={(field: DragDropIdentifier) => true}
plugins={{ uiActions: {} as UiActionsStart }}
/>,
{
preloadedState: {
activeDatasourceId: 'activeDatasource',
datasourceStates: {
activeDatasource: {
isLoading: false,
state: {
age: 'old',
},
},
},
},
storeDeps: mockStoreDeps({ datasourceMap }),
}
);

lensStore = mountResult.lensStore;

datasourceDataPanelProps = renderDataPanel.mock.calls[0][1] as DatasourceDataPanelProps;
});

describe('setState', () => {
it('applies state immediately when option true', async () => {
lensStore.dispatch(disableAutoApply());
selectTriggerApplyChanges(lensStore.getState());

const newDatasourceState = { age: 'new' };
datasourceDataPanelProps.setState(newDatasourceState, { applyImmediately: true });

expect(lensStore.getState().lens.datasourceStates.activeDatasource.state).toEqual(
newDatasourceState
);
expect(selectTriggerApplyChanges(lensStore.getState())).toBeTruthy();
});

it('does not apply state immediately when option false', async () => {
lensStore.dispatch(disableAutoApply());
selectTriggerApplyChanges(lensStore.getState());

const newDatasourceState = { age: 'new' };
datasourceDataPanelProps.setState(newDatasourceState, { applyImmediately: false });

const lensState = lensStore.getState().lens;
expect(lensState.datasourceStates.activeDatasource.state).toEqual(newDatasourceState);
expect(selectTriggerApplyChanges(lensStore.getState())).toBeFalsy();
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
updateDatasourceState,
useLensSelector,
setState,
applyChanges,
selectExecutionContext,
selectActiveDatasourceId,
selectDatasourceStates,
Expand All @@ -45,15 +46,18 @@ export const DataPanelWrapper = memo((props: DataPanelWrapperProps) => {
: true;

const dispatchLens = useLensDispatch();
const setDatasourceState: StateSetter<unknown> = useMemo(() => {
return (updater) => {
const setDatasourceState: StateSetter<unknown, { applyImmediately?: boolean }> = useMemo(() => {
return (updater: unknown | ((prevState: unknown) => unknown), options) => {
dispatchLens(
updateDatasourceState({
updater,
datasourceId: activeDatasourceId!,
clearStagedPreview: true,
})
);
if (options?.applyImmediately) {
dispatchLens(applyChanges());
Copy link
Contributor

@mbondyra mbondyra Feb 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering if it wouldn't be more performant if instead of dispatching 2 actions one after another, we could add a parameter options to updateDatasourceState? So we'd invoke it in this way

dispatchLens(
        updateDatasourceState({
          updater,
          datasourceId: activeDatasourceId!,
          options: {
               ...options,
               clearStagedPreview: true,
        })
);

and then we'd incorporate the logic of applyChanges action inside updateDatasourceState. Same for other places when we run applyChanges right after running another actions (I think there are 3 in this PR) I didn't test it though so not sure if that would work ok. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I went the direction of two dispatches to keep the reducers simple and atomic. Can you help me understand in what way using a single dispatch call would be more performant?

Copy link
Contributor

@mbondyra mbondyra Feb 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So main my concern is that we dispatch one more action so we have one more rerender of the app. I might be wrong though, I might test it on Monday :D Here's a random article that explains it: https://unsplash.com/blog/react-redux-performance-considerations-when-dispatching-multiple-actions/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you get a chance to test this? Not your responsibility, just wanted to check if it has been done.

}
};
}, [activeDatasourceId, dispatchLens]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export function EditorFrame(props: EditorFrameProps) {
const suggestion = getSuggestionForField.current!(field);
if (suggestion) {
trackUiEvent('drop_onto_workspace');
switchToSuggestion(dispatchLens, suggestion, true);
switchToSuggestion(dispatchLens, suggestion, { clearStagedPreview: true });
}
},
[getSuggestionForField, dispatchLens]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ a tilemap in an iframe: https://github.com/elastic/kibana/issues/16457 */
}

&.lnsFrameLayout__pageBody-isFullscreen {
background: $euiColorEmptyShade;
flex: 1;
padding: 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
switchVisualization,
DatasourceStates,
VisualizationState,
applyChanges,
} from '../../state_management';

/**
Expand Down Expand Up @@ -232,7 +233,10 @@ export function switchToSuggestion(
Suggestion,
'visualizationId' | 'visualizationState' | 'datasourceState' | 'datasourceId'
>,
clearStagedPreview?: boolean
options?: {
clearStagedPreview?: boolean;
applyImmediately?: boolean;
}
) {
dispatchLens(
switchVisualization({
Expand All @@ -242,9 +246,12 @@ export function switchToSuggestion(
datasourceState: suggestion.datasourceState,
datasourceId: suggestion.datasourceId!,
},
clearStagedPreview,
clearStagedPreview: options?.clearStagedPreview,
})
);
if (options?.applyImmediately) {
dispatchLens(applyChanges());
}
}

export function getTopSuggestionForField(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,7 @@
text-align: center;
flex-grow: 0;
}

.lnsSuggestionPanel__applyChangesPrompt {
height: $lnsSuggestionHeight;
}
Loading