ydb-embedded-ui 4.26.0 → 4.27.1

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.27.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.27.0...v4.27.1) (2024-01-10)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * enable extract and set user settings manually ([#629](https://github.com/ydb-platform/ydb-embedded-ui/issues/629)) ([5eecd58](https://github.com/ydb-platform/ydb-embedded-ui/commit/5eecd58249688b4a8b3ecad766564f7b404e839c))
9
+
10
+ ## [4.27.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.26.0...v4.27.0) (2023-12-28)
11
+
12
+
13
+ ### Features
14
+
15
+ * migrate from external settings api ([#621](https://github.com/ydb-platform/ydb-embedded-ui/issues/621)) ([ae2fbbe](https://github.com/ydb-platform/ydb-embedded-ui/commit/ae2fbbef66d9aba150012027baf8b89bf79cd741))
16
+
3
17
  ## [4.26.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.25.0...v4.26.0) (2023-12-14)
4
18
 
5
19
 
@@ -16,8 +16,8 @@ import ReduxTooltip from '../ReduxTooltip/ReduxTooltip';
16
16
  import Header from '../Header/Header';
17
17
  import AppIcons from '../AppIcons/AppIcons';
18
18
 
19
- import {getParsedSettingValue} from '../../store/reducers/settings/settings';
20
19
  import {THEME_KEY} from '../../utils/constants';
20
+ import {useSetting} from '../../utils/hooks';
21
21
 
22
22
  import './App.scss';
23
23
  import PropTypes from 'prop-types';
@@ -72,7 +72,10 @@ Content.propTypes = {
72
72
  };
73
73
 
74
74
  function ContentWrapper(props) {
75
- const {theme, singleClusterMode, isAuthenticated} = props;
75
+ const {singleClusterMode, isAuthenticated} = props;
76
+
77
+ const [theme] = useSetting(THEME_KEY);
78
+
76
79
  return (
77
80
  <HistoryContext.Consumer>
78
81
  {(history) => (
@@ -96,7 +99,6 @@ function ContentWrapper(props) {
96
99
  }
97
100
 
98
101
  ContentWrapper.propTypes = {
99
- theme: PropTypes.string,
100
102
  singleClusterMode: PropTypes.bool,
101
103
  isAuthenticated: PropTypes.bool,
102
104
  children: PropTypes.node,
@@ -104,7 +106,6 @@ ContentWrapper.propTypes = {
104
106
 
105
107
  function mapStateToProps(state) {
106
108
  return {
107
- theme: getParsedSettingValue(state, THEME_KEY),
108
109
  isAuthenticated: state.authentication.isAuthenticated,
109
110
  singleClusterMode: state.singleClusterMode,
110
111
  };
@@ -1,5 +1,5 @@
1
1
  import React, {useState} from 'react';
2
- import {connect} from 'react-redux';
2
+ import {useDispatch} from 'react-redux';
3
3
  import {useLocation} from 'react-router';
4
4
  import {useHistory} from 'react-router-dom';
5
5
  import cn from 'bem-cn-lite';
@@ -19,7 +19,6 @@ import settingsIcon from '../../assets/icons/settings.svg';
19
19
  import supportIcon from '../../assets/icons/support.svg';
20
20
 
21
21
  import {logout} from '../../store/reducers/authentication/authentication';
22
- import {getParsedSettingValue, setSettingValue} from '../../store/reducers/settings/settings';
23
22
  import {TENANT_PAGE, TENANT_PAGES_IDS} from '../../store/reducers/tenant/constants';
24
23
  import routes, {TENANT, createHref, parseQuery} from '../../routes';
25
24
  import {useSetting, useTypedSelector} from '../../utils/hooks';
@@ -117,10 +116,6 @@ function YdbUserDropdown({isCompact, popupAnchor, ydbUser}: YdbUserDropdownProps
117
116
 
118
117
  interface AsideNavigationProps {
119
118
  children: React.ReactNode;
120
- ydbUser: string;
121
- compact: boolean;
122
- logout: VoidFunction;
123
- setSettingValue: (name: string, value: string) => void;
124
119
  }
125
120
 
126
121
  enum Panel {
@@ -189,15 +184,19 @@ export const useGetLeftNavigationItems = () => {
189
184
 
190
185
  function AsideNavigation(props: AsideNavigationProps) {
191
186
  const history = useHistory();
187
+ const dispatch = useDispatch();
192
188
 
193
189
  const [visiblePanel, setVisiblePanel] = useState<Panel>();
194
190
 
195
- const setIsCompact = (compact: boolean) => {
196
- props.setSettingValue(ASIDE_HEADER_COMPACT_KEY, JSON.stringify(compact));
197
- };
191
+ const {user: ydbUser} = useTypedSelector((state) => state.authentication);
192
+ const [compact, setIsCompact] = useSetting<boolean>(ASIDE_HEADER_COMPACT_KEY);
198
193
 
199
194
  const menuItems = useGetLeftNavigationItems();
200
195
 
196
+ const onLogout = () => {
197
+ dispatch(logout());
198
+ };
199
+
201
200
  return (
202
201
  <React.Fragment>
203
202
  <AsideHeader
@@ -207,7 +206,7 @@ function AsideNavigation(props: AsideNavigationProps) {
207
206
  onClick: () => history.push('/'),
208
207
  }}
209
208
  menuItems={menuItems}
210
- compact={props.compact}
209
+ compact={compact}
211
210
  onChangeCompact={setIsCompact}
212
211
  className={b()}
213
212
  renderContent={() => props.children}
@@ -248,8 +247,8 @@ function AsideNavigation(props: AsideNavigationProps) {
248
247
  isCompact={compact}
249
248
  popupAnchor={asideRef}
250
249
  ydbUser={{
251
- login: props.ydbUser,
252
- logout: props.logout,
250
+ login: ydbUser,
251
+ logout: onLogout,
253
252
  }}
254
253
  />
255
254
  </React.Fragment>
@@ -269,18 +268,4 @@ function AsideNavigation(props: AsideNavigationProps) {
269
268
  );
270
269
  }
271
270
 
272
- const mapStateToProps = (state: any) => {
273
- const {user: ydbUser} = state.authentication;
274
-
275
- return {
276
- ydbUser,
277
- compact: getParsedSettingValue(state, ASIDE_HEADER_COMPACT_KEY),
278
- };
279
- };
280
-
281
- const mapDispatchToProps = {
282
- logout,
283
- setSettingValue,
284
- };
285
-
286
- export default connect(mapStateToProps, mapDispatchToProps)(AsideNavigation);
271
+ export default AsideNavigation;
@@ -70,10 +70,7 @@ export const Partitions = ({path}: PartitionsProps) => {
70
70
  error: nodesError,
71
71
  } = useTypedSelector((state) => state.nodesList);
72
72
 
73
- const [hiddenColumns, setHiddenColumns] = useSetting<string[]>(
74
- PARTITIONS_HIDDEN_COLUMNS_KEY,
75
- [],
76
- );
73
+ const [hiddenColumns, setHiddenColumns] = useSetting<string[]>(PARTITIONS_HIDDEN_COLUMNS_KEY);
77
74
 
78
75
  const [columns, columnsIdsForSelector] = useGetPartitionsColumns(selectedConsumer);
79
76
 
@@ -17,7 +17,6 @@ import {
17
17
  setTenantPath,
18
18
  } from '../../../../store/reducers/executeQuery';
19
19
  import {getExplainQuery, getExplainQueryAst} from '../../../../store/reducers/explainQuery';
20
- import {getParsedSettingValue, setSettingValue} from '../../../../store/reducers/settings/settings';
21
20
  import {setShowPreview} from '../../../../store/reducers/schema/schema';
22
21
  import {
23
22
  DEFAULT_IS_QUERY_RESULT_COLLAPSED,
@@ -86,6 +85,7 @@ function QueryEditor(props) {
86
85
  const [queryMode, setQueryMode] = useQueryModes();
87
86
  const [useMultiSchema] = useSetting(QUERY_USE_MULTI_SCHEMA_KEY);
88
87
  const [lastUsedQueryAction, setLastUsedQueryAction] = useSetting(LAST_USED_QUERY_ACTION_KEY);
88
+ const [savedQueries, setSavedQueries] = useSetting(SAVED_QUERIES_KEY);
89
89
 
90
90
  useEffect(() => {
91
91
  if (savedPath !== path) {
@@ -417,7 +417,7 @@ function QueryEditor(props) {
417
417
 
418
418
  const storageEventHandler = (event) => {
419
419
  if (event.key === SAVED_QUERIES_KEY) {
420
- props.setSettingValue(SAVED_QUERIES_KEY, event.newValue);
420
+ setSavedQueries(event.newValue);
421
421
  }
422
422
  };
423
423
 
@@ -430,8 +430,6 @@ function QueryEditor(props) {
430
430
  const onSaveQueryHandler = (queryName) => {
431
431
  const {
432
432
  executeQuery: {input},
433
- savedQueries = [],
434
- setSettingValue,
435
433
  } = props;
436
434
 
437
435
  const queryIndex = savedQueries.findIndex(
@@ -445,11 +443,11 @@ function QueryEditor(props) {
445
443
  newSavedQueries.push(newQuery);
446
444
  }
447
445
 
448
- setSettingValue(SAVED_QUERIES_KEY, JSON.stringify(newSavedQueries));
446
+ setSavedQueries(newSavedQueries);
449
447
  };
450
448
 
451
449
  const renderControls = () => {
452
- const {executeQuery, explainQuery, savedQueries} = props;
450
+ const {executeQuery, explainQuery} = props;
453
451
 
454
452
  return (
455
453
  <QueryEditorControls
@@ -511,7 +509,6 @@ const mapStateToProps = (state) => {
511
509
  return {
512
510
  executeQuery: state.executeQuery,
513
511
  explainQuery: state.explainQuery,
514
- savedQueries: getParsedSettingValue(state, SAVED_QUERIES_KEY),
515
512
  showPreview: state.schema.showPreview,
516
513
  currentSchema: state.schema.currentSchema,
517
514
  monacoHotKey: state.executeQuery?.monacoHotKey,
@@ -525,7 +522,6 @@ const mapDispatchToProps = {
525
522
  goToNextQuery,
526
523
  getExplainQuery,
527
524
  getExplainQueryAst,
528
- setSettingValue,
529
525
  setShowPreview,
530
526
  setMonacoHotKey,
531
527
  setTenantPath,
@@ -34,7 +34,6 @@ import type {StorageApiRequestParams} from '../store/reducers/storage/types';
34
34
 
35
35
  import {backend as BACKEND} from '../store';
36
36
  import {prepareSortValue} from '../utils/filters';
37
- import {settingsApi} from '../utils/settings';
38
37
 
39
38
  const config = {withCredentials: !window.custom_backend};
40
39
 
@@ -378,10 +377,12 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
378
377
  path_id: tenantId?.PathId,
379
378
  });
380
379
  }
381
- postSetting(name: string, value: string) {
380
+
381
+ /** @deprecated use localStorage instead */
382
+ postSetting(settingsApi: string, name: string, value: string) {
382
383
  return this.request({
383
384
  method: 'PATCH',
384
- url: settingsApi || '',
385
+ url: settingsApi,
385
386
  data: {[name]: value},
386
387
  });
387
388
  }
@@ -0,0 +1,109 @@
1
+ import {TENANT_PAGES_IDS} from '../store/reducers/tenant/constants';
2
+
3
+ import {
4
+ ASIDE_HEADER_COMPACT_KEY,
5
+ CLUSTER_INFO_HIDDEN_KEY,
6
+ INVERTED_DISKS_KEY,
7
+ LANGUAGE_KEY,
8
+ LAST_USED_QUERY_ACTION_KEY,
9
+ PARTITIONS_HIDDEN_COLUMNS_KEY,
10
+ QUERY_INITIAL_MODE_KEY,
11
+ QUERY_USE_MULTI_SCHEMA_KEY,
12
+ SAVED_QUERIES_KEY,
13
+ TENANT_INITIAL_PAGE_KEY,
14
+ THEME_KEY,
15
+ USE_BACKEND_PARAMS_FOR_TABLES_KEY,
16
+ USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
17
+ } from '../utils/constants';
18
+ import {QUERY_ACTIONS, QUERY_MODES} from '../utils/query';
19
+ import {parseJson} from '../utils/utils';
20
+
21
+ export type SettingsObject = Record<string, unknown>;
22
+
23
+ const USE_LOCAL_STORAGE_FOR_SETTINGS_KEY = 'useLocalStorageForSettings';
24
+
25
+ /** User settings keys and their default values */
26
+ export const DEFAULT_USER_SETTINGS: SettingsObject = {
27
+ [THEME_KEY]: 'system',
28
+ [LANGUAGE_KEY]: undefined,
29
+ [INVERTED_DISKS_KEY]: false,
30
+ [USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY]: false,
31
+ [QUERY_USE_MULTI_SCHEMA_KEY]: false,
32
+ [SAVED_QUERIES_KEY]: [],
33
+ [TENANT_INITIAL_PAGE_KEY]: TENANT_PAGES_IDS.query,
34
+ [QUERY_INITIAL_MODE_KEY]: QUERY_MODES.script,
35
+ [LAST_USED_QUERY_ACTION_KEY]: QUERY_ACTIONS.execute,
36
+ [ASIDE_HEADER_COMPACT_KEY]: true,
37
+ [PARTITIONS_HIDDEN_COLUMNS_KEY]: [],
38
+ [CLUSTER_INFO_HIDDEN_KEY]: true,
39
+ [USE_BACKEND_PARAMS_FOR_TABLES_KEY]: false,
40
+ };
41
+
42
+ class SettingsManager {
43
+ constructor() {
44
+ // Migrate settings to LS if external API was used before
45
+ const settingsApi = window.web_version ? window.systemSettings?.settingsApi : undefined;
46
+
47
+ const useLocalStorage = this.readUserSettingsValue(USE_LOCAL_STORAGE_FOR_SETTINGS_KEY);
48
+
49
+ if (settingsApi && !useLocalStorage) {
50
+ const externalUserSettings = window.userSettings;
51
+
52
+ if (externalUserSettings) {
53
+ Object.entries(externalUserSettings).forEach(([key, value]) =>
54
+ this.setUserSettingsValue(key, value),
55
+ );
56
+ }
57
+
58
+ this.setUserSettingsValue(USE_LOCAL_STORAGE_FOR_SETTINGS_KEY, true);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Returns parsed settings value.
64
+ * If value cannot be parsed, returns initially stored string.
65
+ * If there is no value, return default value
66
+ */
67
+ readUserSettingsValue(key: string, defaultValue?: unknown) {
68
+ return this.readValueFromLS(key) ?? defaultValue;
69
+ }
70
+
71
+ /**
72
+ * Stringify value and set it to LS
73
+ */
74
+ setUserSettingsValue(key: string, value: unknown) {
75
+ return this.setValueToLS(key, value);
76
+ }
77
+
78
+ /**
79
+ * Extract values by provided settings object
80
+ */
81
+ extractSettingsFromLS = (settings: SettingsObject) => {
82
+ return Object.entries(settings).reduce<SettingsObject>((acc, [key, value]) => {
83
+ acc[key] = this.readUserSettingsValue(key, value);
84
+ return acc;
85
+ }, {});
86
+ };
87
+
88
+ private readValueFromLS = (key: string): unknown => {
89
+ try {
90
+ const value = localStorage.getItem(key);
91
+
92
+ return parseJson(value);
93
+ } catch {
94
+ return undefined;
95
+ }
96
+ };
97
+
98
+ private setValueToLS = (key: string, value: unknown): void => {
99
+ try {
100
+ if (typeof value === 'string') {
101
+ localStorage.setItem(key, value);
102
+ } else {
103
+ localStorage.setItem(key, JSON.stringify(value));
104
+ }
105
+ } catch {}
106
+ };
107
+ }
108
+
109
+ export const settingsManager = new SettingsManager();
@@ -9,10 +9,10 @@ import type {
9
9
  QueryInHistory,
10
10
  } from '../../types/store/executeQuery';
11
11
  import type {QueryRequestParams, QueryMode, QuerySyntax} from '../../types/store/query';
12
- import {getValueFromLS, parseJson} from '../../utils/utils';
13
12
  import {QUERIES_HISTORY_KEY} from '../../utils/constants';
14
13
  import {QUERY_MODES, QUERY_SYNTAX, parseQueryAPIExecuteResponse} from '../../utils/query';
15
14
  import {parseQueryError} from '../../utils/error';
15
+ import {settingsManager} from '../../services/settings';
16
16
  import '../../services/api';
17
17
 
18
18
  import {createRequestActionTypes, createApiRequest} from '../utils';
@@ -28,7 +28,10 @@ const GO_TO_NEXT_QUERY = 'query/GO_TO_NEXT_QUERY';
28
28
  const SET_MONACO_HOT_KEY = 'query/SET_MONACO_HOT_KEY';
29
29
  const SET_TENANT_PATH = 'query/SET_TENANT_PATH';
30
30
 
31
- const queriesHistoryInitial: string[] = parseJson(getValueFromLS(QUERIES_HISTORY_KEY, '[]'));
31
+ const queriesHistoryInitial = settingsManager.readUserSettingsValue(
32
+ QUERIES_HISTORY_KEY,
33
+ [],
34
+ ) as string[];
32
35
 
33
36
  const sliceLimit = queriesHistoryInitial.length - MAXIMUM_QUERIES_IN_HISTORY;
34
37
 
@@ -97,7 +100,7 @@ const executeQuery: Reducer<ExecuteQueryState, ExecuteQueryAction> = (
97
100
  const newQueries = [...state.history.queries, {queryText, syntax}].slice(
98
101
  state.history.queries.length >= MAXIMUM_QUERIES_IN_HISTORY ? 1 : 0,
99
102
  );
100
- window.localStorage.setItem(QUERIES_HISTORY_KEY, JSON.stringify(newQueries));
103
+ settingsManager.setUserSettingsValue(QUERIES_HISTORY_KEY, newQueries);
101
104
  const currentIndex = newQueries.length - 1;
102
105
 
103
106
  return {
@@ -1,32 +1,8 @@
1
1
  import type {Reducer} from 'redux';
2
2
  import type {ThunkAction} from 'redux-thunk';
3
3
 
4
- import {
5
- SAVED_QUERIES_KEY,
6
- THEME_KEY,
7
- TENANT_INITIAL_PAGE_KEY,
8
- INVERTED_DISKS_KEY,
9
- ASIDE_HEADER_COMPACT_KEY,
10
- USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
11
- PARTITIONS_HIDDEN_COLUMNS_KEY,
12
- QUERY_INITIAL_MODE_KEY,
13
- CLUSTER_INFO_HIDDEN_KEY,
14
- LAST_USED_QUERY_ACTION_KEY,
15
- USE_BACKEND_PARAMS_FOR_TABLES_KEY,
16
- LANGUAGE_KEY,
17
- QUERY_USE_MULTI_SCHEMA_KEY,
18
- } from '../../../utils/constants';
19
4
  import '../../../services/api';
20
- import {parseJson} from '../../../utils/utils';
21
- import {QUERY_ACTIONS, QUERY_MODES} from '../../../utils/query';
22
- import {
23
- readSavedSettingsValue,
24
- settingsApi,
25
- systemSettings,
26
- userSettings,
27
- } from '../../../utils/settings';
28
-
29
- import {TENANT_PAGES_IDS} from '../tenant/constants';
5
+ import {DEFAULT_USER_SETTINGS, SettingsObject, settingsManager} from '../../../services/settings';
30
6
 
31
7
  import type {RootState} from '..';
32
8
  import type {
@@ -39,45 +15,19 @@ import type {
39
15
 
40
16
  const CHANGE_PROBLEM_FILTER = 'settings/CHANGE_PROBLEM_FILTER';
41
17
  export const SET_SETTING_VALUE = 'settings/SET_VALUE';
18
+ export const SET_USER_SETTINGS = 'settings/SET_USER_SETTINGS';
42
19
 
43
20
  export const ProblemFilterValues = {
44
21
  ALL: 'All',
45
22
  PROBLEMS: 'With problems',
46
23
  } as const;
47
24
 
25
+ const userSettings = settingsManager.extractSettingsFromLS(DEFAULT_USER_SETTINGS);
26
+ const systemSettings = window.systemSettings || {};
27
+
48
28
  export const initialState = {
49
29
  problemFilter: ProblemFilterValues.ALL,
50
- userSettings: {
51
- ...userSettings,
52
- [THEME_KEY]: readSavedSettingsValue(THEME_KEY, 'system'),
53
- [LANGUAGE_KEY]: readSavedSettingsValue(LANGUAGE_KEY),
54
- [INVERTED_DISKS_KEY]: readSavedSettingsValue(INVERTED_DISKS_KEY, 'false'),
55
- [USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY]: readSavedSettingsValue(
56
- USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
57
- 'false',
58
- ),
59
- [QUERY_USE_MULTI_SCHEMA_KEY]: readSavedSettingsValue(QUERY_USE_MULTI_SCHEMA_KEY, 'false'),
60
- [SAVED_QUERIES_KEY]: readSavedSettingsValue(SAVED_QUERIES_KEY, '[]'),
61
- [TENANT_INITIAL_PAGE_KEY]: readSavedSettingsValue(
62
- TENANT_INITIAL_PAGE_KEY,
63
- TENANT_PAGES_IDS.query,
64
- ),
65
- [QUERY_INITIAL_MODE_KEY]: readSavedSettingsValue(
66
- QUERY_INITIAL_MODE_KEY,
67
- QUERY_MODES.script,
68
- ),
69
- [LAST_USED_QUERY_ACTION_KEY]: readSavedSettingsValue(
70
- LAST_USED_QUERY_ACTION_KEY,
71
- QUERY_ACTIONS.execute,
72
- ),
73
- [ASIDE_HEADER_COMPACT_KEY]: readSavedSettingsValue(ASIDE_HEADER_COMPACT_KEY, 'true'),
74
- [PARTITIONS_HIDDEN_COLUMNS_KEY]: readSavedSettingsValue(PARTITIONS_HIDDEN_COLUMNS_KEY),
75
- [CLUSTER_INFO_HIDDEN_KEY]: readSavedSettingsValue(CLUSTER_INFO_HIDDEN_KEY, 'true'),
76
- [USE_BACKEND_PARAMS_FOR_TABLES_KEY]: readSavedSettingsValue(
77
- USE_BACKEND_PARAMS_FOR_TABLES_KEY,
78
- 'false',
79
- ),
80
- },
30
+ userSettings,
81
31
  systemSettings,
82
32
  };
83
33
 
@@ -100,7 +50,15 @@ const settings: Reducer<SettingsState, SettingsAction> = (state = initialState,
100
50
  userSettings: newSettings,
101
51
  };
102
52
  }
103
-
53
+ case SET_USER_SETTINGS: {
54
+ return {
55
+ ...state,
56
+ userSettings: {
57
+ ...state.userSettings,
58
+ ...action.data,
59
+ },
60
+ };
61
+ }
104
62
  default:
105
63
  return state;
106
64
  }
@@ -108,33 +66,21 @@ const settings: Reducer<SettingsState, SettingsAction> = (state = initialState,
108
66
 
109
67
  export const setSettingValue = (
110
68
  name: string,
111
- value: string,
69
+ value: unknown,
112
70
  ): ThunkAction<void, RootState, unknown, SetSettingValueAction> => {
113
71
  return (dispatch) => {
114
72
  dispatch({type: SET_SETTING_VALUE, data: {name, value}});
115
73
 
116
- // If there is no settingsApi, use localStorage
117
- if (settingsApi) {
118
- window.api.postSetting(name, value);
119
- } else {
120
- try {
121
- localStorage.setItem(name, value);
122
- } catch {}
123
- }
74
+ settingsManager.setUserSettingsValue(name, value);
124
75
  };
125
76
  };
126
77
 
127
- export const getSettingValue = (state: SettingsRootStateSlice, name: string) => {
128
- return state.settings.userSettings[name];
78
+ export const setUserSettings = (data: SettingsObject) => {
79
+ return {type: SET_USER_SETTINGS, data} as const;
129
80
  };
130
81
 
131
- /**
132
- * Returns parsed settings value.
133
- * If value cannot be parsed, returns initially stored string
134
- */
135
- export const getParsedSettingValue = (state: SettingsRootStateSlice, name: string) => {
136
- const value = state.settings.userSettings[name];
137
- return parseJson(value);
82
+ export const getSettingValue = (state: SettingsRootStateSlice, name: string) => {
83
+ return state.settings.userSettings[name];
138
84
  };
139
85
 
140
86
  export const changeFilter = (filter: ProblemFilterValue) => {
@@ -1,20 +1,24 @@
1
1
  import type {ValueOf} from '../../../types/common';
2
- import {changeFilter, ProblemFilterValues, SET_SETTING_VALUE} from './settings';
2
+ import type {SettingsObject} from '../../../services/settings';
3
+ import {changeFilter, setUserSettings, ProblemFilterValues, SET_SETTING_VALUE} from './settings';
3
4
 
4
5
  export type ProblemFilterValue = ValueOf<typeof ProblemFilterValues>;
5
6
 
6
7
  export interface SettingsState {
7
8
  problemFilter: ProblemFilterValue;
8
- userSettings: Record<string, string | undefined>;
9
- systemSettings: Record<string, string | undefined>;
9
+ userSettings: SettingsObject;
10
+ systemSettings: SettingsObject;
10
11
  }
11
12
 
12
13
  export type SetSettingValueAction = {
13
14
  type: typeof SET_SETTING_VALUE;
14
- data: {name: string; value: string};
15
+ data: {name: string; value: unknown};
15
16
  };
16
17
 
17
- export type SettingsAction = ReturnType<typeof changeFilter> | SetSettingValueAction;
18
+ export type SettingsAction =
19
+ | ReturnType<typeof changeFilter>
20
+ | ReturnType<typeof setUserSettings>
21
+ | SetSettingValueAction;
18
22
 
19
23
  export interface SettingsRootStateSlice {
20
24
  settings: SettingsState;
@@ -39,8 +39,8 @@ interface Window {
39
39
  __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof import('redux').compose;
40
40
  store?: import('redux').Store;
41
41
 
42
- userSettings?: Record<string, string | undefined>;
43
- systemSettings?: Record<string, string | undefined>;
42
+ userSettings?: import('../services/settings').SettingsObject;
43
+ systemSettings?: import('../services/settings').SettingsObject;
44
44
 
45
45
  api: import('../services/api').YdbEmbeddedAPI;
46
46
  }
@@ -1,22 +1,21 @@
1
1
  import {useCallback} from 'react';
2
2
  import {useDispatch} from 'react-redux';
3
3
 
4
- import {getParsedSettingValue, setSettingValue} from '../../store/reducers/settings/settings';
4
+ import {getSettingValue, setSettingValue} from '../../store/reducers/settings/settings';
5
5
 
6
6
  import {useTypedSelector} from './useTypedSelector';
7
7
 
8
8
  export const useSetting = <T>(key: string, defaultValue?: T): [T, (value: T) => void] => {
9
9
  const dispatch = useDispatch();
10
10
 
11
- const settingValue: T = useTypedSelector(
12
- (state) => getParsedSettingValue(state, key) ?? defaultValue,
13
- );
11
+ const settingValue = useTypedSelector((state) => {
12
+ // Since we type setter value as T, we assume that received value is also T
13
+ return (getSettingValue(state, key) ?? defaultValue) as T;
14
+ });
14
15
 
15
16
  const setValue = useCallback(
16
17
  (value: T) => {
17
- const preparedValue = typeof value === 'string' ? value : JSON.stringify(value);
18
-
19
- dispatch(setSettingValue(key, preparedValue));
18
+ dispatch(setSettingValue(key, value));
20
19
  },
21
20
  [dispatch, key],
22
21
  );
@@ -3,7 +3,7 @@ import {configure as configureUiKit} from '@gravity-ui/uikit';
3
3
  import {configure as configureYdbUiComponents} from 'ydb-ui-components';
4
4
 
5
5
  import {LANGUAGE_KEY} from '../constants';
6
- import {readSavedSettingsValue} from '../settings';
6
+ import {settingsManager} from '../../services/settings';
7
7
 
8
8
  enum Lang {
9
9
  En = 'en',
@@ -11,7 +11,7 @@ enum Lang {
11
11
  }
12
12
 
13
13
  const defaultLang = Lang.En;
14
- const currentLang = readSavedSettingsValue(LANGUAGE_KEY, defaultLang);
14
+ const currentLang = settingsManager.readUserSettingsValue(LANGUAGE_KEY, defaultLang) as Lang;
15
15
 
16
16
  const i18n = new I18N();
17
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.26.0",
3
+ "version": "4.27.1",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -1,13 +0,0 @@
1
- import {getValueFromLS} from './utils';
2
-
3
- export const userSettings = window.userSettings || {};
4
- export const systemSettings = window.systemSettings || {};
5
-
6
- export const settingsApi = window.web_version ? systemSettings.settingsApi : undefined;
7
-
8
- export function readSavedSettingsValue(key: string, defaultValue?: string) {
9
- // If there is no settingsApi, use localStorage
10
- const savedValue = settingsApi ? userSettings[key] : getValueFromLS(key);
11
-
12
- return savedValue ?? defaultValue;
13
- }