ydb-embedded-ui 3.3.2 → 3.3.3
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +18 -0
- package/dist/components/Errors/ResponseError/ResponseError.tsx +17 -0
- package/dist/components/Errors/ResponseError/index.ts +1 -0
- package/dist/components/Errors/i18n/en.json +2 -1
- package/dist/components/Errors/i18n/ru.json +2 -1
- package/dist/components/FullGroupViewer/FullGroupViewer.js +1 -1
- package/dist/components/InfoViewer/InfoViewer.scss +1 -1
- package/dist/components/InfoViewer/InfoViewer.tsx +29 -21
- package/dist/components/InfoViewer/formatters/index.ts +1 -0
- package/dist/components/InfoViewer/formatters/table.ts +40 -0
- package/dist/components/QueryExecutionStatus/QueryExecutionStatus.tsx +26 -8
- package/dist/components/QueryExecutionStatus/index.ts +1 -0
- package/dist/components/QueryResultTable/QueryResultTable.tsx +2 -2
- package/dist/containers/App/Content.js +12 -5
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +10 -13
- package/dist/containers/Authentication/Authentication.scss +6 -0
- package/dist/containers/Authentication/Authentication.tsx +34 -15
- package/dist/containers/Node/NodeStructure/Pdisk.tsx +7 -10
- package/dist/containers/Nodes/Nodes.tsx +1 -1
- package/dist/containers/Nodes/getNodesColumns.tsx +4 -4
- package/dist/containers/Storage/PDisk/PDisk.tsx +25 -17
- package/dist/containers/Storage/PDisk/__tests__/colors.tsx +64 -1
- package/dist/containers/Storage/Storage.js +1 -1
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +4 -3
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +1 -1
- package/dist/containers/Storage/utils/index.ts +26 -10
- package/dist/containers/Tablet/Tablet.js +1 -1
- package/dist/containers/Tenant/Acl/Acl.js +1 -1
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +1 -1
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/OverloadedShards.tsx +6 -1
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +10 -21
- package/dist/containers/Tenant/{Schema/SchemaInfoViewer/SchemaInfoViewer.scss → Diagnostics/Overview/TableInfo/TableInfo.scss} +8 -10
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/TableInfo.tsx +71 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/i18n/en.json +5 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/i18n/ru.json +5 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/TableInfo/prepareTableInfo.ts +96 -0
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +7 -1
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +3 -1
- package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +16 -11
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.js +37 -23
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +4 -0
- package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +1 -1
- package/dist/containers/Tenants/Tenants.js +4 -3
- package/dist/routes.ts +1 -0
- package/dist/services/api.js +4 -1
- package/dist/store/reducers/shardsWorkload.ts +2 -1
- package/dist/store/reducers/storage.js +1 -1
- package/dist/utils/constants.ts +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/prepareQueryExplain.ts +1 -1
- package/package.json +5 -3
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.scss +0 -13
- package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +0 -201
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.3.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.2...v3.3.3) (2023-02-08)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* **Auth:** add a step in history for auth form ([c72d06e](https://github.com/ydb-platform/ydb-embedded-ui/commit/c72d06ecacdba47cac59bd705c1185e1ddf0b20d))
|
9
|
+
* format dates with date-utils ([948598b](https://github.com/ydb-platform/ydb-embedded-ui/commit/948598b83c9bdd09268d128e15a42d5a6e0c15cc))
|
10
|
+
* **InfoViewer:** add prop renderEmptyState ([44fe28f](https://github.com/ydb-platform/ydb-embedded-ui/commit/44fe28f72ea299b3b5d9b5a33a0a0130d471f7dd))
|
11
|
+
* minor fixes in Nodes and Tenants tables ([8dca43a](https://github.com/ydb-platform/ydb-embedded-ui/commit/8dca43a482b0da31dbc618875b416dcfcedac036))
|
12
|
+
* **OverloadedShards:** display IntervalEnd ([c7cbd72](https://github.com/ydb-platform/ydb-embedded-ui/commit/c7cbd7215eaf60601941410acb13ffb25d151eb9))
|
13
|
+
* **Overview:** display error statusText on schema error ([99b030f](https://github.com/ydb-platform/ydb-embedded-ui/commit/99b030f90e6044e98a151e5128603835c84e1b4e))
|
14
|
+
* **PDisk:** calculate severity based on usage ([64c6890](https://github.com/ydb-platform/ydb-embedded-ui/commit/64c6890ac6d5a77aef73da7dfc7f1eaff8a72441))
|
15
|
+
* **QueryEditor:** make client request timeout 9 min ([44528a8](https://github.com/ydb-platform/ydb-embedded-ui/commit/44528a865b039003cda4c7b1b1367840da015d09))
|
16
|
+
* **QueryEditor:** result status for aborted connection ([4b0d84b](https://github.com/ydb-platform/ydb-embedded-ui/commit/4b0d84b550deb41a140d4a3d215e52084507a558))
|
17
|
+
* **QueryResult:** output client error messages ([deef610](https://github.com/ydb-platform/ydb-embedded-ui/commit/deef6103f4d08825837520cab9e8ae5b8c7fd496))
|
18
|
+
* **Storage:** replace hasOwn to hasOwnProperty ([2452310](https://github.com/ydb-platform/ydb-embedded-ui/commit/2452310ce8e953d7a9ee4bbaa2bd466396aa0131))
|
19
|
+
* **TopQueries:** display IntervalEnd ([e5b2b07](https://github.com/ydb-platform/ydb-embedded-ui/commit/e5b2b07cf1e686c20817dcdc1ae32e0c8912a21a))
|
20
|
+
|
3
21
|
## [3.3.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.1...v3.3.2) (2023-01-31)
|
4
22
|
|
5
23
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import type {IResponseError} from '../../../types/api/error';
|
2
|
+
|
3
|
+
import i18n from '../i18n';
|
4
|
+
|
5
|
+
interface ResponseErrorProps {
|
6
|
+
error: IResponseError;
|
7
|
+
className?: string;
|
8
|
+
defaultMessage?: string;
|
9
|
+
}
|
10
|
+
|
11
|
+
export const ResponseError = ({
|
12
|
+
error,
|
13
|
+
className,
|
14
|
+
defaultMessage = i18n('responseError.defaultMessage'),
|
15
|
+
}: ResponseErrorProps) => {
|
16
|
+
return <div className={`error ${className}`}>{error.statusText || defaultMessage}</div>;
|
17
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './ResponseError';
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
import PropTypes from 'prop-types';
|
4
4
|
|
5
|
-
import DataTable from '@
|
5
|
+
import DataTable from '@gravity-ui/react-data-table';
|
6
6
|
|
7
7
|
import InfoViewer from '../InfoViewer/InfoViewer';
|
8
8
|
import EntityStatus from '../EntityStatus/EntityStatus';
|
@@ -15,6 +15,7 @@ interface InfoViewerProps {
|
|
15
15
|
size?: 's';
|
16
16
|
className?: string;
|
17
17
|
multilineLabels?: boolean;
|
18
|
+
renderEmptyState?: (props?: Pick<InfoViewerProps, 'title' | 'size'>) => ReactNode;
|
18
19
|
}
|
19
20
|
|
20
21
|
const b = cn('info-viewer');
|
@@ -26,28 +27,35 @@ const InfoViewer = ({
|
|
26
27
|
size,
|
27
28
|
className,
|
28
29
|
multilineLabels,
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
{
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
30
|
+
renderEmptyState,
|
31
|
+
}: InfoViewerProps) => {
|
32
|
+
if ((!info || !info.length) && renderEmptyState) {
|
33
|
+
return <>{renderEmptyState({title, size})}</>;
|
34
|
+
}
|
35
|
+
|
36
|
+
return (
|
37
|
+
<div className={b({size}, className)}>
|
38
|
+
{title && <div className={b('title')}>{title}</div>}
|
39
|
+
{info && info.length > 0 ? (
|
40
|
+
<div className={b('items')}>
|
41
|
+
{info.map((data, infoIndex) => (
|
42
|
+
<div className={b('row')} key={data.label + infoIndex}>
|
43
|
+
<div className={b('label')}>
|
44
|
+
<div className={b('label-text', {multiline: multilineLabels})}>
|
45
|
+
{data.label}
|
46
|
+
</div>
|
47
|
+
{dots && <div className={b('dots')} />}
|
39
48
|
</div>
|
40
|
-
{dots && <div className={b('dots')} />}
|
41
|
-
</div>
|
42
49
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
);
|
50
|
+
<div className={b('value')}>{data.value}</div>
|
51
|
+
</div>
|
52
|
+
))}
|
53
|
+
</div>
|
54
|
+
) : (
|
55
|
+
<>No {title} data</>
|
56
|
+
)}
|
57
|
+
</div>
|
58
|
+
);
|
59
|
+
};
|
52
60
|
|
53
61
|
export default InfoViewer;
|
@@ -0,0 +1,40 @@
|
|
1
|
+
import type {TFollowerGroup, TPartitionConfig, TTableStats} from '../../../types/api/schema';
|
2
|
+
import type {TMetrics} from '../../../types/api/tenant';
|
3
|
+
import {formatCPU, formatBytes, formatNumber, formatBps, formatDateTime} from '../../../utils';
|
4
|
+
|
5
|
+
import {createInfoFormatter} from '../utils';
|
6
|
+
|
7
|
+
export const formatTabletMetricsItem = createInfoFormatter<TMetrics>({
|
8
|
+
values: {
|
9
|
+
CPU: formatCPU,
|
10
|
+
Memory: formatBytes,
|
11
|
+
Storage: formatBytes,
|
12
|
+
Network: formatBps,
|
13
|
+
ReadThroughput: formatBps,
|
14
|
+
WriteThroughput: formatBps,
|
15
|
+
},
|
16
|
+
defaultValueFormatter: formatNumber,
|
17
|
+
});
|
18
|
+
|
19
|
+
export const formatFollowerGroupItem = createInfoFormatter<TFollowerGroup>({
|
20
|
+
values: {
|
21
|
+
FollowerCount: formatNumber,
|
22
|
+
},
|
23
|
+
});
|
24
|
+
|
25
|
+
export const formatPartitionConfigItem = createInfoFormatter<TPartitionConfig>({
|
26
|
+
values: {
|
27
|
+
FollowerCount: formatNumber,
|
28
|
+
CrossDataCenterFollowerCount: formatNumber,
|
29
|
+
},
|
30
|
+
});
|
31
|
+
|
32
|
+
export const formatTableStatsItem = createInfoFormatter<TTableStats>({
|
33
|
+
values: {
|
34
|
+
DataSize: formatBytes,
|
35
|
+
IndexSize: formatBytes,
|
36
|
+
LastAccessTime: formatDateTime,
|
37
|
+
LastUpdateTime: formatDateTime,
|
38
|
+
},
|
39
|
+
defaultValueFormatter: formatNumber,
|
40
|
+
});
|
@@ -1,19 +1,32 @@
|
|
1
|
+
import type {ReactNode} from 'react';
|
2
|
+
import type {AxiosError} from 'axios';
|
1
3
|
import cn from 'bem-cn-lite';
|
2
4
|
|
5
|
+
import {Icon as UiKitIcon} from '@gravity-ui/uikit';
|
6
|
+
|
3
7
|
import Icon from '../Icon/Icon';
|
4
8
|
|
9
|
+
import questionIcon from '../../assets/icons/question.svg';
|
10
|
+
|
5
11
|
import './QueryExecutionStatus.scss';
|
6
12
|
|
7
13
|
const b = cn('kv-query-execution-status');
|
8
14
|
|
9
15
|
interface QueryExecutionStatusProps {
|
10
16
|
className?: string;
|
11
|
-
|
17
|
+
error?: AxiosError | Record<string, any>;
|
12
18
|
}
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
|
20
|
+
export const QueryExecutionStatus = ({className, error}: QueryExecutionStatusProps) => {
|
21
|
+
let icon: ReactNode;
|
22
|
+
let label: string;
|
23
|
+
|
24
|
+
if (error?.code === 'ECONNABORTED') {
|
25
|
+
icon = <UiKitIcon data={questionIcon} size={16} />;
|
26
|
+
label = 'Connection aborted';
|
27
|
+
} else {
|
28
|
+
const hasError = Boolean(error);
|
29
|
+
icon = (
|
17
30
|
<Icon
|
18
31
|
name={hasError ? 'failure' : 'success'}
|
19
32
|
viewBox={hasError ? '0 0 512 512' : '0 0 16 16'}
|
@@ -21,9 +34,14 @@ function QueryExecutionStatus({className, hasError}: QueryExecutionStatusProps)
|
|
21
34
|
height={16}
|
22
35
|
className={b('result-status-icon', {error: hasError})}
|
23
36
|
/>
|
24
|
-
|
37
|
+
);
|
38
|
+
label = hasError ? 'Failed' : 'Completed';
|
39
|
+
}
|
40
|
+
|
41
|
+
return (
|
42
|
+
<div className={b(null, className)}>
|
43
|
+
{icon}
|
44
|
+
{label}
|
25
45
|
</div>
|
26
46
|
);
|
27
|
-
}
|
28
|
-
|
29
|
-
export default QueryExecutionStatus;
|
47
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export * from './QueryExecutionStatus';
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import {useMemo} from 'react';
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
|
4
|
-
import DataTable from '@
|
5
|
-
import type {Column, DataTableProps, Settings} from '@
|
4
|
+
import DataTable from '@gravity-ui/react-data-table';
|
5
|
+
import type {Column, DataTableProps, Settings} from '@gravity-ui/react-data-table';
|
6
6
|
|
7
7
|
import type {ColumnType, KeyValueRow} from '../../types/api/query';
|
8
8
|
import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
|
@@ -79,11 +79,18 @@ function ContentWrapper(props) {
|
|
79
79
|
<HistoryContext.Consumer>
|
80
80
|
{(history) => (
|
81
81
|
<Router history={history}>
|
82
|
-
<
|
83
|
-
<
|
84
|
-
|
85
|
-
</
|
86
|
-
|
82
|
+
<Switch>
|
83
|
+
<Route path={routes.auth}>
|
84
|
+
<Authentication closable />
|
85
|
+
</Route>
|
86
|
+
<Route>
|
87
|
+
<ThemeProvider theme={theme}>
|
88
|
+
<div className={b({embedded: singleClusterMode})}>
|
89
|
+
{isAuthenticated ? props.children : <Authentication />}
|
90
|
+
</div>
|
91
|
+
</ThemeProvider>
|
92
|
+
</Route>
|
93
|
+
</Switch>
|
87
94
|
</Router>
|
88
95
|
)}
|
89
96
|
</HistoryContext.Consumer>
|
@@ -23,7 +23,7 @@ import UserSettings from '../UserSettings/UserSettings';
|
|
23
23
|
|
24
24
|
import routes, {createHref, CLUSTER_PAGES} from '../../routes';
|
25
25
|
|
26
|
-
import {logout
|
26
|
+
import {logout} from '../../store/reducers/authentication';
|
27
27
|
import {getSettingValue, setSettingValue} from '../../store/reducers/settings';
|
28
28
|
|
29
29
|
import {ASIDE_HEADER_COMPACT_KEY} from '../../utils/constants';
|
@@ -43,10 +43,15 @@ interface MenuItem {
|
|
43
43
|
interface YbdInternalUserProps {
|
44
44
|
ydbUser?: string;
|
45
45
|
logout: VoidFunction;
|
46
|
-
setIsNotAuthenticated: VoidFunction;
|
47
46
|
}
|
48
47
|
|
49
|
-
function YbdInternalUser({ydbUser, logout
|
48
|
+
function YbdInternalUser({ydbUser, logout}: YbdInternalUserProps) {
|
49
|
+
const history = useHistory();
|
50
|
+
|
51
|
+
const handleLoginClick = () => {
|
52
|
+
history.push(createHref(routes.auth, undefined, {returnUrl: encodeURI(location.href)}));
|
53
|
+
};
|
54
|
+
|
50
55
|
return (
|
51
56
|
<div className={b('internal-user')}>
|
52
57
|
<div className={b('user-info-wrapper')}>
|
@@ -58,7 +63,7 @@ function YbdInternalUser({ydbUser, logout, setIsNotAuthenticated}: YbdInternalUs
|
|
58
63
|
<Icon data={signOutIcon} size={16} />
|
59
64
|
</Button>
|
60
65
|
) : (
|
61
|
-
<Button view="flat-secondary"
|
66
|
+
<Button view="flat-secondary" title="login" onClick={handleLoginClick}>
|
62
67
|
<Icon data={signInIcon} size={16} />
|
63
68
|
</Button>
|
64
69
|
)}
|
@@ -71,7 +76,6 @@ interface YdbUserDropdownProps {
|
|
71
76
|
ydbUser: {
|
72
77
|
login?: string;
|
73
78
|
logout: VoidFunction;
|
74
|
-
setIsNotAuthenticated: VoidFunction;
|
75
79
|
};
|
76
80
|
popupAnchor: React.RefObject<HTMLDivElement>;
|
77
81
|
}
|
@@ -96,11 +100,7 @@ function YdbUserDropdown({isCompact, popupAnchor, ydbUser}: YdbUserDropdownProps
|
|
96
100
|
onClosePopup={() => setIsUserDropdownVisible(false)}
|
97
101
|
renderPopupContent={() => (
|
98
102
|
<div className={b('ydb-user-wrapper')}>
|
99
|
-
<YbdInternalUser
|
100
|
-
ydbUser={ydbUser.login}
|
101
|
-
logout={ydbUser.logout}
|
102
|
-
setIsNotAuthenticated={ydbUser.setIsNotAuthenticated}
|
103
|
-
/>
|
103
|
+
<YbdInternalUser ydbUser={ydbUser.login} logout={ydbUser.logout} />
|
104
104
|
</div>
|
105
105
|
)}
|
106
106
|
/>
|
@@ -112,7 +112,6 @@ interface AsideNavigationProps {
|
|
112
112
|
ydbUser: string;
|
113
113
|
compact: boolean;
|
114
114
|
logout: VoidFunction;
|
115
|
-
setIsNotAuthenticated: VoidFunction;
|
116
115
|
setSettingValue: (name: string, value: string) => void;
|
117
116
|
}
|
118
117
|
|
@@ -260,7 +259,6 @@ function AsideNavigation(props: AsideNavigationProps) {
|
|
260
259
|
ydbUser={{
|
261
260
|
login: props.ydbUser,
|
262
261
|
logout: props.logout,
|
263
|
-
setIsNotAuthenticated: props.setIsNotAuthenticated,
|
264
262
|
}}
|
265
263
|
/>
|
266
264
|
</React.Fragment>
|
@@ -291,7 +289,6 @@ const mapStateToProps = (state: any) => {
|
|
291
289
|
|
292
290
|
const mapDispatchToProps = {
|
293
291
|
logout,
|
294
|
-
setIsNotAuthenticated,
|
295
292
|
setSettingValue,
|
296
293
|
};
|
297
294
|
|
@@ -1,19 +1,33 @@
|
|
1
1
|
import {KeyboardEvent, useEffect, useState} from 'react';
|
2
|
+
import {useDispatch} from 'react-redux';
|
3
|
+
import {useHistory} from 'react-router';
|
2
4
|
import cn from 'bem-cn-lite';
|
3
|
-
|
5
|
+
|
4
6
|
import {Button, TextInput, Icon, Link as ExternalLink} from '@gravity-ui/uikit';
|
5
|
-
|
7
|
+
|
6
8
|
import {authenticate} from '../../store/reducers/authentication';
|
9
|
+
import {useTypedSelector} from '../../utils/hooks';
|
7
10
|
|
8
11
|
import ydbLogoIcon from '../../assets/icons/ydb.svg';
|
9
12
|
import showIcon from '../../assets/icons/show.svg';
|
10
13
|
import hideIcon from '../../assets/icons/hide.svg';
|
14
|
+
import closeIcon from '../../assets/icons/close.svg';
|
11
15
|
|
12
16
|
import './Authentication.scss';
|
13
17
|
|
14
18
|
const b = cn('authentication');
|
15
19
|
|
16
|
-
|
20
|
+
interface AuthenticationProps {
|
21
|
+
returnUrl?: string;
|
22
|
+
closable?: boolean;
|
23
|
+
}
|
24
|
+
|
25
|
+
function Authentication({returnUrl, closable = false}: AuthenticationProps) {
|
26
|
+
const dispatch = useDispatch();
|
27
|
+
const history = useHistory();
|
28
|
+
|
29
|
+
const {error} = useTypedSelector((state) => state.authentication);
|
30
|
+
|
17
31
|
const [login, setLogin] = useState('');
|
18
32
|
const [pass, setPass] = useState('');
|
19
33
|
const [loginError, setLoginError] = useState('');
|
@@ -40,7 +54,13 @@ function Authentication({authenticate, error}: any) {
|
|
40
54
|
};
|
41
55
|
|
42
56
|
const onLoginClick = () => {
|
43
|
-
|
57
|
+
// @ts-expect-error
|
58
|
+
// typed dispatch required, remove error expectation after adding it
|
59
|
+
dispatch(authenticate(login, pass)).then(() => {
|
60
|
+
if (returnUrl) {
|
61
|
+
history.replace(decodeURI(returnUrl));
|
62
|
+
}
|
63
|
+
});
|
44
64
|
};
|
45
65
|
|
46
66
|
const onEnterClick = (e: KeyboardEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
@@ -49,6 +69,10 @@ function Authentication({authenticate, error}: any) {
|
|
49
69
|
}
|
50
70
|
};
|
51
71
|
|
72
|
+
const onClose = () => {
|
73
|
+
history.go(-1);
|
74
|
+
};
|
75
|
+
|
52
76
|
const onTogglePasswordVisibility = () => {
|
53
77
|
setShowPassword((prev) => !prev);
|
54
78
|
};
|
@@ -106,18 +130,13 @@ function Authentication({authenticate, error}: any) {
|
|
106
130
|
Sign in
|
107
131
|
</Button>
|
108
132
|
</form>
|
133
|
+
{closable && history.length > 1 && (
|
134
|
+
<Button onClick={onClose} className={b('close')}>
|
135
|
+
<Icon data={closeIcon} size={24} />
|
136
|
+
</Button>
|
137
|
+
)}
|
109
138
|
</section>
|
110
139
|
);
|
111
140
|
}
|
112
141
|
|
113
|
-
|
114
|
-
return {
|
115
|
-
error: state.authentication.error,
|
116
|
-
};
|
117
|
-
}
|
118
|
-
|
119
|
-
const mapDispatchToProps = {
|
120
|
-
authenticate,
|
121
|
-
};
|
122
|
-
|
123
|
-
export default connect(mapStateToProps, mapDispatchToProps)(Authentication);
|
142
|
+
export default Authentication;
|
@@ -4,7 +4,7 @@ import _ from 'lodash';
|
|
4
4
|
|
5
5
|
import {ArrowToggle, Button, Popover} from '@gravity-ui/uikit';
|
6
6
|
|
7
|
-
import DataTable, {Column, Settings} from '@
|
7
|
+
import DataTable, {Column, Settings} from '@gravity-ui/react-data-table';
|
8
8
|
|
9
9
|
import EntityStatus from '../../../components/EntityStatus/EntityStatus';
|
10
10
|
import InfoViewer from '../../../components/InfoViewer/InfoViewer';
|
@@ -295,10 +295,7 @@ export function PDisk(props: PDiskProps) {
|
|
295
295
|
value={data.PDiskId}
|
296
296
|
className={b('pdisk-title-id')}
|
297
297
|
/>
|
298
|
-
<PDiskTitleBadge
|
299
|
-
value={getPDiskType(data)}
|
300
|
-
className={b('pdisk-title-type')}
|
301
|
-
/>
|
298
|
+
<PDiskTitleBadge value={getPDiskType(data)} className={b('pdisk-title-type')} />
|
302
299
|
<ProgressViewer
|
303
300
|
value={data.TotalSize - data.AvailableSize}
|
304
301
|
capacity={data.TotalSize}
|
@@ -306,12 +303,12 @@ export function PDisk(props: PDiskProps) {
|
|
306
303
|
colorizeProgress={true}
|
307
304
|
className={b('pdisk-title-size')}
|
308
305
|
/>
|
309
|
-
<PDiskTitleBadge
|
310
|
-
label="VDisks"
|
311
|
-
value={data.vDisks.length}
|
312
|
-
/>
|
306
|
+
<PDiskTitleBadge label="VDisks" value={data.vDisks.length} />
|
313
307
|
</div>
|
314
|
-
<Button
|
308
|
+
<Button
|
309
|
+
onClick={unfolded ? onClosePDiskDetails : onOpenPDiskDetails}
|
310
|
+
view="flat-secondary"
|
311
|
+
>
|
315
312
|
<ArrowToggle direction={unfolded ? 'top' : 'bottom'} />
|
316
313
|
</Button>
|
317
314
|
</div>
|
@@ -2,7 +2,7 @@ import {useCallback, useEffect} from 'react';
|
|
2
2
|
import cn from 'bem-cn-lite';
|
3
3
|
import {useDispatch} from 'react-redux';
|
4
4
|
|
5
|
-
import DataTable from '@
|
5
|
+
import DataTable from '@gravity-ui/react-data-table';
|
6
6
|
|
7
7
|
import {AccessDenied} from '../../components/Errors/403';
|
8
8
|
import {Illustration} from '../../components/Illustration';
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import cn from 'bem-cn-lite';
|
2
|
-
import DataTable, {Column} from '@
|
2
|
+
import DataTable, {Column} from '@gravity-ui/react-data-table';
|
3
3
|
import {Button, Popover} from '@gravity-ui/uikit';
|
4
4
|
|
5
5
|
import Icon from '../../components/Icon/Icon';
|
@@ -8,7 +8,7 @@ import PoolsGraph from '../../components/PoolsGraph/PoolsGraph';
|
|
8
8
|
import ProgressViewer from '../../components/ProgressViewer/ProgressViewer';
|
9
9
|
import {TabletsStatistic} from '../../components/TabletsStatistic';
|
10
10
|
|
11
|
-
import {
|
11
|
+
import {formatBytesToGigabyte} from '../../utils/index';
|
12
12
|
import {INodesPreparedEntity} from '../../types/store/nodes';
|
13
13
|
import {showTooltip as externalShowTooltip} from '../../store/reducers/tooltip';
|
14
14
|
|
@@ -100,7 +100,7 @@ export function getNodesColumns({
|
|
100
100
|
name: 'Uptime',
|
101
101
|
header: 'Uptime',
|
102
102
|
sortAccessor: ({StartTime}) => StartTime && -StartTime,
|
103
|
-
align: DataTable.
|
103
|
+
align: DataTable.RIGHT,
|
104
104
|
width: '110px',
|
105
105
|
},
|
106
106
|
{
|
@@ -110,7 +110,7 @@ export function getNodesColumns({
|
|
110
110
|
defaultOrder: DataTable.DESCENDING,
|
111
111
|
render: ({row}) => {
|
112
112
|
if (row.MemoryUsed) {
|
113
|
-
return
|
113
|
+
return formatBytesToGigabyte(row.MemoryUsed);
|
114
114
|
} else {
|
115
115
|
return '—';
|
116
116
|
}
|
@@ -17,7 +17,7 @@ import {DiskStateProgressBar, EDiskStateSeverity} from '../DiskStateProgressBar'
|
|
17
17
|
import {PDiskPopup} from '../PDiskPopup';
|
18
18
|
import {VDisk} from '../VDisk';
|
19
19
|
|
20
|
-
import {NOT_AVAILABLE_SEVERITY} from '../utils';
|
20
|
+
import {getUsageSeverityForPDisk, NOT_AVAILABLE_SEVERITY} from '../utils';
|
21
21
|
|
22
22
|
import './PDisk.scss';
|
23
23
|
|
@@ -67,21 +67,6 @@ export const PDisk = ({nodeId, data: rawData = {}}: PDiskProps) => {
|
|
67
67
|
|
68
68
|
const anchor = useRef(null);
|
69
69
|
|
70
|
-
useEffect(() => {
|
71
|
-
const newSeverity = getStateSeverity(data.State);
|
72
|
-
if (severity !== newSeverity) {
|
73
|
-
setSeverity(newSeverity);
|
74
|
-
}
|
75
|
-
}, [data.State]);
|
76
|
-
|
77
|
-
const showPopup = () => {
|
78
|
-
setIsPopupVisible(true);
|
79
|
-
};
|
80
|
-
|
81
|
-
const hidePopup = () => {
|
82
|
-
setIsPopupVisible(false);
|
83
|
-
};
|
84
|
-
|
85
70
|
const pdiskAllocatedPercent = useMemo(() => {
|
86
71
|
const {AvailableSize, TotalSize} = data;
|
87
72
|
|
@@ -94,6 +79,29 @@ export const PDisk = ({nodeId, data: rawData = {}}: PDiskProps) => {
|
|
94
79
|
: undefined;
|
95
80
|
}, [data]);
|
96
81
|
|
82
|
+
useEffect(() => {
|
83
|
+
const newStateSeverity = getStateSeverity(data.State);
|
84
|
+
const newSpaceSeverityFlag = getUsageSeverityForPDisk(pdiskAllocatedPercent || 0);
|
85
|
+
|
86
|
+
let newSeverity: number;
|
87
|
+
|
88
|
+
if (newStateSeverity === NOT_AVAILABLE_SEVERITY || !newSpaceSeverityFlag) {
|
89
|
+
newSeverity = newStateSeverity;
|
90
|
+
} else {
|
91
|
+
newSeverity = Math.max(newStateSeverity, EDiskStateSeverity[newSpaceSeverityFlag]);
|
92
|
+
}
|
93
|
+
|
94
|
+
setSeverity(newSeverity);
|
95
|
+
}, [data.State, pdiskAllocatedPercent]);
|
96
|
+
|
97
|
+
const showPopup = () => {
|
98
|
+
setIsPopupVisible(true);
|
99
|
+
};
|
100
|
+
|
101
|
+
const hidePopup = () => {
|
102
|
+
setIsPopupVisible(false);
|
103
|
+
};
|
104
|
+
|
97
105
|
const renderVDisks = () => {
|
98
106
|
if (!vdisks?.length) {
|
99
107
|
return null;
|
@@ -108,7 +116,7 @@ export const PDisk = ({nodeId, data: rawData = {}}: PDiskProps) => {
|
|
108
116
|
style={{
|
109
117
|
// 1 is small enough for empty disks to be of the minimum width
|
110
118
|
// but if all of them are empty, `flex-grow: 1` would size them evenly
|
111
|
-
flexGrow:
|
119
|
+
flexGrow: Number(vdisk.AllocatedSize) || 1,
|
112
120
|
}}
|
113
121
|
>
|
114
122
|
<VDisk data={vdisk} compact />
|