ydb-embedded-ui 3.2.2 → 3.3.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 (118) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/components/InfoViewer/InfoViewer.scss +10 -0
  3. package/dist/components/InfoViewer/InfoViewer.tsx +12 -2
  4. package/dist/components/InfoViewer/formatters/cdcStream.ts +10 -0
  5. package/dist/components/InfoViewer/formatters/index.ts +3 -0
  6. package/dist/components/InfoViewer/formatters/pqGroup.ts +51 -0
  7. package/dist/components/InfoViewer/formatters/schema.ts +1 -29
  8. package/dist/components/InfoViewer/formatters/topicStats.tsx +50 -0
  9. package/dist/components/InfoViewer/schemaInfo/index.ts +0 -2
  10. package/dist/components/InfoViewer/utils.ts +15 -0
  11. package/dist/components/InternalLink/InternalLink.tsx +17 -0
  12. package/dist/components/InternalLink/index.ts +1 -0
  13. package/dist/components/Tablet/Tablet.js +1 -1
  14. package/dist/components/TabletsStatistic/TabletsStatistic.tsx +1 -1
  15. package/dist/components/VerticalBars/VerticalBars.scss +15 -0
  16. package/dist/components/VerticalBars/VerticalBars.tsx +38 -0
  17. package/dist/components/VerticalBars/index.ts +1 -0
  18. package/dist/containers/App/App.js +0 -11
  19. package/dist/containers/App/App.scss +0 -1
  20. package/dist/containers/Cluster/Cluster.tsx +2 -2
  21. package/dist/containers/Nodes/Nodes.scss +5 -1
  22. package/dist/containers/Nodes/Nodes.tsx +196 -0
  23. package/dist/containers/{App → Nodes}/NodesTable.scss +2 -2
  24. package/dist/{utils/getNodesColumns.js → containers/Nodes/getNodesColumns.tsx} +60 -35
  25. package/dist/containers/Nodes/i18n/en.json +3 -0
  26. package/dist/containers/Nodes/i18n/index.ts +11 -0
  27. package/dist/containers/Nodes/i18n/ru.json +3 -0
  28. package/dist/containers/Nodes/index.ts +1 -0
  29. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +14 -20
  30. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +32 -16
  31. package/dist/containers/Storage/DiskStateProgressBar/index.ts +1 -0
  32. package/dist/containers/Storage/{Pdisk/Pdisk.scss → PDisk/PDisk.scss} +15 -4
  33. package/dist/containers/Storage/PDisk/PDisk.tsx +145 -0
  34. package/dist/containers/Storage/PDisk/__tests__/colors.tsx +37 -0
  35. package/dist/containers/Storage/PDisk/index.ts +1 -0
  36. package/dist/containers/Storage/PDiskPopup/PDiskPopup.scss +3 -0
  37. package/dist/containers/Storage/PDiskPopup/PDiskPopup.tsx +82 -0
  38. package/dist/containers/Storage/PDiskPopup/index.ts +1 -0
  39. package/dist/containers/Storage/Storage.js +1 -1
  40. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +10 -10
  41. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +1 -0
  42. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -4
  43. package/dist/containers/Storage/VDisk/VDisk.scss +7 -0
  44. package/dist/containers/Storage/VDisk/VDisk.tsx +148 -0
  45. package/dist/containers/Storage/VDisk/__tests__/colors.tsx +209 -0
  46. package/dist/containers/Storage/VDisk/index.ts +1 -0
  47. package/dist/containers/Storage/VDiskPopup/VDiskPopup.scss +14 -0
  48. package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +134 -0
  49. package/dist/containers/Storage/VDiskPopup/index.ts +1 -0
  50. package/dist/containers/Storage/utils/constants.ts +2 -9
  51. package/dist/containers/TabletsFilters/TabletsFilters.js +10 -6
  52. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +2 -1
  53. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +2 -2
  54. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -4
  55. package/dist/containers/Tenant/Diagnostics/OverloadedShards/OverloadedShards.tsx +1 -1
  56. package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/ChangefeedInfo.tsx +69 -0
  57. package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/index.ts +1 -0
  58. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +18 -16
  59. package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/TopicInfo.tsx +37 -0
  60. package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/index.ts +1 -0
  61. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.scss +30 -0
  62. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +94 -0
  63. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/en.json +3 -0
  64. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/index.ts +11 -0
  65. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/ru.json +3 -0
  66. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/index.ts +1 -0
  67. package/dist/containers/Tenant/Diagnostics/Overview/utils/index.ts +1 -0
  68. package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +42 -0
  69. package/dist/containers/Tenant/utils/schema.ts +19 -0
  70. package/dist/containers/Tenants/Tenants.js +2 -1
  71. package/dist/containers/UserSettings/UserSettings.tsx +18 -10
  72. package/dist/services/api.d.ts +8 -1
  73. package/dist/services/api.js +27 -8
  74. package/dist/store/reducers/index.ts +3 -1
  75. package/dist/store/reducers/nodes.ts +148 -14
  76. package/dist/store/reducers/{clusterNodes.js → nodesList.js} +0 -41
  77. package/dist/store/reducers/settings.js +10 -4
  78. package/dist/store/reducers/storage.js +24 -13
  79. package/dist/store/reducers/tenant.js +5 -4
  80. package/dist/store/reducers/tooltip.ts +1 -1
  81. package/dist/store/reducers/topic.ts +52 -0
  82. package/dist/styles/mixins.scss +19 -11
  83. package/dist/types/api/common.ts +5 -0
  84. package/dist/types/api/compute.ts +1 -1
  85. package/dist/types/api/consumer.ts +12 -10
  86. package/dist/types/api/nodes.ts +2 -0
  87. package/dist/types/api/pdisk.ts +1 -0
  88. package/dist/types/api/schema.ts +3 -3
  89. package/dist/types/api/topic.ts +5 -4
  90. package/dist/types/api/vdisk.ts +2 -1
  91. package/dist/types/store/nodes.ts +56 -6
  92. package/dist/types/store/tooltip.ts +1 -1
  93. package/dist/types/store/topic.ts +21 -0
  94. package/dist/utils/constants.ts +5 -1
  95. package/dist/utils/i18n/i18n.ts +10 -2
  96. package/dist/utils/index.js +1 -1
  97. package/dist/utils/timeParsers/__test__/formatDuration.test.ts +50 -0
  98. package/dist/utils/timeParsers/__test__/protobuf.test.ts +74 -0
  99. package/dist/utils/timeParsers/formatDuration.ts +46 -0
  100. package/dist/utils/timeParsers/i18n/en.json +7 -0
  101. package/dist/utils/timeParsers/i18n/index.ts +11 -0
  102. package/dist/utils/timeParsers/i18n/ru.json +7 -0
  103. package/dist/utils/timeParsers/index.ts +2 -0
  104. package/dist/utils/timeParsers/protobuf.ts +36 -0
  105. package/package.json +1 -1
  106. package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +0 -48
  107. package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +0 -30
  108. package/dist/components/InternalLink/InternalLink.js +0 -23
  109. package/dist/containers/Nodes/Nodes.js +0 -213
  110. package/dist/containers/NodesViewer/NodesViewer.js +0 -163
  111. package/dist/containers/NodesViewer/NodesViewer.scss +0 -66
  112. package/dist/containers/Storage/Pdisk/Pdisk.tsx +0 -153
  113. package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +0 -41
  114. package/dist/containers/Storage/Vdisk/Vdisk.js +0 -275
  115. package/dist/containers/Storage/Vdisk/Vdisk.scss +0 -22
  116. package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +0 -163
  117. package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +0 -139
  118. package/dist/containers/Tenant/Diagnostics/Compute/Compute.scss +0 -14
@@ -1,213 +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
-
6
- import DataTable from '@yandex-cloud/react-data-table';
7
- import {Loader, TextInput, Label} from '@gravity-ui/uikit';
8
-
9
- import {ProblemFilter} from '../../components/ProblemFilter';
10
- import {Illustration} from '../../components/Illustration';
11
- import {AccessDenied} from '../../components/Errors/403';
12
- import {UptimeFilter} from '../../components/UptimeFIlter';
13
-
14
- import {hideTooltip, showTooltip} from '../../store/reducers/tooltip';
15
- import {withSearch} from '../../HOCS';
16
- import {AUTO_RELOAD_INTERVAL, ALL, DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
17
- import {getFilteredNodes} from '../../store/reducers/clusterNodes';
18
- import {getNodes, setNodesUptimeFilter} from '../../store/reducers/nodes';
19
- import {changeFilter} from '../../store/reducers/settings';
20
- import {setHeader} from '../../store/reducers/header';
21
- import routes, {CLUSTER_PAGES, createHref} from '../../routes';
22
- import {calcUptime} from '../../utils';
23
- import {getNodesColumns} from '../../utils/getNodesColumns';
24
- import {NodesUptimeFilterValues} from '../../utils/nodes';
25
-
26
- import './Nodes.scss';
27
-
28
- const b = cn('cluster-nodes');
29
-
30
- class Nodes extends React.Component {
31
- static renderLoader() {
32
- return (
33
- <div className={'loader'}>
34
- <Loader size="l" />
35
- </div>
36
- );
37
- }
38
-
39
- static propTypes = {
40
- loading: PropTypes.bool,
41
- wasLoaded: PropTypes.bool,
42
- error: PropTypes.bool,
43
- getNodesList: PropTypes.func,
44
- nodes: PropTypes.array,
45
- showTooltip: PropTypes.func,
46
- hideTooltip: PropTypes.func,
47
- searchQuery: PropTypes.string,
48
- handleSearchQuery: PropTypes.func,
49
- problemFilter: PropTypes.string,
50
- changeFilter: PropTypes.func,
51
- setHeader: PropTypes.func,
52
- className: PropTypes.string,
53
- singleClusterMode: PropTypes.bool,
54
- additionalNodesInfo: PropTypes.object,
55
- nodesUptimeFilter: PropTypes.string,
56
- setNodesUptimeFilter: PropTypes.func,
57
- };
58
-
59
- componentDidMount() {
60
- const {getNodesList, setHeader} = this.props;
61
- getNodesList();
62
- this.reloadDescriptor = setInterval(() => getNodesList(), AUTO_RELOAD_INTERVAL);
63
- setHeader([
64
- {
65
- text: CLUSTER_PAGES.nodes.title,
66
- link: createHref(routes.cluster, {activeTab: CLUSTER_PAGES.nodes.id}),
67
- },
68
- ]);
69
- }
70
-
71
- componentWillUnmount() {
72
- this.props.hideTooltip();
73
- clearInterval(this.reloadDescriptor);
74
- }
75
-
76
- handleSearchQueryChange = (search) => {
77
- this.props.handleSearchQuery(search);
78
- };
79
-
80
- handleProblemFilterChange = (value) => {
81
- this.props.changeFilter(value);
82
- };
83
-
84
- handleUptimeFilterChange = (value) => {
85
- this.props.setNodesUptimeFilter(value);
86
- };
87
-
88
- renderControls() {
89
- const {nodes, searchQuery, problemFilter, nodesUptimeFilter} = this.props;
90
-
91
- return (
92
- <div className={b('controls')}>
93
- <TextInput
94
- className={b('search')}
95
- placeholder="Host name"
96
- value={searchQuery}
97
- onUpdate={this.handleSearchQueryChange}
98
- hasClear
99
- autoFocus
100
- />
101
- <ProblemFilter value={problemFilter} onChange={this.handleProblemFilterChange} />
102
- <UptimeFilter value={nodesUptimeFilter} onChange={this.handleUptimeFilterChange} />
103
- <Label theme="info" size="m">{`Nodes: ${nodes?.length}`}</Label>
104
- </div>
105
- );
106
- }
107
-
108
- renderTable = () => {
109
- const {
110
- nodes = [],
111
- problemFilter,
112
- nodesUptimeFilter,
113
- searchQuery,
114
- showTooltip,
115
- hideTooltip,
116
- singleClusterMode,
117
- additionalNodesInfo = {},
118
- } = this.props;
119
-
120
- const columns = getNodesColumns({
121
- showTooltip,
122
- hideTooltip,
123
- singleClusterMode,
124
- getNodeRef: additionalNodesInfo.getNodeRef,
125
- });
126
-
127
- let preparedNodes = searchQuery
128
- ? nodes.filter((node) => {
129
- const re = new RegExp(searchQuery, 'i');
130
- return node.Host ? re.test(node.Host) || re.test(String(node.NodeId)) : true;
131
- })
132
- : nodes;
133
- preparedNodes = preparedNodes.map((node) => ({
134
- ...node,
135
- uptime: calcUptime(node.StartTime),
136
- }));
137
-
138
- if (preparedNodes.length === 0) {
139
- if (problemFilter !== ALL || nodesUptimeFilter !== NodesUptimeFilterValues.All) {
140
- return <Illustration name="thumbsUp" width="200" />;
141
- }
142
- }
143
-
144
- return (
145
- <div className={b('table-wrapper')}>
146
- <div className={b('table-content')}>
147
- <DataTable
148
- theme="yandex-cloud"
149
- data={preparedNodes}
150
- columns={columns}
151
- settings={DEFAULT_TABLE_SETTINGS}
152
- initialSortOrder={{
153
- columnId: 'NodeId',
154
- order: DataTable.ASCENDING,
155
- }}
156
- emptyDataMessage="No such nodes"
157
- />
158
- </div>
159
- </div>
160
- );
161
- };
162
-
163
- renderContent = () => {
164
- return (
165
- <div className={b(null, this.props.className)}>
166
- {this.renderControls()}
167
- {this.renderTable()}
168
- </div>
169
- );
170
- };
171
-
172
- render() {
173
- const {loading, wasLoaded, error} = this.props;
174
-
175
- if (loading && !wasLoaded) {
176
- return Nodes.renderLoader();
177
- } else if (error) {
178
- if (error.status === 403) {
179
- return <AccessDenied />;
180
- }
181
-
182
- return <div>{error.statusText}</div>;
183
- } else {
184
- return this.renderContent();
185
- }
186
- }
187
- }
188
-
189
- const mapStateToProps = (state) => {
190
- const {wasLoaded, loading, error, nodesUptimeFilter} = state.nodes;
191
-
192
- const nodes = getFilteredNodes(state);
193
- return {
194
- singleClusterMode: state.singleClusterMode,
195
- nodes,
196
- wasLoaded,
197
- loading,
198
- error,
199
- problemFilter: state.settings.problemFilter,
200
- nodesUptimeFilter,
201
- };
202
- };
203
-
204
- const mapDispatchToProps = {
205
- getNodesList: getNodes,
206
- hideTooltip,
207
- showTooltip,
208
- changeFilter,
209
- setHeader,
210
- setNodesUptimeFilter,
211
- };
212
-
213
- export default withSearch(connect(mapStateToProps, mapDispatchToProps)(Nodes));
@@ -1,163 +0,0 @@
1
- import React from 'react';
2
- import cn from 'bem-cn-lite';
3
- import PropTypes from 'prop-types';
4
- import {connect} from 'react-redux';
5
-
6
- import {TextInput, Label} from '@gravity-ui/uikit';
7
- import DataTable from '@yandex-cloud/react-data-table';
8
-
9
- import {ProblemFilter} from '../../components/ProblemFilter';
10
- import {UptimeFilter} from '../../components/UptimeFIlter';
11
- import {Illustration} from '../../components/Illustration';
12
-
13
- import {withSearch} from '../../HOCS';
14
- import {calcUptime} from '../../utils';
15
- import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
16
- import {changeFilter} from '../../store/reducers/settings';
17
- import {filterNodesByStatusAndUptime} from '../../store/reducers/clusterNodes';
18
- import {setNodesUptimeFilter} from '../../store/reducers/nodes';
19
- import {hideTooltip, showTooltip} from '../../store/reducers/tooltip';
20
- import {getNodesColumns} from '../../utils/getNodesColumns';
21
-
22
- import './NodesViewer.scss';
23
-
24
- const b = cn('nodes-viewer');
25
-
26
- class NodesViewer extends React.PureComponent {
27
- static selectNodesToShow(nodes, searchQuery) {
28
- let preparedNodes = nodes;
29
- if (nodes && Array.isArray(nodes)) {
30
- preparedNodes = nodes
31
- .map((node) => {
32
- node.uptime = calcUptime(node.StartTime);
33
- return node;
34
- })
35
- /* Filter by nodes with the Host field.
36
- If a node does not have a Host field it is also
37
- included in the filter and displayed with a dash in the corresponding column
38
- */
39
- .filter((node) => (node.Host ? node.Host.includes(searchQuery) : true));
40
- }
41
- return preparedNodes;
42
- }
43
-
44
- static propTypes = {
45
- nodes: PropTypes.array.isRequired,
46
- className: PropTypes.string,
47
- searchQuery: PropTypes.string,
48
- handleSearchQuery: PropTypes.func,
49
- showTooltip: PropTypes.func,
50
- hideTooltip: PropTypes.func,
51
- problemFilter: PropTypes.string,
52
- nodesUptimeFilter: PropTypes.string,
53
- setNodesUptimeFilter: PropTypes.func,
54
- changeFilter: PropTypes.func,
55
- showControls: PropTypes.bool,
56
- additionalNodesInfo: PropTypes.object,
57
- };
58
-
59
- static defaultProps = {
60
- className: '',
61
- showSearch: true,
62
- showControls: true,
63
- };
64
-
65
- handleProblemFilterChange = (value) => {
66
- this.props.changeFilter(value);
67
- };
68
-
69
- handleUptimeFilterChange = (value) => {
70
- this.props.setNodesUptimeFilter(value);
71
- };
72
-
73
- renderControls() {
74
- const {nodes, searchQuery, handleSearchQuery, nodesUptimeFilter, problemFilter} =
75
- this.props;
76
- const nodesToShow = NodesViewer.selectNodesToShow(nodes, searchQuery);
77
-
78
- return (
79
- <div className={b('controls')}>
80
- <TextInput
81
- className={b('search')}
82
- size="s"
83
- placeholder="Host name…"
84
- value={searchQuery}
85
- onUpdate={handleSearchQuery}
86
- hasClear
87
- autoFocus
88
- />
89
- <ProblemFilter value={problemFilter} onChange={this.handleProblemFilterChange} />
90
- <UptimeFilter value={nodesUptimeFilter} onChange={this.handleUptimeFilterChange} />
91
- <Label theme="info" size="m">{`Nodes: ${nodesToShow.length}`}</Label>
92
- </div>
93
- );
94
- }
95
-
96
- render() {
97
- const {
98
- className,
99
- searchQuery,
100
- path,
101
- problemFilter,
102
- showControls,
103
- hideTooltip,
104
- showTooltip,
105
- additionalNodesInfo = {},
106
- nodes,
107
- } = this.props;
108
-
109
- const columns = getNodesColumns({
110
- tabletsPath: path,
111
- hideTooltip,
112
- showTooltip,
113
- getNodeRef: additionalNodesInfo.getNodeRef,
114
- });
115
-
116
- const nodesToShow = NodesViewer.selectNodesToShow(nodes, searchQuery);
117
-
118
- return (
119
- <div className={`${b()} ${className}`}>
120
- {showControls ? this.renderControls() : null}
121
- <div className={b('table-wrapper')}>
122
- {nodesToShow.length === 0 ? (
123
- <Illustration name="thumbsUp" width="200" />
124
- ) : (
125
- <div className={b('table-content')}>
126
- <DataTable
127
- theme="yandex-cloud"
128
- key={problemFilter}
129
- data={nodesToShow}
130
- columns={columns}
131
- settings={DEFAULT_TABLE_SETTINGS}
132
- emptyDataMessage="No such nodes"
133
- />
134
- </div>
135
- )}
136
- </div>
137
- </div>
138
- );
139
- }
140
- }
141
-
142
- const mapStateToProps = (state, ownProps) => {
143
- const {nodesUptimeFilter} = state.nodes;
144
- const {problemFilter} = state.settings;
145
-
146
- const nodes = filterNodesByStatusAndUptime(ownProps.nodes, problemFilter, nodesUptimeFilter);
147
-
148
- return {
149
- problemFilter,
150
- nodesUptimeFilter,
151
- nodes,
152
- };
153
- };
154
-
155
- const mapDispatchToProps = {
156
- changeFilter,
157
- hideTooltip,
158
- showTooltip,
159
- setNodesUptimeFilter,
160
- };
161
-
162
- const ConnectedNodesViewer = connect(mapStateToProps, mapDispatchToProps)(NodesViewer);
163
- export default withSearch(ConnectedNodesViewer);
@@ -1,66 +0,0 @@
1
- @import '../../styles/mixins.scss';
2
-
3
- .nodes-viewer {
4
- overflow: auto;
5
- @include flex-container();
6
-
7
- &__controls {
8
- @include controls;
9
- }
10
-
11
- &__name {
12
- display: inline-block;
13
-
14
- cursor: pointer;
15
- text-decoration: none;
16
-
17
- color: var(--yc-color-base-special);
18
- }
19
-
20
- &__search {
21
- width: 255px;
22
- }
23
-
24
- &__progress {
25
- margin: 0 auto;
26
- }
27
-
28
- &__tablets {
29
- overflow-x: auto;
30
-
31
- padding: 0 !important;
32
-
33
- .tablets-viewer__grid {
34
- justify-content: center;
35
- grid-template-columns: 125px;
36
- }
37
- }
38
-
39
- &__table-wrapper {
40
- overflow: auto;
41
- @include flex-container();
42
- }
43
-
44
- &__table-content {
45
- overflow: auto;
46
-
47
- height: 100%;
48
- @include freeze-nth-column(1);
49
- @include freeze-nth-column(2, 80px);
50
- @include freeze-nth-column(3, 430px);
51
-
52
- @include table-styles;
53
- @include table-sticky-styles;
54
- }
55
- &__version-tooltip {
56
- width: 100%;
57
- span {
58
- display: block;
59
- overflow: hidden;
60
-
61
- width: 100%;
62
-
63
- text-overflow: ellipsis;
64
- }
65
- }
66
- }
@@ -1,153 +0,0 @@
1
- import React, {useEffect, useState, useRef, useMemo} from 'react';
2
- import cn from 'bem-cn-lite';
3
-
4
- import {Popup} from '@gravity-ui/uikit';
5
-
6
- import {InfoViewer} from '../../../components/InfoViewer';
7
- import InternalLink from '../../../components/InternalLink/InternalLink';
8
-
9
- import routes, {createHref} from '../../../routes';
10
- import type {RequiredField} from '../../../types';
11
- import {TPDiskStateInfo, TPDiskState} from '../../../types/api/pdisk';
12
- import {getPDiskId} from '../../../utils';
13
- import {getPDiskType} from '../../../utils/pdisk';
14
- import {bytesToGB} from '../../../utils/utils';
15
-
16
- import {STRUCTURE} from '../../Node/NodePages';
17
-
18
- import DiskStateProgressBar, {
19
- diskProgressColors,
20
- } from '../DiskStateProgressBar/DiskStateProgressBar';
21
-
22
- import {colorSeverity, NOT_AVAILABLE_SEVERITY} from '../utils';
23
-
24
- import './Pdisk.scss';
25
-
26
- const b = cn('pdisk-storage');
27
-
28
- const stateSeverity = {
29
- [TPDiskState.Initial]: 0,
30
- [TPDiskState.Normal]: 1,
31
- [TPDiskState.InitialFormatRead]: 3,
32
- [TPDiskState.InitialSysLogRead]: 3,
33
- [TPDiskState.InitialCommonLogRead]: 3,
34
- [TPDiskState.InitialFormatReadError]: 5,
35
- [TPDiskState.InitialSysLogReadError]: 5,
36
- [TPDiskState.InitialSysLogParseError]: 5,
37
- [TPDiskState.InitialCommonLogReadError]: 5,
38
- [TPDiskState.InitialCommonLogParseError]: 5,
39
- [TPDiskState.CommonLoggerInitError]: 5,
40
- [TPDiskState.OpenFileError]: 5,
41
- [TPDiskState.ChunkQuotaError]: 5,
42
- [TPDiskState.DeviceIoError]: 5,
43
- };
44
-
45
- type PDiskProps = RequiredField<TPDiskStateInfo, 'NodeId'>;
46
-
47
- const isSeverityKey = (key?: TPDiskState): key is keyof typeof stateSeverity =>
48
- key !== undefined && key in stateSeverity;
49
-
50
- const getStateSeverity = (pDiskState?: TPDiskState) => {
51
- return isSeverityKey(pDiskState) ? stateSeverity[pDiskState] : NOT_AVAILABLE_SEVERITY;
52
- };
53
-
54
- function Pdisk(props: PDiskProps) {
55
- const [severity, setSeverity] = useState(getStateSeverity(props.State));
56
- const [isPopupVisible, setIsPopupVisible] = useState(false);
57
-
58
- const anchor = useRef(null);
59
-
60
- useEffect(() => {
61
- const newSeverity = getStateSeverity(props.State);
62
- if (severity !== newSeverity) {
63
- setSeverity(newSeverity);
64
- }
65
- }, [props.State]);
66
-
67
- const showPopup = () => {
68
- setIsPopupVisible(true);
69
- };
70
-
71
- const hidePopup = () => {
72
- setIsPopupVisible(false);
73
- };
74
- /* eslint-disable */
75
- const preparePdiskData = () => {
76
- const {AvailableSize, TotalSize, State, PDiskId, NodeId, Path, Realtime, Device} = props;
77
- const errorColors = [
78
- diskProgressColors[colorSeverity.Orange as keyof typeof diskProgressColors],
79
- diskProgressColors[colorSeverity.Red as keyof typeof diskProgressColors],
80
- diskProgressColors[colorSeverity.Yellow as keyof typeof diskProgressColors],
81
- ];
82
-
83
- const pdiskData: {label: string; value: string | number}[] = [
84
- {label: 'PDisk', value: getPDiskId({NodeId, PDiskId})},
85
- ];
86
-
87
- pdiskData.push({label: 'State', value: State || 'not available'});
88
- pdiskData.push({label: 'Type', value: getPDiskType(props) || 'unknown'});
89
- NodeId && pdiskData.push({label: 'Node Id', value: NodeId});
90
-
91
- Path && pdiskData.push({label: 'Path', value: Path});
92
- pdiskData.push({
93
- label: 'Available',
94
- value: `${bytesToGB(AvailableSize)} of ${bytesToGB(TotalSize)}`,
95
- });
96
- Realtime &&
97
- errorColors.includes(Realtime) &&
98
- pdiskData.push({label: 'Realtime', value: Realtime});
99
- Device && errorColors.includes(Device) && pdiskData.push({label: 'Device', value: Device});
100
- return pdiskData;
101
- };
102
- /* eslint-enable */
103
-
104
- const renderPopup = () => (
105
- <Popup
106
- className={b('popup-wrapper')}
107
- anchorRef={anchor}
108
- open={isPopupVisible}
109
- placement={['top', 'bottom']}
110
- // bigger offset for easier switching to neighbour nodes
111
- // matches the default offset for popup with arrow out of a sense of beauty
112
- offset={[0, 12]}
113
- >
114
- <InfoViewer title="PDisk" info={preparePdiskData()} size="s" />
115
- </Popup>
116
- );
117
-
118
- const pdiskAllocatedPercent = useMemo(() => {
119
- const {AvailableSize, TotalSize} = props;
120
-
121
- if (!AvailableSize || !TotalSize) {
122
- return undefined;
123
- }
124
-
125
- return !isNaN(Number(AvailableSize)) && !isNaN(Number(TotalSize))
126
- ? Math.round(((Number(TotalSize) - Number(AvailableSize)) * 100) / Number(TotalSize))
127
- : undefined;
128
- }, [props.AvailableSize, props.TotalSize]);
129
-
130
- return (
131
- <React.Fragment>
132
- {renderPopup()}
133
- <div className={b()} ref={anchor} onMouseEnter={showPopup} onMouseLeave={hidePopup}>
134
- <InternalLink
135
- to={createHref(
136
- routes.node,
137
- {id: props.NodeId, activeTab: STRUCTURE},
138
- {pdiskId: props.PDiskId || ''},
139
- )}
140
- className={b('content')}
141
- >
142
- <DiskStateProgressBar
143
- diskAllocatedPercent={pdiskAllocatedPercent}
144
- severity={severity as keyof typeof diskProgressColors}
145
- />
146
- <div className={b('media-type')}>{getPDiskType(props)}</div>
147
- </InternalLink>
148
- </div>
149
- </React.Fragment>
150
- );
151
- }
152
-
153
- export default Pdisk;
@@ -1,41 +0,0 @@
1
- import {MemoryRouter} from 'react-router-dom';
2
-
3
- import {renderWithStore} from '../../../../utils/tests/providers';
4
-
5
- import {TPDiskState} from '../../../../types/api/pdisk'
6
-
7
- import PDisk from '../Pdisk'
8
-
9
- describe('PDisk state', () => {
10
- it('Should determine severity based on State', () => {
11
- const {getAllByRole} = renderWithStore(
12
- <MemoryRouter>
13
- <PDisk
14
- NodeId={1}
15
- State={TPDiskState.Normal}
16
- />
17
- <PDisk
18
- NodeId={2}
19
- State={TPDiskState.ChunkQuotaError}
20
- />
21
- </MemoryRouter>
22
- );
23
-
24
- const [normalDisk, erroredDisk] = getAllByRole('meter');
25
-
26
- expect(normalDisk.className).not.toBe(erroredDisk.className);
27
- });
28
-
29
- it('Should display as unavailabe when no State is provided', () => {
30
- const {getByRole} = renderWithStore(
31
- <MemoryRouter>
32
- <PDisk NodeId={1} />
33
- </MemoryRouter>
34
- );
35
-
36
- const disk = getByRole('meter');
37
-
38
- // unavailable disks display with the highest severity
39
- expect(disk.className).toMatch(/_red\b/i);
40
- });
41
- });