ydb-embedded-ui 3.3.2 → 3.3.4
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.
- package/CHANGELOG.md +27 -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 +12 -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/Diagnostics.tsx +3 -3
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +7 -7
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +1 -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/Diagnostics/TopShards/Filters/Filters.scss +8 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/Filters/Filters.tsx +56 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/Filters/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/{OverloadedShards/OverloadedShards.scss → TopShards/TopShards.scss} +2 -10
- package/dist/containers/Tenant/Diagnostics/{OverloadedShards/OverloadedShards.tsx → TopShards/TopShards.tsx} +64 -29
- package/dist/containers/Tenant/Diagnostics/TopShards/i18n/en.json +6 -0
- package/dist/containers/Tenant/Diagnostics/{OverloadedShards → TopShards}/i18n/index.ts +1 -1
- package/dist/containers/Tenant/Diagnostics/TopShards/i18n/ru.json +6 -0
- package/dist/containers/Tenant/Diagnostics/TopShards/index.ts +1 -0
- 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/authentication.js +0 -15
- package/dist/store/reducers/shardsWorkload.ts +30 -3
- package/dist/store/reducers/storage.js +1 -1
- package/dist/store/state-url-mapping.js +3 -0
- package/dist/types/store/shardsWorkload.ts +6 -0
- package/dist/utils/constants.ts +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/prepareQueryExplain.ts +1 -1
- package/dist/utils/typecheckers.ts +5 -0
- package/package.json +5 -3
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/en.json +0 -4
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/ru.json +0 -4
- package/dist/containers/Tenant/Diagnostics/OverloadedShards/index.ts +0 -1
- 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,32 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [3.3.4](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.3...v3.3.4) (2023-02-16)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* **OverloadedShards:** rename to top shards ([ffa4f27](https://github.com/ydb-platform/ydb-embedded-ui/commit/ffa4f27f2cf0a5e12b2800c81bf61b1d3c25912c))
|
9
|
+
* **StorageGroups:** display Erasure ([4a7ebc0](https://github.com/ydb-platform/ydb-embedded-ui/commit/4a7ebc08b87fe75af83df70a38ebd486d64d6d4e))
|
10
|
+
* **TopShards:** switch between history and immediate data ([eeb9bb0](https://github.com/ydb-platform/ydb-embedded-ui/commit/eeb9bb0911b9e889b633558c9d3c13f986f72bfe))
|
11
|
+
|
12
|
+
## [3.3.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.2...v3.3.3) (2023-02-08)
|
13
|
+
|
14
|
+
|
15
|
+
### Bug Fixes
|
16
|
+
|
17
|
+
* **Auth:** add a step in history for auth form ([c72d06e](https://github.com/ydb-platform/ydb-embedded-ui/commit/c72d06ecacdba47cac59bd705c1185e1ddf0b20d))
|
18
|
+
* format dates with date-utils ([948598b](https://github.com/ydb-platform/ydb-embedded-ui/commit/948598b83c9bdd09268d128e15a42d5a6e0c15cc))
|
19
|
+
* **InfoViewer:** add prop renderEmptyState ([44fe28f](https://github.com/ydb-platform/ydb-embedded-ui/commit/44fe28f72ea299b3b5d9b5a33a0a0130d471f7dd))
|
20
|
+
* minor fixes in Nodes and Tenants tables ([8dca43a](https://github.com/ydb-platform/ydb-embedded-ui/commit/8dca43a482b0da31dbc618875b416dcfcedac036))
|
21
|
+
* **OverloadedShards:** display IntervalEnd ([c7cbd72](https://github.com/ydb-platform/ydb-embedded-ui/commit/c7cbd7215eaf60601941410acb13ffb25d151eb9))
|
22
|
+
* **Overview:** display error statusText on schema error ([99b030f](https://github.com/ydb-platform/ydb-embedded-ui/commit/99b030f90e6044e98a151e5128603835c84e1b4e))
|
23
|
+
* **PDisk:** calculate severity based on usage ([64c6890](https://github.com/ydb-platform/ydb-embedded-ui/commit/64c6890ac6d5a77aef73da7dfc7f1eaff8a72441))
|
24
|
+
* **QueryEditor:** make client request timeout 9 min ([44528a8](https://github.com/ydb-platform/ydb-embedded-ui/commit/44528a865b039003cda4c7b1b1367840da015d09))
|
25
|
+
* **QueryEditor:** result status for aborted connection ([4b0d84b](https://github.com/ydb-platform/ydb-embedded-ui/commit/4b0d84b550deb41a140d4a3d215e52084507a558))
|
26
|
+
* **QueryResult:** output client error messages ([deef610](https://github.com/ydb-platform/ydb-embedded-ui/commit/deef6103f4d08825837520cab9e8ae5b8c7fd496))
|
27
|
+
* **Storage:** replace hasOwn to hasOwnProperty ([2452310](https://github.com/ydb-platform/ydb-embedded-ui/commit/2452310ce8e953d7a9ee4bbaa2bd466396aa0131))
|
28
|
+
* **TopQueries:** display IntervalEnd ([e5b2b07](https://github.com/ydb-platform/ydb-embedded-ui/commit/e5b2b07cf1e686c20817dcdc1ae32e0c8912a21a))
|
29
|
+
|
3
30
|
## [3.3.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.3.1...v3.3.2) (2023-01-31)
|
4
31
|
|
5
32
|
|
@@ -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 />
|