ydb-embedded-ui 3.4.2 → 3.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. package/CHANGELOG.md +16 -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 +17 -10
  9. package/dist/containers/Storage/PDisk/PDisk.tsx +9 -4
  10. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +2 -2
  11. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +4 -0
  12. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +2 -1
  13. package/dist/containers/Storage/VDisk/VDisk.tsx +2 -2
  14. package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +2 -2
  15. package/dist/containers/Tablet/Tablet.tsx +121 -0
  16. package/dist/containers/Tablet/TabletControls/TabletControls.tsx +159 -0
  17. package/dist/containers/Tablet/TabletControls/index.ts +1 -0
  18. package/dist/containers/Tablet/TabletInfo/TabletInfo.tsx +80 -0
  19. package/dist/containers/Tablet/TabletInfo/index.ts +1 -0
  20. package/dist/containers/Tablet/TabletTable/TabletTable.tsx +59 -0
  21. package/dist/containers/Tablet/TabletTable/index.ts +1 -0
  22. package/dist/containers/Tablet/i18n/en.json +10 -0
  23. package/dist/containers/Tablet/i18n/index.ts +11 -0
  24. package/dist/containers/Tablet/i18n/ru.json +10 -0
  25. package/dist/containers/Tablet/index.ts +1 -0
  26. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +2 -1
  27. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +4 -4
  28. package/dist/store/reducers/storage.js +1 -0
  29. package/dist/types/api/nodes.ts +1 -1
  30. package/dist/utils/nodes.ts +7 -0
  31. package/dist/utils/storage.ts +1 -1
  32. package/package.json +5 -2
  33. 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);