ydb-embedded-ui 3.2.2 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +27 -0
- package/dist/components/InfoViewer/InfoViewer.scss +10 -0
- package/dist/components/InfoViewer/InfoViewer.tsx +12 -2
- package/dist/components/InfoViewer/formatters/cdcStream.ts +10 -0
- package/dist/components/InfoViewer/formatters/index.ts +3 -0
- package/dist/components/InfoViewer/formatters/pqGroup.ts +51 -0
- package/dist/components/InfoViewer/formatters/schema.ts +1 -29
- package/dist/components/InfoViewer/formatters/topicStats.tsx +50 -0
- package/dist/components/InfoViewer/schemaInfo/index.ts +0 -2
- package/dist/components/InfoViewer/utils.ts +15 -0
- package/dist/components/InternalLink/InternalLink.tsx +17 -0
- package/dist/components/InternalLink/index.ts +1 -0
- package/dist/components/Tablet/Tablet.js +1 -1
- package/dist/components/TabletsStatistic/TabletsStatistic.tsx +1 -1
- package/dist/components/VerticalBars/VerticalBars.scss +15 -0
- package/dist/components/VerticalBars/VerticalBars.tsx +38 -0
- package/dist/components/VerticalBars/index.ts +1 -0
- package/dist/containers/App/App.js +0 -11
- package/dist/containers/App/App.scss +0 -1
- package/dist/containers/Cluster/Cluster.tsx +2 -2
- package/dist/containers/Nodes/Nodes.scss +5 -1
- package/dist/containers/Nodes/Nodes.tsx +196 -0
- package/dist/containers/{App → Nodes}/NodesTable.scss +2 -2
- package/dist/{utils/getNodesColumns.js → containers/Nodes/getNodesColumns.tsx} +60 -35
- package/dist/containers/Nodes/i18n/en.json +3 -0
- package/dist/containers/Nodes/i18n/index.ts +11 -0
- package/dist/containers/Nodes/i18n/ru.json +3 -0
- package/dist/containers/Nodes/index.ts +1 -0
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +14 -20
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +32 -16
- package/dist/containers/Storage/DiskStateProgressBar/index.ts +1 -0
- package/dist/containers/Storage/{Pdisk/Pdisk.scss → PDisk/PDisk.scss} +15 -4
- package/dist/containers/Storage/PDisk/PDisk.tsx +145 -0
- package/dist/containers/Storage/PDisk/__tests__/colors.tsx +37 -0
- package/dist/containers/Storage/PDisk/index.ts +1 -0
- package/dist/containers/Storage/PDiskPopup/PDiskPopup.scss +3 -0
- package/dist/containers/Storage/PDiskPopup/PDiskPopup.tsx +82 -0
- package/dist/containers/Storage/PDiskPopup/index.ts +1 -0
- package/dist/containers/Storage/Storage.js +1 -1
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +10 -10
- package/dist/containers/Storage/StorageNodes/StorageNodes.scss +1 -0
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -4
- package/dist/containers/Storage/VDisk/VDisk.scss +7 -0
- package/dist/containers/Storage/VDisk/VDisk.tsx +148 -0
- package/dist/containers/Storage/VDisk/__tests__/colors.tsx +209 -0
- package/dist/containers/Storage/VDisk/index.ts +1 -0
- package/dist/containers/Storage/VDiskPopup/VDiskPopup.scss +14 -0
- package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +134 -0
- package/dist/containers/Storage/VDiskPopup/index.ts +1 -0
- package/dist/containers/Storage/utils/constants.ts +2 -9
- package/dist/containers/TabletsFilters/TabletsFilters.js +10 -6
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +2 -1
- package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +2 -2
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -4
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/OverloadedShards.tsx +1 -1
- package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/ChangefeedInfo.tsx +69 -0
- package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +18 -16
- package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/TopicInfo.tsx +37 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.scss +30 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +94 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/en.json +3 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/ru.json +3 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/utils/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +42 -0
- package/dist/containers/Tenant/utils/schema.ts +19 -0
- package/dist/containers/Tenants/Tenants.js +2 -1
- package/dist/containers/UserSettings/UserSettings.tsx +18 -10
- package/dist/services/api.d.ts +8 -1
- package/dist/services/api.js +27 -8
- package/dist/store/reducers/index.ts +3 -1
- package/dist/store/reducers/nodes.ts +148 -14
- package/dist/store/reducers/{clusterNodes.js → nodesList.js} +0 -41
- package/dist/store/reducers/settings.js +10 -4
- package/dist/store/reducers/storage.js +24 -13
- package/dist/store/reducers/tenant.js +5 -4
- package/dist/store/reducers/tooltip.ts +1 -1
- package/dist/store/reducers/topic.ts +52 -0
- package/dist/styles/mixins.scss +19 -11
- package/dist/types/api/common.ts +5 -0
- package/dist/types/api/compute.ts +1 -1
- package/dist/types/api/consumer.ts +12 -10
- package/dist/types/api/nodes.ts +2 -0
- package/dist/types/api/pdisk.ts +1 -0
- package/dist/types/api/schema.ts +3 -3
- package/dist/types/api/topic.ts +5 -4
- package/dist/types/api/vdisk.ts +2 -1
- package/dist/types/store/nodes.ts +56 -6
- package/dist/types/store/tooltip.ts +1 -1
- package/dist/types/store/topic.ts +21 -0
- package/dist/utils/constants.ts +5 -1
- package/dist/utils/i18n/i18n.ts +10 -2
- package/dist/utils/index.js +1 -1
- package/dist/utils/timeParsers/__test__/formatDuration.test.ts +50 -0
- package/dist/utils/timeParsers/__test__/protobuf.test.ts +74 -0
- package/dist/utils/timeParsers/formatDuration.ts +46 -0
- package/dist/utils/timeParsers/i18n/en.json +7 -0
- package/dist/utils/timeParsers/i18n/index.ts +11 -0
- package/dist/utils/timeParsers/i18n/ru.json +7 -0
- package/dist/utils/timeParsers/index.ts +2 -0
- package/dist/utils/timeParsers/protobuf.ts +36 -0
- package/package.json +1 -1
- package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +0 -48
- package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +0 -30
- package/dist/components/InternalLink/InternalLink.js +0 -23
- package/dist/containers/Nodes/Nodes.js +0 -213
- package/dist/containers/NodesViewer/NodesViewer.js +0 -163
- package/dist/containers/NodesViewer/NodesViewer.scss +0 -66
- package/dist/containers/Storage/Pdisk/Pdisk.tsx +0 -153
- package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +0 -41
- package/dist/containers/Storage/Vdisk/Vdisk.js +0 -275
- package/dist/containers/Storage/Vdisk/Vdisk.scss +0 -22
- package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +0 -163
- package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +0 -139
- package/dist/containers/Tenant/Diagnostics/Compute/Compute.scss +0 -14
package/dist/types/api/schema.ts
CHANGED
@@ -479,7 +479,7 @@ interface TKeyComponentSchema {
|
|
479
479
|
TypeId?: number;
|
480
480
|
}
|
481
481
|
|
482
|
-
enum EMeteringMode {
|
482
|
+
export enum EMeteringMode {
|
483
483
|
METERING_MODE_RESERVED_CAPACITY = 'METERING_MODE_RESERVED_CAPACITY',
|
484
484
|
METERING_MODE_REQUEST_UNITS = 'METERING_MODE_REQUEST_UNITS',
|
485
485
|
}
|
@@ -526,7 +526,7 @@ interface TMirrorPartitionConfig {
|
|
526
526
|
SyncWriteTime?: boolean;
|
527
527
|
}
|
528
528
|
|
529
|
-
interface TPQPartitionConfig {
|
529
|
+
export interface TPQPartitionConfig {
|
530
530
|
MaxCountInPartition?: number;
|
531
531
|
/** int64 */
|
532
532
|
MaxSizeInPartition?: string;
|
@@ -559,7 +559,7 @@ interface TPQPartitionConfig {
|
|
559
559
|
MirrorFrom?: TMirrorPartitionConfig;
|
560
560
|
}
|
561
561
|
|
562
|
-
interface TPQTabletConfig {
|
562
|
+
export interface TPQTabletConfig {
|
563
563
|
/** uint64 */
|
564
564
|
CacheSize?: string;
|
565
565
|
PartitionConfig: TPQPartitionConfig;
|
package/dist/types/api/topic.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
/* eslint-disable camelcase */
|
2
2
|
|
3
|
+
import {IProtobufTimeObject} from './common';
|
3
4
|
import {Consumer, Entry, MultipleWindowsStat, PartitionStats, SupportedCodecs} from './consumer';
|
4
5
|
|
5
6
|
/**
|
@@ -27,7 +28,7 @@ export interface DescribeTopicResult {
|
|
27
28
|
*
|
28
29
|
* How long data in partition should be stored.
|
29
30
|
*/
|
30
|
-
retention_period?: string;
|
31
|
+
retention_period?: string | IProtobufTimeObject;
|
31
32
|
|
32
33
|
/**
|
33
34
|
* int64
|
@@ -98,7 +99,7 @@ interface PartitionInfo {
|
|
98
99
|
partition_stats?: PartitionStats;
|
99
100
|
}
|
100
101
|
|
101
|
-
interface TopicStats {
|
102
|
+
export interface TopicStats {
|
102
103
|
/**
|
103
104
|
* int64
|
104
105
|
*
|
@@ -111,14 +112,14 @@ interface TopicStats {
|
|
111
112
|
*
|
112
113
|
* Minimum of timestamps of last write among all partitions.
|
113
114
|
*/
|
114
|
-
min_last_write_time?: string;
|
115
|
+
min_last_write_time?: string | IProtobufTimeObject;
|
115
116
|
|
116
117
|
/**
|
117
118
|
* google.protobuf.Duration
|
118
119
|
*
|
119
120
|
* Maximum of differences between write timestamp and create timestamp for all messages, written during last minute.
|
120
121
|
*/
|
121
|
-
max_write_time_lag?: string;
|
122
|
+
max_write_time_lag?: string | IProtobufTimeObject;
|
122
123
|
|
123
124
|
/** How much bytes were written statistics. */
|
124
125
|
bytes_written?: MultipleWindowsStat;
|
package/dist/types/api/vdisk.ts
CHANGED
@@ -10,6 +10,7 @@ export interface TVDiskStateInfo {
|
|
10
10
|
CreateTime?: string;
|
11
11
|
/** uint64 */
|
12
12
|
ChangeTime?: string;
|
13
|
+
PDiskId?: number;
|
13
14
|
PDisk?: TPDiskStateInfo;
|
14
15
|
VDiskSlotId?: number;
|
15
16
|
/** uint64 */
|
@@ -113,7 +114,7 @@ interface TRank {
|
|
113
114
|
Flag?: EFlag;
|
114
115
|
}
|
115
116
|
|
116
|
-
enum EVDiskState {
|
117
|
+
export enum EVDiskState {
|
117
118
|
Initial = 'Initial',
|
118
119
|
LocalRecoveryError = 'LocalRecoveryError',
|
119
120
|
SyncGuidRecovery = 'SyncGuidRecovery',
|
@@ -1,30 +1,80 @@
|
|
1
|
+
import type {IResponseError} from '../api/error';
|
2
|
+
import type {TEndpoint, TPoolStats} from '../api/nodes';
|
3
|
+
import type {TTabletStateInfo as TComputeTabletStateInfo} from '../api/compute';
|
4
|
+
import type {TTabletStateInfo as TFullTabletStateInfo} from '../api/tablet';
|
5
|
+
import type {EFlag} from '../api/enums';
|
6
|
+
|
1
7
|
import {NodesUptimeFilterValues} from '../../utils/nodes';
|
2
8
|
import {
|
3
9
|
FETCH_NODES,
|
4
|
-
|
10
|
+
resetNodesState,
|
5
11
|
setDataWasNotLoaded,
|
6
12
|
setNodesUptimeFilter,
|
13
|
+
setSearchValue,
|
7
14
|
} from '../../store/reducers/nodes';
|
8
15
|
import {ApiRequestAction} from '../../store/utils';
|
9
|
-
|
10
|
-
|
16
|
+
|
17
|
+
// Since nodes from different endpoints can have different types,
|
18
|
+
// This type describes fields, that are expected by tables with nodes
|
19
|
+
export interface INodesPreparedEntity {
|
20
|
+
NodeId: number;
|
21
|
+
Host?: string;
|
22
|
+
SystemState?: EFlag;
|
23
|
+
DataCenter?: string;
|
24
|
+
Rack?: string;
|
25
|
+
Version?: string;
|
26
|
+
StartTime?: string;
|
27
|
+
Uptime: string;
|
28
|
+
MemoryUsed?: string;
|
29
|
+
PoolStats?: TPoolStats[];
|
30
|
+
LoadAverage?: number[];
|
31
|
+
Tablets?: TFullTabletStateInfo[] | TComputeTabletStateInfo[];
|
32
|
+
TenantName?: string;
|
33
|
+
Endpoints?: TEndpoint[];
|
34
|
+
}
|
11
35
|
|
12
36
|
export interface INodesState {
|
13
37
|
loading: boolean;
|
14
38
|
wasLoaded: boolean;
|
15
39
|
nodesUptimeFilter: NodesUptimeFilterValues;
|
16
|
-
|
40
|
+
searchValue: string;
|
41
|
+
data?: INodesPreparedEntity[];
|
42
|
+
totalNodes?: number;
|
17
43
|
error?: IResponseError;
|
18
44
|
}
|
19
45
|
|
20
|
-
type
|
46
|
+
type INodesApiRequestNodeType = 'static' | 'dynamic' | 'any';
|
47
|
+
|
48
|
+
// Space - out of space nodes
|
49
|
+
// Missing - nodes with missing disks
|
50
|
+
type INodesApiRequestProblemType = 'missing' | 'space';
|
51
|
+
|
52
|
+
export interface INodesApiRequestParams {
|
53
|
+
tenant?: string;
|
54
|
+
type?: INodesApiRequestNodeType;
|
55
|
+
filter?: INodesApiRequestProblemType;
|
56
|
+
storage?: boolean;
|
57
|
+
tablets?: boolean;
|
58
|
+
}
|
59
|
+
|
60
|
+
export interface INodesHandledResponse {
|
61
|
+
Nodes?: INodesPreparedEntity[];
|
62
|
+
TotalNodes: number;
|
63
|
+
}
|
64
|
+
|
65
|
+
type INodesApiRequestAction = ApiRequestAction<
|
66
|
+
typeof FETCH_NODES,
|
67
|
+
INodesHandledResponse,
|
68
|
+
IResponseError
|
69
|
+
>;
|
21
70
|
|
22
71
|
export type INodesAction =
|
23
72
|
| INodesApiRequestAction
|
24
73
|
| (
|
25
|
-
| ReturnType<typeof clearNodes>
|
26
74
|
| ReturnType<typeof setDataWasNotLoaded>
|
27
75
|
| ReturnType<typeof setNodesUptimeFilter>
|
76
|
+
| ReturnType<typeof setSearchValue>
|
77
|
+
| ReturnType<typeof resetNodesState>
|
28
78
|
);
|
29
79
|
|
30
80
|
export interface INodesRootStateSlice {
|
@@ -11,7 +11,7 @@ export interface ITooltipPositions {
|
|
11
11
|
export interface ITooltipState {
|
12
12
|
toolTipVisible: boolean;
|
13
13
|
positions?: ITooltipPositions;
|
14
|
-
currentHoveredRef?: EventTarget;
|
14
|
+
currentHoveredRef?: EventTarget | null;
|
15
15
|
template: (data: any) => JSX.Element;
|
16
16
|
templateType: ITooltipTemplateType;
|
17
17
|
data?: any;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import {FETCH_TOPIC} from '../../store/reducers/topic';
|
2
|
+
import type {ApiRequestAction} from '../../store/utils';
|
3
|
+
import type {IResponseError} from '../api/error';
|
4
|
+
import type {DescribeTopicResult} from '../api/topic';
|
5
|
+
|
6
|
+
export interface ITopicState {
|
7
|
+
loading: boolean;
|
8
|
+
wasLoaded: boolean;
|
9
|
+
data?: DescribeTopicResult;
|
10
|
+
error?: IResponseError;
|
11
|
+
}
|
12
|
+
|
13
|
+
export type ITopicAction = ApiRequestAction<
|
14
|
+
typeof FETCH_TOPIC,
|
15
|
+
DescribeTopicResult,
|
16
|
+
IResponseError
|
17
|
+
>;
|
18
|
+
|
19
|
+
export interface ITopicRootStateSlice {
|
20
|
+
topic: ITopicState;
|
21
|
+
}
|
package/dist/utils/constants.ts
CHANGED
@@ -14,9 +14,12 @@ export const GIGABYTE = 1_000_000_000;
|
|
14
14
|
export const TERABYTE = 1_000_000_000_000;
|
15
15
|
export const GROUP = 'group';
|
16
16
|
|
17
|
-
export const
|
17
|
+
export const MINUTE_IN_SECONDS = 60;
|
18
|
+
export const HOUR_IN_SECONDS = 60 * MINUTE_IN_SECONDS;
|
18
19
|
export const DAY_IN_SECONDS = 24 * HOUR_IN_SECONDS;
|
19
20
|
|
21
|
+
export const MS_IN_NANOSECONDS = 1000000;
|
22
|
+
|
20
23
|
export const TABLET_STATES = {
|
21
24
|
TABLET_VOLATILE_STATE_UNKNOWN: 'unknown',
|
22
25
|
TABLET_VOLATILE_STATE_STOPPED: 'stopped',
|
@@ -89,6 +92,7 @@ export type IProblemFilterValues = typeof ALL | typeof PROBLEMS;
|
|
89
92
|
|
90
93
|
export const THEME_KEY = 'theme';
|
91
94
|
export const INVERTED_DISKS_KEY = 'invertedDisks';
|
95
|
+
export const USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY = 'useNodesEndpointInDiagnostics';
|
92
96
|
export const SAVED_QUERIES_KEY = 'saved_queries';
|
93
97
|
export const ASIDE_HEADER_COMPACT_KEY = 'asideHeaderCompact';
|
94
98
|
export const QUERIES_HISTORY_KEY = 'queries_history';
|
package/dist/utils/i18n/i18n.ts
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
import {I18N} from '@gravity-ui/i18n';
|
2
|
+
import {configure as configureUiKit} from '@gravity-ui/uikit';
|
3
|
+
import {configure as configureYdbUiComponents} from 'ydb-ui-components';
|
2
4
|
|
3
|
-
|
5
|
+
enum Lang {
|
4
6
|
En = 'en',
|
5
7
|
Ru = 'ru',
|
6
8
|
}
|
7
9
|
|
8
|
-
|
10
|
+
const i18n = new I18N();
|
11
|
+
|
12
|
+
i18n.setLang(Lang.En);
|
13
|
+
configureYdbUiComponents({lang: Lang.En});
|
14
|
+
configureUiKit({lang: Lang.En});
|
15
|
+
|
16
|
+
export {i18n, Lang};
|
package/dist/utils/index.js
CHANGED
@@ -2,7 +2,7 @@ import numeral from 'numeral';
|
|
2
2
|
import locales from 'numeral/locales'; // eslint-disable-line no-unused-vars
|
3
3
|
|
4
4
|
import {i18n} from './i18n';
|
5
|
-
import {MEGABYTE, TERABYTE,
|
5
|
+
import {MEGABYTE, TERABYTE, GIGABYTE, DAY_IN_SECONDS} from './constants';
|
6
6
|
import {isNumeric} from './utils';
|
7
7
|
|
8
8
|
numeral.locale(i18n.lang);
|
@@ -0,0 +1,50 @@
|
|
1
|
+
import {formatDurationToShortTimeFormat} from '../formatDuration';
|
2
|
+
import i18n from '../i18n';
|
3
|
+
|
4
|
+
describe('formatDurationToShortTimeFormat', () => {
|
5
|
+
// 1 - ms
|
6
|
+
const timeWithMs = 123;
|
7
|
+
const formattedTimeWithMs = i18n('ms', {seconds: 0, ms: 123});
|
8
|
+
|
9
|
+
// 2 - seconds and ms
|
10
|
+
const timeWithSecondsAndMsInMs = 12345;
|
11
|
+
const formattedTimeWithSecondsAndMs = i18n('secMs', {seconds: 12, ms: 345});
|
12
|
+
|
13
|
+
// 3 - minutes
|
14
|
+
const timeWithMinutesInMs = 754567;
|
15
|
+
const formattedTimeWithMinutes = i18n('minSec', {minutes: 12, seconds: 34});
|
16
|
+
|
17
|
+
// 4 - hours
|
18
|
+
const timeWithHoursInMs = 9245678;
|
19
|
+
const formattedTimeWithHours = i18n('hoursMin', {hours: 2, minutes: 34});
|
20
|
+
|
21
|
+
// 5 - days
|
22
|
+
const timeWithDaysInMs = 439234123;
|
23
|
+
const formattedTimeWithDays = i18n('daysHours', {days: 5, hours: 2});
|
24
|
+
|
25
|
+
// 6 - zero
|
26
|
+
const formattedZero = i18n('ms', {seconds: 0, ms: 0});
|
27
|
+
|
28
|
+
it('should return ms on values less than second', () => {
|
29
|
+
expect(formatDurationToShortTimeFormat(timeWithMs)).toEqual(formattedTimeWithMs);
|
30
|
+
});
|
31
|
+
it('should return seconds and ms', () => {
|
32
|
+
expect(formatDurationToShortTimeFormat(timeWithSecondsAndMsInMs)).toEqual(
|
33
|
+
formattedTimeWithSecondsAndMs,
|
34
|
+
);
|
35
|
+
});
|
36
|
+
it('should return minutes and seconds', () => {
|
37
|
+
expect(formatDurationToShortTimeFormat(timeWithMinutesInMs)).toEqual(
|
38
|
+
formattedTimeWithMinutes,
|
39
|
+
);
|
40
|
+
});
|
41
|
+
it('should return hours and minutes', () => {
|
42
|
+
expect(formatDurationToShortTimeFormat(timeWithHoursInMs)).toEqual(formattedTimeWithHours);
|
43
|
+
});
|
44
|
+
it('should return days and hours', () => {
|
45
|
+
expect(formatDurationToShortTimeFormat(timeWithDaysInMs)).toEqual(formattedTimeWithDays);
|
46
|
+
});
|
47
|
+
it('should process zero values', () => {
|
48
|
+
expect(formatDurationToShortTimeFormat(0)).toEqual(formattedZero);
|
49
|
+
});
|
50
|
+
});
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import {
|
2
|
+
parseProtobufDurationToMs,
|
3
|
+
parseProtobufTimeObjectToMs,
|
4
|
+
parseProtobufTimestampToMs,
|
5
|
+
} from '../';
|
6
|
+
|
7
|
+
describe('Protobuf time parsers', () => {
|
8
|
+
// 1 - nanoseconds only
|
9
|
+
const timeObjectWithNanoseconds = {
|
10
|
+
nanos: 123000000,
|
11
|
+
};
|
12
|
+
const timeWithNanosecondsInMs = 123;
|
13
|
+
|
14
|
+
// 2 - seconds only
|
15
|
+
const timeObjectWithSeconds = {
|
16
|
+
seconds: '12',
|
17
|
+
};
|
18
|
+
const timeWithSecondsInMs = 12000;
|
19
|
+
const stringDurationSeconds = '12s';
|
20
|
+
|
21
|
+
// 3 - days
|
22
|
+
const timeObjectWithDays = {
|
23
|
+
seconds: '439234',
|
24
|
+
nanos: 123000000,
|
25
|
+
};
|
26
|
+
const timeWithDaysInMs = 439234123;
|
27
|
+
|
28
|
+
// 4 - TimeStamp
|
29
|
+
const timestamp = '2023-01-16T14:26:34.466Z';
|
30
|
+
const timestampInMs = 1673879194466;
|
31
|
+
const timestampObject = {
|
32
|
+
seconds: '1673879194',
|
33
|
+
nanos: 466000000,
|
34
|
+
};
|
35
|
+
|
36
|
+
describe('parseProtobufTimeObjectToMs', () => {
|
37
|
+
it('should work with timestamp object values', () => {
|
38
|
+
expect(parseProtobufTimeObjectToMs(timeObjectWithDays)).toEqual(timeWithDaysInMs);
|
39
|
+
});
|
40
|
+
it('should work with timestamp object without seconds', () => {
|
41
|
+
expect(parseProtobufTimeObjectToMs(timeObjectWithNanoseconds)).toEqual(
|
42
|
+
timeWithNanosecondsInMs,
|
43
|
+
);
|
44
|
+
});
|
45
|
+
it('should work with timestamp object without nanos', () => {
|
46
|
+
expect(parseProtobufTimeObjectToMs(timeObjectWithSeconds)).toEqual(timeWithSecondsInMs);
|
47
|
+
});
|
48
|
+
it('should work with empty object values', () => {
|
49
|
+
expect(parseProtobufTimeObjectToMs({})).toEqual(0);
|
50
|
+
});
|
51
|
+
});
|
52
|
+
describe('parseProtobufTimestampToMs', () => {
|
53
|
+
it('should work with string date values', () => {
|
54
|
+
expect(parseProtobufTimestampToMs(timestamp)).toEqual(timestampInMs);
|
55
|
+
});
|
56
|
+
it('should work with timestamp object values', () => {
|
57
|
+
expect(parseProtobufTimestampToMs(timestampObject)).toEqual(timestampInMs);
|
58
|
+
});
|
59
|
+
it('should work with empty object values', () => {
|
60
|
+
expect(parseProtobufTimestampToMs({})).toEqual(0);
|
61
|
+
});
|
62
|
+
});
|
63
|
+
describe('parseProtobufDurationToMs', () => {
|
64
|
+
it('should work with string values', () => {
|
65
|
+
expect(parseProtobufDurationToMs(stringDurationSeconds)).toEqual(timeWithSecondsInMs);
|
66
|
+
});
|
67
|
+
it('should work with duration object values', () => {
|
68
|
+
expect(parseProtobufDurationToMs(timeObjectWithDays)).toEqual(timeWithDaysInMs);
|
69
|
+
});
|
70
|
+
it('should work with empty object values', () => {
|
71
|
+
expect(parseProtobufDurationToMs({})).toEqual(0);
|
72
|
+
});
|
73
|
+
});
|
74
|
+
});
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import {DAY_IN_SECONDS, HOUR_IN_SECONDS} from '../constants';
|
2
|
+
|
3
|
+
import i18n from './i18n';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Process time difference in ms and returns formated time.
|
7
|
+
* Only two major values are returned (days & hours, hours & minutes, minutes & seconds, etc.)
|
8
|
+
*/
|
9
|
+
export const formatDurationToShortTimeFormat = (value: number) => {
|
10
|
+
const ms = value % 1000;
|
11
|
+
let remain = Math.floor(value / 1000);
|
12
|
+
|
13
|
+
const days = Math.floor(remain / DAY_IN_SECONDS);
|
14
|
+
remain = remain % DAY_IN_SECONDS;
|
15
|
+
|
16
|
+
const hours = Math.floor(remain / HOUR_IN_SECONDS);
|
17
|
+
remain = remain % HOUR_IN_SECONDS;
|
18
|
+
|
19
|
+
const minutes = Math.floor(remain / 60);
|
20
|
+
remain = remain % 60;
|
21
|
+
|
22
|
+
const seconds = remain;
|
23
|
+
|
24
|
+
const duration = {
|
25
|
+
days,
|
26
|
+
hours,
|
27
|
+
minutes,
|
28
|
+
seconds,
|
29
|
+
ms,
|
30
|
+
};
|
31
|
+
|
32
|
+
if (days > 0) {
|
33
|
+
return i18n('daysHours', duration);
|
34
|
+
}
|
35
|
+
if (hours > 0) {
|
36
|
+
return i18n('hoursMin', duration);
|
37
|
+
}
|
38
|
+
if (minutes > 0) {
|
39
|
+
return i18n('minSec', duration);
|
40
|
+
}
|
41
|
+
if (seconds > 0) {
|
42
|
+
return i18n('secMs', duration);
|
43
|
+
}
|
44
|
+
|
45
|
+
return i18n('ms', duration);
|
46
|
+
};
|
@@ -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-time-parsers';
|
7
|
+
|
8
|
+
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
+
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
+
|
11
|
+
export default i18n.keyset(COMPONENT);
|
@@ -0,0 +1,36 @@
|
|
1
|
+
import type {IProtobufTimeObject} from '../../types/api/common';
|
2
|
+
|
3
|
+
import {MS_IN_NANOSECONDS} from '../constants';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Parses Google.protobuf Duration and Timestamp represented by objects
|
7
|
+
*/
|
8
|
+
export const parseProtobufTimeObjectToMs = (value: IProtobufTimeObject): number => {
|
9
|
+
const secondsInMs = value.seconds ? Number(value.seconds) * 1000 : 0;
|
10
|
+
const nanosecondsInMs = value.nanos ? value.nanos / MS_IN_NANOSECONDS : 0;
|
11
|
+
return secondsInMs + nanosecondsInMs;
|
12
|
+
};
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Parses Google.protobuf Timestamp to ms.
|
16
|
+
* Timestamp could be represented as object or as date string
|
17
|
+
*/
|
18
|
+
export const parseProtobufTimestampToMs = (value: string | IProtobufTimeObject) => {
|
19
|
+
if (typeof value === 'string') {
|
20
|
+
return Date.parse(value);
|
21
|
+
} else {
|
22
|
+
return parseProtobufTimeObjectToMs(value);
|
23
|
+
}
|
24
|
+
};
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Parses Google.protobuf Duration to ms.
|
28
|
+
* Duration could be represented as object or as string with format '12345s'
|
29
|
+
*/
|
30
|
+
export const parseProtobufDurationToMs = (value: string | IProtobufTimeObject) => {
|
31
|
+
if (typeof value === 'string') {
|
32
|
+
return parseInt(value, 10) * 1000;
|
33
|
+
} else {
|
34
|
+
return parseProtobufTimeObjectToMs(value);
|
35
|
+
}
|
36
|
+
};
|
package/package.json
CHANGED
@@ -1,48 +0,0 @@
|
|
1
|
-
import type {TEvDescribeSchemeResult, TCdcStreamDescription} from '../../../types/api/schema';
|
2
|
-
import {useTypedSelector} from '../../../utils/hooks';
|
3
|
-
import {selectSchemaData} from '../../../store/reducers/schema';
|
4
|
-
import {getEntityName} from '../../../containers/Tenant/utils';
|
5
|
-
|
6
|
-
import {formatCdcStreamItem, formatPQGroupItem, formatCommonItem} from '../formatters';
|
7
|
-
import {InfoViewer, InfoViewerItem} from '..';
|
8
|
-
|
9
|
-
const DISPLAYED_FIELDS: Set<keyof TCdcStreamDescription> = new Set(['Mode', 'Format']);
|
10
|
-
|
11
|
-
interface CDCStreamInfoProps {
|
12
|
-
data?: TEvDescribeSchemeResult;
|
13
|
-
childrenPaths?: string[];
|
14
|
-
}
|
15
|
-
|
16
|
-
export const CDCStreamInfo = ({data, childrenPaths}: CDCStreamInfoProps) => {
|
17
|
-
const pqGroupData = useTypedSelector((state) => selectSchemaData(state, childrenPaths?.[0]));
|
18
|
-
|
19
|
-
const entityName = getEntityName(data?.PathDescription);
|
20
|
-
|
21
|
-
if (!data || !pqGroupData) {
|
22
|
-
return <div className="error">No {entityName} data</div>;
|
23
|
-
}
|
24
|
-
|
25
|
-
const cdcStream = data.PathDescription?.CdcStreamDescription;
|
26
|
-
const pqGroup = pqGroupData?.PathDescription?.PersQueueGroup;
|
27
|
-
|
28
|
-
const info: Array<InfoViewerItem> = [];
|
29
|
-
|
30
|
-
info.push(formatCommonItem('CreateStep', data.PathDescription?.Self?.CreateStep));
|
31
|
-
|
32
|
-
let key: keyof TCdcStreamDescription;
|
33
|
-
for (key in cdcStream) {
|
34
|
-
if (DISPLAYED_FIELDS.has(key)) {
|
35
|
-
info.push(formatCdcStreamItem(key, cdcStream?.[key]));
|
36
|
-
}
|
37
|
-
}
|
38
|
-
|
39
|
-
info.push(formatPQGroupItem('Partitions', pqGroup?.Partitions || []));
|
40
|
-
info.push(
|
41
|
-
formatPQGroupItem(
|
42
|
-
'PQTabletConfig',
|
43
|
-
pqGroup?.PQTabletConfig || {PartitionConfig: {LifetimeSeconds: 0}},
|
44
|
-
),
|
45
|
-
);
|
46
|
-
|
47
|
-
return <InfoViewer title={entityName} info={info} />;
|
48
|
-
};
|
@@ -1,30 +0,0 @@
|
|
1
|
-
import type {TEvDescribeSchemeResult} from '../../../types/api/schema';
|
2
|
-
import {getEntityName} from '../../../containers/Tenant/utils';
|
3
|
-
|
4
|
-
import {formatPQGroupItem} from '../formatters';
|
5
|
-
import {InfoViewer, InfoViewerItem} from '..';
|
6
|
-
|
7
|
-
interface PersQueueGrouopInfoProps {
|
8
|
-
data?: TEvDescribeSchemeResult;
|
9
|
-
}
|
10
|
-
|
11
|
-
export const PersQueueGroupInfo = ({data}: PersQueueGrouopInfoProps) => {
|
12
|
-
const entityName = getEntityName(data?.PathDescription);
|
13
|
-
|
14
|
-
if (!data) {
|
15
|
-
return <div className="error">No {entityName} data</div>;
|
16
|
-
}
|
17
|
-
|
18
|
-
const pqGroup = data.PathDescription?.PersQueueGroup;
|
19
|
-
const info: Array<InfoViewerItem> = [];
|
20
|
-
|
21
|
-
info.push(formatPQGroupItem('Partitions', pqGroup?.Partitions || []));
|
22
|
-
info.push(
|
23
|
-
formatPQGroupItem(
|
24
|
-
'PQTabletConfig',
|
25
|
-
pqGroup?.PQTabletConfig || {PartitionConfig: {LifetimeSeconds: 0}},
|
26
|
-
),
|
27
|
-
);
|
28
|
-
|
29
|
-
return <InfoViewer title={entityName} info={info} />;
|
30
|
-
};
|
@@ -1,23 +0,0 @@
|
|
1
|
-
import PropTypes from 'prop-types';
|
2
|
-
import cn from 'bem-cn-lite';
|
3
|
-
|
4
|
-
import {Link} from 'react-router-dom';
|
5
|
-
|
6
|
-
const bLink = cn('yc-link');
|
7
|
-
|
8
|
-
export default function InternalLink({to, children, onClick, className}) {
|
9
|
-
return to ? (
|
10
|
-
<Link className={bLink({view: 'normal'}, className)} to={to} onClick={onClick}>
|
11
|
-
{children}
|
12
|
-
</Link>
|
13
|
-
) : (
|
14
|
-
children
|
15
|
-
);
|
16
|
-
}
|
17
|
-
|
18
|
-
InternalLink.propTypes = {
|
19
|
-
to: PropTypes.string.isRequired,
|
20
|
-
children: PropTypes.node,
|
21
|
-
onClick: PropTypes.func,
|
22
|
-
className: PropTypes.string,
|
23
|
-
};
|