ydb-embedded-ui 3.4.5 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/components/InfoViewer/formatters/table.ts +6 -0
  3. package/dist/components/TruncatedQuery/TruncatedQuery.js +1 -1
  4. package/dist/components/TruncatedQuery/TruncatedQuery.scss +7 -3
  5. package/dist/containers/Node/{NodePages.js → NodePages.ts} +1 -1
  6. package/dist/containers/Tablet/TabletControls/TabletControls.tsx +2 -2
  7. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +11 -43
  8. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.tsx +19 -17
  9. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +192 -37
  10. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +20 -14
  11. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +49 -12
  12. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +37 -18
  13. package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.tsx +3 -3
  14. package/dist/containers/Tenant/QueryEditor/QueryDuration/QueryDuration.scss +8 -0
  15. package/dist/containers/Tenant/QueryEditor/QueryDuration/QueryDuration.tsx +21 -0
  16. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +58 -82
  17. package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +0 -33
  18. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/OldQueryEditorControls.tsx +83 -0
  19. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.scss +57 -0
  20. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/QueryEditorControls.tsx +84 -0
  21. package/dist/containers/Tenant/QueryEditor/QueryEditorControls/shared.ts +23 -0
  22. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +12 -23
  23. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.js +4 -6
  24. package/dist/containers/Tenant/QueryEditor/i18n/en.json +3 -0
  25. package/dist/containers/Tenant/QueryEditor/i18n/index.ts +11 -0
  26. package/dist/containers/Tenant/QueryEditor/i18n/ru.json +3 -0
  27. package/dist/containers/UserSettings/UserSettings.tsx +30 -1
  28. package/dist/routes.ts +1 -1
  29. package/dist/services/api.d.ts +4 -3
  30. package/dist/services/api.js +5 -5
  31. package/dist/store/reducers/{executeQuery.js → executeQuery.ts} +48 -43
  32. package/dist/store/reducers/executeTopQueries.ts +5 -1
  33. package/dist/store/reducers/{explainQuery.js → explainQuery.ts} +44 -59
  34. package/dist/store/reducers/{olapStats.js → olapStats.ts} +8 -18
  35. package/dist/store/reducers/settings.js +19 -4
  36. package/dist/store/reducers/storage.js +5 -7
  37. package/dist/types/api/error.ts +14 -0
  38. package/dist/types/api/query.ts +227 -115
  39. package/dist/types/api/schema.ts +523 -3
  40. package/dist/types/common.ts +1 -0
  41. package/dist/types/store/executeQuery.ts +38 -0
  42. package/dist/types/store/explainQuery.ts +38 -0
  43. package/dist/types/store/olapStats.ts +14 -0
  44. package/dist/types/store/query.ts +23 -3
  45. package/dist/utils/constants.ts +2 -1
  46. package/dist/utils/error.ts +25 -0
  47. package/dist/utils/index.js +0 -49
  48. package/dist/utils/prepareQueryExplain.ts +7 -24
  49. package/dist/utils/query.test.ts +148 -213
  50. package/dist/utils/query.ts +68 -90
  51. package/dist/utils/timeParsers/formatDuration.ts +30 -12
  52. package/dist/utils/timeParsers/i18n/en.json +9 -5
  53. package/dist/utils/timeParsers/i18n/ru.json +9 -5
  54. package/dist/utils/timeParsers/parsers.ts +9 -0
  55. package/dist/utils/utils.js +1 -2
  56. package/package.json +1 -1
@@ -1,35 +1,40 @@
1
- import {createRequestActionTypes, createApiRequest} from '../utils';
2
- import '../../services/api';
1
+ import type {Reducer} from 'redux';
2
+
3
+ import type {ExecuteActions} from '../../types/api/query';
4
+ import type {
5
+ ExecuteQueryAction,
6
+ ExecuteQueryState,
7
+ MonacoHotKeyAction,
8
+ } from '../../types/store/executeQuery';
9
+ import type {QueryRequestParams, QueryModes} from '../../types/store/query';
3
10
  import {getValueFromLS, parseJson} from '../../utils/utils';
4
- import {QUERIES_HISTORY_KEY, QUERY_INITIAL_RUN_ACTION_KEY} from '../../utils/constants';
11
+ import {QUERIES_HISTORY_KEY} from '../../utils/constants';
5
12
  import {parseQueryAPIExecuteResponse} from '../../utils/query';
6
- import {readSavedSettingsValue} from './settings';
13
+ import {parseQueryError} from '../../utils/error';
14
+ import '../../services/api';
15
+
16
+ import {createRequestActionTypes, createApiRequest} from '../utils';
7
17
 
8
18
  const MAXIMUM_QUERIES_IN_HISTORY = 20;
9
19
 
10
- const SEND_QUERY = createRequestActionTypes('query', 'SEND_QUERY');
20
+ export const SEND_QUERY = createRequestActionTypes('query', 'SEND_QUERY');
21
+
11
22
  const CHANGE_USER_INPUT = 'query/CHANGE_USER_INPUT';
12
23
  const SAVE_QUERY_TO_HISTORY = 'query/SAVE_QUERY_TO_HISTORY';
13
24
  const GO_TO_PREVIOUS_QUERY = 'query/GO_TO_PREVIOUS_QUERY';
14
25
  const GO_TO_NEXT_QUERY = 'query/GO_TO_NEXT_QUERY';
15
- const SELECT_RUN_ACTION = 'query/SELECT_RUN_ACTION';
16
26
  const MONACO_HOT_KEY = 'query/MONACO_HOT_KEY';
17
27
 
18
- const queriesHistoryInitial = parseJson(getValueFromLS(QUERIES_HISTORY_KEY, '[]'));
28
+ const queriesHistoryInitial: string[] = parseJson(getValueFromLS(QUERIES_HISTORY_KEY, '[]'));
19
29
 
20
30
  const sliceLimit = queriesHistoryInitial.length - MAXIMUM_QUERIES_IN_HISTORY;
21
31
 
22
- export const RUN_ACTIONS_VALUES = {
23
- script: 'execute-script',
24
- scan: 'execute-scan',
25
- };
26
-
27
32
  export const MONACO_HOT_KEY_ACTIONS = {
28
33
  sendQuery: 'sendQuery',
29
34
  goPrev: 'goPrev',
30
35
  goNext: 'goNext',
31
36
  getExplain: 'getExplain',
32
- };
37
+ } as const;
33
38
 
34
39
  const initialState = {
35
40
  loading: false,
@@ -41,11 +46,13 @@ const initialState = {
41
46
  ? MAXIMUM_QUERIES_IN_HISTORY - 1
42
47
  : queriesHistoryInitial.length - 1,
43
48
  },
44
- runAction: readSavedSettingsValue(QUERY_INITIAL_RUN_ACTION_KEY, RUN_ACTIONS_VALUES.script),
45
49
  monacoHotKey: null,
46
50
  };
47
51
 
48
- const executeQuery = (state = initialState, action) => {
52
+ const executeQuery: Reducer<ExecuteQueryState, ExecuteQueryAction> = (
53
+ state = initialState,
54
+ action,
55
+ ) => {
49
56
  switch (action.type) {
50
57
  case SEND_QUERY.REQUEST: {
51
58
  return {
@@ -64,22 +71,14 @@ const executeQuery = (state = initialState, action) => {
64
71
  error: undefined,
65
72
  };
66
73
  }
67
- // 401 Unauthorized error is handled by GenericAPI
68
74
  case SEND_QUERY.FAILURE: {
69
75
  return {
70
76
  ...state,
71
- error: action.error || 'Unauthorized',
77
+ error: parseQueryError(action.error),
72
78
  loading: false,
73
79
  };
74
80
  }
75
81
 
76
- case SELECT_RUN_ACTION: {
77
- return {
78
- ...state,
79
- runAction: action.data,
80
- };
81
- }
82
-
83
82
  case CHANGE_USER_INPUT: {
84
83
  return {
85
84
  ...state,
@@ -141,51 +140,57 @@ const executeQuery = (state = initialState, action) => {
141
140
  }
142
141
  };
143
142
 
144
- export const sendQuery = ({query, database, action}) => {
143
+ interface SendQueryParams extends QueryRequestParams {
144
+ mode?: QueryModes;
145
+ }
146
+
147
+ export const sendExecuteQuery = ({query, database, mode}: SendQueryParams) => {
148
+ const action: ExecuteActions = mode ? `execute-${mode}` : 'execute';
149
+
145
150
  return createApiRequest({
146
- request: window.api.sendQuery({schema: 'modern', query, database, action, stats: 'profile'}),
151
+ request: window.api.sendQuery({
152
+ schema: 'modern',
153
+ query,
154
+ database,
155
+ action,
156
+ stats: 'profile',
157
+ }),
147
158
  actions: SEND_QUERY,
148
159
  dataHandler: parseQueryAPIExecuteResponse,
149
160
  });
150
161
  };
151
162
 
152
- export const saveQueryToHistory = (query) => {
163
+ export const saveQueryToHistory = (query: string) => {
153
164
  return {
154
165
  type: SAVE_QUERY_TO_HISTORY,
155
166
  data: query,
156
- };
157
- };
158
-
159
- export const selectRunAction = (value) => {
160
- return {
161
- type: SELECT_RUN_ACTION,
162
- data: value,
163
- };
167
+ } as const;
164
168
  };
165
169
 
166
170
  export const goToPreviousQuery = () => {
167
171
  return {
168
172
  type: GO_TO_PREVIOUS_QUERY,
169
- };
173
+ } as const;
170
174
  };
171
175
 
172
176
  export const goToNextQuery = () => {
173
177
  return {
174
178
  type: GO_TO_NEXT_QUERY,
175
- };
179
+ } as const;
176
180
  };
177
181
 
178
- export const changeUserInput = ({input}) => {
179
- return (dispatch) => {
180
- dispatch({type: CHANGE_USER_INPUT, data: {input}});
181
- };
182
+ export const changeUserInput = ({input}: {input: string}) => {
183
+ return {
184
+ type: CHANGE_USER_INPUT,
185
+ data: {input},
186
+ } as const;
182
187
  };
183
188
 
184
- export const setMonacoHotKey = (value) => {
189
+ export const setMonacoHotKey = (value: MonacoHotKeyAction) => {
185
190
  return {
186
191
  type: MONACO_HOT_KEY,
187
192
  data: value,
188
- };
193
+ } as const;
189
194
  };
190
195
 
191
196
  export default executeQuery;
@@ -66,7 +66,11 @@ const getQueryText = (path: string, filters?: ITopQueriesFilters) => {
66
66
  SELECT
67
67
  CPUTime as CPUTimeUs,
68
68
  QueryText,
69
- IntervalEnd
69
+ IntervalEnd,
70
+ EndTime,
71
+ ReadRows,
72
+ ReadBytes,
73
+ UserSID
70
74
  FROM \`${path}/.sys/top_queries_by_cpu_time_one_hour\`
71
75
  WHERE ${filterConditions || 'true'}
72
76
  `;
@@ -1,21 +1,33 @@
1
+ import type {Reducer} from 'redux';
2
+ import type {ExplainPlanNodeData, GraphNode, Link} from '@gravity-ui/paranoid';
1
3
  import _ from 'lodash';
2
4
 
3
5
  import '../../services/api';
6
+ import type {ExplainActions} from '../../types/api/query';
7
+ import type {
8
+ ExplainQueryAction,
9
+ ExplainQueryState,
10
+ PreparedExplainResponse,
11
+ } from '../../types/store/explainQuery';
12
+ import type {QueryRequestParams, QueryModes} from '../../types/store/query';
4
13
 
5
- import {getExplainNodeId, getMetaForExplainNode} from '../../utils';
6
14
  import {preparePlan} from '../../utils/prepareQueryExplain';
7
- import {parseQueryAPIExplainResponse} from '../../utils/query';
15
+ import {parseQueryAPIExplainResponse, parseQueryExplainPlan} from '../../utils/query';
16
+ import {parseQueryError} from '../../utils/error';
8
17
 
9
18
  import {createRequestActionTypes, createApiRequest} from '../utils';
10
19
 
11
- const GET_EXPLAIN_QUERY = createRequestActionTypes('query', 'GET_EXPLAIN_QUERY');
12
- const GET_EXPLAIN_QUERY_AST = createRequestActionTypes('query', 'GET_EXPLAIN_QUERY_AST');
20
+ export const GET_EXPLAIN_QUERY = createRequestActionTypes('query', 'GET_EXPLAIN_QUERY');
21
+ export const GET_EXPLAIN_QUERY_AST = createRequestActionTypes('query', 'GET_EXPLAIN_QUERY_AST');
13
22
 
14
23
  const initialState = {
15
24
  loading: false,
16
25
  };
17
26
 
18
- const explainQuery = (state = initialState, action) => {
27
+ const explainQuery: Reducer<ExplainQueryState, ExplainQueryAction> = (
28
+ state = initialState,
29
+ action,
30
+ ) => {
19
31
  switch (action.type) {
20
32
  case GET_EXPLAIN_QUERY.REQUEST: {
21
33
  return {
@@ -36,11 +48,10 @@ const explainQuery = (state = initialState, action) => {
36
48
  error: undefined,
37
49
  };
38
50
  }
39
- // 401 Unauthorized error is handled by GenericAPI
40
51
  case GET_EXPLAIN_QUERY.FAILURE: {
41
52
  return {
42
53
  ...state,
43
- error: action.error || 'Unauthorized',
54
+ error: parseQueryError(action.error),
44
55
  loading: false,
45
56
  };
46
57
  }
@@ -63,7 +74,7 @@ const explainQuery = (state = initialState, action) => {
63
74
  case GET_EXPLAIN_QUERY_AST.FAILURE: {
64
75
  return {
65
76
  ...state,
66
- errorAst: action.error || 'Unauthorized',
77
+ errorAst: parseQueryError(action.error),
67
78
  loadingAst: false,
68
79
  };
69
80
  }
@@ -73,7 +84,7 @@ const explainQuery = (state = initialState, action) => {
73
84
  }
74
85
  };
75
86
 
76
- export const getExplainQueryAst = ({query, database}) => {
87
+ export const getExplainQueryAst = ({query, database}: QueryRequestParams) => {
77
88
  return createApiRequest({
78
89
  request: window.api.getExplainQueryAst(query, database),
79
90
  actions: GET_EXPLAIN_QUERY_AST,
@@ -82,74 +93,48 @@ export const getExplainQueryAst = ({query, database}) => {
82
93
  };
83
94
 
84
95
  export const explainVersions = {
85
- v1: '0.1',
86
96
  v2: '0.2',
87
97
  };
88
98
 
89
99
  const supportedExplainQueryVersions = Object.values(explainVersions);
90
100
 
91
- export const getExplainQuery = ({query, database}) => {
101
+ interface ExplainQueryParams extends QueryRequestParams {
102
+ mode?: QueryModes;
103
+ }
104
+
105
+ export const getExplainQuery = ({query, database, mode}: ExplainQueryParams) => {
106
+ const action: ExplainActions = mode ? `explain-${mode}` : 'explain';
107
+
92
108
  return createApiRequest({
93
- request: window.api.getExplainQuery(query, database),
109
+ request: window.api.getExplainQuery(query, database, action),
94
110
  actions: GET_EXPLAIN_QUERY,
95
- dataHandler: (response) => {
96
- const {plan: result, ast} = parseQueryAPIExplainResponse(response);
111
+ dataHandler: (response): PreparedExplainResponse => {
112
+ const {plan: rawPlan, ast} = parseQueryAPIExplainResponse(response);
97
113
 
98
- if (!result) {
114
+ if (!rawPlan) {
99
115
  return {ast};
100
116
  }
101
117
 
102
- let links = [];
103
- let nodes = [];
104
- const {tables, meta, Plan} = result;
118
+ const {tables, meta, Plan} = parseQueryExplainPlan(rawPlan);
105
119
 
106
120
  if (supportedExplainQueryVersions.indexOf(meta.version) === -1) {
121
+ // Do not prepare plan for not supported versions
107
122
  return {
108
- pristine: result,
109
- version: meta.version,
123
+ plan: {
124
+ pristine: rawPlan,
125
+ version: meta.version,
126
+ },
127
+ ast,
110
128
  };
111
129
  }
112
- if (meta.version === explainVersions.v2) {
130
+
131
+ let links: Link[] = [];
132
+ let nodes: GraphNode<ExplainPlanNodeData>[] = [];
133
+
134
+ if (Plan) {
113
135
  const preparedPlan = preparePlan(Plan);
114
136
  links = preparedPlan.links;
115
137
  nodes = preparedPlan.nodes;
116
- } else {
117
- _.forEach(tables, (table) => {
118
- nodes.push({
119
- name: table.name,
120
- });
121
-
122
- const tableTypes = {};
123
-
124
- const {reads = [], writes = []} = table;
125
- let prevNodeId = table.name;
126
-
127
- _.forEach([...reads, ...writes], (node) => {
128
- if (tableTypes[node.type]) {
129
- tableTypes[node.type] = tableTypes[node.type] + 1;
130
- } else {
131
- tableTypes[node.type] = 1;
132
- }
133
-
134
- const nodeId = getExplainNodeId(
135
- table.name,
136
- node.type,
137
- tableTypes[node.type],
138
- );
139
-
140
- links.push({
141
- from: prevNodeId,
142
- to: nodeId,
143
- });
144
- nodes.push({
145
- name: nodeId,
146
- meta: getMetaForExplainNode(node),
147
- id: nodeId,
148
- });
149
-
150
- prevNodeId = nodeId;
151
- });
152
- });
153
138
  }
154
139
 
155
140
  return {
@@ -158,7 +143,7 @@ export const getExplainQuery = ({query, database}) => {
158
143
  nodes,
159
144
  tables,
160
145
  version: meta.version,
161
- pristine: result,
146
+ pristine: rawPlan,
162
147
  },
163
148
  ast,
164
149
  };
@@ -1,11 +1,13 @@
1
- import '../../services/api';
1
+ import type {Reducer} from 'redux';
2
+
3
+ import type {OlapStatsAction, OlapStatsState} from '../../types/store/olapStats';
2
4
 
5
+ import '../../services/api';
3
6
  import {parseQueryAPIExecuteResponse} from '../../utils/query';
4
7
 
5
8
  import {createRequestActionTypes, createApiRequest} from '../utils';
6
9
 
7
- const FETCH_OLAP_STATS = createRequestActionTypes('query', 'SEND_OLAP_STATS_QUERY');
8
- const SET_OLAP_STATS_OPTIONS = createRequestActionTypes('query', 'SET_OLAP_STATS_OPTIONS');
10
+ export const FETCH_OLAP_STATS = createRequestActionTypes('query', 'SEND_OLAP_STATS_QUERY');
9
11
  const RESET_LOADING_STATE = 'olapStats/RESET_LOADING_STATE';
10
12
 
11
13
  const initialState = {
@@ -13,13 +15,13 @@ const initialState = {
13
15
  wasLoaded: false,
14
16
  };
15
17
 
16
- function createOlatStatsQuery(path) {
18
+ function createOlatStatsQuery(path: string) {
17
19
  return `SELECT * FROM \`${path}/.sys/primary_index_stats\``;
18
20
  }
19
21
 
20
22
  const queryAction = 'execute-scan';
21
23
 
22
- const olapStats = (state = initialState, action) => {
24
+ const olapStats: Reducer<OlapStatsState, OlapStatsAction> = (state = initialState, action) => {
23
25
  switch (action.type) {
24
26
  case FETCH_OLAP_STATS.REQUEST: {
25
27
  return {
@@ -44,11 +46,6 @@ const olapStats = (state = initialState, action) => {
44
46
  loading: false,
45
47
  };
46
48
  }
47
- case SET_OLAP_STATS_OPTIONS:
48
- return {
49
- ...state,
50
- ...action.data,
51
- };
52
49
  case RESET_LOADING_STATE: {
53
50
  return {
54
51
  ...state,
@@ -73,17 +70,10 @@ export const getOlapStats = ({path = ''}) => {
73
70
  });
74
71
  };
75
72
 
76
- export function setOlapStatsOptions(options) {
77
- return {
78
- type: SET_OLAP_STATS_OPTIONS,
79
- data: options,
80
- };
81
- }
82
-
83
73
  export function resetLoadingState() {
84
74
  return {
85
75
  type: RESET_LOADING_STATE,
86
- };
76
+ } as const;
87
77
  }
88
78
 
89
79
  export default olapStats;
@@ -3,14 +3,16 @@ import {
3
3
  SAVED_QUERIES_KEY,
4
4
  THEME_KEY,
5
5
  TENANT_INITIAL_TAB_KEY,
6
- QUERY_INITIAL_RUN_ACTION_KEY,
7
6
  INVERTED_DISKS_KEY,
8
7
  ASIDE_HEADER_COMPACT_KEY,
9
8
  USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
10
9
  PARTITIONS_SELECTED_COLUMNS_KEY,
10
+ QUERY_INITIAL_MODE_KEY,
11
+ ENABLE_QUERY_MODES_FOR_EXPLAIN,
11
12
  } from '../../utils/constants';
12
13
  import '../../services/api';
13
- import {getValueFromLS} from '../../utils/utils';
14
+ import {getValueFromLS, parseJson} from '../../utils/utils';
15
+ import {QueryModes} from '../../types/store/query';
14
16
 
15
17
  const CHANGE_PROBLEM_FILTER = 'settings/CHANGE_PROBLEM_FILTER';
16
18
  const SET_SETTING_VALUE = 'settings/SET_VALUE';
@@ -38,15 +40,19 @@ export const initialState = {
38
40
  problemFilter: ALL,
39
41
  userSettings: {
40
42
  ...userSettings,
41
- [THEME_KEY]: readSavedSettingsValue(THEME_KEY, 'light'),
43
+ [THEME_KEY]: readSavedSettingsValue(THEME_KEY, 'system'),
42
44
  [INVERTED_DISKS_KEY]: readSavedSettingsValue(INVERTED_DISKS_KEY, 'false'),
43
45
  [USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY]: readSavedSettingsValue(
44
46
  USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
45
47
  'false',
46
48
  ),
49
+ [ENABLE_QUERY_MODES_FOR_EXPLAIN]: readSavedSettingsValue(
50
+ ENABLE_QUERY_MODES_FOR_EXPLAIN,
51
+ 'false',
52
+ ),
47
53
  [SAVED_QUERIES_KEY]: readSavedSettingsValue(SAVED_QUERIES_KEY, '[]'),
48
54
  [TENANT_INITIAL_TAB_KEY]: readSavedSettingsValue(TENANT_INITIAL_TAB_KEY),
49
- [QUERY_INITIAL_RUN_ACTION_KEY]: readSavedSettingsValue(QUERY_INITIAL_RUN_ACTION_KEY),
55
+ [QUERY_INITIAL_MODE_KEY]: readSavedSettingsValue(QUERY_INITIAL_MODE_KEY, QueryModes.script),
50
56
  [ASIDE_HEADER_COMPACT_KEY]: readSavedSettingsValue(
51
57
  ASIDE_HEADER_COMPACT_KEY,
52
58
  legacyAsideNavCompactState || 'true',
@@ -97,6 +103,15 @@ export const getSettingValue = (state, name) => {
97
103
  return state.settings.userSettings[name];
98
104
  };
99
105
 
106
+ /**
107
+ * Returns parsed settings value.
108
+ * If value cannot be parsed, returns initially stored string
109
+ */
110
+ export const getParsedSettingValue = (state, name) => {
111
+ const value = state.settings.userSettings[name];
112
+ return parseJson(value);
113
+ };
114
+
100
115
  export const changeFilter = (filter) => {
101
116
  return {
102
117
  type: CHANGE_PROBLEM_FILTER,
@@ -243,13 +243,11 @@ export const getFlatListStorageGroups = createSelector([getStoragePools], (stora
243
243
  const limitSizeBytes = _.reduce(
244
244
  group.VDisks,
245
245
  (acc, vDisk) => {
246
- return (
247
- acc +
248
- (Number(vDisk.AvailableSize) ||
249
- Number(vDisk.PDisk?.AvailableSize) ||
250
- 0) +
251
- (Number(vDisk.AllocatedSize) || 0)
252
- );
246
+ const {AvailableSize, AllocatedSize, PDisk} = vDisk;
247
+ const available = (AvailableSize ?? PDisk?.AvailableSize) || 0;
248
+ const allocated = AllocatedSize || 0;
249
+
250
+ return acc + Number(available) + Number(allocated);
253
251
  },
254
252
  0,
255
253
  );
@@ -4,3 +4,17 @@ export interface IResponseError {
4
4
  statusText?: string;
5
5
  isCancelled?: boolean;
6
6
  }
7
+
8
+ // Error on offline backend or requests blocked by CORS
9
+ export interface NetworkError {
10
+ code?: unknown;
11
+ columnNumber?: unknown;
12
+ config?: Record<string, unknown>;
13
+ description?: unknown;
14
+ fileName?: unknown;
15
+ lineNumber?: unknown;
16
+ message?: 'Network Error';
17
+ name?: string;
18
+ number?: unknown;
19
+ stack?: string;
20
+ }