From ad3b03eecd9fc2d29f75275f4d23cf59157f85df Mon Sep 17 00:00:00 2001 From: Ashwin Pc Date: Tue, 26 Jul 2022 11:22:20 +0000 Subject: [PATCH 1/3] fest: Adds autosave while editing agg Signed-off-by: Ashwin Pc --- .../components/data_tab/config_panel.tsx | 6 ++- .../components/data_tab/secondary_panel.tsx | 39 +++++++++++---- .../components/data_tab/use/use_dropbox.tsx | 8 ++-- .../application/components/workspace.tsx | 2 +- .../utils/state_management/metadata_slice.ts | 48 +++++++++++++++++++ .../utils/state_management/preload.ts | 3 ++ .../utils/state_management/store.ts | 2 + .../state_management/visualization_slice.ts | 13 ++--- 8 files changed, 96 insertions(+), 25 deletions(-) create mode 100644 src/plugins/wizard/public/application/utils/state_management/metadata_slice.ts diff --git a/src/plugins/wizard/public/application/components/data_tab/config_panel.tsx b/src/plugins/wizard/public/application/components/data_tab/config_panel.tsx index 1c0e67693471..be0ec12bbff2 100644 --- a/src/plugins/wizard/public/application/components/data_tab/config_panel.tsx +++ b/src/plugins/wizard/public/application/components/data_tab/config_panel.tsx @@ -13,7 +13,9 @@ import { SecondaryPanel } from './secondary_panel'; export function ConfigPanel() { const vizType = useVisualizationType(); - const draftAgg = useTypedSelector((state) => state.visualization.activeVisualization?.draftAgg); + const editingState = useTypedSelector( + (state) => state.visualization.activeVisualization?.draftAgg + ); const schemas = vizType.ui.containerConfig.data.schemas; if (!schemas) return null; @@ -21,7 +23,7 @@ export function ConfigPanel() { const mainPanel = mapSchemaToAggPanel(schemas); return ( - +
{mainPanel}
diff --git a/src/plugins/wizard/public/application/components/data_tab/secondary_panel.tsx b/src/plugins/wizard/public/application/components/data_tab/secondary_panel.tsx index 21bdf256422d..309e8c5ced33 100644 --- a/src/plugins/wizard/public/application/components/data_tab/secondary_panel.tsx +++ b/src/plugins/wizard/public/application/components/data_tab/secondary_panel.tsx @@ -12,11 +12,14 @@ import { useIndexPatterns, useVisualizationType } from '../../utils/use'; import { useOpenSearchDashboards } from '../../../../../opensearch_dashboards_react/public'; import { WizardServices } from '../../../types'; import { IAggType } from '../../../../../data/public'; -import { saveAgg, editAgg } from '../../utils/state_management/visualization_slice'; +import { saveDraftAgg, editDraftAgg } from '../../utils/state_management/visualization_slice'; +import { setValid } from '../../utils/state_management/metadata_slice'; + +const EDITOR_KEY = 'CONFIG_PANEL'; export function SecondaryPanel() { const draftAgg = useTypedSelector((state) => state.visualization.activeVisualization!.draftAgg); - const [valid, setValid] = useState(true); + const valid = useTypedSelector((state) => state.metadata.editorState.valid[EDITOR_KEY]); const [touched, setTouched] = useState(false); const dispatch = useTypedDispatch(); const vizType = useVisualizationType(); @@ -46,9 +49,20 @@ export function SecondaryPanel() { const showAggParamEditor = !!(aggConfig && indexPattern); const closeMenu = useCallback(() => { - // Save the agg if valid else discard - dispatch(saveAgg(valid)); - }, [dispatch, valid]); + dispatch(editDraftAgg(undefined)); + }, [dispatch]); + + const handleSetValid = useCallback( + (isValid: boolean) => { + dispatch( + setValid({ + key: EDITOR_KEY, + valid: isValid, + }) + ); + }, + [dispatch] + ); return (
@@ -58,7 +72,7 @@ export function SecondaryPanel() { className="wizConfig__aggEditor" agg={aggConfig!} indexPattern={indexPattern!} - setValidity={setValid} + setValidity={handleSetValid} setTouched={setTouched} schemas={schemas} formIsTouched={false} @@ -66,8 +80,8 @@ export function SecondaryPanel() { metricAggs={[]} state={{ data: {}, - description: 'Falalala', - title: 'Title for the aggParams', + description: '', + title: '', }} setAggParamValue={function ( aggId: string, @@ -75,11 +89,16 @@ export function SecondaryPanel() { value: any ): void { aggConfig.params[paramName] = value; - dispatch(editAgg(aggConfig.serialize())); + dispatch(editDraftAgg(aggConfig.serialize())); + + // Autosave changes if valid + if (valid) { + dispatch(saveDraftAgg()); + } }} onAggTypeChange={function (aggId: string, aggType: IAggType): void { aggConfig.type = aggType; - dispatch(editAgg(aggConfig.serialize())); + dispatch(editDraftAgg(aggConfig.serialize())); }} /> )} diff --git a/src/plugins/wizard/public/application/components/data_tab/use/use_dropbox.tsx b/src/plugins/wizard/public/application/components/data_tab/use/use_dropbox.tsx index decad4a2c334..af9122d8ebd7 100644 --- a/src/plugins/wizard/public/application/components/data_tab/use/use_dropbox.tsx +++ b/src/plugins/wizard/public/application/components/data_tab/use/use_dropbox.tsx @@ -12,7 +12,7 @@ import { useTypedDispatch, useTypedSelector } from '../../../utils/state_managem import { DropboxDisplay, DropboxProps } from '../dropbox'; import { useDrop } from '../../../utils/drag_drop'; import { - editAgg, + editDraftAgg, reorderAgg, updateAggConfigParams, } from '../../../utils/state_management/visualization_slice'; @@ -88,18 +88,18 @@ export const useDropbox = (props: UseDropboxProps): DropboxProps => { throw new Error('Missing new aggConfig'); } - dispatch(editAgg(newAggConfig.serialize())); + dispatch(editDraftAgg(newAggConfig.serialize())); }, [aggConfigs, aggService, aggs, dispatch, indexPattern, schema.name]); const onEditField = useCallback( - (aggId) => { + (aggId: string) => { const aggConfig = aggConfigs?.aggs.find((agg) => agg.id === aggId); if (!aggConfig) { throw new Error('Could not find agg in aggConfigs'); } - dispatch(editAgg(aggConfig.serialize())); + dispatch(editDraftAgg(aggConfig.serialize())); }, [aggConfigs?.aggs, dispatch] ); diff --git a/src/plugins/wizard/public/application/components/workspace.tsx b/src/plugins/wizard/public/application/components/workspace.tsx index 39d75a7c43d2..ab320c8257ad 100644 --- a/src/plugins/wizard/public/application/components/workspace.tsx +++ b/src/plugins/wizard/public/application/components/workspace.tsx @@ -95,7 +95,7 @@ export const Workspace: FC = ({ children }) => { ) : ( Drop some fields to start} + title={

Add a field to start

} body={ <>

Drag a field to the configuration panel to generate a visualization.

diff --git a/src/plugins/wizard/public/application/utils/state_management/metadata_slice.ts b/src/plugins/wizard/public/application/utils/state_management/metadata_slice.ts new file mode 100644 index 000000000000..a736e0915508 --- /dev/null +++ b/src/plugins/wizard/public/application/utils/state_management/metadata_slice.ts @@ -0,0 +1,48 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { WizardServices } from '../../../types'; + +export interface MetadataState { + editorState: { + valid: { + // Vaidity for each section in the editor + [key: string]: boolean; + }; + }; +} + +const initialState: MetadataState = { + editorState: { + valid: {}, + }, +}; + +export const getPreloadedState = async ({ + types, + data, +}: WizardServices): Promise => { + const preloadedState = { ...initialState }; + + return preloadedState; +}; + +export const slice = createSlice({ + name: 'metadata', + initialState, + reducers: { + setValid: (state, action: PayloadAction<{ key: string; valid: boolean }>) => { + const { key, valid } = action.payload; + state.editorState.valid[key] = valid; + }, + setState: (_state, action: PayloadAction) => { + return action.payload; + }, + }, +}); + +export const { reducer } = slice; +export const { setValid, setState } = slice.actions; diff --git a/src/plugins/wizard/public/application/utils/state_management/preload.ts b/src/plugins/wizard/public/application/utils/state_management/preload.ts index d9cefa21a064..1d96608e33cc 100644 --- a/src/plugins/wizard/public/application/utils/state_management/preload.ts +++ b/src/plugins/wizard/public/application/utils/state_management/preload.ts @@ -7,6 +7,7 @@ import { PreloadedState } from '@reduxjs/toolkit'; import { WizardServices } from '../../..'; import { getPreloadedState as getPreloadedStyleState } from './style_slice'; import { getPreloadedState as getPreloadedVisualizationState } from './visualization_slice'; +import { getPreloadedState as getPreloadedMetadataState } from './metadata_slice'; import { RootState } from './store'; export const getPreloadedState = async ( @@ -14,9 +15,11 @@ export const getPreloadedState = async ( ): Promise> => { const styleState = await getPreloadedStyleState(services); const visualizationState = await getPreloadedVisualizationState(services); + const metadataState = await getPreloadedMetadataState(services); return { style: styleState, visualization: visualizationState, + metadata: metadataState, }; }; diff --git a/src/plugins/wizard/public/application/utils/state_management/store.ts b/src/plugins/wizard/public/application/utils/state_management/store.ts index d8fff094cd1e..932a5f4d8914 100644 --- a/src/plugins/wizard/public/application/utils/state_management/store.ts +++ b/src/plugins/wizard/public/application/utils/state_management/store.ts @@ -6,12 +6,14 @@ import { combineReducers, configureStore, PreloadedState } from '@reduxjs/toolkit'; import { reducer as styleReducer } from './style_slice'; import { reducer as visualizationReducer } from './visualization_slice'; +import { reducer as metadataReducer } from './metadata_slice'; import { WizardServices } from '../../..'; import { getPreloadedState } from './preload'; const rootReducer = combineReducers({ style: styleReducer, visualization: visualizationReducer, + metadata: metadataReducer, }); export const configurePreloadedStore = (preloadedState: PreloadedState) => { diff --git a/src/plugins/wizard/public/application/utils/state_management/visualization_slice.ts b/src/plugins/wizard/public/application/utils/state_management/visualization_slice.ts index 06c865e14395..fe1277f33432 100644 --- a/src/plugins/wizard/public/application/utils/state_management/visualization_slice.ts +++ b/src/plugins/wizard/public/application/utils/state_management/visualization_slice.ts @@ -59,15 +59,13 @@ export const slice = createSlice({ setSearchField: (state, action: PayloadAction) => { state.searchField = action.payload; }, - editAgg: (state, action: PayloadAction) => { + editDraftAgg: (state, action: PayloadAction) => { state.activeVisualization!.draftAgg = action.payload; }, - saveAgg: (state, action: PayloadAction) => { - const saveDraft = action.payload; + saveDraftAgg: (state, action: PayloadAction) => { const draftAgg = state.activeVisualization!.draftAgg; - // Delete the aggConfigParam if the save is not true - if (saveDraft && draftAgg) { + if (draftAgg) { const aggIndex = state.activeVisualization!.aggConfigParams.findIndex( (agg) => agg.id === draftAgg.id ); @@ -78,7 +76,6 @@ export const slice = createSlice({ state.activeVisualization!.aggConfigParams.splice(aggIndex, 1, draftAgg); } } - delete state.activeVisualization!.draftAgg; }, reorderAgg: ( state, @@ -116,9 +113,9 @@ export const { setActiveVisualization, setIndexPattern, setSearchField, - editAgg, + editDraftAgg, + saveDraftAgg, updateAggConfigParams, - saveAgg, reorderAgg, setState, } = slice.actions; From a702aba713b99d133e2c7b41b5bdd3d564e7e47e Mon Sep 17 00:00:00 2001 From: Ashwin Pc Date: Tue, 26 Jul 2022 11:30:44 +0000 Subject: [PATCH 2/3] fix: autosave order Signed-off-by: Ashwin Pc --- .../components/data_tab/secondary_panel.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/plugins/wizard/public/application/components/data_tab/secondary_panel.tsx b/src/plugins/wizard/public/application/components/data_tab/secondary_panel.tsx index 309e8c5ced33..a0fa9c160227 100644 --- a/src/plugins/wizard/public/application/components/data_tab/secondary_panel.tsx +++ b/src/plugins/wizard/public/application/components/data_tab/secondary_panel.tsx @@ -54,14 +54,20 @@ export function SecondaryPanel() { const handleSetValid = useCallback( (isValid: boolean) => { + // Set validity state globally dispatch( setValid({ key: EDITOR_KEY, valid: isValid, }) ); + + // Autosave changes if valid + if (valid) { + dispatch(saveDraftAgg()); + } }, - [dispatch] + [dispatch, valid] ); return ( @@ -90,11 +96,6 @@ export function SecondaryPanel() { ): void { aggConfig.params[paramName] = value; dispatch(editDraftAgg(aggConfig.serialize())); - - // Autosave changes if valid - if (valid) { - dispatch(saveDraftAgg()); - } }} onAggTypeChange={function (aggId: string, aggType: IAggType): void { aggConfig.type = aggType; From 5e9739c66021888c1a694669cdb0c451c604529e Mon Sep 17 00:00:00 2001 From: Ashwin P Chandran Date: Tue, 26 Jul 2022 09:15:40 -0700 Subject: [PATCH 3/3] fix: spelling Co-authored-by: Josh Romero --- .../public/application/utils/state_management/metadata_slice.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/wizard/public/application/utils/state_management/metadata_slice.ts b/src/plugins/wizard/public/application/utils/state_management/metadata_slice.ts index a736e0915508..6e0902220079 100644 --- a/src/plugins/wizard/public/application/utils/state_management/metadata_slice.ts +++ b/src/plugins/wizard/public/application/utils/state_management/metadata_slice.ts @@ -9,7 +9,7 @@ import { WizardServices } from '../../../types'; export interface MetadataState { editorState: { valid: { - // Vaidity for each section in the editor + // Validity for each section in the editor [key: string]: boolean; }; };