Skip to content

Commit

Permalink
feat(user-settings): sync user settings with LS (#951)
Browse files Browse the repository at this point in the history
  • Loading branch information
ValeraS authored Jun 27, 2024
1 parent 190992e commit 9919358
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 115 deletions.
8 changes: 6 additions & 2 deletions src/containers/Nodes/Nodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import {selectAutoRefreshInterval} from '../../store/reducers/autoRefreshControl
import {nodesApi} from '../../store/reducers/nodes/nodes';
import {filterNodes} from '../../store/reducers/nodes/selectors';
import type {NodesSortParams} from '../../store/reducers/nodes/types';
import {ProblemFilterValues, changeFilter} from '../../store/reducers/settings/settings';
import {
ProblemFilterValues,
changeFilter,
selectProblemFilter,
} from '../../store/reducers/settings/settings';
import type {ProblemFilterValue} from '../../store/reducers/settings/types';
import type {AdditionalNodesProps} from '../../types/additionalProps';
import {cn} from '../../utils/cn';
Expand Down Expand Up @@ -58,7 +62,7 @@ export const Nodes = ({path, additionalNodesProps = {}}: NodesProps) => {

const isClusterNodes = !path;

const problemFilter = useTypedSelector((state) => state.settings.problemFilter);
const problemFilter = useTypedSelector(selectProblemFilter);
const autorefresh = useTypedSelector(selectAutoRefreshInterval);

const [useNodesEndpoint] = useSetting(USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY);
Expand Down
8 changes: 6 additions & 2 deletions src/containers/Nodes/VirtualNodes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import type {
} from '../../components/VirtualTable';
import {ResizeableVirtualTable} from '../../components/VirtualTable/ResizeableVirtualTable';
import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
import {ProblemFilterValues, changeFilter} from '../../store/reducers/settings/settings';
import {
ProblemFilterValues,
changeFilter,
selectProblemFilter,
} from '../../store/reducers/settings/settings';
import type {ProblemFilterValue} from '../../store/reducers/settings/types';
import type {AdditionalNodesProps} from '../../types/additionalProps';
import {cn} from '../../utils/cn';
Expand Down Expand Up @@ -56,7 +60,7 @@ export const VirtualNodes = ({path, parentContainer, additionalNodesProps}: Node

const dispatch = useTypedDispatch();

const problemFilter = useTypedSelector((state) => state.settings.problemFilter);
const problemFilter = useTypedSelector(selectProblemFilter);

const filters = React.useMemo(() => {
return [path, searchValue, problemFilter, uptimeFilter];
Expand Down
4 changes: 2 additions & 2 deletions src/containers/Tenant/Diagnostics/HotKeys/HotKeys.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {hotKeysApi} from '../../../../store/reducers/hotKeys/hotKeys';
import {schemaApi} from '../../../../store/reducers/schema/schema';
import type {HotKey} from '../../../../types/api/hotkeys';
import {cn} from '../../../../utils/cn';
import {DEFAULT_TABLE_SETTINGS, IS_HOTKEYS_HELP_HIDDDEN_KEY} from '../../../../utils/constants';
import {DEFAULT_TABLE_SETTINGS, IS_HOTKEYS_HELP_HIDDEN_KEY} from '../../../../utils/constants';
import {useSetting} from '../../../../utils/hooks';

import i18n from './i18n';
Expand Down Expand Up @@ -108,7 +108,7 @@ export function HotKeys({path}: HotKeysProps) {
}

function HelpCard() {
const [helpHidden, setHelpHidden] = useSetting(IS_HOTKEYS_HELP_HIDDDEN_KEY);
const [helpHidden, setHelpHidden] = useSetting(IS_HOTKEYS_HELP_HIDDEN_KEY);

if (helpHidden) {
return null;
Expand Down
15 changes: 0 additions & 15 deletions src/containers/Tenant/Query/QueryEditor/QueryEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
import {useQueryModes, useSetting} from '../../../../utils/hooks';
import {LANGUAGE_YQL_ID} from '../../../../utils/monaco/yql/constants';
import {QUERY_ACTIONS} from '../../../../utils/query';
import {parseJson} from '../../../../utils/utils';
import type {InitialPaneState} from '../../utils/paneVisibilityToggleHelpers';
import {
PaneVisibilityActionTypes,
Expand Down Expand Up @@ -146,20 +145,6 @@ function QueryEditor(props: QueryEditorProps) {
};
}, []);

React.useEffect(() => {
const storageEventHandler = (event: StorageEvent) => {
if (event.key === SAVED_QUERIES_KEY) {
const v = parseJson(event.newValue);
setSavedQueries(v);
}
};

window.addEventListener('storage', storageEventHandler);
return () => {
window.removeEventListener('storage', storageEventHandler);
};
}, [setSavedQueries]);

React.useEffect(() => {
dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerCollapse);
}, []);
Expand Down
2 changes: 1 addition & 1 deletion src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export {default as appRoutes} from './routes';
export {createApi, YdbEmbeddedAPI, YdbWebVersionAPI} from './services/api';
export {settingsManager} from './services/settings';
export {settings as userSettings} from './containers/UserSettings/settings';
export {setUserSettings} from './store/reducers/settings/settings';
export {setSettingValue, getSettingValue} from './store/reducers/settings/settings';

export {componentsRegistry} from './components/ComponentsProvider/componentsRegistry';
export {useSetting, useTypedSelector} from './utils/hooks';
Expand Down
4 changes: 2 additions & 2 deletions src/services/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
BINARY_DATA_IN_PLAIN_TEXT_DISPLAY,
ENABLE_AUTOCOMPLETE,
INVERTED_DISKS_KEY,
IS_HOTKEYS_HELP_HIDDDEN_KEY,
IS_HOTKEYS_HELP_HIDDEN_KEY,
LANGUAGE_KEY,
LAST_USED_QUERY_ACTION_KEY,
PARTITIONS_HIDDEN_COLUMNS_KEY,
Expand Down Expand Up @@ -41,7 +41,7 @@ export const DEFAULT_USER_SETTINGS = {
[USE_CLUSTER_BALANCER_AS_BACKEND_KEY]: true,
[ENABLE_AUTOCOMPLETE]: true,
[AUTOCOMPLETE_ON_ENTER]: true,
[IS_HOTKEYS_HELP_HIDDDEN_KEY]: false,
[IS_HOTKEYS_HELP_HIDDEN_KEY]: false,
} as const satisfies SettingsObject;

class SettingsManager {
Expand Down
3 changes: 3 additions & 0 deletions src/store/configureStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {createApi} from '../services/api';
import {getUrlData} from './getUrlData';
import rootReducer from './reducers';
import {api as storeApi} from './reducers/api';
import {syncUserSettingsFromLS} from './reducers/settings/settings';
import {UPDATE_REF} from './reducers/tooltip';
import getLocationMiddleware from './state-url-mapping';

Expand Down Expand Up @@ -37,6 +38,8 @@ function _configureStore<
}).concat(locationMiddleware, ...middleware),
});

syncUserSettingsFromLS(store);

return store;
}

Expand Down
120 changes: 50 additions & 70 deletions src/store/reducers/settings/settings.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
import type {Reducer, ThunkAction} from '@reduxjs/toolkit';
import type {Store} from '@reduxjs/toolkit';
import {createSlice} from '@reduxjs/toolkit';

import type {RootState} from '../..';
import type {SettingsObject} from '../../../services/settings';
import {DEFAULT_USER_SETTINGS, settingsManager} from '../../../services/settings';
import {parseJson} from '../../../utils/utils';
import type {AppDispatch} from '../../defaultStore';

import type {
ProblemFilterValue,
SetSettingValueAction,
SettingsAction,
SettingsRootStateSlice,
SettingsState,
} from './types';

const CHANGE_PROBLEM_FILTER = 'settings/CHANGE_PROBLEM_FILTER';
export const SET_SETTING_VALUE = 'settings/SET_VALUE';
export const SET_USER_SETTINGS = 'settings/SET_USER_SETTINGS';
import type {ProblemFilterValue, SettingsState} from './types';

export const ProblemFilterValues = {
ALL: 'All',
Expand All @@ -24,71 +15,60 @@ export const ProblemFilterValues = {
const userSettings = settingsManager.extractSettingsFromLS(DEFAULT_USER_SETTINGS);
const systemSettings = window.systemSettings || {};

export const initialState = {
export const initialState: SettingsState = {
problemFilter: ProblemFilterValues.ALL,
userSettings,
systemSettings,
};

const settings: Reducer<SettingsState, SettingsAction> = (state = initialState, action) => {
switch (action.type) {
case CHANGE_PROBLEM_FILTER:
return {
...state,
problemFilter: action.data,
};

case SET_SETTING_VALUE: {
const newSettings = {
...state.userSettings,
[action.data.name]: action.data.value,
};

return {
...state,
userSettings: newSettings,
};
}
case SET_USER_SETTINGS: {
return {
...state,
userSettings: {
...state.userSettings,
...action.data,
},
};
}
default:
return state;
}
};

export const setSettingValue = (
name: string,
value: unknown,
): ThunkAction<void, RootState, unknown, SetSettingValueAction> => {
return (dispatch) => {
dispatch({type: SET_SETTING_VALUE, data: {name, value}});
const settingsSlice = createSlice({
name: 'settings',
initialState,
reducers: (create) => ({
changeFilter: create.reducer<ProblemFilterValue>((state, action) => {
state.problemFilter = action.payload;
}),
setSettingValue: create.reducer<{name: string; value: unknown}>((state, action) => {
state.userSettings[action.payload.name] = action.payload.value;
}),
}),
selectors: {
getSettingValue: (state, name: string) => state.userSettings[name],
selectProblemFilter: (state) => state.problemFilter,
},
});

export const {changeFilter} = settingsSlice.actions;
export const {getSettingValue, selectProblemFilter} = settingsSlice.selectors;

export const setSettingValue = (name: string, value: unknown) => {
return (dispatch: AppDispatch) => {
dispatch(settingsSlice.actions.setSettingValue({name, value}));

settingsManager.setUserSettingsValue(name, value);
};
};

export const setUserSettings = (data: SettingsObject) => {
return {type: SET_USER_SETTINGS, data} as const;
};

export const getSettingValue = (state: SettingsRootStateSlice, name: string) => {
return state.settings.userSettings[name];
};

export const changeFilter = (filter: ProblemFilterValue) => {
return {
type: CHANGE_PROBLEM_FILTER,
data: filter,
} as const;
};
export function syncUserSettingsFromLS(store: Store) {
if (typeof window === 'undefined') {
return;
}

export const selectProblemFilter = (state: SettingsRootStateSlice) => state.settings.problemFilter;
window.addEventListener('storage', (event) => {
if (event.key && event.key in DEFAULT_USER_SETTINGS) {
const name = event.key as keyof typeof DEFAULT_USER_SETTINGS;
let value = DEFAULT_USER_SETTINGS[name];
if (event.newValue !== null) {
value = parseJson(event.newValue);
}
store.dispatch(
settingsSlice.actions.setSettingValue({
name,
value,
}),
);
}
});
}

export default settings;
export default settingsSlice.reducer;
21 changes: 1 addition & 20 deletions src/store/reducers/settings/types.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import type {SettingsObject} from '../../../services/settings';
import type {ValueOf} from '../../../types/common';

import type {
ProblemFilterValues,
SET_SETTING_VALUE,
changeFilter,
setUserSettings,
} from './settings';
import type {ProblemFilterValues} from './settings';

export type ProblemFilterValue = ValueOf<typeof ProblemFilterValues>;

Expand All @@ -15,17 +10,3 @@ export interface SettingsState {
userSettings: SettingsObject;
systemSettings: SettingsObject;
}

export type SetSettingValueAction = {
type: typeof SET_SETTING_VALUE;
data: {name: string; value: unknown};
};

export type SettingsAction =
| ReturnType<typeof changeFilter>
| ReturnType<typeof setUserSettings>
| SetSettingValueAction;

export interface SettingsRootStateSlice {
settings: SettingsState;
}
2 changes: 1 addition & 1 deletion src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,4 @@ export const ENABLE_AUTOCOMPLETE = 'enableAutocomplete';

export const AUTOCOMPLETE_ON_ENTER = 'autocompleteOnEnter';

export const IS_HOTKEYS_HELP_HIDDDEN_KEY = 'isHotKeysHelpHidden';
export const IS_HOTKEYS_HELP_HIDDEN_KEY = 'isHotKeysHelpHidden';

0 comments on commit 9919358

Please sign in to comment.