ydb-embedded-ui 4.5.0 → 4.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/components/CriticalActionDialog/CriticalActionDialog.tsx +3 -0
  3. package/dist/components/FullNodeViewer/FullNodeViewer.js +1 -1
  4. package/dist/components/PoolUsage/PoolUsage.scss +1 -1
  5. package/dist/components/PoolUsage/PoolUsage.tsx +50 -0
  6. package/dist/containers/Node/Node.tsx +1 -1
  7. package/dist/containers/Node/NodeStructure/NodeStructure.tsx +19 -17
  8. package/dist/containers/Tablet/Tablet.scss +4 -0
  9. package/dist/containers/Tablet/Tablet.tsx +2 -1
  10. package/dist/containers/Tablet/TabletControls/TabletControls.tsx +19 -27
  11. package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +2 -2
  12. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +37 -38
  13. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -28
  14. package/dist/containers/Tenant/Diagnostics/Network/Network.js +2 -2
  15. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +3 -3
  16. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +5 -3
  17. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +2 -3
  18. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +3 -3
  19. package/dist/containers/Tenant/Tenant.tsx +14 -15
  20. package/dist/containers/Tenant/TenantPages.tsx +3 -6
  21. package/dist/containers/Tenant/utils/schemaActions.ts +4 -4
  22. package/dist/containers/Versions/GroupedNodesTree/GroupedNodesTree.scss +1 -0
  23. package/dist/containers/Versions/NodesTable/NodesTable.tsx +2 -3
  24. package/dist/routes.ts +1 -1
  25. package/dist/services/api.ts +2 -2
  26. package/dist/store/reducers/index.ts +4 -4
  27. package/dist/store/reducers/{network.js → network/network.ts} +11 -8
  28. package/dist/store/reducers/network/types.ts +16 -0
  29. package/dist/store/reducers/node/node.ts +102 -0
  30. package/dist/store/reducers/node/selectors.ts +59 -0
  31. package/dist/store/reducers/node/types.ts +44 -0
  32. package/dist/store/reducers/{schemaAcl.js → schemaAcl/schemaAcl.ts} +20 -9
  33. package/dist/store/reducers/schemaAcl/types.ts +15 -0
  34. package/dist/store/reducers/tenant/constants.ts +19 -0
  35. package/dist/store/reducers/{tenant.js → tenant/tenant.ts} +27 -36
  36. package/dist/store/reducers/tenant/types.ts +25 -0
  37. package/dist/types/api/acl.ts +1 -1
  38. package/dist/utils/index.js +2 -1
  39. package/package.json +2 -1
  40. package/dist/components/Breadcrumbs/Breadcrumbs.js +0 -25
  41. package/dist/components/Breadcrumbs/Breadcrumbs.scss +0 -5
  42. package/dist/components/Collapse/Collapse.js +0 -84
  43. package/dist/components/Collapse/Collapse.scss +0 -70
  44. package/dist/components/PoolUsage/PoolUsage.js +0 -54
  45. package/dist/store/reducers/node.js +0 -141
@@ -1,13 +1,20 @@
1
- import {createRequestActionTypes, createApiRequest} from '../utils';
2
- import '../../services/api';
3
- import _ from 'lodash';
1
+ import type {Reducer} from 'redux';
2
+
3
+ import type {TTenant} from '../../../types/api/tenant';
4
+ import type {TenantAction, TenantDiagnosticsTab, TenantGeneralTab, TenantState} from './types';
5
+
6
+ import '../../../services/api';
7
+ import {createRequestActionTypes, createApiRequest} from '../../utils';
8
+
9
+ export const FETCH_TENANT = createRequestActionTypes('tenant', 'FETCH_TENANT');
4
10
 
5
- const FETCH_TENANT = createRequestActionTypes('tenant', 'FETCH_TENANT');
6
11
  const SET_TOP_LEVEL_TAB = 'tenant/SET_TOP_LEVEL_TAB';
7
12
  const SET_DIAGNOSTICS_TAB = 'tenant/SET_DIAGNOSTICS_TAB';
8
13
  const CLEAR_TENANT = 'tenant/CLEAR_TENANT';
9
14
 
10
- const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, action) => {
15
+ const initialState = {loading: false, wasLoaded: false};
16
+
17
+ const tenantReducer: Reducer<TenantState, TenantAction> = (state = initialState, action) => {
11
18
  switch (action.type) {
12
19
  case FETCH_TENANT.REQUEST: {
13
20
  return {
@@ -17,12 +24,9 @@ const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, a
17
24
  }
18
25
 
19
26
  case FETCH_TENANT.SUCCESS: {
20
- const {tenant, tenantNodes} = action.data;
21
-
22
27
  return {
23
28
  ...state,
24
- tenant,
25
- tenantNodes,
29
+ tenant: action.data,
26
30
  loading: false,
27
31
  wasLoaded: true,
28
32
  error: undefined,
@@ -32,7 +36,7 @@ const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, a
32
36
  case FETCH_TENANT.FAILURE: {
33
37
  return {
34
38
  ...state,
35
- data: action.error,
39
+ error: action.error,
36
40
  loading: false,
37
41
  wasLoaded: true,
38
42
  };
@@ -41,7 +45,7 @@ const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, a
41
45
  case CLEAR_TENANT: {
42
46
  return {
43
47
  ...state,
44
- tenant: {},
48
+ tenant: undefined,
45
49
  loading: true,
46
50
  };
47
51
  }
@@ -65,45 +69,32 @@ const tenantReducer = (state = {loading: false, wasLoaded: false, tenant: {}}, a
65
69
  }
66
70
  };
67
71
 
68
- export const clearTenant = () => {
69
- return {type: CLEAR_TENANT};
70
- };
71
-
72
- export const getTenantInfo = ({path}) => {
72
+ export const getTenantInfo = ({path}: {path: string}) => {
73
73
  return createApiRequest({
74
- request: Promise.all([window.api.getTenantInfo({path}), window.api.getCompute(path)]),
74
+ request: window.api.getTenantInfo({path}),
75
75
  actions: FETCH_TENANT,
76
- dataHandler: ([tenantData, nodesData]) => {
77
- const tenant = tenantData.TenantInfo[0];
78
- const tenantNodes = _.map(nodesData?.Tenants[0]?.Nodes, (item) => {
79
- if (item.Host && item.Endpoints) {
80
- const address = _.find(item.Endpoints, {Name: 'http-mon'})?.Address;
81
- return {
82
- id: item.NodeId,
83
- backend: `${item.Host}${address ? address : ''}`,
84
- };
85
- }
86
-
87
- return undefined;
88
- }).filter(Boolean);
89
-
90
- return {tenant, tenantNodes};
76
+ dataHandler: (tenantData): TTenant | undefined => {
77
+ return tenantData.TenantInfo?.[0];
91
78
  },
92
79
  });
93
80
  };
94
81
 
95
- export function setTopLevelTab(tab) {
82
+ export const clearTenant = () => {
83
+ return {type: CLEAR_TENANT} as const;
84
+ };
85
+
86
+ export function setTopLevelTab(tab: TenantGeneralTab) {
96
87
  return {
97
88
  type: SET_TOP_LEVEL_TAB,
98
89
  data: tab,
99
- };
90
+ } as const;
100
91
  }
101
92
 
102
- export function setDiagnosticsTab(tab) {
93
+ export function setDiagnosticsTab(tab: TenantDiagnosticsTab) {
103
94
  return {
104
95
  type: SET_DIAGNOSTICS_TAB,
105
96
  data: tab,
106
- };
97
+ } as const;
107
98
  }
108
99
 
109
100
  export default tenantReducer;
@@ -0,0 +1,25 @@
1
+ import type {IResponseError} from '../../../types/api/error';
2
+ import type {TTenant} from '../../../types/api/tenant';
3
+ import type {ValueOf} from '../../../types/common';
4
+ import type {ApiRequestAction} from '../../utils';
5
+
6
+ import {TENANT_DIAGNOSTICS_TABS_IDS, TENANT_GENERAL_TABS_IDS} from './constants';
7
+ import {FETCH_TENANT, clearTenant, setDiagnosticsTab, setTopLevelTab} from './tenant';
8
+
9
+ export type TenantGeneralTab = ValueOf<typeof TENANT_GENERAL_TABS_IDS>;
10
+ export type TenantDiagnosticsTab = ValueOf<typeof TENANT_DIAGNOSTICS_TABS_IDS>;
11
+
12
+ export interface TenantState {
13
+ loading: boolean;
14
+ wasLoaded: boolean;
15
+ topLevelTab?: TenantGeneralTab;
16
+ diagnosticsTab?: TenantDiagnosticsTab;
17
+ tenant?: TTenant;
18
+ error?: IResponseError;
19
+ }
20
+
21
+ export type TenantAction =
22
+ | ApiRequestAction<typeof FETCH_TENANT, TTenant | undefined, IResponseError>
23
+ | ReturnType<typeof clearTenant>
24
+ | ReturnType<typeof setTopLevelTab>
25
+ | ReturnType<typeof setDiagnosticsTab>;
@@ -16,7 +16,7 @@ export interface TMetaCommonInfo {
16
16
  ACL?: TACE[];
17
17
  }
18
18
 
19
- interface TACE {
19
+ export interface TACE {
20
20
  AccessType: string;
21
21
  AccessRights?: string[];
22
22
  Subject: string;
@@ -97,7 +97,8 @@ export const formatDateTime = (value) => {
97
97
 
98
98
  export const calcUptimeInSeconds = (milliseconds) => {
99
99
  const currentDate = new Date();
100
- return (currentDate - Number(milliseconds)) / 1000;
100
+ const diff = currentDate - Number(milliseconds);
101
+ return diff <= 0 ? 0 : diff / 1000;
101
102
  };
102
103
 
103
104
  export const calcUptime = (milliseconds) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.5.0",
3
+ "version": "4.5.2",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -48,6 +48,7 @@
48
48
  "//build:embedded": "echo 'PUBLIC_URL is a setting for create-react-app. Embedded version is built and hosted as is on ydb servers, with no way of knowing the final URL pattern. PUBLIC_URL=. keeps paths to all static relative, allowing servers to handle them as needed'",
49
49
  "build:embedded": "rm -rf build && PUBLIC_URL=. REACT_APP_BACKEND=http://localhost:8765 npm run build",
50
50
  "lint:styles": "stylelint 'src/**/*.scss'",
51
+ "unimported": "npx unimported --no-cache",
51
52
  "package": "rm -rf dist && copyfiles -u 1 'src/**/*' dist",
52
53
  "test": "react-app-rewired test",
53
54
  "eject": "react-scripts eject",
@@ -1,25 +0,0 @@
1
- import React from 'react';
2
- import PropTypes from 'prop-types';
3
- import cn from 'bem-cn-lite';
4
- import {Breadcrumbs as BreadcrumbsUiKit} from '@gravity-ui/uikit';
5
-
6
- import './Breadcrumbs.scss';
7
-
8
- const b = cn('kv-breadcrumbs');
9
-
10
- class Breadcrumbs extends React.Component {
11
- static propTypes = {
12
- items: PropTypes.array,
13
- };
14
-
15
- static defaultProps = {
16
- items: [],
17
- };
18
-
19
- render() {
20
- const {items} = this.props;
21
- return <BreadcrumbsUiKit items={items} firstDisplayedItemsCount={1} className={b()} />;
22
- }
23
- }
24
-
25
- export default Breadcrumbs;
@@ -1,5 +0,0 @@
1
- .kv-breadcrumbs {
2
- padding: 20px 0;
3
-
4
- font-size: var(--yc-text-body-2-font-size);
5
- }
@@ -1,84 +0,0 @@
1
- import {useState, useEffect, useRef} from 'react';
2
- import block from 'bem-cn-lite';
3
- import {ArrowToggle, Button} from '@gravity-ui/uikit';
4
-
5
- import './Collapse.scss';
6
-
7
- const b = block('yc-collapse');
8
-
9
- function useEffectSkipFirst(fn, arr) {
10
- const isFirst = useRef(true);
11
-
12
- useEffect(() => {
13
- if (isFirst.current) {
14
- isFirst.current = false;
15
- return;
16
- }
17
-
18
- return fn();
19
- }, arr);
20
- }
21
-
22
- export const Collapse = ({
23
- title,
24
- children,
25
- arrowView = 'icon',
26
- emptyState = 'No data',
27
- titleSize = 'l',
28
- contentMarginTop = 12,
29
- defaultIsExpand,
30
- onChange,
31
- }) => {
32
- const [isExpand, setIsExpand] = useState(defaultIsExpand);
33
-
34
- const arrowDirection = isExpand ? 'top' : 'bottom';
35
-
36
- const arrowComponent =
37
- arrowView === 'button' ? (
38
- <Button view="flat" className={b('arrow-button')}>
39
- <ArrowToggle className={b('arrow')} direction={arrowDirection} size={20} />
40
- </Button>
41
- ) : (
42
- <ArrowToggle className={b('arrow')} direction={arrowDirection} size={20} />
43
- );
44
-
45
- useEffectSkipFirst(onChange, [isExpand]);
46
-
47
- return (
48
- <div className={b()}>
49
- <div
50
- className={b('panel', {
51
- 'no-data': !children,
52
- })}
53
- onClick={() => {
54
- setIsExpand(!isExpand);
55
- }}
56
- >
57
- {typeof title === 'string' ? (
58
- <h2
59
- className={b('title', {
60
- size: titleSize,
61
- })}
62
- >
63
- {title}
64
- </h2>
65
- ) : (
66
- title
67
- )}
68
-
69
- {children && <div className={b('arrow-wrapper')}>{arrowComponent}</div>}
70
- </div>
71
-
72
- {!children && <h4 className={b('empty-state-title')}>{emptyState}</h4>}
73
-
74
- {children && (
75
- <div
76
- className={b('content', {visible: isExpand})}
77
- style={{marginTop: contentMarginTop}}
78
- >
79
- {children}
80
- </div>
81
- )}
82
- </div>
83
- );
84
- };
@@ -1,70 +0,0 @@
1
- .yc-collapse {
2
- &__panel {
3
- display: inline-flex;
4
- align-items: center;
5
-
6
- cursor: pointer;
7
-
8
- &_no-data {
9
- cursor: default;
10
- }
11
- }
12
-
13
- &__title {
14
- margin: 0;
15
- }
16
-
17
- &__title_secondary {
18
- color: var(--yc-color-text-secondary);
19
- }
20
-
21
- &__title_size {
22
- &_s {
23
- font-size: var(--yc-text-body-1-font-size);
24
- line-height: var(--yc-text-body-1-line-height);
25
- }
26
-
27
- &_m {
28
- font-size: var(--yc-text-body-2-font-size);
29
- line-height: var(--yc-text-body-2-line-height);
30
- }
31
-
32
- &_l {
33
- font-size: var(--yc-text-body-3-font-size);
34
- line-height: var(--yc-text-body-3-line-height);
35
- }
36
- }
37
-
38
- &__arrow-wrapper {
39
- margin-left: 8px;
40
- }
41
-
42
- &__arrow-wrapper_secondary {
43
- color: var(--yc-color-text-secondary);
44
- .button2__text {
45
- color: var(--yc-color-text-secondary);
46
- }
47
- }
48
-
49
- &__content {
50
- display: none;
51
-
52
- &_visible {
53
- display: block;
54
- }
55
- }
56
-
57
- &__empty-state-title {
58
- font-size: var(--yc-text-body-1-font-size);
59
- font-weight: normal;
60
- line-height: var(--yc-text-body-1-line-height);
61
-
62
- opacity: 0.5;
63
- }
64
-
65
- &__arrow-button {
66
- .button2__text {
67
- margin: 0 4px;
68
- }
69
- }
70
- }
@@ -1,54 +0,0 @@
1
- import React from 'react';
2
- import cn from 'bem-cn-lite';
3
- import './PoolUsage.scss';
4
- import PropTypes from 'prop-types';
5
- const b = cn('pool-usage');
6
-
7
- const formatUsage = (usage) => (typeof usage === 'undefined' ? '' : Math.floor(usage * 100));
8
- const getLineType = (fillWidth) => {
9
- let fillColor = 'green';
10
- if (fillWidth > 60 && fillWidth <= 80) {
11
- fillColor = 'yellow';
12
- } else if (fillWidth > 80) {
13
- fillColor = 'red';
14
- }
15
-
16
- return fillColor;
17
- };
18
- export class PoolUsage extends React.Component {
19
- static propTypes = {
20
- data: PropTypes.object.isRequired,
21
- };
22
-
23
- render() {
24
- const {data: pool = {}} = this.props;
25
-
26
- const {Threads, Name = 'Unknown', Usage} = pool;
27
- const dataExist = Usage && Threads;
28
-
29
- const value = formatUsage(pool.Usage);
30
- const fillWidth = value > 100 ? 100 : value;
31
-
32
- return (
33
- <div className={b()}>
34
- <div className={b('info')}>
35
- <div className={b('pool-name')}>{Name}</div>
36
- {dataExist && (
37
- <div className={b('value')}>
38
- <div className={b('percents')}>{value < 1 ? '<1' : value}%</div>
39
- <div className={b('threads')}>(×{Threads})</div>
40
- </div>
41
- )}
42
- </div>
43
- <div className={b('visual')}>
44
- <div
45
- className={b('usage-line', {type: getLineType(fillWidth)})}
46
- style={{width: `${fillWidth}%`}}
47
- />
48
- </div>
49
- </div>
50
- );
51
- }
52
- }
53
-
54
- export default PoolUsage;
@@ -1,141 +0,0 @@
1
- import {createRequestActionTypes, createApiRequest} from '../utils';
2
- import '../../services/api';
3
- import {stringifyVdiskId} from '../../utils';
4
- import {createSelector} from 'reselect';
5
-
6
- const FETCH_NODE = createRequestActionTypes('node', 'FETCH_NODE');
7
- const FETCH_NODE_STRUCTURE = createRequestActionTypes('node', 'FETCH_NODE_STRUCTURE');
8
- const RESET_NODE = 'node/RESET_NODE';
9
-
10
- const node = (
11
- state = {
12
- data: {},
13
- loading: true,
14
- wasLoaded: false,
15
- nodeStructure: {},
16
- loadingStructure: true,
17
- wasLoadedStructure: false,
18
- },
19
- action,
20
- ) => {
21
- switch (action.type) {
22
- case FETCH_NODE.REQUEST: {
23
- return {
24
- ...state,
25
- loading: true,
26
- };
27
- }
28
- case FETCH_NODE.SUCCESS: {
29
- return {
30
- ...state,
31
- data: action.data,
32
- loading: false,
33
- wasLoaded: true,
34
- error: undefined,
35
- };
36
- }
37
- case FETCH_NODE.FAILURE: {
38
- return {
39
- ...state,
40
- error: action.error,
41
- loading: false,
42
- };
43
- }
44
- case FETCH_NODE_STRUCTURE.REQUEST: {
45
- return {
46
- ...state,
47
- loadingStructure: true,
48
- };
49
- }
50
- case FETCH_NODE_STRUCTURE.SUCCESS: {
51
- return {
52
- ...state,
53
- nodeStructure: action.data,
54
- loadingStructure: false,
55
- wasLoadedStructure: true,
56
- errorStructure: undefined,
57
- };
58
- }
59
- case FETCH_NODE_STRUCTURE.FAILURE: {
60
- return {
61
- ...state,
62
- errorStructure: action.error,
63
- loadingStructure: false,
64
- };
65
- }
66
- case RESET_NODE: {
67
- return {
68
- ...state,
69
- data: {},
70
- wasLoaded: false,
71
- nodeStructure: {},
72
- wasLoadedStructure: false,
73
- };
74
- }
75
- default:
76
- return state;
77
- }
78
- };
79
-
80
- export const getNodeInfo = (id) => {
81
- return createApiRequest({
82
- request: window.api.getNodeInfo(id),
83
- actions: FETCH_NODE,
84
- });
85
- };
86
-
87
- export const getNodeStructure = (nodeId) => {
88
- return createApiRequest({
89
- request: window.api.getStorageInfo({nodeId}, {concurrentId: 'getNodeStructure'}),
90
- actions: FETCH_NODE_STRUCTURE,
91
- });
92
- };
93
-
94
- export function resetNode() {
95
- return {
96
- type: RESET_NODE,
97
- };
98
- }
99
-
100
- const getNodeId = (state) => state.node?.data?.SystemStateInfo?.[0].NodeId;
101
-
102
- const getRawNodeStructure = (state) => state.node?.nodeStructure;
103
-
104
- export const selectNodeStructure = createSelector(
105
- [getNodeId, getRawNodeStructure],
106
- (nodeId, rawNodeStructure) => {
107
- const pools = rawNodeStructure?.StoragePools;
108
- const structure = {};
109
- pools?.forEach((pool) => {
110
- const groups = pool.Groups;
111
- groups?.forEach((group) => {
112
- const vDisks = group.VDisks?.filter((el) => el.NodeId === nodeId);
113
- vDisks?.forEach((vd) => {
114
- const vDiskId = stringifyVdiskId(vd.VDiskId);
115
- const pDiskId = vd.PDisk?.PDiskId;
116
- if (!structure[String(pDiskId)]) {
117
- structure[String(pDiskId)] = {vDisks: {}, ...vd.PDisk};
118
- }
119
- structure[String(pDiskId)].vDisks[vDiskId] = {
120
- ...vd,
121
- // VDisk doesn't have its own StoragePoolName when located inside StoragePool data
122
- StoragePoolName: pool.Name,
123
- };
124
- });
125
- });
126
- });
127
-
128
- const structureWithVdisksArray = Object.keys(structure).reduce((acc, el) => {
129
- const vDisks = structure[el].vDisks;
130
- const vDisksArray = Object.keys(vDisks).reduce((acc, key, index) => {
131
- acc.push({...vDisks[key], id: key, order: index});
132
- return acc;
133
- }, []);
134
- acc[el] = {...structure[el], vDisks: vDisksArray};
135
- return acc;
136
- }, {});
137
- return structureWithVdisksArray;
138
- },
139
- );
140
-
141
- export default node;