ydb-embedded-ui 4.5.0 → 4.5.2

Sign up to get free protection for your applications and to get access to all the features.
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;