ydb-embedded-ui 3.4.1 → 3.4.3

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 (36) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +31 -10
  3. package/dist/components/CriticalActionDialog/CriticalActionDialog.scss +1 -1
  4. package/dist/components/CriticalActionDialog/{CriticalActionDialog.js → CriticalActionDialog.tsx} +21 -16
  5. package/dist/components/CriticalActionDialog/index.ts +1 -0
  6. package/dist/containers/App/Content.js +1 -1
  7. package/dist/containers/Nodes/Nodes.scss +4 -0
  8. package/dist/containers/Nodes/Nodes.tsx +2 -1
  9. package/dist/containers/Storage/PDisk/PDisk.scss +15 -0
  10. package/dist/containers/Storage/PDisk/PDisk.tsx +43 -13
  11. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +2 -2
  12. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +8 -2
  13. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +3 -1
  14. package/dist/containers/Storage/VDisk/VDisk.tsx +2 -2
  15. package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +2 -2
  16. package/dist/containers/Tablet/Tablet.tsx +121 -0
  17. package/dist/containers/Tablet/TabletControls/TabletControls.tsx +159 -0
  18. package/dist/containers/Tablet/TabletControls/index.ts +1 -0
  19. package/dist/containers/Tablet/TabletInfo/TabletInfo.tsx +80 -0
  20. package/dist/containers/Tablet/TabletInfo/index.ts +1 -0
  21. package/dist/containers/Tablet/TabletTable/TabletTable.tsx +59 -0
  22. package/dist/containers/Tablet/TabletTable/index.ts +1 -0
  23. package/dist/containers/Tablet/i18n/en.json +10 -0
  24. package/dist/containers/Tablet/i18n/index.ts +11 -0
  25. package/dist/containers/Tablet/i18n/ru.json +10 -0
  26. package/dist/containers/Tablet/index.ts +1 -0
  27. package/dist/containers/Tenant/Diagnostics/Partitions/Partitions.tsx +9 -15
  28. package/dist/containers/Tenant/Diagnostics/Partitions/PartitionsWrapper.tsx +2 -0
  29. package/dist/store/reducers/storage.js +1 -0
  30. package/dist/store/reducers/topic.ts +13 -0
  31. package/dist/types/api/nodes.ts +1 -1
  32. package/dist/types/store/topic.ts +3 -2
  33. package/dist/utils/nodes.ts +7 -0
  34. package/dist/utils/storage.ts +1 -1
  35. package/package.json +5 -2
  36. package/dist/containers/Tablet/Tablet.js +0 -448
@@ -1,448 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import {connect} from 'react-redux';
4
- import {Link} from 'react-router-dom';
5
- import cn from 'bem-cn-lite';
6
- import _ from 'lodash';
7
-
8
- import {calcUptime} from '../../utils';
9
- import {backend} from '../../store';
10
- import {getTablet, getTabletDescribe} from '../../store/reducers/tablet';
11
- import '../../services/api';
12
-
13
- import InfoViewer from '../../components/InfoViewer/InfoViewer';
14
- import EntityStatus from '../../components/EntityStatus/EntityStatus';
15
- import {Tag} from '../../components/Tag';
16
- import {Icon} from '../../components/Icon';
17
- import {EmptyState} from '../../components/EmptyState';
18
- import {Link as ExternalLink, Button, Loader} from '@gravity-ui/uikit';
19
- import DataTable from '@gravity-ui/react-data-table';
20
- import CriticalActionDialog from '../../components/CriticalActionDialog/CriticalActionDialog';
21
- import routes, {createHref} from '../../routes';
22
- import {getDefaultNodePath} from '../Node/NodePages';
23
-
24
- import './Tablet.scss';
25
-
26
- const b = cn('tablet-page');
27
-
28
- const TABLE_SETTINGS = {
29
- displayIndices: false,
30
- };
31
-
32
- const CLUSTERS_COLUMNS = [
33
- {
34
- name: 'generation',
35
- header: 'Generation',
36
- align: DataTable.RIGHT,
37
- },
38
- {
39
- name: 'nodeId',
40
- header: 'Node ID',
41
- align: DataTable.RIGHT,
42
- sortable: false,
43
- },
44
- {
45
- name: 'changeTime',
46
- header: 'Change time',
47
- align: DataTable.RIGHT,
48
- sortable: false,
49
- render: ({value}) => calcUptime(value),
50
- },
51
- {
52
- name: 'state',
53
- header: 'State',
54
- sortable: false,
55
- },
56
- {
57
- name: 'follower_id',
58
- header: 'Follower ID',
59
- sortable: false,
60
- render: ({row}) => {
61
- return row.leader ? 'leader' : row.followerId;
62
- },
63
- },
64
- ];
65
-
66
- class Tablet extends React.Component {
67
- static propTypes = {
68
- id: PropTypes.string,
69
- tablet: PropTypes.object,
70
- loading: PropTypes.bool,
71
- getTablet: PropTypes.func,
72
- getTabletDescribe: PropTypes.func,
73
- tenantPath: PropTypes.string,
74
- tabletId: PropTypes.string,
75
- };
76
-
77
- componentDidMount() {
78
- this.fetchTabletInfo();
79
- }
80
-
81
- componentDidUpdate(prevProps) {
82
- const {version} = this.props;
83
-
84
- if (version && !prevProps.version) {
85
- this.fetchTabletInfo();
86
- }
87
- }
88
-
89
- componentWillUnmount() {
90
- if (this.fetcher) {
91
- clearInterval(this.fetcher);
92
- }
93
- }
94
-
95
- state = {
96
- typeVisibleDialog: null,
97
- dialogVisible: false,
98
- isFirstFetchData: true,
99
- tenantPath: '-',
100
- disableTabletActions: false,
101
- };
102
-
103
- makeShowDialog = (type) => () => this.setState({dialogVisible: true, typeVisibleDialog: type});
104
- showKillDialog = this.makeShowDialog('kill');
105
- showStopDialog = this.makeShowDialog('stop');
106
- showResumeDialog = this.makeShowDialog('resume');
107
- hideDialog = () => this.setState({dialogVisible: false, typeVisibleDialog: null});
108
-
109
- fetchTabletInfo = () => {
110
- const {version, id} = this.props;
111
- const {isFirstFetchData} = this.state;
112
-
113
- if (version && this.isValidVersion()) {
114
- this.props.getTablet(id).then(({tabletData}) => {
115
- if (isFirstFetchData && tabletData.TenantId) {
116
- this.props.getTabletDescribe(tabletData.TenantId);
117
- }
118
-
119
- this.setState({isFirstFetchData: false});
120
- });
121
-
122
- if (this.fetcher) {
123
- clearInterval(this.fetcher);
124
- this.fetcher = null;
125
- }
126
-
127
- this.fetcher = setInterval(() => {
128
- this.props.getTablet(id).then(() => {
129
- this.setState({disableTabletActions: false});
130
- });
131
- }, 10000);
132
- }
133
- };
134
-
135
- isValidVersion = () => {
136
- const {version} = this.props;
137
-
138
- if (/\d+.stable-19-6$/.exec(version)) {
139
- return false;
140
- } else if (/\d+.stable-29/.exec(version)) {
141
- return false;
142
- }
143
-
144
- return true;
145
- };
146
- renderLoader() {
147
- return (
148
- <div className={'loader'}>
149
- <Loader size="l" />
150
- </div>
151
- );
152
- }
153
- renderPlaceholder() {
154
- return (
155
- <div className={b('placeholder')}>
156
- <EmptyState title="The tablet was not found" />
157
- </div>
158
- );
159
- }
160
- renderExternalLinks = (link, index) => {
161
- return (
162
- <li key={index} className={b('link', {external: true})}>
163
- <ExternalLink href={`${backend}${link.path}`} target="_blank">
164
- {link.name}
165
- </ExternalLink>
166
- </li>
167
- );
168
- };
169
- _onKillClick = () => {
170
- const {TabletId: id} = this.props.tablet;
171
-
172
- this.setState({disableTabletActions: true});
173
-
174
- return window.api.killTablet(id);
175
- };
176
- _onStopClick = () => {
177
- const {TabletId: id, HiveId: hiveId} = this.props.tablet;
178
-
179
- this.setState({disableTabletActions: true});
180
-
181
- return window.api.stopTablet(id, hiveId);
182
- };
183
- _onResumeClick = () => {
184
- const {TabletId: id, HiveId: hiveId} = this.props.tablet;
185
-
186
- this.setState({disableTabletActions: true});
187
-
188
- return window.api.resumeTablet(id, hiveId);
189
- };
190
- renderDialog = () => {
191
- const {dialogVisible, typeVisibleDialog} = this.state;
192
-
193
- if (!dialogVisible) {
194
- return null;
195
- }
196
-
197
- switch (typeVisibleDialog) {
198
- case 'kill': {
199
- return (
200
- <CriticalActionDialog
201
- visible={dialogVisible}
202
- text="The tablet will be restarted. Do you want to proceed?"
203
- onClose={this.hideDialog}
204
- onConfirm={this._onKillClick}
205
- />
206
- );
207
- }
208
- case 'stop': {
209
- return (
210
- <CriticalActionDialog
211
- visible={dialogVisible}
212
- text="The tablet will be stopped. Do you want to proceed?"
213
- onClose={this.hideDialog}
214
- onConfirm={this._onStopClick}
215
- />
216
- );
217
- }
218
- case 'resume': {
219
- return (
220
- <CriticalActionDialog
221
- visible={dialogVisible}
222
- text="The tablet will be resumed. Do you want to proceed?"
223
- onClose={this.hideDialog}
224
- onConfirm={this._onResumeClick}
225
- />
226
- );
227
- }
228
- default:
229
- return null;
230
- }
231
- };
232
-
233
- hasUptime = () => {
234
- const {tablet} = this.props;
235
-
236
- return tablet.State === 'Active';
237
- };
238
-
239
- hasHiveId = () => {
240
- const {tablet} = this.props;
241
- const {HiveId} = tablet;
242
-
243
- return HiveId && HiveId !== '0';
244
- };
245
-
246
- getSchemeShard = () => {
247
- const {tablet} = this.props;
248
-
249
- return _.get(tablet, 'TenantId.SchemeShard');
250
- };
251
-
252
- isDisabledResume = () => {
253
- const {tablet} = this.props;
254
- const {disableTabletActions} = this.state;
255
-
256
- if (disableTabletActions) {
257
- return true;
258
- }
259
-
260
- return tablet.State !== 'Stopped' && tablet.State !== 'Dead';
261
- };
262
-
263
- isDisabledKill = () => {
264
- const {disableTabletActions} = this.state;
265
-
266
- return disableTabletActions;
267
- };
268
-
269
- isDisabledStop = () => {
270
- const {tablet} = this.props;
271
- const {disableTabletActions} = this.state;
272
-
273
- if (disableTabletActions) {
274
- return true;
275
- }
276
-
277
- return tablet.State === 'Stopped' || tablet.State === 'Deleted';
278
- };
279
-
280
- renderTablet = () => {
281
- const {tablet, tenantPath} = this.props;
282
- const {TabletId: id} = tablet;
283
- const schemeShard = this.getSchemeShard();
284
-
285
- const tabletInfo = [
286
- {label: 'Database', value: tenantPath},
287
- this.hasHiveId()
288
- ? {
289
- label: 'HiveId',
290
- value: (
291
- <ExternalLink
292
- href={createHref(routes.tablet, {id: tablet.HiveId})}
293
- target="_blank"
294
- >
295
- {tablet.HiveId}
296
- </ExternalLink>
297
- ),
298
- }
299
- : null,
300
- schemeShard
301
- ? {
302
- label: 'SchemeShard',
303
- value: (
304
- <ExternalLink
305
- href={createHref(routes.tablet, {id: schemeShard})}
306
- target="_blank"
307
- >
308
- {schemeShard}
309
- </ExternalLink>
310
- ),
311
- }
312
- : null,
313
- {label: 'Type', value: tablet.Type},
314
- {label: 'State', value: tablet.State},
315
- this.hasUptime() ? {label: 'Uptime', value: calcUptime(tablet.ChangeTime)} : null,
316
- {label: 'Generation', value: tablet.Generation},
317
- {
318
- label: 'Node',
319
- value: (
320
- <Link className={b('link')} to={getDefaultNodePath(String(tablet.NodeId))}>
321
- {tablet.NodeId}
322
- </Link>
323
- ),
324
- },
325
- ].filter(Boolean);
326
-
327
- if (tablet.SlaveId || tablet.FollowerId) {
328
- tabletInfo.push({label: 'Follower', value: tablet.SlaveId || tablet.FollowerId});
329
- }
330
-
331
- const externalLinks = [
332
- {
333
- name: 'Internal viewer - tablet',
334
- path: `/tablets?TabletID=${id}`,
335
- },
336
- ];
337
-
338
- return (
339
- <div className={b()}>
340
- <div className={b('pane-wrapper')}>
341
- <div className={b('left-pane')}>
342
- <ul className={b('links')}>
343
- {externalLinks.map(this.renderExternalLinks)}
344
- </ul>
345
- <div className={b('row', {header: true})}>
346
- <span className={b('title')}>Tablet</span>
347
- <EntityStatus status={tablet.Overall} name={tablet.TabletId} />
348
- <a
349
- rel="noopener noreferrer"
350
- className={b('link', {external: true})}
351
- href={`${backend}/tablets?TabletID=${tablet.TabletId}`}
352
- target="_blank"
353
- >
354
- <Icon name="external" />
355
- </a>
356
- {(tablet.Master || tablet.Leader) && <Tag text="Leader" type="blue" />}
357
- </div>
358
- <InfoViewer info={tabletInfo} />
359
- <div className={b('controls')}>
360
- <Button
361
- onClick={this.showKillDialog}
362
- view="action"
363
- disabled={this.isDisabledKill()}
364
- className={b('control')}
365
- >
366
- Restart
367
- </Button>
368
- {this.hasHiveId() ? (
369
- <React.Fragment>
370
- <Button
371
- onClick={this.showStopDialog}
372
- view="action"
373
- disabled={this.isDisabledStop()}
374
- className={b('control')}
375
- >
376
- Stop
377
- </Button>
378
- <Button
379
- onClick={this.showResumeDialog}
380
- view="action"
381
- disabled={this.isDisabledResume()}
382
- className={b('control')}
383
- >
384
- Resume
385
- </Button>
386
- </React.Fragment>
387
- ) : null}
388
- </div>
389
- </div>
390
- <div className={b('rigth-pane')}>
391
- <DataTable
392
- data={this.props.history}
393
- columns={CLUSTERS_COLUMNS}
394
- settings={TABLE_SETTINGS}
395
- initialSortOrder={{
396
- columnId: 'generation',
397
- order: DataTable.DESCENDING,
398
- }}
399
- />
400
- </div>
401
- </div>
402
- {this.renderDialog()}
403
- </div>
404
- );
405
- };
406
-
407
- renderContent = () => {
408
- const {tablet} = this.props;
409
- return tablet && Object.keys(tablet).length
410
- ? this.renderTablet()
411
- : this.renderPlaceholder();
412
- };
413
- render() {
414
- const {loading, tabletId, id} = this.props;
415
- const {isFirstFetchData} = this.state;
416
-
417
- if (this.isValidVersion()) {
418
- return loading && id !== tabletId && isFirstFetchData
419
- ? this.renderLoader()
420
- : this.renderContent();
421
- }
422
-
423
- return null;
424
- }
425
- }
426
-
427
- const mapStateToProps = (state, ownProps) => {
428
- const {data: tablet = {}, loading, id: tabletId, history = [], tenantPath} = state.tablet;
429
- const {id} = ownProps.match.params;
430
- const {data: host} = state.host;
431
-
432
- return {
433
- tablet,
434
- loading,
435
- id,
436
- tabletId,
437
- history,
438
- version: host.Version,
439
- tenantPath,
440
- };
441
- };
442
-
443
- const mapDispatchToProps = {
444
- getTablet,
445
- getTabletDescribe,
446
- };
447
-
448
- export default connect(mapStateToProps, mapDispatchToProps)(Tablet);