ydb-embedded-ui 3.3.4 → 3.4.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.
- package/CHANGELOG.md +19 -0
- package/dist/components/Errors/ResponseError/ResponseError.tsx +2 -2
- package/dist/components/InfoViewer/formatters/topicStats.tsx +8 -29
- package/dist/components/LabelWithPopover/LabelWithPopover.tsx +20 -0
- package/dist/components/LabelWithPopover/index.ts +1 -0
- package/dist/components/LagImages/LagImages.tsx +205 -0
- package/dist/components/LagImages/index.ts +1 -0
- package/dist/components/SpeedMultiMeter/SpeedMultiMeter.scss +92 -0
- package/dist/components/SpeedMultiMeter/SpeedMultiMeter.tsx +120 -0
- package/dist/components/SpeedMultiMeter/i18n/en.json +6 -0
- package/dist/components/SpeedMultiMeter/i18n/index.ts +13 -0
- package/dist/components/SpeedMultiMeter/i18n/ru.json +6 -0
- package/dist/components/SpeedMultiMeter/index.ts +1 -0
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +18 -14
- package/dist/containers/Storage/VDisk/VDisk.tsx +20 -5
- package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +34 -5
- package/dist/containers/Storage/utils/types.ts +5 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.scss +32 -3
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +62 -69
- package/dist/containers/Tenant/Diagnostics/Consumers/Headers/Headers.scss +13 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Headers/Headers.tsx +27 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Headers/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.scss +32 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.tsx +43 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/TopicStats/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/columns/Columns.scss +5 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +66 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/columns/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/en.json +4 -3
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/ru.json +4 -3
- package/dist/containers/Tenant/Diagnostics/Consumers/utils/constants.ts +23 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +4 -0
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +8 -2
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.scss +9 -1
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +6 -8
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/Headers.scss +33 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/Headers.tsx +76 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/Headers/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/Partitions.scss +45 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/Partitions.tsx +254 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/PartitionsWrapper.tsx +79 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/columns/Columns.scss +13 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/columns/columns.tsx +246 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/columns/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/i18n/en.json +13 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/i18n/ru.json +13 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/utils/constants.ts +74 -0
- package/dist/containers/Tenant/Diagnostics/Partitions/utils/types.ts +6 -0
- package/dist/containers/Tenant/utils/schema.ts +1 -16
- package/dist/services/api.d.ts +4 -0
- package/dist/services/api.js +22 -6
- package/dist/store/reducers/consumer.ts +160 -0
- package/dist/store/reducers/index.ts +2 -0
- package/dist/store/reducers/settings.js +2 -0
- package/dist/store/reducers/topic.ts +82 -2
- package/dist/types/store/consumer.ts +55 -0
- package/dist/types/store/topic.ts +23 -6
- package/dist/utils/bytesParsers/convertBytesObjectToSpeed.ts +24 -0
- package/dist/utils/bytesParsers/formatBytesCustom.ts +57 -0
- package/dist/utils/bytesParsers/i18n/en.json +7 -0
- package/dist/utils/bytesParsers/i18n/index.ts +11 -0
- package/dist/utils/bytesParsers/i18n/ru.json +7 -0
- package/dist/utils/bytesParsers/index.ts +2 -0
- package/dist/utils/constants.ts +3 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/storage.ts +2 -2
- package/dist/utils/timeParsers/index.ts +2 -1
- package/dist/utils/timeParsers/parsers.ts +18 -0
- package/dist/utils/timeParsers/{protobuf.ts → protobufParsers.ts} +0 -0
- package/dist/utils/utils.js +3 -3
- package/package.json +2 -2
@@ -1,16 +1,28 @@
|
|
1
|
+
/* eslint-disable camelcase */
|
1
2
|
import type {Reducer} from 'redux';
|
3
|
+
import {createSelector, Selector} from 'reselect';
|
2
4
|
|
3
|
-
import type {
|
5
|
+
import type {
|
6
|
+
IPreparedConsumerData,
|
7
|
+
IPreparedTopicStats,
|
8
|
+
ITopicAction,
|
9
|
+
ITopicRootStateSlice,
|
10
|
+
ITopicState,
|
11
|
+
} from '../../types/store/topic';
|
4
12
|
import '../../services/api';
|
5
13
|
|
6
14
|
import {createRequestActionTypes, createApiRequest} from '../utils';
|
15
|
+
import {parseLag, parseTimestampToIdleTime} from '../../utils/timeParsers';
|
16
|
+
import {convertBytesObjectToSpeed} from '../../utils/bytesParsers';
|
7
17
|
|
8
18
|
export const FETCH_TOPIC = createRequestActionTypes('topic', 'FETCH_TOPIC');
|
9
19
|
|
20
|
+
const SET_DATA_WAS_NOT_LOADED = 'topic/SET_DATA_WAS_NOT_LOADED';
|
21
|
+
|
10
22
|
const initialState = {
|
11
23
|
loading: true,
|
12
24
|
wasLoaded: false,
|
13
|
-
data:
|
25
|
+
data: undefined,
|
14
26
|
};
|
15
27
|
|
16
28
|
const topic: Reducer<ITopicState, ITopicAction> = (state = initialState, action) => {
|
@@ -22,6 +34,11 @@ const topic: Reducer<ITopicState, ITopicAction> = (state = initialState, action)
|
|
22
34
|
};
|
23
35
|
}
|
24
36
|
case FETCH_TOPIC.SUCCESS: {
|
37
|
+
// On older version it can return HTML page of Internal Viewer with an error
|
38
|
+
if (typeof action.data !== 'object') {
|
39
|
+
return {...state, loading: false, error: {}};
|
40
|
+
}
|
41
|
+
|
25
42
|
return {
|
26
43
|
...state,
|
27
44
|
data: action.data,
|
@@ -31,17 +48,33 @@ const topic: Reducer<ITopicState, ITopicAction> = (state = initialState, action)
|
|
31
48
|
};
|
32
49
|
}
|
33
50
|
case FETCH_TOPIC.FAILURE: {
|
51
|
+
if (action.error?.isCancelled) {
|
52
|
+
return state;
|
53
|
+
}
|
54
|
+
|
34
55
|
return {
|
35
56
|
...state,
|
36
57
|
error: action.error,
|
37
58
|
loading: false,
|
38
59
|
};
|
39
60
|
}
|
61
|
+
case SET_DATA_WAS_NOT_LOADED: {
|
62
|
+
return {
|
63
|
+
...state,
|
64
|
+
wasLoaded: false,
|
65
|
+
};
|
66
|
+
}
|
40
67
|
default:
|
41
68
|
return state;
|
42
69
|
}
|
43
70
|
};
|
44
71
|
|
72
|
+
export const setDataWasNotLoaded = () => {
|
73
|
+
return {
|
74
|
+
type: SET_DATA_WAS_NOT_LOADED,
|
75
|
+
} as const;
|
76
|
+
};
|
77
|
+
|
45
78
|
export function getTopic(path?: string) {
|
46
79
|
return createApiRequest({
|
47
80
|
request: window.api.getTopic({path}),
|
@@ -49,4 +82,51 @@ export function getTopic(path?: string) {
|
|
49
82
|
});
|
50
83
|
}
|
51
84
|
|
85
|
+
const selectTopicStats = (state: ITopicRootStateSlice) => state.topic.data?.topic_stats;
|
86
|
+
const selectConsumers = (state: ITopicRootStateSlice) => state.topic.data?.consumers;
|
87
|
+
|
88
|
+
export const selectPreparedTopicStats: Selector<
|
89
|
+
ITopicRootStateSlice,
|
90
|
+
IPreparedTopicStats | undefined
|
91
|
+
> = createSelector([selectTopicStats], (rawTopicStats) => {
|
92
|
+
if (!rawTopicStats) {
|
93
|
+
return undefined;
|
94
|
+
}
|
95
|
+
|
96
|
+
const {
|
97
|
+
store_size_bytes = '0',
|
98
|
+
min_last_write_time,
|
99
|
+
max_write_time_lag,
|
100
|
+
bytes_written,
|
101
|
+
} = rawTopicStats || {};
|
102
|
+
|
103
|
+
return {
|
104
|
+
storeSize: store_size_bytes,
|
105
|
+
partitionsIdleTime: parseTimestampToIdleTime(min_last_write_time),
|
106
|
+
partitionsWriteLag: parseLag(max_write_time_lag),
|
107
|
+
writeSpeed: convertBytesObjectToSpeed(bytes_written),
|
108
|
+
};
|
109
|
+
});
|
110
|
+
|
111
|
+
export const selectPreparedConsumersData: Selector<
|
112
|
+
ITopicRootStateSlice,
|
113
|
+
IPreparedConsumerData[] | undefined
|
114
|
+
> = createSelector([selectConsumers], (consumers) => {
|
115
|
+
return consumers?.map((consumer) => {
|
116
|
+
const {name, consumer_stats} = consumer || {};
|
117
|
+
|
118
|
+
const {min_partitions_last_read_time, max_read_time_lag, max_write_time_lag, bytes_read} =
|
119
|
+
consumer_stats || {};
|
120
|
+
|
121
|
+
return {
|
122
|
+
name,
|
123
|
+
readSpeed: convertBytesObjectToSpeed(bytes_read),
|
124
|
+
|
125
|
+
writeLag: parseLag(max_write_time_lag),
|
126
|
+
readLag: parseLag(max_read_time_lag),
|
127
|
+
readIdleTime: parseTimestampToIdleTime(min_partitions_last_read_time),
|
128
|
+
};
|
129
|
+
});
|
130
|
+
});
|
131
|
+
|
52
132
|
export default topic;
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import type {IProcessSpeedStats} from '../../utils/bytesParsers';
|
2
|
+
import type {ApiRequestAction} from '../../store/utils';
|
3
|
+
|
4
|
+
import {FETCH_CONSUMER, setDataWasNotLoaded} from '../../store/reducers/consumer';
|
5
|
+
|
6
|
+
import type {DescribeConsumerResult} from '../api/consumer';
|
7
|
+
import type {IResponseError} from '../api/error';
|
8
|
+
|
9
|
+
// All fields should be present though they could be undefined
|
10
|
+
export interface IPreparedPartitionData {
|
11
|
+
partitionId: string;
|
12
|
+
storeSize: string;
|
13
|
+
|
14
|
+
writeSpeed: IProcessSpeedStats;
|
15
|
+
readSpeed: IProcessSpeedStats;
|
16
|
+
|
17
|
+
partitionWriteLag: number;
|
18
|
+
partitionWriteIdleTime: number;
|
19
|
+
|
20
|
+
consumerWriteLag: number;
|
21
|
+
consumerReadLag: number;
|
22
|
+
consumerReadIdleTime: number;
|
23
|
+
|
24
|
+
uncommitedMessages: number;
|
25
|
+
unreadMessages: number;
|
26
|
+
|
27
|
+
startOffset: string;
|
28
|
+
endOffset: string;
|
29
|
+
commitedOffset: string;
|
30
|
+
|
31
|
+
readSessionId: string | undefined;
|
32
|
+
readerName: string | undefined;
|
33
|
+
|
34
|
+
partitionNodeId: number;
|
35
|
+
connectionNodeId: number;
|
36
|
+
}
|
37
|
+
|
38
|
+
export interface IConsumerState {
|
39
|
+
loading: boolean;
|
40
|
+
wasLoaded: boolean;
|
41
|
+
data?: DescribeConsumerResult;
|
42
|
+
error?: IResponseError;
|
43
|
+
}
|
44
|
+
|
45
|
+
type IConsumerApiRequestAction = ApiRequestAction<
|
46
|
+
typeof FETCH_CONSUMER,
|
47
|
+
DescribeConsumerResult,
|
48
|
+
IResponseError
|
49
|
+
>;
|
50
|
+
|
51
|
+
export type IConsumerAction = IConsumerApiRequestAction | ReturnType<typeof setDataWasNotLoaded>;
|
52
|
+
|
53
|
+
export interface IConsumerRootStateSlice {
|
54
|
+
consumer: IConsumerState;
|
55
|
+
}
|
@@ -1,8 +1,27 @@
|
|
1
|
-
import {FETCH_TOPIC} from '../../store/reducers/topic';
|
1
|
+
import {FETCH_TOPIC, setDataWasNotLoaded} from '../../store/reducers/topic';
|
2
2
|
import type {ApiRequestAction} from '../../store/utils';
|
3
|
+
import type {IProcessSpeedStats} from '../../utils/bytesParsers';
|
3
4
|
import type {IResponseError} from '../api/error';
|
4
5
|
import type {DescribeTopicResult} from '../api/topic';
|
5
6
|
|
7
|
+
export interface IPreparedConsumerData {
|
8
|
+
name: string | undefined;
|
9
|
+
readSpeed: IProcessSpeedStats;
|
10
|
+
|
11
|
+
writeLag: number;
|
12
|
+
readLag: number;
|
13
|
+
readIdleTime: number;
|
14
|
+
}
|
15
|
+
|
16
|
+
export interface IPreparedTopicStats {
|
17
|
+
storeSize: string;
|
18
|
+
|
19
|
+
partitionsWriteLag: number;
|
20
|
+
partitionsIdleTime: number;
|
21
|
+
|
22
|
+
writeSpeed: IProcessSpeedStats;
|
23
|
+
}
|
24
|
+
|
6
25
|
export interface ITopicState {
|
7
26
|
loading: boolean;
|
8
27
|
wasLoaded: boolean;
|
@@ -10,11 +29,9 @@ export interface ITopicState {
|
|
10
29
|
error?: IResponseError;
|
11
30
|
}
|
12
31
|
|
13
|
-
export type ITopicAction =
|
14
|
-
typeof FETCH_TOPIC,
|
15
|
-
|
16
|
-
IResponseError
|
17
|
-
>;
|
32
|
+
export type ITopicAction =
|
33
|
+
| ApiRequestAction<typeof FETCH_TOPIC, DescribeTopicResult, IResponseError>
|
34
|
+
| ReturnType<typeof setDataWasNotLoaded>;
|
18
35
|
|
19
36
|
export interface ITopicRootStateSlice {
|
20
37
|
topic: ITopicState;
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import type {MultipleWindowsStat} from '../../types/api/consumer';
|
2
|
+
|
3
|
+
import {DAY_IN_SECONDS, HOUR_IN_SECONDS, MINUTE_IN_SECONDS} from '../constants';
|
4
|
+
|
5
|
+
export interface IProcessSpeedStats {
|
6
|
+
perMinute: number;
|
7
|
+
perHour: number;
|
8
|
+
perDay: number;
|
9
|
+
}
|
10
|
+
|
11
|
+
/**
|
12
|
+
* Convert data of type MultipleWindowsStat.
|
13
|
+
* This data format is specific for describe_topic and describe_consumer endpoints
|
14
|
+
*/
|
15
|
+
export const convertBytesObjectToSpeed = (
|
16
|
+
data: MultipleWindowsStat | undefined,
|
17
|
+
): IProcessSpeedStats => {
|
18
|
+
return {
|
19
|
+
perMinute:
|
20
|
+
data && data.per_minute ? Math.round(Number(data.per_minute) / MINUTE_IN_SECONDS) : 0,
|
21
|
+
perHour: data && data.per_hour ? Math.round(Number(data.per_hour) / HOUR_IN_SECONDS) : 0,
|
22
|
+
perDay: data && data.per_day ? Math.round(Number(data.per_day) / DAY_IN_SECONDS) : 0,
|
23
|
+
};
|
24
|
+
};
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import {GIGABYTE, KILOBYTE, MEGABYTE} from '../constants';
|
2
|
+
import {isNumeric} from '../utils';
|
3
|
+
|
4
|
+
import i18n from './i18n';
|
5
|
+
|
6
|
+
const sizes = {
|
7
|
+
b: {
|
8
|
+
value: 1,
|
9
|
+
label: i18n('b'),
|
10
|
+
},
|
11
|
+
kb: {
|
12
|
+
value: KILOBYTE,
|
13
|
+
label: i18n('kb'),
|
14
|
+
},
|
15
|
+
mb: {
|
16
|
+
value: MEGABYTE,
|
17
|
+
label: i18n('mb'),
|
18
|
+
},
|
19
|
+
gb: {
|
20
|
+
value: GIGABYTE,
|
21
|
+
label: i18n('gb'),
|
22
|
+
},
|
23
|
+
};
|
24
|
+
|
25
|
+
export type IBytesSizes = keyof typeof sizes;
|
26
|
+
|
27
|
+
interface FormatBytesArgs {
|
28
|
+
value: number | string | undefined;
|
29
|
+
size?: IBytesSizes;
|
30
|
+
precision?: number;
|
31
|
+
withLabel?: boolean;
|
32
|
+
isSpeed?: boolean;
|
33
|
+
}
|
34
|
+
|
35
|
+
export const formatBytesCustom = ({
|
36
|
+
value,
|
37
|
+
size = 'mb',
|
38
|
+
precision = 0,
|
39
|
+
withLabel = true,
|
40
|
+
isSpeed = false,
|
41
|
+
}: FormatBytesArgs) => {
|
42
|
+
if (!isNumeric(value)) {
|
43
|
+
return '';
|
44
|
+
}
|
45
|
+
|
46
|
+
let result = (Number(value) / sizes[size].value).toFixed(precision);
|
47
|
+
|
48
|
+
if (withLabel) {
|
49
|
+
result += ` ${sizes[size].label}`;
|
50
|
+
|
51
|
+
if (isSpeed) {
|
52
|
+
result += i18n('perSecond');
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
return result;
|
57
|
+
};
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import {i18n, Lang} from '../../i18n';
|
2
|
+
|
3
|
+
import en from './en.json';
|
4
|
+
import ru from './ru.json';
|
5
|
+
|
6
|
+
const COMPONENT = 'ydb-bytes-parsers';
|
7
|
+
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
+
|
11
|
+
export default i18n.keyset(COMPONENT);
|
package/dist/utils/constants.ts
CHANGED
@@ -9,6 +9,7 @@ export const AUTO_RELOAD_INTERVAL = 10 * SECOND;
|
|
9
9
|
// by agreement, display all byte values in decimal scale
|
10
10
|
// values in data are always in bytes, never in higher units,
|
11
11
|
// therefore there is no issue arbitrary converting them in UI
|
12
|
+
export const KILOBYTE = 1_000;
|
12
13
|
export const MEGABYTE = 1_000_000;
|
13
14
|
export const GIGABYTE = 1_000_000_000;
|
14
15
|
export const TERABYTE = 1_000_000_000_000;
|
@@ -118,3 +119,5 @@ export const DEFAULT_TABLE_SETTINGS = {
|
|
118
119
|
|
119
120
|
export const TENANT_INITIAL_TAB_KEY = 'saved_tenant_initial_tab';
|
120
121
|
export const QUERY_INITIAL_RUN_ACTION_KEY = 'query_initial_run_action';
|
122
|
+
|
123
|
+
export const PARTITIONS_SELECTED_COLUMNS_KEY = 'partitionsSelectedColumns';
|
package/dist/utils/index.js
CHANGED
@@ -9,6 +9,8 @@ import {isNumeric} from './utils';
|
|
9
9
|
|
10
10
|
numeral.locale(i18n.lang);
|
11
11
|
|
12
|
+
// Here you can't control displayed size and precision
|
13
|
+
// If you need more custom format, use formatBytesCustom instead
|
12
14
|
export const formatBytes = (bytes) => {
|
13
15
|
if (!isNumeric(bytes)) {
|
14
16
|
return '';
|
@@ -42,6 +44,10 @@ export const formatUptime = (seconds) => {
|
|
42
44
|
return uptime;
|
43
45
|
};
|
44
46
|
|
47
|
+
export const formatMsToUptime = (ms) => {
|
48
|
+
return formatUptime(ms / 1000);
|
49
|
+
};
|
50
|
+
|
45
51
|
export const formatIOPS = (value, capacity) => {
|
46
52
|
return [Math.floor(value), Math.floor(capacity) + ' IOPS'];
|
47
53
|
};
|
package/dist/utils/storage.ts
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
import type {TVSlotId, TVDiskStateInfo} from '../types/api/vdisk';
|
2
2
|
import type {IStoragePoolGroup} from '../types/store/storage';
|
3
3
|
|
4
|
-
export const
|
5
|
-
'VDiskId' in
|
4
|
+
export const isFullVDiksData = (disk: TVDiskStateInfo | TVSlotId): disk is TVDiskStateInfo =>
|
5
|
+
'VDiskId' in disk;
|
6
6
|
|
7
7
|
export const getUsage = (data: IStoragePoolGroup, step = 1) => {
|
8
8
|
// if limit is 0, display 0
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import type {IProtobufTimeObject} from '../../types/api/common';
|
2
|
+
|
3
|
+
import {parseProtobufDurationToMs, parseProtobufTimestampToMs} from '.';
|
4
|
+
|
5
|
+
export const parseLag = (value: string | IProtobufTimeObject | undefined) =>
|
6
|
+
value ? parseProtobufDurationToMs(value) : 0;
|
7
|
+
|
8
|
+
export const parseTimestampToIdleTime = (value: string | IProtobufTimeObject | undefined) => {
|
9
|
+
if (!value) {
|
10
|
+
return 0;
|
11
|
+
}
|
12
|
+
|
13
|
+
const duration = Date.now() - parseProtobufTimestampToMs(value);
|
14
|
+
|
15
|
+
// Duration could be negative because of the difference between server and local time
|
16
|
+
// Usually it below 100ms, so it could be omitted
|
17
|
+
return duration < 0 ? 0 : duration;
|
18
|
+
};
|
File without changes
|
package/dist/utils/utils.js
CHANGED
@@ -76,9 +76,9 @@ export function bytesToGB(bytes, shouldRound) {
|
|
76
76
|
|
77
77
|
export function pad9(val) {
|
78
78
|
const len = String(val).length;
|
79
|
-
let result = val
|
79
|
+
let result = val;
|
80
80
|
for (let i = len; i < 9; i++) {
|
81
|
-
result =
|
81
|
+
result = '0' + result;
|
82
82
|
}
|
83
83
|
return result;
|
84
84
|
}
|
@@ -88,4 +88,4 @@ export function isNumeric(value) {
|
|
88
88
|
// - isNaN treats true/false/''/etc. as numbers, parseFloat fixes this
|
89
89
|
// - parseFloat treats '123qwe' as number, isNaN fixes this
|
90
90
|
return !isNaN(value) && !isNaN(parseFloat(value));
|
91
|
-
}
|
91
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "ydb-embedded-ui",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.4.0",
|
4
4
|
"files": [
|
5
5
|
"dist"
|
6
6
|
],
|
@@ -39,7 +39,7 @@
|
|
39
39
|
"reselect": "4.1.6",
|
40
40
|
"sass": "1.32.8",
|
41
41
|
"web-vitals": "1.1.2",
|
42
|
-
"ydb-ui-components": "^3.0.
|
42
|
+
"ydb-ui-components": "^3.0.3"
|
43
43
|
},
|
44
44
|
"scripts": {
|
45
45
|
"start": "react-app-rewired start",
|