ydb-embedded-ui 4.9.0 → 4.10.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 (64) hide show
  1. package/CHANGELOG.md +12 -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/ProblemFilter/ProblemFilter.tsx +2 -2
  9. package/dist/components/SpeedMultiMeter/SpeedMultiMeter.tsx +4 -4
  10. package/dist/components/TruncatedQuery/{TruncatedQuery.js → TruncatedQuery.tsx} +10 -8
  11. package/dist/containers/AsideNavigation/AsideNavigation.tsx +6 -6
  12. package/dist/containers/Cluster/Cluster.tsx +10 -6
  13. package/dist/containers/Node/Node.tsx +3 -3
  14. package/dist/containers/Nodes/Nodes.tsx +2 -2
  15. package/dist/containers/Storage/PDisk/PDisk.tsx +2 -7
  16. package/dist/containers/Storage/Storage.tsx +240 -0
  17. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +45 -40
  18. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +12 -16
  19. package/dist/containers/Storage/UsageFilter/UsageFilter.scss +1 -0
  20. package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +17 -17
  21. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -3
  22. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +7 -4
  23. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +0 -15
  24. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +10 -3
  25. package/dist/containers/Tenant/{Preview → Query/Preview}/Preview.scss +1 -1
  26. package/dist/containers/Tenant/Query/Preview/Preview.tsx +121 -0
  27. package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +1 -1
  28. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +6 -8
  29. package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.tsx +1 -1
  30. package/dist/containers/Tenant/Query/i18n/en.json +8 -1
  31. package/dist/containers/Tenant/Query/i18n/ru.json +8 -1
  32. package/dist/containers/Tenants/Tenants.tsx +269 -0
  33. package/dist/services/api.ts +8 -3
  34. package/dist/store/reducers/nodes/nodes.ts +4 -4
  35. package/dist/store/reducers/partitions/types.ts +3 -3
  36. package/dist/store/reducers/settings/settings.ts +4 -2
  37. package/dist/store/reducers/settings/types.ts +3 -1
  38. package/dist/store/reducers/storage/selectors.ts +279 -0
  39. package/dist/store/reducers/storage/storage.ts +191 -0
  40. package/dist/store/reducers/storage/types.ts +80 -0
  41. package/dist/store/reducers/tenants/selectors.ts +46 -0
  42. package/dist/store/reducers/tenants/tenants.ts +21 -14
  43. package/dist/store/reducers/tenants/types.ts +20 -5
  44. package/dist/store/reducers/tenants/utils.ts +68 -0
  45. package/dist/types/additionalProps.ts +8 -0
  46. package/dist/types/api/storage.ts +1 -1
  47. package/dist/types/store/topic.ts +3 -3
  48. package/dist/utils/bytesParsers/__test__/formatBytes.test.ts +38 -0
  49. package/dist/utils/bytesParsers/convertBytesObjectToSpeed.ts +2 -2
  50. package/dist/utils/bytesParsers/formatBytes.ts +132 -0
  51. package/dist/utils/bytesParsers/i18n/en.json +1 -0
  52. package/dist/utils/bytesParsers/i18n/ru.json +1 -0
  53. package/dist/utils/bytesParsers/index.ts +1 -1
  54. package/dist/utils/index.js +5 -10
  55. package/dist/utils/numeral.ts +8 -0
  56. package/package.json +1 -1
  57. package/dist/components/FullNodeViewer/FullNodeViewer.js +0 -89
  58. package/dist/containers/Node/NodeOverview/NodeOverview.scss +0 -0
  59. package/dist/containers/Node/NodeOverview/NodeOverview.tsx +0 -21
  60. package/dist/containers/Storage/Storage.js +0 -350
  61. package/dist/containers/Tenant/Preview/Preview.js +0 -168
  62. package/dist/containers/Tenants/Tenants.js +0 -363
  63. package/dist/store/reducers/storage/storage.js +0 -404
  64. package/dist/utils/bytesParsers/formatBytesCustom.ts +0 -57
@@ -1,363 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import cn from 'bem-cn-lite';
4
- import {connect} from 'react-redux';
5
- import _ from 'lodash';
6
- import {escapeRegExp} from 'lodash/fp';
7
-
8
- import DataTable from '@gravity-ui/react-data-table';
9
- import {Loader, TextInput, Button} from '@gravity-ui/uikit';
10
-
11
- import EntityStatus from '../../components/EntityStatus/EntityStatus';
12
- import {PoolsGraph} from '../../components/PoolsGraph/PoolsGraph';
13
- import {TabletsStatistic} from '../../components/TabletsStatistic';
14
- import {ProblemFilter} from '../../components/ProblemFilter';
15
- import {Illustration} from '../../components/Illustration';
16
- import {AutoFetcher} from '../../utils/autofetcher';
17
-
18
- import routes, {createHref} from '../../routes';
19
- import {formatCPU, formatBytesToGigabyte, formatNumber} from '../../utils';
20
- import {withSearch} from '../../HOCS';
21
- import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
22
- import {getTenantsInfo} from '../../store/reducers/tenants/tenants';
23
- import {changeFilter, ProblemFilterValues} from '../../store/reducers/settings/settings';
24
-
25
- import {clusterName} from '../../store';
26
- import {TenantTabsGroups, TENANT_INFO_TABS} from '../Tenant/TenantPages';
27
-
28
- import './Tenants.scss';
29
-
30
- const b = cn('tenants');
31
-
32
- class Tenants extends React.Component {
33
- static renderLoader() {
34
- return (
35
- <div className={'loader'}>
36
- <Loader size="l" />
37
- </div>
38
- );
39
- }
40
-
41
- static propTypes = {
42
- loading: PropTypes.bool,
43
- wasLoaded: PropTypes.bool,
44
- error: PropTypes.bool,
45
- getTenantsInfo: PropTypes.func,
46
- tenants: PropTypes.array,
47
- searchQuery: PropTypes.string,
48
- handleSearchQuery: PropTypes.func,
49
- filter: PropTypes.string,
50
- changeFilter: PropTypes.func,
51
- cluster: PropTypes.object,
52
- singleClusterMode: PropTypes.bool,
53
- additionalTenantsInfo: PropTypes.object,
54
- };
55
-
56
- static defaultProps = {
57
- className: '',
58
- };
59
-
60
- static filterTenants(tenants, filter) {
61
- if (filter === ProblemFilterValues.ALL) {
62
- return tenants;
63
- }
64
-
65
- return _.filter(tenants, (tenant) => {
66
- return tenant.Overall && tenant.Overall !== 'Green';
67
- });
68
- }
69
-
70
- componentDidMount() {
71
- this.autofetcher = new AutoFetcher();
72
- this.props.getTenantsInfo(clusterName);
73
- this.autofetcher.fetch(() => this.props.getTenantsInfo(clusterName));
74
- }
75
-
76
- componentWillUnmount() {
77
- this.autofetcher.stop();
78
- }
79
-
80
- renderControls() {
81
- const {searchQuery, handleSearchQuery, filter, changeFilter} = this.props;
82
-
83
- return (
84
- <div className={b('controls')}>
85
- <div className={b('search')}>
86
- <TextInput
87
- placeholder="Database name"
88
- value={searchQuery}
89
- onUpdate={handleSearchQuery}
90
- hasClear
91
- autoFocus
92
- />
93
- </div>
94
- <ProblemFilter value={filter} onChange={changeFilter} />
95
- </div>
96
- );
97
- }
98
-
99
- getControlPlaneValue = (item) => {
100
- const parts = _.get(item, 'Name', []).split('/');
101
- const defaultValue = parts.length ? parts[parts.length - 1] : '—';
102
-
103
- return _.get(item, 'ControlPlane.name', defaultValue);
104
- };
105
-
106
- renderTable = () => {
107
- const {
108
- tenants = [],
109
- searchQuery,
110
- filter,
111
- handleSearchQuery,
112
- additionalTenantsInfo = {},
113
- } = this.props;
114
-
115
- const filteredTenantsBySearch = tenants.filter((item) => {
116
- const re = new RegExp(escapeRegExp(searchQuery), 'i');
117
- return re.test(item.Name) || re.test(this.getControlPlaneValue(item));
118
- });
119
- const filteredTenants = Tenants.filterTenants(filteredTenantsBySearch, filter);
120
-
121
- const initialTenantInfoTab = TENANT_INFO_TABS[0].id;
122
-
123
- const getTenantBackend = (tenant) => {
124
- const backend = tenant.MonitoringEndpoint ?? tenant.backend;
125
- return additionalTenantsInfo.tenantBackend
126
- ? additionalTenantsInfo.tenantBackend(backend)
127
- : undefined;
128
- };
129
-
130
- const columns = [
131
- {
132
- name: 'Name',
133
- header: 'Database',
134
- render: ({value, row}) => {
135
- const backend = getTenantBackend(row);
136
- const isExternalLink = Boolean(backend);
137
- return (
138
- <div className={b('name-wrapper')}>
139
- <EntityStatus
140
- externalLink={isExternalLink}
141
- className={b('name')}
142
- name={value || 'unknown database'}
143
- withLeftTrim={true}
144
- status={row.Overall}
145
- hasClipboardButton
146
- path={createHref(routes.tenant, undefined, {
147
- name: value,
148
- backend,
149
- [TenantTabsGroups.info]: initialTenantInfoTab,
150
- })}
151
- />
152
- {additionalTenantsInfo.name && additionalTenantsInfo.name(value, row)}
153
- </div>
154
- );
155
- },
156
- width: 440,
157
- sortable: true,
158
- defaultOrder: DataTable.DESCENDING,
159
- },
160
- {
161
- name: 'ControlPlaneName',
162
- header: 'Name',
163
- render: ({row}) => {
164
- return this.getControlPlaneValue(row);
165
- },
166
- width: 200,
167
- sortable: true,
168
- defaultOrder: DataTable.DESCENDING,
169
- },
170
- {
171
- name: 'Type',
172
- width: 200,
173
- render: ({value, row}) => {
174
- if (value !== 'Serverless') {
175
- return value;
176
- }
177
-
178
- const sharedTenantName = _.find(tenants, {Id: row.ResourceId}).Name;
179
-
180
- return (
181
- <div className={b('type')}>
182
- <span className={b('type-value')}>{value}</span>
183
- <Button
184
- className={b('type-button')}
185
- onClick={() => handleSearchQuery(sharedTenantName)}
186
- >
187
- Show shared
188
- </Button>
189
- </div>
190
- );
191
- },
192
- },
193
- {
194
- name: 'State',
195
- width: 90,
196
- render: ({value}) => (value ? value.toLowerCase() : '—'),
197
- customStyle: () => ({textTransform: 'capitalize'}),
198
- },
199
- {
200
- name: 'cpu',
201
- header: 'CPU',
202
- width: 80,
203
- sortAccessor: ({Metrics = {}, CoresUsed}) => {
204
- const cpuRaw =
205
- CoresUsed !== undefined ? Number(CoresUsed) * 1_000_000 : Metrics.CPU;
206
- return isNaN(Number(cpuRaw)) ? 0 : Number(cpuRaw);
207
- },
208
- accessor: ({Metrics = {}, CoresUsed}) => {
209
- if (!isNaN(Number(CoresUsed))) {
210
- return Number(CoresUsed) * 100 > 1
211
- ? formatCPU(Number(CoresUsed) * 1_000_000)
212
- : '—';
213
- } else {
214
- return Number(Metrics.CPU) ? formatCPU(Number(Metrics.CPU)) : '—';
215
- }
216
- },
217
- align: DataTable.RIGHT,
218
- defaultOrder: DataTable.DESCENDING,
219
- },
220
- {
221
- name: 'memory',
222
- header: 'Memory',
223
- width: 120,
224
- accessor: ({Metrics = {}, MemoryUsed}) => {
225
- return !isNaN(Number(MemoryUsed)) ? Number(MemoryUsed) : Number(Metrics.Memory);
226
- },
227
- sortAccessor: ({Metrics = {}, MemoryUsed}) => {
228
- const memory = MemoryUsed ?? Metrics.Memory;
229
- return isNaN(Number(memory)) ? 0 : Number(memory);
230
- },
231
- render: ({value}) => (value ? formatBytesToGigabyte(value) : '—'),
232
- align: DataTable.RIGHT,
233
- defaultOrder: DataTable.DESCENDING,
234
- },
235
- {
236
- name: 'storage',
237
- header: 'Storage',
238
- width: 120,
239
- accessor: ({Metrics = {}, StorageAllocatedSize}) => {
240
- return !isNaN(Number(StorageAllocatedSize))
241
- ? Number(StorageAllocatedSize)
242
- : Number(Metrics.Storage);
243
- },
244
- sortAccessor: ({Metrics = {}, StorageAllocatedSize}) => {
245
- const storage = StorageAllocatedSize ?? Metrics.Storage;
246
- return isNaN(Number(storage)) ? 0 : Number(storage);
247
- },
248
- render: ({value}) => (value ? formatBytesToGigabyte(value) : '—'),
249
- align: DataTable.RIGHT,
250
- defaultOrder: DataTable.DESCENDING,
251
- },
252
- {
253
- name: 'NodeIds',
254
- header: 'Nodes',
255
- width: 100,
256
- accessor: ({NodeIds}) => NodeIds?.length || 0,
257
- sortAccessor: ({NodeIds}) => NodeIds?.length || 0,
258
- render: ({value}) => formatNumber(value),
259
- align: DataTable.RIGHT,
260
- defaultOrder: DataTable.DESCENDING,
261
- },
262
- {
263
- name: 'StorageGroups',
264
- header: 'Groups',
265
- width: 100,
266
- sortAccessor: ({StorageGroups}) =>
267
- isNaN(Number(StorageGroups)) ? 0 : Number(StorageGroups),
268
- render: ({value}) => formatNumber(value) || '—',
269
- align: DataTable.RIGHT,
270
- defaultOrder: DataTable.DESCENDING,
271
- },
272
- {
273
- name: 'PoolStats',
274
- header: 'Pools',
275
- width: 100,
276
- sortAccessor: ({PoolStats = []}) =>
277
- PoolStats.reduce((acc, item) => acc + item.Usage, 0),
278
- defaultOrder: DataTable.DESCENDING,
279
- align: DataTable.LEFT,
280
- render: ({value}) => <PoolsGraph rowInfo={value} pools={value} />,
281
- },
282
- {
283
- name: 'Tablets',
284
- header: 'Tablets States',
285
- sortable: false,
286
- width: 430,
287
- render: ({value, row}) => {
288
- const backend = getTenantBackend(row);
289
-
290
- return value ? (
291
- <TabletsStatistic
292
- path={row.Name}
293
- tablets={value}
294
- nodeIds={row.NodeIds}
295
- backend={backend}
296
- />
297
- ) : (
298
- '—'
299
- );
300
- },
301
- },
302
- ];
303
-
304
- if (filteredTenants.length === 0 && filter !== ProblemFilterValues.ALL) {
305
- return <Illustration name="thumbsUp" width="200" />;
306
- }
307
-
308
- return (
309
- <div className={b('table-wrapper')}>
310
- <DataTable
311
- theme="yandex-cloud"
312
- data={filteredTenants}
313
- columns={columns}
314
- settings={DEFAULT_TABLE_SETTINGS}
315
- dynamicRender={true}
316
- emptyDataMessage="No such tenants"
317
- />
318
- </div>
319
- );
320
- };
321
-
322
- renderContent = () => {
323
- return (
324
- <div className={b()}>
325
- {this.renderControls()}
326
- {this.renderTable()}
327
- </div>
328
- );
329
- };
330
-
331
- render() {
332
- const {loading, wasLoaded, error} = this.props;
333
-
334
- if (loading && !wasLoaded) {
335
- return Tenants.renderLoader();
336
- } else if (error) {
337
- return <div>{error.statusText}</div>;
338
- } else {
339
- return this.renderContent();
340
- }
341
- }
342
- }
343
-
344
- const mapStateToProps = (state) => {
345
- const {tenants, wasLoaded, loading, error} = state.tenants;
346
- const {singleClusterMode} = state;
347
-
348
- return {
349
- singleClusterMode,
350
- tenants,
351
- wasLoaded,
352
- loading,
353
- error,
354
- filter: state.settings.problemFilter,
355
- };
356
- };
357
-
358
- const mapDispatchToProps = {
359
- getTenantsInfo,
360
- changeFilter,
361
- };
362
-
363
- export default withSearch(connect(mapStateToProps, mapDispatchToProps)(Tenants));