ydb-embedded-ui 3.2.3 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) 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/Diagnostics.scss +2 -2
  53. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -4
  54. package/dist/containers/Tenant/Diagnostics/OverloadedShards/OverloadedShards.tsx +1 -1
  55. package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/ChangefeedInfo.tsx +69 -0
  56. package/dist/containers/Tenant/Diagnostics/Overview/ChangefeedInfo/index.ts +1 -0
  57. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +18 -16
  58. package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/TopicInfo.tsx +37 -0
  59. package/dist/containers/Tenant/Diagnostics/Overview/TopicInfo/index.ts +1 -0
  60. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.scss +30 -0
  61. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +94 -0
  62. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/en.json +3 -0
  63. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/index.ts +11 -0
  64. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/i18n/ru.json +3 -0
  65. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/index.ts +1 -0
  66. package/dist/containers/Tenant/Diagnostics/Overview/utils/index.ts +1 -0
  67. package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +42 -0
  68. package/dist/containers/Tenant/utils/schema.ts +19 -0
  69. package/dist/containers/UserSettings/UserSettings.scss +9 -0
  70. package/dist/containers/UserSettings/UserSettings.tsx +41 -11
  71. package/dist/services/api.d.ts +8 -1
  72. package/dist/services/api.js +27 -8
  73. package/dist/store/reducers/index.ts +3 -1
  74. package/dist/store/reducers/nodes.ts +148 -14
  75. package/dist/store/reducers/{clusterNodes.js → nodesList.js} +0 -41
  76. package/dist/store/reducers/settings.js +10 -4
  77. package/dist/store/reducers/storage.js +24 -13
  78. package/dist/store/reducers/tenant.js +5 -4
  79. package/dist/store/reducers/tooltip.ts +1 -1
  80. package/dist/store/reducers/topic.ts +52 -0
  81. package/dist/styles/mixins.scss +19 -11
  82. package/dist/types/api/common.ts +5 -0
  83. package/dist/types/api/compute.ts +1 -1
  84. package/dist/types/api/consumer.ts +12 -10
  85. package/dist/types/api/nodes.ts +2 -0
  86. package/dist/types/api/pdisk.ts +1 -0
  87. package/dist/types/api/schema.ts +3 -3
  88. package/dist/types/api/topic.ts +5 -4
  89. package/dist/types/api/vdisk.ts +2 -1
  90. package/dist/types/store/nodes.ts +56 -6
  91. package/dist/types/store/tooltip.ts +1 -1
  92. package/dist/types/store/topic.ts +21 -0
  93. package/dist/utils/constants.ts +5 -1
  94. package/dist/utils/i18n/i18n.ts +10 -2
  95. package/dist/utils/index.js +1 -1
  96. package/dist/utils/timeParsers/__test__/formatDuration.test.ts +50 -0
  97. package/dist/utils/timeParsers/__test__/protobuf.test.ts +74 -0
  98. package/dist/utils/timeParsers/formatDuration.ts +46 -0
  99. package/dist/utils/timeParsers/i18n/en.json +7 -0
  100. package/dist/utils/timeParsers/i18n/index.ts +11 -0
  101. package/dist/utils/timeParsers/i18n/ru.json +7 -0
  102. package/dist/utils/timeParsers/index.ts +2 -0
  103. package/dist/utils/timeParsers/protobuf.ts +36 -0
  104. package/package.json +1 -1
  105. package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +0 -48
  106. package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +0 -30
  107. package/dist/components/InternalLink/InternalLink.js +0 -23
  108. package/dist/containers/Nodes/Nodes.js +0 -214
  109. package/dist/containers/NodesViewer/NodesViewer.js +0 -163
  110. package/dist/containers/NodesViewer/NodesViewer.scss +0 -66
  111. package/dist/containers/Storage/Pdisk/Pdisk.tsx +0 -153
  112. package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +0 -41
  113. package/dist/containers/Storage/Vdisk/Vdisk.js +0 -275
  114. package/dist/containers/Storage/Vdisk/Vdisk.scss +0 -22
  115. package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +0 -163
  116. package/dist/containers/Tenant/Diagnostics/Compute/Compute.js +0 -139
  117. package/dist/containers/Tenant/Diagnostics/Compute/Compute.scss +0 -14
@@ -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;
@@ -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;
@@ -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
- clearNodes,
10
+ resetNodesState,
5
11
  setDataWasNotLoaded,
6
12
  setNodesUptimeFilter,
13
+ setSearchValue,
7
14
  } from '../../store/reducers/nodes';
8
15
  import {ApiRequestAction} from '../../store/utils';
9
- import {IResponseError} from '../api/error';
10
- import {TNodesInfo} from '../api/nodes';
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
- data?: TNodesInfo;
40
+ searchValue: string;
41
+ data?: INodesPreparedEntity[];
42
+ totalNodes?: number;
17
43
  error?: IResponseError;
18
44
  }
19
45
 
20
- type INodesApiRequestAction = ApiRequestAction<typeof FETCH_NODES, TNodesInfo, IResponseError>;
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
+ }
@@ -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 HOUR_IN_SECONDS = 60 * 60;
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';
@@ -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
- export enum Lang {
5
+ enum Lang {
4
6
  En = 'en',
5
7
  Ru = 'ru',
6
8
  }
7
9
 
8
- export const i18n = new I18N();
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};
@@ -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, DAY_IN_SECONDS, GIGABYTE} from './constants';
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,7 @@
1
+ {
2
+ "daysHours": "{{days}}d {{hours}}h",
3
+ "hoursMin": "{{hours}}h {{minutes}}m",
4
+ "minSec": "{{minutes}}m {{seconds}}s",
5
+ "secMs": "{{seconds}}s {{ms}}ms",
6
+ "ms": "{{ms}}ms"
7
+ }
@@ -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,7 @@
1
+ {
2
+ "daysHours": "{{days}}д {{hours}}ч",
3
+ "hoursMin": "{{hours}}ч {{minutes}}м",
4
+ "minSec": "{{minutes}}м {{seconds}}с",
5
+ "secMs": "{{seconds}}с {{ms}}мс",
6
+ "ms": "{{ms}}мс"
7
+ }
@@ -0,0 +1,2 @@
1
+ export * from './formatDuration';
2
+ export * from './protobuf';
@@ -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,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "3.2.3",
3
+ "version": "3.3.1",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -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
- };