ydb-embedded-ui 4.16.2 → 4.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/components/CircularProgressBar/CircularProgressBar.scss +42 -0
  3. package/dist/components/CircularProgressBar/CircularProgressBar.tsx +59 -0
  4. package/dist/components/DiagnosticCard/DiagnosticCard.scss +20 -3
  5. package/dist/components/DiagnosticCard/DiagnosticCard.tsx +5 -6
  6. package/dist/components/FullNodeViewer/FullNodeViewer.tsx +2 -2
  7. package/dist/components/InfoViewer/formatters/common.ts +1 -1
  8. package/dist/components/InfoViewer/formatters/pqGroup.ts +1 -1
  9. package/dist/components/InfoViewer/formatters/table.ts +6 -1
  10. package/dist/components/ProgressViewer/ProgressViewer.tsx +99 -0
  11. package/dist/components/TooltipsContent/TabletTooltipContent/TabletTooltipContent.tsx +1 -1
  12. package/dist/containers/AsideNavigation/AsideNavigation.tsx +3 -1
  13. package/dist/containers/Authentication/Authentication.tsx +14 -4
  14. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +2 -2
  15. package/dist/containers/Heatmap/Heatmap.tsx +1 -1
  16. package/dist/containers/Heatmap/Histogram/Histogram.js +1 -1
  17. package/dist/containers/Node/NodeStructure/Pdisk.tsx +2 -2
  18. package/dist/containers/Node/NodeStructure/Vdisk.tsx +5 -2
  19. package/dist/containers/Nodes/getNodesColumns.tsx +2 -2
  20. package/dist/containers/Storage/PDisk/PDisk.tsx +1 -1
  21. package/dist/containers/Storage/PDiskPopup/PDiskPopup.tsx +1 -1
  22. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +1 -1
  23. package/dist/containers/Storage/VDisk/VDisk.tsx +1 -1
  24. package/dist/containers/Storage/VDiskPopup/VDiskPopup.tsx +1 -1
  25. package/dist/containers/Tablet/TabletInfo/TabletInfo.tsx +1 -1
  26. package/dist/containers/Tablet/TabletTable/TabletTable.tsx +1 -1
  27. package/dist/containers/Tenant/Diagnostics/Consumers/TopicStats/ConsumersTopicStats.tsx +1 -1
  28. package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +1 -1
  29. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +1 -5
  30. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +40 -17
  31. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/Details.tsx +3 -3
  32. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.scss +27 -14
  33. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Healthcheck.tsx +6 -6
  34. package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/Preview.tsx +15 -16
  35. package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +1 -1
  36. package/dist/containers/Tenant/Diagnostics/Overview/TopicStats/TopicStats.tsx +1 -1
  37. package/dist/containers/Tenant/Diagnostics/Partitions/columns/columns.tsx +1 -1
  38. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/Healthcheck.scss +108 -0
  39. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckDetails.tsx +45 -0
  40. package/dist/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +83 -0
  41. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.scss +1 -3
  42. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTree.tsx +1 -1
  43. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +1 -1
  44. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/en.json +2 -1
  45. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/index.ts +1 -1
  46. package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/i18n/ru.json +2 -1
  47. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.scss +52 -0
  48. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricCard/MetricCard.tsx +48 -0
  49. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.scss +12 -0
  50. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +134 -0
  51. package/dist/containers/Tenant/Diagnostics/TenantOverview/OldTenantOverview.tsx +155 -0
  52. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +3 -5
  53. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +76 -86
  54. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +3 -1
  55. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +3 -1
  56. package/dist/containers/Tenant/Diagnostics/TenantOverview/useHealthcheck.ts +53 -0
  57. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +1 -1
  58. package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +1 -1
  59. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +1 -1
  60. package/dist/containers/Tenant/TenantPages.tsx +1 -0
  61. package/dist/containers/Tenants/Tenants.tsx +5 -1
  62. package/dist/containers/UserSettings/i18n/en.json +4 -1
  63. package/dist/containers/UserSettings/i18n/ru.json +4 -1
  64. package/dist/containers/UserSettings/settings.ts +7 -0
  65. package/dist/containers/Versions/NodesTable/NodesTable.tsx +2 -2
  66. package/dist/services/api.ts +6 -4
  67. package/dist/store/reducers/clusterNodes/clusterNodes.tsx +1 -1
  68. package/dist/store/reducers/healthcheckInfo.ts +20 -12
  69. package/dist/store/reducers/node/selectors.ts +1 -1
  70. package/dist/store/reducers/nodes/selectors.ts +1 -1
  71. package/dist/store/reducers/nodes/types.ts +1 -1
  72. package/dist/store/reducers/nodes/utils.ts +1 -1
  73. package/dist/store/reducers/settings/settings.ts +6 -1
  74. package/dist/store/reducers/storage/types.ts +1 -1
  75. package/dist/store/reducers/storage/utils.ts +1 -1
  76. package/dist/store/reducers/tenant/constants.ts +7 -0
  77. package/dist/store/reducers/tenant/tenant.ts +15 -0
  78. package/dist/store/reducers/tenant/types.ts +5 -0
  79. package/dist/store/reducers/tenants/contants.ts +6 -0
  80. package/dist/store/reducers/tenants/types.ts +4 -0
  81. package/dist/store/reducers/tenants/utils.ts +114 -7
  82. package/dist/store/state-url-mapping.js +3 -0
  83. package/dist/styles/constants.scss +2 -0
  84. package/dist/types/api/tenant.ts +3 -0
  85. package/dist/types/api/vdisk.ts +1 -1
  86. package/dist/utils/bytesParsers/formatBytes.ts +1 -1
  87. package/dist/utils/constants.ts +2 -0
  88. package/dist/utils/dataFormatters/dataFormatters.ts +128 -0
  89. package/dist/utils/dataFormatters/i18n/en.json +3 -0
  90. package/dist/utils/dataFormatters/i18n/index.ts +11 -0
  91. package/dist/utils/dataFormatters/i18n/ru.json +3 -0
  92. package/dist/utils/index.js +0 -102
  93. package/package.json +1 -1
  94. package/dist/components/ProgressViewer/ProgressViewer.js +0 -92
  95. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Details/index.ts +0 -0
  96. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/Preview/index.ts +0 -0
  97. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → OldHealthcheck}/index.ts +0 -0
  98. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +0 -0
  99. /package/dist/containers/Tenant/Diagnostics/{Healthcheck → TenantOverview/Healthcheck}/IssuesViewer/IssueTreeItem/index.ts +0 -0
@@ -7,9 +7,12 @@ import {Button, Modal} from '@gravity-ui/uikit';
7
7
  import type {EPathType} from '../../../../types/api/schema';
8
8
  import type {AdditionalTenantsProps} from '../../../../types/additionalProps';
9
9
  import {Icon} from '../../../../components/Icon';
10
+ import {useSetting} from '../../../../utils/hooks';
11
+ import {DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS} from '../../../../utils/constants';
10
12
  import Overview from '../Overview/Overview';
11
- import {Healthcheck} from '../Healthcheck';
13
+ import {Healthcheck} from '../OldHealthcheck';
12
14
  import {TenantOverview} from '../TenantOverview/TenantOverview';
15
+ import {OldTenantOverview} from '../TenantOverview/OldTenantOverview';
13
16
 
14
17
  import './DetailedOverview.scss';
15
18
 
@@ -23,10 +26,14 @@ interface DetailedOverviewProps {
23
26
  const b = cn('kv-detailed-overview');
24
27
 
25
28
  function DetailedOverview(props: DetailedOverviewProps) {
29
+ const {type, tenantName, additionalTenantProps} = props;
30
+
26
31
  const [isModalVisible, setIsModalVisible] = useState(false);
27
32
 
28
33
  const {currentSchemaPath} = useSelector((state: any) => state.schema);
29
34
 
35
+ const [displayMetricsCards] = useSetting(DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS);
36
+
30
37
  const openModalHandler = () => {
31
38
  setIsModalVisible(true);
32
39
  };
@@ -51,27 +58,43 @@ function DetailedOverview(props: DetailedOverviewProps) {
51
58
  );
52
59
  };
53
60
 
61
+ const renderTenantOverview = () => {
62
+ if (displayMetricsCards) {
63
+ return (
64
+ <div className={b('section')}>
65
+ <TenantOverview
66
+ tenantName={tenantName}
67
+ additionalTenantProps={additionalTenantProps}
68
+ />
69
+ </div>
70
+ );
71
+ }
72
+
73
+ return (
74
+ <>
75
+ <div className={b('section')}>
76
+ <OldTenantOverview
77
+ tenantName={tenantName}
78
+ additionalTenantProps={additionalTenantProps}
79
+ />
80
+ </div>
81
+ <div className={b('section')}>
82
+ <Healthcheck
83
+ tenant={tenantName}
84
+ preview={true}
85
+ showMoreHandler={openModalHandler}
86
+ />
87
+ </div>
88
+ </>
89
+ );
90
+ };
91
+
54
92
  const renderContent = () => {
55
- const {type, tenantName, additionalTenantProps} = props;
56
93
  const isTenant = tenantName === currentSchemaPath;
57
94
  return (
58
95
  <div className={b()}>
59
96
  {isTenant ? (
60
- <>
61
- <div className={b('section')}>
62
- <TenantOverview
63
- tenantName={tenantName}
64
- additionalTenantProps={additionalTenantProps}
65
- />
66
- </div>
67
- <div className={b('section')}>
68
- <Healthcheck
69
- tenant={tenantName}
70
- preview={true}
71
- showMoreHandler={openModalHandler}
72
- />
73
- </div>
74
- </>
97
+ renderTenantOverview()
75
98
  ) : (
76
99
  <Overview type={type} tenantName={tenantName} />
77
100
  )}
@@ -8,11 +8,11 @@ import type {IResponseError} from '../../../../../types/api/error';
8
8
  import type {IIssuesTree} from '../../../../../types/store/healthcheck';
9
9
  import {ResponseError} from '../../../../../components/Errors/ResponseError';
10
10
 
11
- import IssueTree from '../IssuesViewer/IssueTree';
11
+ import IssueTree from '../../TenantOverview/Healthcheck/IssuesViewer/IssueTree';
12
12
 
13
- import i18n from '../i18n';
13
+ import i18n from '../../TenantOverview/Healthcheck/i18n';
14
14
 
15
- const b = cn('healthcheck');
15
+ const b = cn('old-healthcheck');
16
16
 
17
17
  interface DetailsProps {
18
18
  issueTrees?: IIssuesTree[];
@@ -1,8 +1,7 @@
1
- @use '../DetailedOverview/DetailedOverview.scss' as detailedOverview;
2
1
  @import '../../../../styles/mixins.scss';
3
2
  @import '@gravity-ui/uikit/styles/mixins.scss';
4
3
 
5
- .healthcheck {
4
+ .old-healthcheck {
6
5
  display: flex;
7
6
 
8
7
  &_expanded {
@@ -12,6 +11,7 @@
12
11
  }
13
12
 
14
13
  &__details {
14
+ width: 860px;
15
15
  padding: 25px 20px 20px;
16
16
  }
17
17
 
@@ -27,11 +27,6 @@
27
27
  max-height: 70vh;
28
28
  }
29
29
 
30
- &__loader {
31
- display: flex;
32
- justify-content: center;
33
- }
34
-
35
30
  &__message-container {
36
31
  padding: 15px 0;
37
32
  }
@@ -53,34 +48,52 @@
53
48
  margin-left: 10px;
54
49
  }
55
50
 
56
- &__status-wrapper {
57
- display: flex;
51
+ &__preview {
52
+ width: 206px;
53
+ padding: 16px;
54
+ padding-bottom: 28px;
58
55
 
59
- margin-bottom: detailedOverview.$section-title-margin;
56
+ border: 1px solid var(--yc-color-line-generic);
57
+ border-radius: 8px;
58
+ background-color: transparent;
59
+ }
60
+
61
+ &__preview-header {
62
+ margin-bottom: var(--diagnostics-section-title-margin);
60
63
  gap: 8px;
61
64
  }
62
65
 
63
66
  &__preview-title {
64
67
  font-weight: 600;
65
- line-height: detailedOverview.$section-title-line-height;
68
+ @include lead-typography();
66
69
  }
67
70
 
68
71
  &__preview-content {
69
72
  line-height: 24px;
70
73
  }
71
74
 
75
+ &__preview-title-wrapper {
76
+ display: flex;
77
+ align-items: center;
78
+
79
+ margin-bottom: 4px;
80
+
81
+ gap: 8px;
82
+ }
83
+
72
84
  &__issues-statistics {
73
85
  display: flex;
74
86
  flex-wrap: wrap;
75
87
  align-items: center;
76
88
 
77
- margin: 10px 0;
89
+ margin: 8px 0;
78
90
 
79
- column-gap: 26px;
80
- row-gap: 16px;
91
+ gap: 10px;
81
92
  }
82
93
 
83
94
  &__self-check-status-indicator {
95
+ display: inline-block;
96
+
84
97
  padding: 0 8px;
85
98
 
86
99
  font-size: 13px;
@@ -12,7 +12,6 @@ import {
12
12
  selectIssuesTrees,
13
13
  setDataWasNotLoaded,
14
14
  } from '../../../../store/reducers/healthcheckInfo';
15
- import {DiagnosticCard} from '../../../../components/DiagnosticCard/DiagnosticCard';
16
15
 
17
16
  import {Details} from './Details';
18
17
  import {Preview} from './Preview';
@@ -26,7 +25,7 @@ interface HealthcheckProps {
26
25
  showMoreHandler?: VoidFunction;
27
26
  }
28
27
 
29
- const b = cn('healthcheck');
28
+ const b = cn('old-healthcheck');
30
29
 
31
30
  export const Healthcheck = (props: HealthcheckProps) => {
32
31
  const {tenant, preview, fetchData = true, showMoreHandler} = props;
@@ -34,12 +33,12 @@ export const Healthcheck = (props: HealthcheckProps) => {
34
33
  const dispatch = useDispatch();
35
34
 
36
35
  const {data, loading, wasLoaded, error} = useTypedSelector((state) => state.healthcheckInfo);
37
- const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
38
-
39
36
  const issuesStatistics = useTypedSelector(selectIssuesStatistics);
40
37
  const issueTrees = useTypedSelector(selectIssuesTrees);
41
38
  const {autorefresh} = useTypedSelector((state) => state.schema);
42
39
 
40
+ const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
41
+
43
42
  const fetchHealthcheck = useCallback(
44
43
  (isBackground = true) => {
45
44
  if (!isBackground) {
@@ -64,11 +63,12 @@ export const Healthcheck = (props: HealthcheckProps) => {
64
63
  const renderContent = () => {
65
64
  if (loading && !wasLoaded) {
66
65
  return (
67
- <DiagnosticCard className={b('loader')}>
66
+ <div className={b('old-preview', {loader: true})}>
68
67
  <Loader size="m" />
69
- </DiagnosticCard>
68
+ </div>
70
69
  );
71
70
  }
71
+
72
72
  return preview ? (
73
73
  <Preview
74
74
  issuesStatistics={issuesStatistics}
@@ -6,13 +6,12 @@ import updateArrow from '../../../../../assets/icons/update-arrow.svg';
6
6
 
7
7
  import {SelfCheckResult, type StatusFlag} from '../../../../../types/api/healthcheck';
8
8
  import type {IResponseError} from '../../../../../types/api/error';
9
- import {DiagnosticCard} from '../../../../../components/DiagnosticCard/DiagnosticCard';
10
9
  import EntityStatus from '../../../../../components/EntityStatus/EntityStatus';
11
10
  import {ResponseError} from '../../../../../components/Errors/ResponseError';
12
11
 
13
- import i18n from '../i18n';
12
+ import i18n from '../../TenantOverview/Healthcheck/i18n';
14
13
 
15
- const b = cn('healthcheck');
14
+ const b = cn('old-healthcheck');
16
15
 
17
16
  interface PreviewProps {
18
17
  selfCheckResult: SelfCheckResult;
@@ -26,20 +25,20 @@ interface PreviewProps {
26
25
  export const Preview = (props: PreviewProps) => {
27
26
  const {selfCheckResult, issuesStatistics, loading, onShowMore, onUpdate, error} = props;
28
27
 
29
- const isStatusOK = selfCheckResult === SelfCheckResult.GOOD;
30
-
31
- const renderStatus = () => {
28
+ const renderHeader = () => {
32
29
  const modifier = selfCheckResult.toLowerCase();
33
30
 
34
31
  return (
35
- <div className={b('status-wrapper')}>
36
- <div className={b('preview-title')}>{i18n('title.healthcheck')}</div>
32
+ <div className={b('preview-header')}>
33
+ <div className={b('preview-title-wrapper')}>
34
+ <div className={b('preview-title')}>{i18n('title.healthcheck')}</div>
35
+ <Button size="s" onClick={onUpdate} loading={loading} view="flat-secondary">
36
+ <Icon data={updateArrow} width={20} height={20} />
37
+ </Button>
38
+ </div>
37
39
  <div className={b('self-check-status-indicator', {[modifier]: true})}>
38
40
  {selfCheckResult}
39
41
  </div>
40
- <Button size="s" onClick={onUpdate} loading={loading} view="flat-secondary">
41
- <Icon data={updateArrow} width={20} height={20} />
42
- </Button>
43
42
  </div>
44
43
  );
45
44
  };
@@ -51,11 +50,11 @@ export const Preview = (props: PreviewProps) => {
51
50
 
52
51
  return (
53
52
  <div className={b('preview-content')}>
54
- {isStatusOK || !issuesStatistics || !issuesStatistics.length ? (
53
+ {!issuesStatistics || !issuesStatistics.length ? (
55
54
  i18n('status_message.ok')
56
55
  ) : (
57
56
  <>
58
- <div>Issues:</div>
57
+ <div>{i18n('label.issues')}</div>
59
58
  <div className={b('issues-statistics')}>
60
59
  {issuesStatistics.map(([status, count]) => (
61
60
  <EntityStatus
@@ -75,9 +74,9 @@ export const Preview = (props: PreviewProps) => {
75
74
  };
76
75
 
77
76
  return (
78
- <DiagnosticCard className={b('preview')}>
79
- {renderStatus()}
77
+ <div className={b('preview')}>
78
+ {renderHeader()}
80
79
  {renderContent()}
81
- </DiagnosticCard>
80
+ </div>
82
81
  );
83
82
  };
@@ -8,7 +8,7 @@ import type {
8
8
  import type {KeyValueRow} from '../../../../../types/api/query';
9
9
  import {EPathType} from '../../../../../types/api/schema';
10
10
  import {isNumeric} from '../../../../../utils/utils';
11
- import {formatBytes, formatNumber} from '../../../../../utils';
11
+ import {formatBytes, formatNumber} from '../../../../../utils/dataFormatters/dataFormatters';
12
12
  import {formatDurationToShortTimeFormat} from '../../../../../utils/timeParsers';
13
13
  import {formatObject, InfoViewerItem} from '../../../../../components/InfoViewer';
14
14
  import {
@@ -11,7 +11,7 @@ import {ResponseError} from '../../../../../components/Errors/ResponseError';
11
11
 
12
12
  import {useTypedSelector} from '../../../../../utils/hooks';
13
13
  import {formatDurationToShortTimeFormat} from '../../../../../utils/timeParsers';
14
- import {formatBps, formatBytes} from '../../../../../utils';
14
+ import {formatBps, formatBytes} from '../../../../../utils/dataFormatters/dataFormatters';
15
15
 
16
16
  import {selectPreparedTopicStats} from '../../../../../store/reducers/topic';
17
17
 
@@ -4,7 +4,7 @@ import block from 'bem-cn-lite';
4
4
  import {SpeedMultiMeter} from '../../../../../components/SpeedMultiMeter';
5
5
  import EntityStatus from '../../../../../components/EntityStatus/EntityStatus';
6
6
  import {getDefaultNodePath} from '../../../../Node/NodePages';
7
- import {formatBytes, formatMsToUptime} from '../../../../../utils';
7
+ import {formatBytes, formatMsToUptime} from '../../../../../utils/dataFormatters/dataFormatters';
8
8
  import {isNumeric} from '../../../../../utils/utils';
9
9
 
10
10
  import {
@@ -0,0 +1,108 @@
1
+ @import '../../../../../styles/mixins.scss';
2
+
3
+ .healthcheck {
4
+ display: flex;
5
+
6
+ &_expanded {
7
+ // Since most of the inner containers have fixed width, we can set fixed width here as well
8
+ // Thus we will get rid of unneeded layout shift when scrollbar appear
9
+ min-width: 885px;
10
+ }
11
+
12
+ &__issue-preview {
13
+ margin-bottom: 15px;
14
+ }
15
+
16
+ &__message-container {
17
+ padding: 15px 0;
18
+ }
19
+
20
+ &__details {
21
+ width: 872px;
22
+ }
23
+
24
+ &__details-content-wrapper {
25
+ overflow-x: hidden;
26
+ }
27
+
28
+ &__preview {
29
+ height: 100%;
30
+ }
31
+
32
+ &__preview-header {
33
+ margin-bottom: var(--diagnostics-section-title-margin);
34
+ gap: 8px;
35
+ }
36
+
37
+ &__preview-title {
38
+ font-weight: 600;
39
+ @include lead-typography();
40
+ }
41
+
42
+ &__preview-content {
43
+ line-height: 24px;
44
+ }
45
+
46
+ &__preview-title-wrapper {
47
+ display: flex;
48
+ align-items: center;
49
+
50
+ margin-bottom: 4px;
51
+
52
+ gap: 8px;
53
+ }
54
+
55
+ &__issues-statistics {
56
+ display: flex;
57
+ flex-wrap: wrap;
58
+ align-items: center;
59
+
60
+ margin: 8px 0;
61
+
62
+ gap: 10px;
63
+ }
64
+
65
+ &__self-check-status-indicator {
66
+ display: inline-block;
67
+
68
+ padding: 0 8px;
69
+
70
+ font-size: 13px;
71
+ line-height: 24px;
72
+
73
+ border-radius: 4px;
74
+
75
+ &_good,
76
+ &_green {
77
+ color: var(--yc-color-text-positive);
78
+ background-color: var(--yc-color-base-positive);
79
+ }
80
+ &_degraded,
81
+ &_yellow {
82
+ color: var(--yc-color-text-warning);
83
+ background-color: var(--yc-color-base-warning);
84
+ }
85
+
86
+ &_blue {
87
+ color: var(--yc-color-text-info);
88
+ background-color: var(--yc-color-base-info);
89
+ }
90
+
91
+ &_emergency,
92
+ &_red {
93
+ color: var(--yc-color-text-danger);
94
+ background-color: var(--yc-color-base-danger);
95
+ }
96
+ &_unspecified,
97
+ &_gray,
98
+ &_grey {
99
+ color: var(--yc-color-text-misc);
100
+ background-color: var(--yc-color-base-misc);
101
+ }
102
+ &_maintenance_required,
103
+ &_orange {
104
+ color: var(--yc-color-text-warning-heavy);
105
+ background-color: var(--yc-color-infographics-warning-light);
106
+ }
107
+ }
108
+ }
@@ -0,0 +1,45 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import type {IResponseError} from '../../../../../types/api/error';
4
+ import type {IIssuesTree} from '../../../../../types/store/healthcheck';
5
+ import {ResponseError} from '../../../../../components/Errors/ResponseError';
6
+
7
+ import IssueTree from './IssuesViewer/IssueTree';
8
+
9
+ import i18n from './i18n';
10
+ import './Healthcheck.scss';
11
+
12
+ const b = cn('healthcheck');
13
+
14
+ interface HealthcheckDetailsProps {
15
+ issueTrees?: IIssuesTree[];
16
+ error?: IResponseError;
17
+ }
18
+
19
+ export function HealthcheckDetails(props: HealthcheckDetailsProps) {
20
+ const {issueTrees, error} = props;
21
+
22
+ const renderContent = () => {
23
+ if (error) {
24
+ return <ResponseError error={error} defaultMessage={i18n('no-data')} />;
25
+ }
26
+
27
+ if (!issueTrees || !issueTrees.length) {
28
+ return i18n('status_message.ok');
29
+ }
30
+
31
+ return (
32
+ <>
33
+ {issueTrees.map((issueTree) => (
34
+ <IssueTree key={issueTree.id} issueTree={issueTree} />
35
+ ))}
36
+ </>
37
+ );
38
+ };
39
+
40
+ return (
41
+ <div className={b('details')}>
42
+ <div className={b('details-content-wrapper')}>{renderContent()}</div>
43
+ </div>
44
+ );
45
+ }
@@ -0,0 +1,83 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import {Button, Icon} from '@gravity-ui/uikit';
4
+
5
+ import updateArrow from '../../../../../assets/icons/update-arrow.svg';
6
+
7
+ import {SelfCheckResult, type StatusFlag} from '../../../../../types/api/healthcheck';
8
+ import type {IResponseError} from '../../../../../types/api/error';
9
+ import {DiagnosticCard} from '../../../../../components/DiagnosticCard/DiagnosticCard';
10
+ import EntityStatus from '../../../../../components/EntityStatus/EntityStatus';
11
+ import {ResponseError} from '../../../../../components/Errors/ResponseError';
12
+
13
+ import i18n from './i18n';
14
+ import './Healthcheck.scss';
15
+
16
+ const b = cn('healthcheck');
17
+
18
+ interface HealthcheckPreviewProps {
19
+ selfCheckResult: SelfCheckResult;
20
+ issuesStatistics?: [StatusFlag, number][];
21
+ loading?: boolean;
22
+ onUpdate: VoidFunction;
23
+ error?: IResponseError;
24
+ active?: boolean;
25
+ }
26
+
27
+ export function HealthcheckPreview(props: HealthcheckPreviewProps) {
28
+ const {selfCheckResult, issuesStatistics, loading, onUpdate, error, active} = props;
29
+
30
+ const renderHeader = () => {
31
+ const modifier = selfCheckResult.toLowerCase();
32
+
33
+ return (
34
+ <div className={b('preview-header')}>
35
+ <div className={b('preview-title-wrapper')}>
36
+ <div className={b('preview-title')}>{i18n('title.healthcheck')}</div>
37
+ <Button size="s" onClick={onUpdate} loading={loading} view="flat-secondary">
38
+ <Icon data={updateArrow} width={20} height={20} />
39
+ </Button>
40
+ </div>
41
+ <div className={b('self-check-status-indicator', {[modifier]: true})}>
42
+ {selfCheckResult}
43
+ </div>
44
+ </div>
45
+ );
46
+ };
47
+
48
+ const renderContent = () => {
49
+ if (error) {
50
+ return <ResponseError error={error} defaultMessage={i18n('no-data')} />;
51
+ }
52
+
53
+ return (
54
+ <div className={b('preview-content')}>
55
+ {!issuesStatistics || !issuesStatistics.length ? (
56
+ i18n('status_message.ok')
57
+ ) : (
58
+ <>
59
+ <div>{i18n('label.issues')}</div>
60
+ <div className={b('issues-statistics')}>
61
+ {issuesStatistics.map(([status, count]) => (
62
+ <EntityStatus
63
+ key={status}
64
+ mode="icons"
65
+ status={status}
66
+ label={count.toString()}
67
+ size="l"
68
+ />
69
+ ))}
70
+ </div>
71
+ </>
72
+ )}
73
+ </div>
74
+ );
75
+ };
76
+
77
+ return (
78
+ <DiagnosticCard className={b('preview')} active={active}>
79
+ {renderHeader()}
80
+ {renderContent()}
81
+ </DiagnosticCard>
82
+ );
83
+ }
@@ -1,4 +1,4 @@
1
- @import '../../../../../styles/mixins.scss';
1
+ @import '../../../../../../styles/mixins.scss';
2
2
 
3
3
  .indicator {
4
4
  width: 12px;
@@ -38,8 +38,6 @@
38
38
  .issue-tree {
39
39
  display: flex;
40
40
 
41
- width: 820px;
42
-
43
41
  &__block {
44
42
  width: 100%;
45
43
  }
@@ -7,7 +7,7 @@ import JSONTree from 'react-json-inspector';
7
7
 
8
8
  import {TreeView} from 'ydb-ui-components';
9
9
 
10
- import {IIssuesTree} from '../../../../../types/store/healthcheck';
10
+ import {IIssuesTree} from '../../../../../../types/store/healthcheck';
11
11
 
12
12
  import {IssueTreeItem} from './IssueTreeItem';
13
13
 
@@ -1,6 +1,6 @@
1
1
  import cn from 'bem-cn-lite';
2
2
 
3
- import EntityStatus from '../../../../../../components/EntityStatus/EntityStatus';
3
+ import EntityStatus from '../../../../../../../components/EntityStatus/EntityStatus';
4
4
 
5
5
  import './IssueTreeItem.scss';
6
6
 
@@ -2,6 +2,7 @@
2
2
  "title.healthcheck": "Healthcheck",
3
3
  "label.update": "Update",
4
4
  "label.show-details": "Show details",
5
- "status_message.ok": "No issues have been found on this database",
5
+ "label.issues": "Issues:",
6
+ "status_message.ok": "No issues",
6
7
  "no-data": "no healthcheck data"
7
8
  }
@@ -1,4 +1,4 @@
1
- import {i18n, Lang} from '../../../../../utils/i18n';
1
+ import {i18n, Lang} from '../../../../../../utils/i18n';
2
2
 
3
3
  import en from './en.json';
4
4
  import ru from './ru.json';
@@ -2,6 +2,7 @@
2
2
  "title.healthcheck": "Healthcheck",
3
3
  "label.update": "Обновить",
4
4
  "label.show-details": "Посмотреть подробности",
5
- "status_message.ok": "В базе данных нет проблем",
5
+ "label.issues": "Проблемы:",
6
+ "status_message.ok": "Нет проблем",
6
7
  "no-data": "нет данных healthcheck"
7
8
  }