ydb-embedded-ui 4.8.2 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/BasicNodeViewer/BasicNodeViewer.tsx +7 -4
  3. package/dist/components/EntityStatus/EntityStatus.js +3 -1
  4. package/dist/components/FormattedBytes/FormattedBytes.tsx +10 -0
  5. package/dist/components/FormattedBytes/utils.tsx +13 -0
  6. package/dist/components/FullNodeViewer/FullNodeViewer.tsx +73 -0
  7. package/dist/components/InfoViewer/formatters/table.ts +6 -5
  8. package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +2 -2
  9. package/dist/components/ProblemFilter/ProblemFilter.tsx +2 -2
  10. package/dist/components/SpeedMultiMeter/SpeedMultiMeter.tsx +4 -4
  11. package/dist/components/TruncatedQuery/{TruncatedQuery.js → TruncatedQuery.tsx} +10 -8
  12. package/dist/containers/AsideNavigation/AsideNavigation.tsx +6 -6
  13. package/dist/containers/Cluster/Cluster.tsx +10 -6
  14. package/dist/containers/Node/Node.tsx +3 -3
  15. package/dist/containers/Nodes/Nodes.tsx +3 -3
  16. package/dist/containers/Nodes/getNodesColumns.tsx +2 -2
  17. package/dist/containers/Storage/PDisk/PDisk.tsx +2 -7
  18. package/dist/containers/Storage/Storage.tsx +240 -0
  19. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +59 -57
  20. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +23 -25
  21. package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +27 -0
  22. package/dist/containers/Storage/StorageVisibleEntityFilter/StorageVisibleEntityFilter.tsx +31 -0
  23. package/dist/containers/Storage/UsageFilter/UsageFilter.scss +1 -0
  24. package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +17 -17
  25. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -3
  26. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +7 -4
  27. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +0 -15
  28. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +10 -3
  29. package/dist/containers/Tenant/{Preview → Query/Preview}/Preview.scss +1 -1
  30. package/dist/containers/Tenant/Query/Preview/Preview.tsx +121 -0
  31. package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +1 -1
  32. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +23 -51
  33. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.scss +20 -15
  34. package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.tsx +74 -27
  35. package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.tsx +1 -1
  36. package/dist/containers/Tenant/Query/i18n/en.json +9 -2
  37. package/dist/containers/Tenant/Query/i18n/ru.json +9 -2
  38. package/dist/containers/Tenants/Tenants.tsx +269 -0
  39. package/dist/containers/UserSettings/i18n/en.json +1 -1
  40. package/dist/containers/UserSettings/i18n/ru.json +1 -1
  41. package/dist/services/api.ts +14 -16
  42. package/dist/store/reducers/executeQuery.ts +2 -3
  43. package/dist/store/reducers/explainQuery.ts +2 -2
  44. package/dist/store/reducers/index.ts +2 -2
  45. package/dist/store/reducers/{nodes.ts → nodes/nodes.ts} +33 -32
  46. package/dist/{types/store/nodes.ts → store/reducers/nodes/types.ts} +24 -27
  47. package/dist/store/reducers/partitions/types.ts +3 -3
  48. package/dist/store/reducers/settings/settings.ts +14 -4
  49. package/dist/store/reducers/settings/types.ts +3 -1
  50. package/dist/store/reducers/storage/constants.ts +10 -0
  51. package/dist/store/reducers/storage/selectors.ts +279 -0
  52. package/dist/store/reducers/storage/storage.ts +191 -0
  53. package/dist/store/reducers/storage/types.ts +92 -0
  54. package/dist/store/reducers/tenants/selectors.ts +46 -0
  55. package/dist/store/reducers/tenants/tenants.ts +21 -14
  56. package/dist/store/reducers/tenants/types.ts +20 -5
  57. package/dist/store/reducers/tenants/utils.ts +68 -0
  58. package/dist/types/additionalProps.ts +8 -0
  59. package/dist/types/api/storage.ts +1 -1
  60. package/dist/types/store/query.ts +5 -6
  61. package/dist/types/store/topic.ts +3 -3
  62. package/dist/utils/bytesParsers/__test__/formatBytes.test.ts +38 -0
  63. package/dist/utils/bytesParsers/convertBytesObjectToSpeed.ts +2 -2
  64. package/dist/utils/bytesParsers/formatBytes.ts +132 -0
  65. package/dist/utils/bytesParsers/i18n/en.json +1 -0
  66. package/dist/utils/bytesParsers/i18n/ru.json +1 -0
  67. package/dist/utils/bytesParsers/index.ts +1 -1
  68. package/dist/utils/constants.ts +1 -0
  69. package/dist/utils/index.js +5 -10
  70. package/dist/utils/nodes.ts +2 -2
  71. package/dist/utils/numeral.ts +8 -0
  72. package/dist/utils/query.ts +12 -0
  73. package/package.json +1 -1
  74. package/dist/components/FullNodeViewer/FullNodeViewer.js +0 -89
  75. package/dist/containers/Node/NodeOverview/NodeOverview.scss +0 -0
  76. package/dist/containers/Node/NodeOverview/NodeOverview.tsx +0 -21
  77. package/dist/containers/Storage/Storage.js +0 -372
  78. package/dist/containers/Tenant/Preview/Preview.js +0 -168
  79. package/dist/containers/Tenant/Query/QueryEditorControls/OldQueryEditorControls.tsx +0 -90
  80. package/dist/containers/Tenant/Query/QueryEditorControls/shared.ts +0 -18
  81. package/dist/containers/Tenants/Tenants.js +0 -363
  82. package/dist/store/reducers/storage.js +0 -438
  83. package/dist/utils/bytesParsers/formatBytesCustom.ts +0 -57
@@ -1,24 +1,49 @@
1
- import {Button, DropdownMenu} from '@gravity-ui/uikit';
1
+ import block from 'bem-cn-lite';
2
+
3
+ import {Button, ButtonView, DropdownMenu} from '@gravity-ui/uikit';
2
4
  import {useMemo} from 'react';
3
5
 
4
- import {QueryModes} from '../../../../types/store/query';
6
+ import type {QueryAction, QueryMode} from '../../../../types/store/query';
7
+ import {QUERY_MODES} from '../../../../utils/query';
5
8
  import {Icon} from '../../../../components/Icon';
6
9
 
7
10
  import SaveQuery from '../SaveQuery/SaveQuery';
8
11
 
9
12
  import i18n from '../i18n';
10
13
 
11
- import {QueryEditorControlsProps, b} from './shared';
12
-
13
14
  import './QueryEditorControls.scss';
14
15
 
15
- export const QueryModeSelectorTitles = {
16
- [QueryModes.script]: 'Script',
17
- [QueryModes.scan]: 'Scan',
18
- [QueryModes.data]: 'Data',
19
- [QueryModes.query]: 'Query',
16
+ const queryModeSelectorQa = 'query-mode-selector';
17
+ const queryModeSelectorPopupQa = 'query-mode-selector-popup';
18
+
19
+ const b = block('ydb-query-editor-controls');
20
+
21
+ const OldQueryModeSelectorTitles = {
22
+ [QUERY_MODES.script]: 'YQL Script',
23
+ [QUERY_MODES.scan]: 'Scan',
24
+ } as const;
25
+
26
+ const QueryModeSelectorTitles = {
27
+ [QUERY_MODES.script]: 'YQL Script',
28
+ [QUERY_MODES.scan]: 'Scan',
29
+ [QUERY_MODES.data]: 'Data',
30
+ [QUERY_MODES.query]: 'YQL - QueryService',
20
31
  } as const;
21
32
 
33
+ interface QueryEditorControlsProps {
34
+ onRunButtonClick: (mode?: QueryMode) => void;
35
+ runIsLoading: boolean;
36
+ onExplainButtonClick: (mode?: QueryMode) => void;
37
+ explainIsLoading: boolean;
38
+ onSaveQueryClick: (queryName: string) => void;
39
+ savedQueries: unknown;
40
+ disabled: boolean;
41
+ onUpdateQueryMode: (mode: QueryMode) => void;
42
+ queryMode: QueryMode;
43
+ enableAdditionalQueryModes: boolean;
44
+ highlitedAction: QueryAction;
45
+ }
46
+
22
47
  export const QueryEditorControls = ({
23
48
  onRunButtonClick,
24
49
  runIsLoading,
@@ -29,17 +54,27 @@ export const QueryEditorControls = ({
29
54
  disabled,
30
55
  onUpdateQueryMode,
31
56
  queryMode,
57
+ highlitedAction,
58
+ enableAdditionalQueryModes,
32
59
  }: QueryEditorControlsProps) => {
33
60
  const querySelectorMenuItems = useMemo(() => {
34
- return Object.entries(QueryModeSelectorTitles).map(([mode, title]) => {
61
+ const titles = enableAdditionalQueryModes
62
+ ? QueryModeSelectorTitles
63
+ : OldQueryModeSelectorTitles;
64
+
65
+ return Object.entries(titles).map(([mode, title]) => {
35
66
  return {
36
67
  text: title,
37
68
  action: () => {
38
- onUpdateQueryMode(mode as QueryModes);
69
+ onUpdateQueryMode(mode as QueryMode);
39
70
  },
40
71
  };
41
72
  });
42
- }, [onUpdateQueryMode]);
73
+ }, [onUpdateQueryMode, enableAdditionalQueryModes]);
74
+
75
+ const runView: ButtonView | undefined = highlitedAction === 'execute' ? 'action' : undefined;
76
+ const explainView: ButtonView | undefined =
77
+ highlitedAction === 'explain' ? 'action' : undefined;
43
78
 
44
79
  return (
45
80
  <div className={b()}>
@@ -49,9 +84,9 @@ export const QueryEditorControls = ({
49
84
  onClick={() => {
50
85
  onRunButtonClick(queryMode);
51
86
  }}
52
- view="action"
53
87
  disabled={disabled}
54
88
  loading={runIsLoading}
89
+ view={runView}
55
90
  >
56
91
  <Icon name="startPlay" viewBox="0 0 16 16" width={16} height={16} />
57
92
  {'Run'}
@@ -63,23 +98,35 @@ export const QueryEditorControls = ({
63
98
  }}
64
99
  disabled={disabled}
65
100
  loading={explainIsLoading}
101
+ view={explainView}
66
102
  >
67
103
  Explain
68
104
  </Button>
69
- <DropdownMenu
70
- items={querySelectorMenuItems}
71
- popupProps={{className: b('mode-selector__popup')}}
72
- switcher={
73
- <Button className={b('mode-selector__button')}>
74
- <span className={b('mode-selector__button-content')}>
75
- {`${i18n('controls.query-mode-selector_type')} ${
76
- QueryModeSelectorTitles[queryMode]
77
- }`}
78
- <Icon name="chevron-down" width={16} height={16} />
79
- </span>
80
- </Button>
81
- }
82
- />
105
+ <div
106
+ className={b('mode-selector', {
107
+ extended: enableAdditionalQueryModes,
108
+ })}
109
+ >
110
+ <DropdownMenu
111
+ items={querySelectorMenuItems}
112
+ popupProps={{
113
+ className: b('mode-selector__popup', {
114
+ extended: enableAdditionalQueryModes,
115
+ }),
116
+ qa: queryModeSelectorPopupQa,
117
+ }}
118
+ switcher={
119
+ <Button className={b('mode-selector__button')} qa={queryModeSelectorQa}>
120
+ <span className={b('mode-selector__button-content')}>
121
+ {`${i18n('controls.query-mode-selector_type')} ${
122
+ QueryModeSelectorTitles[queryMode]
123
+ }`}
124
+ <Icon name="chevron-down" width={16} height={16} />
125
+ </span>
126
+ </Button>
127
+ }
128
+ />
129
+ </div>
83
130
  </div>
84
131
  <SaveQuery
85
132
  savedQueries={savedQueries}
@@ -10,7 +10,7 @@ import {setQueryNameToEdit} from '../../../../store/reducers/saveQuery';
10
10
  import {setQueryTab} from '../../../../store/reducers/tenant/tenant';
11
11
  import {TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
12
12
 
13
- import TruncatedQuery from '../../../../components/TruncatedQuery/TruncatedQuery';
13
+ import {TruncatedQuery} from '../../../../components/TruncatedQuery/TruncatedQuery';
14
14
  import {IconWrapper} from '../../../../components/Icon';
15
15
 
16
16
  import {MAX_QUERY_HEIGHT, QUERY_TABLE_SETTINGS} from '../../utils/constants';
@@ -1,12 +1,19 @@
1
1
  {
2
- "controls.query-mode-selector_type": "Type:",
2
+ "controls.query-mode-selector_type": "Query type:",
3
+
3
4
  "tabs.newQuery": "New query",
4
5
  "tabs.history": "History",
5
6
  "tabs.saved": "Saved",
7
+
6
8
  "history.empty": "History is empty",
7
9
  "saved.empty": "There are no saved queries",
10
+
8
11
  "delete-dialog.header": "Delete query",
9
12
  "delete-dialog.question": "Are you sure you want to delete query",
10
13
  "delete-dialog.delete": "Delete",
11
- "delete-dialog.cancel": "Cancel"
14
+ "delete-dialog.cancel": "Cancel",
15
+
16
+ "preview.title": "Preview",
17
+ "preview.not-available": "Preview is not available",
18
+ "preview.close": "Close preview"
12
19
  }
@@ -1,12 +1,19 @@
1
1
  {
2
- "controls.query-mode-selector_type": "Тип:",
2
+ "controls.query-mode-selector_type": "Тип запроса:",
3
+
3
4
  "tabs.newQuery": "Новый запрос",
4
5
  "tabs.history": "История",
5
6
  "tabs.saved": "Сохраненные",
7
+
6
8
  "history.empty": "История пуста",
7
9
  "saved.empty": "Нет сохраненных запросов",
10
+
8
11
  "delete-dialog.header": "Удалить запрос",
9
12
  "delete-dialog.question": "Вы уверены что хотите удалить запрос",
10
13
  "delete-dialog.delete": "Удалить",
11
- "delete-dialog.cancel": "Отменить"
14
+ "delete-dialog.cancel": "Отменить",
15
+
16
+ "preview.title": "Предпросмотр",
17
+ "preview.not-available": "Предпросмотр недоступен",
18
+ "preview.close": "Закрыть предпросмотр"
12
19
  }
@@ -0,0 +1,269 @@
1
+ import cn from 'bem-cn-lite';
2
+ import {useDispatch} from 'react-redux';
3
+
4
+ import DataTable, {Column} from '@gravity-ui/react-data-table';
5
+ import {Loader, Button} from '@gravity-ui/uikit';
6
+
7
+ import EntityStatus from '../../components/EntityStatus/EntityStatus';
8
+ import {PoolsGraph} from '../../components/PoolsGraph/PoolsGraph';
9
+ import {TabletsStatistic} from '../../components/TabletsStatistic';
10
+ import {ProblemFilter} from '../../components/ProblemFilter';
11
+ import {Illustration} from '../../components/Illustration';
12
+ import {Search} from '../../components/Search';
13
+ import {ResponseError} from '../../components/Errors/ResponseError';
14
+
15
+ import type {AdditionalTenantsProps} from '../../types/additionalProps';
16
+ import type {ProblemFilterValue} from '../../store/reducers/settings/types';
17
+ import type {PreparedTenant} from '../../store/reducers/tenants/types';
18
+ import {getTenantsInfo, setSearchValue} from '../../store/reducers/tenants/tenants';
19
+ import {
20
+ selectFilteredTenants,
21
+ selectTenantsSearchValue,
22
+ } from '../../store/reducers/tenants/selectors';
23
+ import {
24
+ changeFilter,
25
+ ProblemFilterValues,
26
+ selectProblemFilter,
27
+ } from '../../store/reducers/settings/settings';
28
+ import {formatCPU, formatBytesToGigabyte, formatNumber} from '../../utils';
29
+ import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
30
+ import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
31
+ import {clusterName} from '../../store';
32
+
33
+ import {TenantTabsGroups, TENANT_INFO_TABS, getTenantPath} from '../Tenant/TenantPages';
34
+
35
+ import './Tenants.scss';
36
+
37
+ const b = cn('tenants');
38
+
39
+ interface TenantsProps {
40
+ additionalTenantsProps?: AdditionalTenantsProps;
41
+ }
42
+
43
+ export const Tenants = ({additionalTenantsProps}: TenantsProps) => {
44
+ const dispatch = useDispatch();
45
+
46
+ const {error, loading, wasLoaded} = useTypedSelector((state) => state.tenants);
47
+ const searchValue = useTypedSelector(selectTenantsSearchValue);
48
+ const filteredTenants = useTypedSelector(selectFilteredTenants);
49
+ const problemFilter = useTypedSelector(selectProblemFilter);
50
+
51
+ useAutofetcher(
52
+ () => {
53
+ dispatch(getTenantsInfo(clusterName));
54
+ },
55
+ [dispatch],
56
+ true,
57
+ );
58
+
59
+ const handleProblemFilterChange = (value: string) => {
60
+ dispatch(changeFilter(value as ProblemFilterValue));
61
+ };
62
+
63
+ const handleSearchChange = (value: string) => {
64
+ dispatch(setSearchValue(value));
65
+ };
66
+
67
+ const renderControls = () => {
68
+ return (
69
+ <div className={b('controls')}>
70
+ <Search
71
+ value={searchValue}
72
+ onChange={handleSearchChange}
73
+ placeholder="Database name"
74
+ className={b('search')}
75
+ />
76
+ <ProblemFilter value={problemFilter} onChange={handleProblemFilterChange} />
77
+ </div>
78
+ );
79
+ };
80
+
81
+ const renderTable = () => {
82
+ const initialTenantInfoTab = TENANT_INFO_TABS[0].id;
83
+
84
+ const getTenantBackend = (tenant: PreparedTenant) => {
85
+ const backend = tenant.MonitoringEndpoint ?? tenant.backend;
86
+ return additionalTenantsProps?.prepareTenantBackend?.(backend);
87
+ };
88
+
89
+ const columns: Column<PreparedTenant>[] = [
90
+ {
91
+ name: 'Name',
92
+ header: 'Database',
93
+ render: ({row}) => {
94
+ const backend = getTenantBackend(row);
95
+ const isExternalLink = Boolean(backend);
96
+ return (
97
+ <div className={b('name-wrapper')}>
98
+ <EntityStatus
99
+ externalLink={isExternalLink}
100
+ className={b('name')}
101
+ name={row.Name || 'unknown database'}
102
+ withLeftTrim={true}
103
+ status={row.Overall}
104
+ hasClipboardButton
105
+ path={getTenantPath({
106
+ name: row.Name,
107
+ backend,
108
+ [TenantTabsGroups.info]: initialTenantInfoTab,
109
+ })}
110
+ />
111
+ {additionalTenantsProps?.getMonitoringLink?.(row.Name, row.Type)}
112
+ </div>
113
+ );
114
+ },
115
+ width: 440,
116
+ sortable: true,
117
+ defaultOrder: DataTable.DESCENDING,
118
+ },
119
+ {
120
+ name: 'controlPlaneName',
121
+ header: 'Name',
122
+ render: ({row}) => {
123
+ return row.controlPlaneName;
124
+ },
125
+ width: 200,
126
+ sortable: true,
127
+ defaultOrder: DataTable.DESCENDING,
128
+ },
129
+ {
130
+ name: 'Type',
131
+ width: 200,
132
+ render: ({row}) => {
133
+ if (row.Type !== 'Serverless') {
134
+ return row.Type;
135
+ }
136
+
137
+ return (
138
+ <div className={b('type')}>
139
+ <span className={b('type-value')}>{row.Type}</span>
140
+ <Button
141
+ className={b('type-button')}
142
+ onClick={() => handleSearchChange(row.sharedTenantName || '')}
143
+ >
144
+ Show shared
145
+ </Button>
146
+ </div>
147
+ );
148
+ },
149
+ },
150
+ {
151
+ name: 'State',
152
+ width: 90,
153
+ render: ({row}) => (row.State ? row.State.toLowerCase() : '—'),
154
+ customStyle: () => ({textTransform: 'capitalize'}),
155
+ },
156
+ {
157
+ name: 'cpu',
158
+ header: 'CPU',
159
+ width: 80,
160
+ render: ({row}) => {
161
+ // Don't show values below 0.01 when formatted
162
+ if (row.cpu > 10_000) {
163
+ return formatCPU(row.cpu);
164
+ }
165
+ return '—';
166
+ },
167
+ align: DataTable.RIGHT,
168
+ defaultOrder: DataTable.DESCENDING,
169
+ },
170
+ {
171
+ name: 'memory',
172
+ header: 'Memory',
173
+ width: 120,
174
+ render: ({row}) => (row.memory ? formatBytesToGigabyte(row.memory) : '—'),
175
+ align: DataTable.RIGHT,
176
+ defaultOrder: DataTable.DESCENDING,
177
+ },
178
+ {
179
+ name: 'storage',
180
+ header: 'Storage',
181
+ width: 120,
182
+ render: ({row}) => (row.storage ? formatBytesToGigabyte(row.storage) : '—'),
183
+ align: DataTable.RIGHT,
184
+ defaultOrder: DataTable.DESCENDING,
185
+ },
186
+ {
187
+ name: 'nodesCount',
188
+ header: 'Nodes',
189
+ width: 100,
190
+ render: ({row}) => (row.nodesCount ? formatNumber(row.nodesCount) : '—'),
191
+ align: DataTable.RIGHT,
192
+ defaultOrder: DataTable.DESCENDING,
193
+ },
194
+ {
195
+ name: 'groupsCount',
196
+ header: 'Groups',
197
+ width: 100,
198
+ render: ({row}) => (row.groupsCount ? formatNumber(row.groupsCount) : '—'),
199
+ align: DataTable.RIGHT,
200
+ defaultOrder: DataTable.DESCENDING,
201
+ },
202
+ {
203
+ name: 'PoolStats',
204
+ header: 'Pools',
205
+ width: 100,
206
+ sortAccessor: ({PoolStats = []}) =>
207
+ PoolStats.reduce((acc, item) => acc + (item.Usage || 0), 0),
208
+ defaultOrder: DataTable.DESCENDING,
209
+ align: DataTable.LEFT,
210
+ render: ({row}) => <PoolsGraph pools={row.PoolStats} />,
211
+ },
212
+ {
213
+ name: 'Tablets',
214
+ header: 'Tablets States',
215
+ sortable: false,
216
+ width: 430,
217
+ render: ({row}) => {
218
+ const backend = getTenantBackend(row);
219
+
220
+ return row.Tablets ? (
221
+ <TabletsStatistic
222
+ path={row.Name}
223
+ tablets={row.Tablets}
224
+ nodeIds={row.NodeIds || []}
225
+ backend={backend}
226
+ />
227
+ ) : (
228
+ '—'
229
+ );
230
+ },
231
+ },
232
+ ];
233
+
234
+ if (filteredTenants.length === 0 && problemFilter !== ProblemFilterValues.ALL) {
235
+ return <Illustration name="thumbsUp" width="200" />;
236
+ }
237
+
238
+ return (
239
+ <div className={b('table-wrapper')}>
240
+ <DataTable
241
+ theme="yandex-cloud"
242
+ data={filteredTenants}
243
+ columns={columns}
244
+ settings={DEFAULT_TABLE_SETTINGS}
245
+ emptyDataMessage="No such tenants"
246
+ />
247
+ </div>
248
+ );
249
+ };
250
+
251
+ if (loading && !wasLoaded) {
252
+ return (
253
+ <div className={'loader'}>
254
+ <Loader size="l" />
255
+ </div>
256
+ );
257
+ }
258
+
259
+ if (error) {
260
+ return <ResponseError error={error} />;
261
+ }
262
+
263
+ return (
264
+ <div className={b()}>
265
+ {renderControls()}
266
+ {renderTable()}
267
+ </div>
268
+ );
269
+ };
@@ -16,5 +16,5 @@
16
16
  "settings.useNodesEndpoint.popover": "Use /viewer/json/nodes endpoint for Nodes Tab in diagnostics. It returns incorrect data on versions before 23-1",
17
17
 
18
18
  "settings.enableAdditionalQueryModes.title": "Enable additional query modes",
19
- "settings.enableAdditionalQueryModes.popover": "Adds 'data' and 'query' modes for run. Enables query modes for explain. May not work on some versions"
19
+ "settings.enableAdditionalQueryModes.popover": "Adds 'Data' and 'YQL - QueryService' modes. May not work on some versions"
20
20
  }
@@ -16,5 +16,5 @@
16
16
  "settings.useNodesEndpoint.popover": "Использовать эндпоинт /viewer/json/nodes для вкладки Nodes в диагностике. Может возвращать некорректные данные на версиях до 23-1",
17
17
 
18
18
  "settings.enableAdditionalQueryModes.title": "Включить дополнительные режимы выполнения запросов",
19
- "settings.enableAdditionalQueryModes.popover": "Добавляет режимы 'data' и 'query' для run. Включает возможность выбрать режим выполнения запроса для explain. Может работать некорректно на некоторых версиях"
19
+ "settings.enableAdditionalQueryModes.popover": "Добавляет режимы 'Data' и 'YQL - QueryService'. Может работать некорректно на некоторых версиях"
20
20
  }
@@ -28,7 +28,8 @@ import type {DescribeTopicResult} from '../types/api/topic';
28
28
  import type {TEvPDiskStateResponse} from '../types/api/pdisk';
29
29
  import type {TEvVDiskStateResponse} from '../types/api/vdisk';
30
30
  import type {TUserToken} from '../types/api/whoami';
31
- import type {INodesApiRequestParams} from '../types/store/nodes';
31
+ import type {NodesApiRequestParams} from '../store/reducers/nodes/types';
32
+ import type {StorageApiRequestParams} from '../store/reducers/storage/types';
32
33
 
33
34
  import {backend as BACKEND} from '../store';
34
35
 
@@ -81,14 +82,14 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
81
82
  });
82
83
  }
83
84
  getNodes(
84
- {tenant, filter, storage, type = 'any', tablets = true}: INodesApiRequestParams,
85
+ {tenant, visibleEntities, storage, type = 'any', tablets = true}: NodesApiRequestParams,
85
86
  {concurrentId}: AxiosOptions = {},
86
87
  ) {
87
88
  return this.get<TNodesInfo>(
88
89
  this.getPath('/viewer/json/nodes?enums=true'),
89
90
  {
90
91
  tenant,
91
- with: filter,
92
+ with: visibleEntities,
92
93
  storage,
93
94
  type,
94
95
  tablets,
@@ -102,15 +103,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
102
103
  return this.get<TComputeInfo>(this.getPath('/viewer/json/compute?enums=true'), {path});
103
104
  }
104
105
  getStorageInfo(
105
- {
106
- tenant,
107
- filter,
108
- nodeId,
109
- }: {
110
- tenant?: string;
111
- filter?: string;
112
- nodeId: string;
113
- },
106
+ {tenant, visibleEntities, nodeId}: StorageApiRequestParams,
114
107
  {concurrentId}: AxiosOptions = {},
115
108
  ) {
116
109
  return this.get<TStorageInfo>(
@@ -118,7 +111,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
118
111
  {
119
112
  tenant,
120
113
  node_id: nodeId,
121
- with: filter,
114
+ with: visibleEntities,
122
115
  },
123
116
  {
124
117
  concurrentId,
@@ -289,19 +282,24 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
289
282
  },
290
283
  {concurrentId}: AxiosOptions = {},
291
284
  ) {
285
+ // Time difference to ensure that timeout from ui will be shown rather than backend error
286
+ const uiTimeout = 9 * 60 * 1000;
287
+ const backendTimeout = 10 * 60 * 1000;
288
+
292
289
  return this.post<QueryAPIResponse<Action, Schema>>(
293
- this.getPath(`/viewer/json/query${schema ? `?schema=${schema}` : ''}`),
290
+ this.getPath(
291
+ `/viewer/json/query?timeout=${backendTimeout}${schema ? `&schema=${schema}` : ''}`,
292
+ ),
294
293
  {
295
294
  query,
296
295
  database,
297
296
  action,
298
297
  stats,
299
- timeout: 600000,
300
298
  },
301
299
  {},
302
300
  {
303
301
  concurrentId,
304
- timeout: 9 * 60 * 1000,
302
+ timeout: uiTimeout,
305
303
  },
306
304
  );
307
305
  }
@@ -6,7 +6,7 @@ import type {
6
6
  ExecuteQueryState,
7
7
  MonacoHotKeyAction,
8
8
  } from '../../types/store/executeQuery';
9
- import type {QueryRequestParams, QueryModes} from '../../types/store/query';
9
+ import type {QueryRequestParams, QueryMode} from '../../types/store/query';
10
10
  import {getValueFromLS, parseJson} from '../../utils/utils';
11
11
  import {QUERIES_HISTORY_KEY} from '../../utils/constants';
12
12
  import {parseQueryAPIExecuteResponse} from '../../utils/query';
@@ -34,7 +34,6 @@ export const MONACO_HOT_KEY_ACTIONS = {
34
34
  sendQuery: 'sendQuery',
35
35
  goPrev: 'goPrev',
36
36
  goNext: 'goNext',
37
- getExplain: 'getExplain',
38
37
  } as const;
39
38
 
40
39
  const initialState = {
@@ -148,7 +147,7 @@ const executeQuery: Reducer<ExecuteQueryState, ExecuteQueryAction> = (
148
147
  };
149
148
 
150
149
  interface SendQueryParams extends QueryRequestParams {
151
- mode?: QueryModes;
150
+ mode?: QueryMode;
152
151
  }
153
152
 
154
153
  export const sendExecuteQuery = ({query, database, mode}: SendQueryParams) => {
@@ -9,7 +9,7 @@ import type {
9
9
  ExplainQueryState,
10
10
  PreparedExplainResponse,
11
11
  } from '../../types/store/explainQuery';
12
- import type {QueryRequestParams, QueryModes} from '../../types/store/query';
12
+ import type {QueryRequestParams, QueryMode} from '../../types/store/query';
13
13
 
14
14
  import {preparePlan} from '../../utils/prepareQueryExplain';
15
15
  import {parseQueryAPIExplainResponse, parseQueryExplainPlan} from '../../utils/query';
@@ -99,7 +99,7 @@ export const explainVersions = {
99
99
  const supportedExplainQueryVersions = Object.values(explainVersions);
100
100
 
101
101
  interface ExplainQueryParams extends QueryRequestParams {
102
- mode?: QueryModes;
102
+ mode?: QueryMode;
103
103
  }
104
104
 
105
105
  export const getExplainQuery = ({query, database, mode}: ExplainQueryParams) => {
@@ -1,10 +1,10 @@
1
1
  import {combineReducers} from 'redux';
2
2
 
3
- import nodes from './nodes';
3
+ import nodes from './nodes/nodes';
4
4
  import cluster from './cluster/cluster';
5
5
  import clusterNodes from './clusterNodes/clusterNodes';
6
6
  import tenant from './tenant/tenant';
7
- import storage from './storage';
7
+ import storage from './storage/storage';
8
8
  import node from './node/node';
9
9
  import tooltip from './tooltip';
10
10
  import tablets from './tablets';