ydb-embedded-ui 4.6.0 → 4.8.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +27 -0
- package/dist/assets/icons/versions.svg +3 -0
- package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +6 -1
- package/dist/components/Tablet/Tablet.tsx +17 -3
- package/dist/components/TabletsStatistic/TabletsStatistic.tsx +23 -16
- package/dist/containers/App/Content.js +5 -2
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +50 -18
- package/dist/containers/Cluster/Cluster.tsx +6 -13
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +3 -3
- package/dist/containers/Cluster/{utils.ts → utils.tsx} +11 -0
- package/dist/containers/Header/Header.scss +9 -0
- package/dist/containers/Header/Header.tsx +70 -14
- package/dist/containers/Header/breadcrumbs.ts +146 -0
- package/dist/containers/Node/Node.tsx +21 -27
- package/dist/containers/Node/NodePages.ts +10 -6
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +11 -3
- package/dist/containers/Tablet/Tablet.tsx +35 -27
- package/dist/containers/Tablet/TabletInfo/TabletInfo.tsx +2 -2
- package/dist/containers/TabletsFilters/TabletsFilters.js +13 -15
- package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +1 -1
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +5 -1
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +4 -14
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +5 -3
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +1 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +2 -1
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +9 -16
- package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +11 -11
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +7 -3
- package/dist/containers/Tenant/{QueryEditor/QueryResult/QueryResult.js → Query/ExecuteResult/ExecuteResult.js} +3 -5
- package/dist/containers/Tenant/{QueryEditor/QueryResult/QueryResult.scss → Query/ExecuteResult/ExecuteResult.scss} +1 -1
- package/dist/containers/Tenant/{QueryEditor/QueryExplain/QueryExplain.js → Query/ExplainResult/ExplainResult.js} +3 -5
- package/dist/containers/Tenant/{QueryEditor/QueryExplain/QueryExplain.scss → Query/ExplainResult/ExplainResult.scss} +1 -1
- package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.scss +20 -0
- package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +60 -0
- package/dist/containers/Tenant/Query/Query.scss +16 -0
- package/dist/containers/Tenant/Query/Query.tsx +73 -0
- package/dist/containers/Tenant/{QueryEditor → Query/QueryEditor}/QueryEditor.js +39 -88
- package/dist/containers/Tenant/{QueryEditor → Query/QueryEditor}/QueryEditor.scss +7 -23
- package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/QueryEditorControls.scss +1 -4
- package/dist/containers/Tenant/Query/QueryTabs/QueryTabs.tsx +59 -0
- package/dist/containers/Tenant/{QueryEditor → Query}/SaveQuery/SaveQuery.js +5 -5
- package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.scss +55 -0
- package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.tsx +150 -0
- package/dist/containers/Tenant/Query/i18n/en.json +12 -0
- package/dist/containers/Tenant/Query/i18n/ru.json +12 -0
- package/dist/containers/Tenant/Query/utils/getPreparedResult.ts +30 -0
- package/dist/containers/Tenant/Tenant.scss +0 -8
- package/dist/containers/Tenant/Tenant.tsx +24 -46
- package/dist/containers/Tenant/TenantPages.tsx +7 -16
- package/dist/containers/Tenant/utils/constants.ts +10 -0
- package/dist/containers/Tenant/utils/schemaActions.ts +9 -4
- package/dist/containers/Tenants/Tenants.js +26 -13
- package/dist/routes.ts +21 -7
- package/dist/services/api.ts +9 -5
- package/dist/store/reducers/executeQuery.ts +18 -4
- package/dist/store/reducers/header/header.ts +31 -0
- package/dist/store/reducers/header/types.ts +54 -0
- package/dist/store/reducers/index.ts +1 -1
- package/dist/store/reducers/node/types.ts +2 -0
- package/dist/store/reducers/settings/settings.ts +8 -3
- package/dist/store/reducers/tablet.ts +18 -1
- package/dist/store/reducers/tenant/constants.ts +9 -1
- package/dist/store/reducers/tenant/tenant.ts +23 -4
- package/dist/store/reducers/tenant/types.ts +9 -5
- package/dist/store/reducers/topic.ts +1 -1
- package/dist/store/state-url-mapping.js +6 -3
- package/dist/types/store/executeQuery.ts +4 -1
- package/dist/types/store/query.ts +5 -0
- package/dist/types/store/tablet.ts +7 -4
- package/dist/utils/constants.ts +5 -1
- package/package.json +2 -1
- package/dist/containers/Tenant/ObjectGeneralTabs/ObjectGeneralTabs.scss +0 -9
- package/dist/containers/Tenant/ObjectGeneralTabs/ObjectGeneralTabs.tsx +0 -68
- package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.scss +0 -85
- package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.tsx +0 -95
- package/dist/containers/Tenant/QueryEditor/SavedQueries/SavedQueries.js +0 -161
- package/dist/containers/Tenant/QueryEditor/SavedQueries/SavedQueries.scss +0 -93
- package/dist/containers/Tenant/QueryEditor/i18n/en.json +0 -3
- package/dist/containers/Tenant/QueryEditor/i18n/ru.json +0 -3
- package/dist/store/reducers/header.ts +0 -26
- /package/dist/containers/Tenant/{QueryEditor → Query}/Issues/Issues.scss +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/Issues/Issues.tsx +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/Issues/models.ts +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/QueryDuration/QueryDuration.scss +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/QueryDuration/QueryDuration.tsx +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/OldQueryEditorControls.tsx +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/QueryEditorControls.tsx +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/shared.ts +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/SaveQuery/SaveQuery.scss +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/i18n/index.ts +0 -0
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,32 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [4.8.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.7.0...v4.8.0) (2023-06-26)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* **Tenant:** transform general tabs into left navigation items ([#431](https://github.com/ydb-platform/ydb-embedded-ui/issues/431)) ([7117b96](https://github.com/ydb-platform/ydb-embedded-ui/commit/7117b9622d5f6469dcc2bcc1c0d5cb71d4f94c0b))
|
9
|
+
|
10
|
+
## [4.7.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.6.0...v4.7.0) (2023-06-23)
|
11
|
+
|
12
|
+
|
13
|
+
### Features
|
14
|
+
|
15
|
+
* **QueryEditor:** transform history and saved to tabs ([#427](https://github.com/ydb-platform/ydb-embedded-ui/issues/427)) ([6378ca7](https://github.com/ydb-platform/ydb-embedded-ui/commit/6378ca7013239b33e55c1f88fdde7cab3a102df6))
|
16
|
+
* update breadcrumbs ([#432](https://github.com/ydb-platform/ydb-embedded-ui/issues/432)) ([e583a03](https://github.com/ydb-platform/ydb-embedded-ui/commit/e583a03fe0d77698f29c924e611133f015c3f7ad))
|
17
|
+
|
18
|
+
|
19
|
+
### Bug Fixes
|
20
|
+
|
21
|
+
* **Cluster:** add icons to tabs ([#430](https://github.com/ydb-platform/ydb-embedded-ui/issues/430)) ([e9e649f](https://github.com/ydb-platform/ydb-embedded-ui/commit/e9e649f614691e44172c9b93dd3119066c145413))
|
22
|
+
* **ClusterInfo:** hide by default ([#435](https://github.com/ydb-platform/ydb-embedded-ui/issues/435)) ([ef2b353](https://github.com/ydb-platform/ydb-embedded-ui/commit/ef2b3535f2c6324a34c4386680f5050655a04eb4))
|
23
|
+
* **Cluster:** use counter from uikit for tabs ([#428](https://github.com/ydb-platform/ydb-embedded-ui/issues/428)) ([19ca3bd](https://github.com/ydb-platform/ydb-embedded-ui/commit/19ca3bd14b15bdab1a9621939ddceee6d23b08ac))
|
24
|
+
* **DetailedOverview:** prevent tenant info scroll on overflow ([#434](https://github.com/ydb-platform/ydb-embedded-ui/issues/434)) ([8ed6076](https://github.com/ydb-platform/ydb-embedded-ui/commit/8ed60760d54913d05f39d35d00a34c8b1d7d9738))
|
25
|
+
* rename Internal Viewer to Developer UI ([#423](https://github.com/ydb-platform/ydb-embedded-ui/issues/423)) ([3eb21f3](https://github.com/ydb-platform/ydb-embedded-ui/commit/3eb21f35a230cc591f02ef9b195f99031f832e8a))
|
26
|
+
* **Storage:** update columns ([#437](https://github.com/ydb-platform/ydb-embedded-ui/issues/437)) ([264fbc9](https://github.com/ydb-platform/ydb-embedded-ui/commit/264fbc984cd9ef1467110d3e2f5ed9b29a526c2b))
|
27
|
+
* **Tablet:** clear tablet data on unmount ([#425](https://github.com/ydb-platform/ydb-embedded-ui/issues/425)) ([5d308cd](https://github.com/ydb-platform/ydb-embedded-ui/commit/5d308cdded342d7a40cbc6a91431d3f286c39b8a))
|
28
|
+
* **TabletsStatistic:** use tenant backend ([#429](https://github.com/ydb-platform/ydb-embedded-ui/issues/429)) ([d290684](https://github.com/ydb-platform/ydb-embedded-ui/commit/d290684ba08aec8b66c0492ba571a5337b5b896c))
|
29
|
+
|
3
30
|
## [4.6.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.5.2...v4.6.0) (2023-06-13)
|
4
31
|
|
5
32
|
|
@@ -0,0 +1,3 @@
|
|
1
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
|
2
|
+
<path d="M8.625 13.0156C8.625 13.2695 8.47266 13.498 8.24414 13.5742C8.04102 13.6758 7.76172 13.6504 7.58398 13.4727L5.55273 11.6445C5.42578 11.543 5.375 11.3652 5.375 11.1875C5.375 11.0352 5.42578 10.8574 5.55273 10.7559L7.58398 8.92773C7.76172 8.75 8.04102 8.72461 8.24414 8.82617C8.47266 8.90234 8.625 9.13086 8.625 9.35938V10.5781H9.03125C10.0215 10.5781 10.8594 9.76562 10.8594 8.75V4.61133C10.0215 4.35742 9.4375 3.57031 9.4375 2.65625C9.4375 1.53906 10.3262 0.625 11.4688 0.625C12.5859 0.625 13.5 1.53906 13.5 2.65625C13.5 3.57031 12.8906 4.35742 12.0781 4.61133V8.75C12.0781 10.4512 10.707 11.7969 9.03125 11.7969H8.625V13.0156ZM12.2812 2.65625C12.2812 2.22461 11.9004 1.84375 11.4688 1.84375C11.0117 1.84375 10.6562 2.22461 10.6562 2.65625C10.6562 3.11328 11.0117 3.46875 11.4688 3.46875C11.9004 3.46875 12.2812 3.11328 12.2812 2.65625ZM5.375 1.23438C5.375 1.00586 5.50195 0.777344 5.73047 0.701172C5.93359 0.599609 6.21289 0.625 6.39062 0.802734L8.42188 2.63086C8.54883 2.73242 8.625 2.91016 8.625 3.0625C8.625 3.24023 8.54883 3.41797 8.42188 3.51953L6.39062 5.34766C6.21289 5.52539 5.93359 5.55078 5.73047 5.44922C5.50195 5.37305 5.375 5.14453 5.375 4.89062V3.67188H4.96875C3.95312 3.67188 3.14062 4.50977 3.14062 5.5V9.66406C3.95312 9.91797 4.5625 10.7051 4.5625 11.5938C4.5625 12.7363 3.64844 13.625 2.53125 13.625C1.38867 13.625 0.5 12.7363 0.5 11.5938C0.5 10.7051 1.08398 9.91797 1.92188 9.66406V5.5C1.92188 3.82422 3.26758 2.45312 4.96875 2.45312H5.375V1.23438ZM1.71875 11.5938C1.71875 12.0508 2.07422 12.4062 2.53125 12.4062C2.96289 12.4062 3.34375 12.0508 3.34375 11.5938C3.34375 11.1621 2.96289 10.7812 2.53125 10.7812C2.07422 10.7812 1.71875 11.1621 1.71875 11.5938Z"/>
|
3
|
+
</svg>
|
@@ -26,6 +26,11 @@ export const NodeHostWrapper = ({node, getNodeRef}: NodeHostWrapperProps) => {
|
|
26
26
|
|
27
27
|
const isNodeAvailable = !isUnavailableNode(node);
|
28
28
|
const nodeRef = isNodeAvailable && getNodeRef ? getNodeRef(node) + 'internal' : undefined;
|
29
|
+
const nodePath = isNodeAvailable
|
30
|
+
? getDefaultNodePath(node.NodeId, {
|
31
|
+
tenantName: node.TenantName,
|
32
|
+
})
|
33
|
+
: undefined;
|
29
34
|
|
30
35
|
return (
|
31
36
|
<div className={b()}>
|
@@ -39,7 +44,7 @@ export const NodeHostWrapper = ({node, getNodeRef}: NodeHostWrapperProps) => {
|
|
39
44
|
<EntityStatus
|
40
45
|
name={node.Host}
|
41
46
|
status={node.SystemState}
|
42
|
-
path={
|
47
|
+
path={nodePath}
|
43
48
|
hasClipboardButton
|
44
49
|
className={b('host')}
|
45
50
|
/>
|
@@ -14,18 +14,32 @@ const b = cn('tablet');
|
|
14
14
|
|
15
15
|
interface TabletProps {
|
16
16
|
tablet?: TTabletStateInfo;
|
17
|
+
tenantName?: string;
|
17
18
|
}
|
18
19
|
|
19
|
-
export const Tablet = ({tablet = {}}: TabletProps) => {
|
20
|
-
const {TabletId: id} = tablet;
|
20
|
+
export const Tablet = ({tablet = {}, tenantName}: TabletProps) => {
|
21
|
+
const {TabletId: id, NodeId, Type, State} = tablet;
|
21
22
|
const status = tablet.Overall?.toLowerCase();
|
22
23
|
|
24
|
+
const tabletPath =
|
25
|
+
id &&
|
26
|
+
createHref(
|
27
|
+
routes.tablet,
|
28
|
+
{id},
|
29
|
+
{
|
30
|
+
nodeId: NodeId,
|
31
|
+
type: Type,
|
32
|
+
state: State,
|
33
|
+
tenantName,
|
34
|
+
},
|
35
|
+
);
|
36
|
+
|
23
37
|
return (
|
24
38
|
<ContentWithPopup
|
25
39
|
className={b('wrapper')}
|
26
40
|
content={<TabletTooltipContent data={tablet} className={b('popup-content')} />}
|
27
41
|
>
|
28
|
-
<InternalLink to={
|
42
|
+
<InternalLink to={tabletPath}>
|
29
43
|
<div className={b({status})}>
|
30
44
|
<div className={b('type')}>{[getTabletLabel(tablet.Type)]}</div>
|
31
45
|
</div>
|
@@ -12,9 +12,9 @@ import './TabletsStatistic.scss';
|
|
12
12
|
|
13
13
|
const b = cn('tablets-statistic');
|
14
14
|
|
15
|
-
type
|
15
|
+
type Tablets = TFullTabletStateInfo[] | TComputeTabletStateInfo[];
|
16
16
|
|
17
|
-
const prepareTablets = (tablets:
|
17
|
+
const prepareTablets = (tablets: Tablets) => {
|
18
18
|
const res = tablets.map((tablet) => {
|
19
19
|
return {
|
20
20
|
label: getTabletLabel(tablet.Type),
|
@@ -28,25 +28,32 @@ const prepareTablets = (tablets: ITablets) => {
|
|
28
28
|
};
|
29
29
|
|
30
30
|
interface TabletsStatisticProps {
|
31
|
-
tablets:
|
31
|
+
tablets: Tablets;
|
32
32
|
path: string | undefined;
|
33
33
|
nodeIds: string[] | number[];
|
34
|
+
backend?: string;
|
34
35
|
}
|
35
36
|
|
36
|
-
export const TabletsStatistic = ({tablets = [], path, nodeIds}: TabletsStatisticProps) => {
|
37
|
+
export const TabletsStatistic = ({tablets = [], path, nodeIds, backend}: TabletsStatisticProps) => {
|
37
38
|
const renderTabletInfo = (item: ReturnType<typeof prepareTablets>[number], index: number) => {
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
39
|
+
const tabletsPath = createHref(routes.tabletsFilters, undefined, {
|
40
|
+
nodeIds,
|
41
|
+
state: item.state,
|
42
|
+
type: item.type,
|
43
|
+
path,
|
44
|
+
backend,
|
45
|
+
});
|
46
|
+
|
47
|
+
const label = `${item.label}: ${item.count}`;
|
48
|
+
const className = b('tablet', {state: item.state?.toLowerCase()});
|
49
|
+
|
50
|
+
return backend ? (
|
51
|
+
<a href={tabletsPath} key={index} className={className}>
|
52
|
+
{label}
|
53
|
+
</a>
|
54
|
+
) : (
|
55
|
+
<Link to={tabletsPath} key={index} className={className}>
|
56
|
+
{label}
|
50
57
|
</Link>
|
51
58
|
);
|
52
59
|
};
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import {Switch, Route, Redirect, Router} from 'react-router-dom';
|
2
|
+
import {Switch, Route, Redirect, Router, useLocation} from 'react-router-dom';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
import {connect} from 'react-redux';
|
5
5
|
|
@@ -28,6 +28,8 @@ import {clusterTabsIds} from '../Cluster/utils';
|
|
28
28
|
const b = cn('app');
|
29
29
|
|
30
30
|
export function Content(props) {
|
31
|
+
const location = useLocation();
|
32
|
+
|
31
33
|
const {singleClusterMode} = props;
|
32
34
|
const isClustersPage =
|
33
35
|
location.pathname.includes('/clusters') ||
|
@@ -54,7 +56,7 @@ export function Content(props) {
|
|
54
56
|
};
|
55
57
|
return (
|
56
58
|
<React.Fragment>
|
57
|
-
{!isClustersPage && <Header
|
59
|
+
{!isClustersPage && <Header mainPage={props.mainPage} />}
|
58
60
|
<main className={b('main')}>{renderRoute()}</main>
|
59
61
|
<ReduxTooltip />
|
60
62
|
<AppIcons />
|
@@ -66,6 +68,7 @@ Content.propTypes = {
|
|
66
68
|
singleClusterMode: PropTypes.bool,
|
67
69
|
children: PropTypes.node,
|
68
70
|
clusterName: PropTypes.string,
|
71
|
+
mainPage: PropTypes.object,
|
69
72
|
};
|
70
73
|
|
71
74
|
function ContentWrapper(props) {
|
@@ -7,6 +7,9 @@ import cn from 'bem-cn-lite';
|
|
7
7
|
import {Icon, Button} from '@gravity-ui/uikit';
|
8
8
|
import {AsideHeader, MenuItem as AsideHeaderMenuItem, FooterItem} from '@gravity-ui/navigation';
|
9
9
|
|
10
|
+
import squareChartBarIcon from '@gravity-ui/icons/svgs/square-chart-bar.svg';
|
11
|
+
import pulseIcon from '@gravity-ui/icons/svgs/pulse.svg';
|
12
|
+
|
10
13
|
import signOutIcon from '../../assets/icons/signOut.svg';
|
11
14
|
import signInIcon from '../../assets/icons/signIn.svg';
|
12
15
|
import ydbLogoIcon from '../../assets/icons/ydb.svg';
|
@@ -15,18 +18,20 @@ import userChecked from '../../assets/icons/user-check.svg';
|
|
15
18
|
import settingsIcon from '../../assets/icons/settings.svg';
|
16
19
|
import supportIcon from '../../assets/icons/support.svg';
|
17
20
|
|
18
|
-
import {UserSettings} from '../UserSettings/UserSettings';
|
19
|
-
|
20
|
-
import routes, {createHref} from '../../routes';
|
21
|
-
|
22
21
|
import {logout} from '../../store/reducers/authentication';
|
23
22
|
import {getParsedSettingValue, setSettingValue} from '../../store/reducers/settings/settings';
|
23
|
+
import {TENANT_PAGE, TENANT_PAGES_IDS} from '../../store/reducers/tenant/constants';
|
24
|
+
import routes, {TENANT, createHref, parseQuery} from '../../routes';
|
25
|
+
import {useSetting, useTypedSelector} from '../../utils/hooks';
|
26
|
+
import {ASIDE_HEADER_COMPACT_KEY, TENANT_INITIAL_PAGE_KEY} from '../../utils/constants';
|
24
27
|
|
25
|
-
import {
|
28
|
+
import {getTenantPath} from '../Tenant/TenantPages';
|
29
|
+
import {UserSettings} from '../UserSettings/UserSettings';
|
26
30
|
|
27
31
|
import './AsideNavigation.scss';
|
28
32
|
|
29
33
|
const b = cn('kv-navigation');
|
34
|
+
|
30
35
|
interface MenuItem {
|
31
36
|
id: string;
|
32
37
|
title: string;
|
@@ -111,9 +116,6 @@ interface AsideNavigationProps {
|
|
111
116
|
setSettingValue: (name: string, value: string) => void;
|
112
117
|
}
|
113
118
|
|
114
|
-
// FIXME: add items or delete
|
115
|
-
const items: MenuItem[] = [];
|
116
|
-
|
117
119
|
enum Panel {
|
118
120
|
UserSettings = 'UserSettings',
|
119
121
|
}
|
@@ -124,19 +126,49 @@ function AsideNavigation(props: AsideNavigationProps) {
|
|
124
126
|
|
125
127
|
const [visiblePanel, setVisiblePanel] = useState<Panel>();
|
126
128
|
|
129
|
+
const [initialTenantPage, setInitialTenantPage] = useSetting<string>(TENANT_INITIAL_PAGE_KEY);
|
130
|
+
const {tenantPage = initialTenantPage} = useTypedSelector((state) => state.tenant);
|
131
|
+
|
127
132
|
const setIsCompact = (compact: boolean) => {
|
128
133
|
props.setSettingValue(ASIDE_HEADER_COMPACT_KEY, JSON.stringify(compact));
|
129
134
|
};
|
130
135
|
|
136
|
+
const {pathname} = location;
|
137
|
+
const queryParams = parseQuery(location);
|
138
|
+
|
139
|
+
const isTenantPage = pathname === `/${TENANT}`;
|
140
|
+
|
131
141
|
const menuItems: AsideHeaderMenuItem[] = React.useMemo(() => {
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
142
|
+
if (!isTenantPage) {
|
143
|
+
return [];
|
144
|
+
}
|
145
|
+
|
146
|
+
const items: MenuItem[] = [
|
147
|
+
{
|
148
|
+
id: TENANT_PAGES_IDS.diagnostics,
|
149
|
+
title: 'Diagnostics',
|
150
|
+
icon: squareChartBarIcon,
|
151
|
+
iconSize: 20,
|
152
|
+
location: getTenantPath({
|
153
|
+
...queryParams,
|
154
|
+
[TENANT_PAGE]: TENANT_PAGES_IDS.diagnostics,
|
155
|
+
}),
|
156
|
+
},
|
157
|
+
{
|
158
|
+
id: TENANT_PAGES_IDS.query,
|
159
|
+
title: 'Query',
|
160
|
+
icon: pulseIcon,
|
161
|
+
iconSize: 20,
|
162
|
+
location: getTenantPath({
|
163
|
+
...queryParams,
|
164
|
+
[TENANT_PAGE]: TENANT_PAGES_IDS.query,
|
165
|
+
}),
|
166
|
+
},
|
167
|
+
];
|
168
|
+
|
169
|
+
return items.map((item) => {
|
170
|
+
const current = item.id === tenantPage;
|
171
|
+
|
140
172
|
return {
|
141
173
|
id: item.id,
|
142
174
|
title: item.title,
|
@@ -144,12 +176,12 @@ function AsideNavigation(props: AsideNavigationProps) {
|
|
144
176
|
iconSize: item.iconSize,
|
145
177
|
current,
|
146
178
|
onItemClick: () => {
|
179
|
+
setInitialTenantPage(item.id);
|
147
180
|
history.push(item.location);
|
148
181
|
},
|
149
182
|
};
|
150
183
|
});
|
151
|
-
|
152
|
-
}, [location, history]);
|
184
|
+
}, [tenantPage, isTenantPage, setInitialTenantPage, history, queryParams]);
|
153
185
|
|
154
186
|
return (
|
155
187
|
<React.Fragment>
|
@@ -10,7 +10,7 @@ import type {AdditionalClusterProps, AdditionalVersionsProps} from '../../types/
|
|
10
10
|
import type {AdditionalNodesInfo} from '../../utils/nodes';
|
11
11
|
import routes from '../../routes';
|
12
12
|
|
13
|
-
import {
|
13
|
+
import {setHeaderBreadcrumbs} from '../../store/reducers/header/header';
|
14
14
|
import {getClusterInfo} from '../../store/reducers/cluster/cluster';
|
15
15
|
import {getClusterNodes} from '../../store/reducers/clusterNodes/clusterNodes';
|
16
16
|
import {parseNodesToVersionsValues, parseVersionsToVersionToColorMap} from '../../utils/versions';
|
@@ -80,14 +80,7 @@ function Cluster({
|
|
80
80
|
);
|
81
81
|
|
82
82
|
useEffect(() => {
|
83
|
-
dispatch(
|
84
|
-
setHeader([
|
85
|
-
{
|
86
|
-
text: Name || 'Cluster',
|
87
|
-
link: getClusterPath(),
|
88
|
-
},
|
89
|
-
]),
|
90
|
-
);
|
83
|
+
dispatch(setHeaderBreadcrumbs('cluster', {}));
|
91
84
|
}, [dispatch, Name]);
|
92
85
|
|
93
86
|
const versionToColor = useMemo(() => {
|
@@ -124,13 +117,13 @@ function Cluster({
|
|
124
117
|
const getTabEntityCount = (tabId: ClusterTab) => {
|
125
118
|
switch (tabId) {
|
126
119
|
case clusterTabsIds.tenants: {
|
127
|
-
return cluster?.Tenants;
|
120
|
+
return cluster?.Tenants ? Number(cluster.Tenants) : undefined;
|
128
121
|
}
|
129
122
|
case clusterTabsIds.nodes: {
|
130
|
-
return cluster?.NodesTotal;
|
123
|
+
return cluster?.NodesTotal ? Number(cluster.NodesTotal) : undefined;
|
131
124
|
}
|
132
125
|
default: {
|
133
|
-
return
|
126
|
+
return undefined;
|
134
127
|
}
|
135
128
|
}
|
136
129
|
};
|
@@ -153,7 +146,7 @@ function Cluster({
|
|
153
146
|
items={clusterTabs.map((item) => {
|
154
147
|
return {
|
155
148
|
...item,
|
156
|
-
|
149
|
+
counter: getTabEntityCount(item.id),
|
157
150
|
};
|
158
151
|
})}
|
159
152
|
wrapTo={({id}, node) => {
|
@@ -18,7 +18,7 @@ import type {TClusterInfo} from '../../../types/api/cluster';
|
|
18
18
|
import {backend, customBackend} from '../../../store';
|
19
19
|
import {formatStorageValues} from '../../../utils';
|
20
20
|
import {useSetting, useTypedSelector} from '../../../utils/hooks';
|
21
|
-
import {CLUSTER_INFO_HIDDEN_KEY} from '../../../utils/constants';
|
21
|
+
import {CLUSTER_INFO_HIDDEN_KEY, DEVELOPER_UI} from '../../../utils/constants';
|
22
22
|
|
23
23
|
import {VersionsBar} from '../VersionsBar/VersionsBar';
|
24
24
|
import {ClusterInfoSkeleton} from '../ClusterInfoSkeleton/ClusterInfoSkeleton';
|
@@ -126,7 +126,7 @@ export const ClusterInfo = ({
|
|
126
126
|
}: ClusterInfoProps) => {
|
127
127
|
const singleClusterMode = useTypedSelector((state) => state.singleClusterMode);
|
128
128
|
|
129
|
-
const [clusterInfoHidden, setClusterInfoHidden] = useSetting(CLUSTER_INFO_HIDDEN_KEY
|
129
|
+
const [clusterInfoHidden, setClusterInfoHidden] = useSetting<boolean>(CLUSTER_INFO_HIDDEN_KEY);
|
130
130
|
|
131
131
|
const togleClusterInfoVisibility = () => {
|
132
132
|
setClusterInfoHidden(!clusterInfoHidden);
|
@@ -141,7 +141,7 @@ export const ClusterInfo = ({
|
|
141
141
|
const {info = [], links = []} = additionalClusterProps;
|
142
142
|
|
143
143
|
const clusterInfo = getInfo(cluster, versionsValues, info, [
|
144
|
-
{title:
|
144
|
+
{title: DEVELOPER_UI, url: internalLink},
|
145
145
|
...links,
|
146
146
|
]);
|
147
147
|
|
@@ -1,3 +1,10 @@
|
|
1
|
+
import {Icon} from '@gravity-ui/uikit';
|
2
|
+
import cubes3Icon from '@gravity-ui/icons/svgs/cubes-3.svg';
|
3
|
+
import databasesIcon from '@gravity-ui/icons/svgs/databases.svg';
|
4
|
+
import hardDriveIcon from '@gravity-ui/icons/svgs/hard-drive.svg';
|
5
|
+
|
6
|
+
import versionsIcon from '../../assets/icons/versions.svg';
|
7
|
+
|
1
8
|
import type {ValueOf} from '../../types/common';
|
2
9
|
import routes, {createHref} from '../../routes';
|
3
10
|
|
@@ -13,18 +20,22 @@ export type ClusterTab = ValueOf<typeof clusterTabsIds>;
|
|
13
20
|
const tenants = {
|
14
21
|
id: clusterTabsIds.tenants,
|
15
22
|
title: 'Databases',
|
23
|
+
icon: <Icon data={databasesIcon} />,
|
16
24
|
};
|
17
25
|
const nodes = {
|
18
26
|
id: clusterTabsIds.nodes,
|
19
27
|
title: 'Nodes',
|
28
|
+
icon: <Icon data={cubes3Icon} />,
|
20
29
|
};
|
21
30
|
const storage = {
|
22
31
|
id: clusterTabsIds.storage,
|
23
32
|
title: 'Storage',
|
33
|
+
icon: <Icon data={hardDriveIcon} />,
|
24
34
|
};
|
25
35
|
const versions = {
|
26
36
|
id: clusterTabsIds.versions,
|
27
37
|
title: 'Versions',
|
38
|
+
icon: <Icon data={versionsIcon} />,
|
28
39
|
};
|
29
40
|
|
30
41
|
export const clusterTabs = [tenants, nodes, storage, versions];
|
@@ -1,13 +1,19 @@
|
|
1
|
+
import {useEffect, useMemo} from 'react';
|
2
|
+
import {useHistory, useLocation} from 'react-router';
|
3
|
+
import {useDispatch} from 'react-redux';
|
1
4
|
import block from 'bem-cn-lite';
|
2
|
-
import {useHistory} from 'react-router';
|
3
5
|
|
4
|
-
import {Breadcrumbs,
|
6
|
+
import {Breadcrumbs, Icon} from '@gravity-ui/uikit';
|
5
7
|
|
6
8
|
import {ExternalLinkWithIcon} from '../../components/ExternalLinkWithIcon/ExternalLinkWithIcon';
|
7
9
|
|
8
10
|
import {backend, customBackend} from '../../store';
|
9
|
-
import {
|
11
|
+
import {getClusterInfo} from '../../store/reducers/cluster/cluster';
|
10
12
|
import {useTypedSelector} from '../../utils/hooks';
|
13
|
+
import {DEVELOPER_UI} from '../../utils/constants';
|
14
|
+
import {parseQuery} from '../../routes';
|
15
|
+
|
16
|
+
import {RawBreadcrumbItem, getBreadcrumbs} from './breadcrumbs';
|
11
17
|
|
12
18
|
import './Header.scss';
|
13
19
|
|
@@ -21,23 +27,57 @@ const getInternalLink = (singleClusterMode: boolean) => {
|
|
21
27
|
return backend + '/internal';
|
22
28
|
};
|
23
29
|
|
24
|
-
|
25
|
-
|
26
|
-
|
30
|
+
interface HeaderProps {
|
31
|
+
mainPage?: RawBreadcrumbItem;
|
32
|
+
}
|
27
33
|
|
34
|
+
function Header({mainPage}: HeaderProps) {
|
35
|
+
const dispatch = useDispatch();
|
28
36
|
const history = useHistory();
|
37
|
+
const location = useLocation();
|
29
38
|
|
30
|
-
const
|
31
|
-
|
39
|
+
const singleClusterMode = useTypedSelector((state) => state.singleClusterMode);
|
40
|
+
const {page, pageBreadcrumbsOptions} = useTypedSelector((state) => state.header);
|
41
|
+
const {data} = useTypedSelector((state) => state.cluster);
|
42
|
+
|
43
|
+
const queryParams = parseQuery(location);
|
44
|
+
|
45
|
+
const clusterNameFromQuery = queryParams.clusterName?.toString();
|
46
|
+
|
47
|
+
const clusterNameFinal = data?.Name || clusterNameFromQuery;
|
48
|
+
|
49
|
+
useEffect(() => {
|
50
|
+
dispatch(getClusterInfo(clusterNameFromQuery));
|
51
|
+
}, [dispatch, clusterNameFromQuery]);
|
52
|
+
|
53
|
+
const breadcrumbItems = useMemo(() => {
|
54
|
+
const rawBreadcrumbs: RawBreadcrumbItem[] = [];
|
55
|
+
let options = pageBreadcrumbsOptions;
|
56
|
+
|
57
|
+
if (mainPage) {
|
58
|
+
rawBreadcrumbs.push(mainPage);
|
59
|
+
}
|
60
|
+
|
61
|
+
if (clusterNameFinal) {
|
62
|
+
options = {
|
63
|
+
...pageBreadcrumbsOptions,
|
64
|
+
clusterName: clusterNameFinal,
|
65
|
+
};
|
66
|
+
}
|
67
|
+
|
68
|
+
const breadcrumbs = getBreadcrumbs(page, options, rawBreadcrumbs, queryParams);
|
69
|
+
|
70
|
+
return breadcrumbs.map((item) => {
|
32
71
|
const action = () => {
|
33
|
-
if (
|
34
|
-
history.push(
|
72
|
+
if (item.link) {
|
73
|
+
history.push(item.link);
|
35
74
|
}
|
36
75
|
};
|
37
|
-
|
38
|
-
|
39
|
-
|
76
|
+
return {...item, action};
|
77
|
+
});
|
78
|
+
}, [clusterNameFinal, mainPage, history, queryParams, page, pageBreadcrumbsOptions]);
|
40
79
|
|
80
|
+
const renderHeader = () => {
|
41
81
|
return (
|
42
82
|
<header className={b()}>
|
43
83
|
<div>
|
@@ -45,11 +85,27 @@ function Header() {
|
|
45
85
|
items={breadcrumbItems}
|
46
86
|
lastDisplayedItemsCount={1}
|
47
87
|
firstDisplayedItemsCount={1}
|
88
|
+
renderItemContent={({icon, text}) => {
|
89
|
+
if (!icon) {
|
90
|
+
return text;
|
91
|
+
}
|
92
|
+
return (
|
93
|
+
<span className={b('breadcrumb')}>
|
94
|
+
<Icon
|
95
|
+
width={16}
|
96
|
+
height={16}
|
97
|
+
data={icon}
|
98
|
+
className={b('breadcrumb__icon')}
|
99
|
+
/>
|
100
|
+
{text}
|
101
|
+
</span>
|
102
|
+
);
|
103
|
+
}}
|
48
104
|
/>
|
49
105
|
</div>
|
50
106
|
|
51
107
|
<ExternalLinkWithIcon
|
52
|
-
title={
|
108
|
+
title={DEVELOPER_UI}
|
53
109
|
url={getInternalLink(singleClusterMode)}
|
54
110
|
/>
|
55
111
|
</header>
|