ydb-embedded-ui 4.10.0 → 4.10.1
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 +13 -0
- package/dist/components/InfoViewer/formatters/schema.ts +3 -1
- package/dist/components/TableWithControlsLayout/TableWithControlsLayout.scss +32 -0
- package/dist/components/TableWithControlsLayout/TableWithControlsLayout.tsx +43 -0
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +2 -2
- package/dist/containers/Cluster/Cluster.scss +4 -5
- package/dist/containers/Cluster/Cluster.tsx +3 -22
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +4 -0
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +7 -0
- package/dist/containers/Cluster/ClusterInfoSkeleton/ClusterInfoSkeleton.tsx +1 -1
- package/dist/containers/Cluster/utils.tsx +0 -11
- package/dist/containers/Header/Header.scss +1 -5
- package/dist/containers/Nodes/Nodes.scss +1 -24
- package/dist/containers/Nodes/Nodes.tsx +28 -38
- package/dist/containers/Storage/Storage.scss +1 -14
- package/dist/containers/Storage/Storage.tsx +15 -18
- package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +3 -1
- package/dist/containers/Storage/{StorageVisibleEntityFilter/StorageVisibleEntityFilter.tsx → StorageVisibleEntitiesFilter/StorageVisibleEntitiesFilter.tsx} +4 -2
- package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +6 -2
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +3 -12
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +2 -7
- package/dist/containers/Tenant/Query/i18n/en.json +1 -1
- package/dist/containers/Tenant/Query/i18n/ru.json +1 -1
- package/dist/containers/Tenants/Tenants.scss +1 -13
- package/dist/containers/Tenants/Tenants.tsx +17 -24
- package/dist/store/reducers/nodes/nodes.ts +4 -112
- package/dist/store/reducers/nodes/selectors.ts +74 -0
- package/dist/store/reducers/nodes/utils.ts +46 -0
- package/dist/store/reducers/storage/selectors.ts +1 -1
- package/dist/types/api/compute.ts +27 -2
- package/dist/types/api/nodes.ts +12 -1
- package/dist/types/api/schema/cdcStream.ts +32 -0
- package/dist/types/api/schema/columnEntity.ts +138 -0
- package/dist/types/api/schema/externalDataSource.ts +24 -0
- package/dist/types/api/schema/externalTable.ts +14 -0
- package/dist/types/api/schema/index.ts +10 -0
- package/dist/types/api/schema/persQueueGroup.ts +191 -0
- package/dist/types/api/schema/schema.ts +299 -0
- package/dist/types/api/schema/shared.ts +42 -0
- package/dist/types/api/schema/table.ts +616 -0
- package/dist/types/api/schema/tableIndex.ts +33 -0
- package/package.json +1 -1
- package/dist/assets/icons/versions.svg +0 -3
- package/dist/types/api/schema.ts +0 -1326
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [4.10.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.10.0...v4.10.1) (2023-07-14)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* apply design fixes ([#475](https://github.com/ydb-platform/ydb-embedded-ui/issues/475)) ([5e7c9ca](https://github.com/ydb-platform/ydb-embedded-ui/commit/5e7c9caa9f54094a3eb6448d92d43242d3e738dd))
|
9
|
+
* **AsideNavigation:** replace query icon ([#466](https://github.com/ydb-platform/ydb-embedded-ui/issues/466)) ([4495eb2](https://github.com/ydb-platform/ydb-embedded-ui/commit/4495eb2634e48feda677c03591b92393ad28981e))
|
10
|
+
* **ClusterInfo:** add Databases field ([#474](https://github.com/ydb-platform/ydb-embedded-ui/issues/474)) ([28a9936](https://github.com/ydb-platform/ydb-embedded-ui/commit/28a99364bf5e916381a54a59d4d3f979b35f6eff))
|
11
|
+
* **Cluster:** make global scroll ([#470](https://github.com/ydb-platform/ydb-embedded-ui/issues/470)) ([30f8bc5](https://github.com/ydb-platform/ydb-embedded-ui/commit/30f8bc5ce52fceda076d278b1464d413e899ae21))
|
12
|
+
* **Cluster:** remove tabs icons and numbers ([#473](https://github.com/ydb-platform/ydb-embedded-ui/issues/473)) ([d2e43d4](https://github.com/ydb-platform/ydb-embedded-ui/commit/d2e43d41759b085f34b7f29f52f3aba60cd0588f))
|
13
|
+
* **Query:** rename New Query tab to Query ([#467](https://github.com/ydb-platform/ydb-embedded-ui/issues/467)) ([c3f5585](https://github.com/ydb-platform/ydb-embedded-ui/commit/c3f5585562a204ef0831d0c45766b17c3dc72f82))
|
14
|
+
* **TableIndexInfo:** format DataSize ([#468](https://github.com/ydb-platform/ydb-embedded-ui/issues/468)) ([a189b8c](https://github.com/ydb-platform/ydb-embedded-ui/commit/a189b8cf9610f6b1b7b5f4c01896eda5f8347ebf))
|
15
|
+
|
3
16
|
## [4.10.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.9.0...v4.10.0) (2023-07-07)
|
4
17
|
|
5
18
|
|
@@ -1,4 +1,5 @@
|
|
1
|
-
import {TIndexDescription} from '../../../types/api/schema';
|
1
|
+
import type {TIndexDescription} from '../../../types/api/schema';
|
2
|
+
import {toFormattedSize} from '../../FormattedBytes/utils';
|
2
3
|
|
3
4
|
import {createInfoFormatter} from '../utils';
|
4
5
|
|
@@ -8,6 +9,7 @@ export const formatTableIndexItem = createInfoFormatter<TIndexDescription>({
|
|
8
9
|
State: (value) => value?.substring(11), // trims EIndexState prefix
|
9
10
|
KeyColumnNames: (value) => value?.join(', '),
|
10
11
|
DataColumnNames: (value) => value?.join(', '),
|
12
|
+
DataSize: toFormattedSize,
|
11
13
|
},
|
12
14
|
labels: {
|
13
15
|
KeyColumnNames: 'Columns',
|
@@ -0,0 +1,32 @@
|
|
1
|
+
@import '../../styles/mixins.scss';
|
2
|
+
|
3
|
+
.ydb-table-with-controls-layout {
|
4
|
+
display: inline-block;
|
5
|
+
|
6
|
+
box-sizing: border-box;
|
7
|
+
min-width: 100%;
|
8
|
+
|
9
|
+
&__controls-wrapper {
|
10
|
+
z-index: 3;
|
11
|
+
|
12
|
+
box-sizing: border-box;
|
13
|
+
width: 100%;
|
14
|
+
|
15
|
+
@include sticky-top();
|
16
|
+
}
|
17
|
+
|
18
|
+
&__controls {
|
19
|
+
z-index: 3;
|
20
|
+
|
21
|
+
width: max-content;
|
22
|
+
height: 62px;
|
23
|
+
|
24
|
+
@include controls();
|
25
|
+
@include sticky-top();
|
26
|
+
}
|
27
|
+
|
28
|
+
.data-table__sticky_moving {
|
29
|
+
// Place table head right after controls
|
30
|
+
top: 62px !important;
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import type {ReactNode} from 'react';
|
2
|
+
import block from 'bem-cn-lite';
|
3
|
+
|
4
|
+
import {TableSkeleton} from '../TableSkeleton/TableSkeleton';
|
5
|
+
|
6
|
+
import './TableWithControlsLayout.scss';
|
7
|
+
|
8
|
+
const b = block('ydb-table-with-controls-layout');
|
9
|
+
|
10
|
+
interface TableWithControlsLayoutItemProps {
|
11
|
+
children: ReactNode;
|
12
|
+
className?: string;
|
13
|
+
}
|
14
|
+
|
15
|
+
interface TableProps extends TableWithControlsLayoutItemProps {
|
16
|
+
loading?: boolean;
|
17
|
+
}
|
18
|
+
|
19
|
+
export const TableWithControlsLayout = ({
|
20
|
+
children,
|
21
|
+
className,
|
22
|
+
}: TableWithControlsLayoutItemProps) => {
|
23
|
+
return <div className={b(null, className)}>{children}</div>;
|
24
|
+
};
|
25
|
+
|
26
|
+
TableWithControlsLayout.Controls = function TableControls({
|
27
|
+
children,
|
28
|
+
className,
|
29
|
+
}: TableWithControlsLayoutItemProps) {
|
30
|
+
return (
|
31
|
+
<div className={b('controls-wrapper')}>
|
32
|
+
<div className={b('controls', className)}>{children}</div>
|
33
|
+
</div>
|
34
|
+
);
|
35
|
+
};
|
36
|
+
|
37
|
+
TableWithControlsLayout.Table = function Table({children, loading, className}: TableProps) {
|
38
|
+
if (loading) {
|
39
|
+
return <TableSkeleton className={b('loader')} />;
|
40
|
+
}
|
41
|
+
|
42
|
+
return <div className={b('table', className)}>{children}</div>;
|
43
|
+
};
|
@@ -7,7 +7,7 @@ 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
|
10
|
+
import terminalIcon from '@gravity-ui/icons/svgs/terminal.svg';
|
11
11
|
import pulseIcon from '@gravity-ui/icons/svgs/pulse.svg';
|
12
12
|
|
13
13
|
import signOutIcon from '../../assets/icons/signOut.svg';
|
@@ -141,7 +141,7 @@ export const useGetLeftNavigationItems = () => {
|
|
141
141
|
{
|
142
142
|
id: TENANT_PAGES_IDS.query,
|
143
143
|
title: 'Query',
|
144
|
-
icon:
|
144
|
+
icon: terminalIcon,
|
145
145
|
iconSize: 20,
|
146
146
|
location: getTenantPath({
|
147
147
|
...queryParams,
|
@@ -118,20 +118,6 @@ function Cluster({
|
|
118
118
|
}
|
119
119
|
};
|
120
120
|
|
121
|
-
const getTabEntityCount = (tabId: ClusterTab) => {
|
122
|
-
switch (tabId) {
|
123
|
-
case clusterTabsIds.tenants: {
|
124
|
-
return cluster?.Tenants ? Number(cluster.Tenants) : undefined;
|
125
|
-
}
|
126
|
-
case clusterTabsIds.nodes: {
|
127
|
-
return cluster?.NodesTotal ? Number(cluster.NodesTotal) : undefined;
|
128
|
-
}
|
129
|
-
default: {
|
130
|
-
return undefined;
|
131
|
-
}
|
132
|
-
}
|
133
|
-
};
|
134
|
-
|
135
121
|
return (
|
136
122
|
<div className={b()}>
|
137
123
|
<ClusterInfo
|
@@ -142,17 +128,12 @@ function Cluster({
|
|
142
128
|
additionalClusterProps={additionalClusterProps}
|
143
129
|
/>
|
144
130
|
|
145
|
-
<div>
|
131
|
+
<div className={b('tabs')}>
|
146
132
|
<Tabs
|
147
133
|
size="l"
|
148
134
|
allowNotSelected={true}
|
149
135
|
activeTab={activeTab as string}
|
150
|
-
items={clusterTabs
|
151
|
-
return {
|
152
|
-
...item,
|
153
|
-
counter: getTabEntityCount(item.id),
|
154
|
-
};
|
155
|
-
})}
|
136
|
+
items={clusterTabs}
|
156
137
|
wrapTo={({id}, node) => {
|
157
138
|
const path = getClusterPath(id as ClusterTab, queryParams);
|
158
139
|
return (
|
@@ -164,7 +145,7 @@ function Cluster({
|
|
164
145
|
/>
|
165
146
|
</div>
|
166
147
|
|
167
|
-
<div
|
148
|
+
<div>{renderTab()}</div>
|
168
149
|
</div>
|
169
150
|
);
|
170
151
|
}
|
@@ -18,7 +18,7 @@ interface ClusterInfoSkeletonProps {
|
|
18
18
|
rows?: number;
|
19
19
|
}
|
20
20
|
|
21
|
-
export const ClusterInfoSkeleton = ({rows =
|
21
|
+
export const ClusterInfoSkeleton = ({rows = 7, className}: ClusterInfoSkeletonProps) => (
|
22
22
|
<div className={b(null, className)}>
|
23
23
|
{[...new Array(rows)].map((_, index) => (
|
24
24
|
<div className={b('row')} key={`skeleton-row-${index}`}>
|
@@ -1,10 +1,3 @@
|
|
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
|
-
|
8
1
|
import type {ValueOf} from '../../types/common';
|
9
2
|
import routes, {createHref} from '../../routes';
|
10
3
|
|
@@ -20,22 +13,18 @@ export type ClusterTab = ValueOf<typeof clusterTabsIds>;
|
|
20
13
|
const tenants = {
|
21
14
|
id: clusterTabsIds.tenants,
|
22
15
|
title: 'Databases',
|
23
|
-
icon: <Icon data={databasesIcon} />,
|
24
16
|
};
|
25
17
|
const nodes = {
|
26
18
|
id: clusterTabsIds.nodes,
|
27
19
|
title: 'Nodes',
|
28
|
-
icon: <Icon data={cubes3Icon} />,
|
29
20
|
};
|
30
21
|
const storage = {
|
31
22
|
id: clusterTabsIds.storage,
|
32
23
|
title: 'Storage',
|
33
|
-
icon: <Icon data={hardDriveIcon} />,
|
34
24
|
};
|
35
25
|
const versions = {
|
36
26
|
id: clusterTabsIds.versions,
|
37
27
|
title: 'Versions',
|
38
|
-
icon: <Icon data={versionsIcon} />,
|
39
28
|
};
|
40
29
|
|
41
30
|
export const clusterTabs = [tenants, nodes, storage, versions];
|
@@ -6,14 +6,10 @@
|
|
6
6
|
justify-content: space-between;
|
7
7
|
align-items: center;
|
8
8
|
|
9
|
-
padding: 0 20px 0
|
10
|
-
|
11
|
-
font-weight: 600;
|
9
|
+
padding: 0 20px 0 12px;
|
12
10
|
|
13
11
|
border-bottom: 1px solid var(--yc-color-line-generic);
|
14
12
|
|
15
|
-
@include body2-typography;
|
16
|
-
|
17
13
|
&__breadcrumb {
|
18
14
|
display: flex;
|
19
15
|
align-items: center;
|
@@ -1,21 +1,10 @@
|
|
1
1
|
@import '../../styles/mixins.scss';
|
2
2
|
|
3
3
|
.ydb-nodes {
|
4
|
-
overflow: auto;
|
5
|
-
flex-grow: 1;
|
6
|
-
|
7
|
-
height: 100%;
|
8
|
-
|
9
|
-
@include flex-container();
|
10
|
-
|
11
4
|
&__search {
|
12
5
|
@include search();
|
13
6
|
}
|
14
7
|
|
15
|
-
&__controls {
|
16
|
-
@include controls();
|
17
|
-
}
|
18
|
-
|
19
8
|
&__show-all-wrapper {
|
20
9
|
position: sticky;
|
21
10
|
left: 0;
|
@@ -23,19 +12,7 @@
|
|
23
12
|
margin-bottom: 15px;
|
24
13
|
}
|
25
14
|
|
26
|
-
&__table
|
27
|
-
overflow: auto;
|
28
|
-
@include flex-container();
|
29
|
-
}
|
30
|
-
|
31
|
-
&__table-content {
|
32
|
-
overflow: auto;
|
33
|
-
|
34
|
-
height: 100%;
|
35
|
-
|
36
|
-
@include freeze-nth-column(1);
|
37
|
-
@include freeze-nth-column(2, 80px);
|
38
|
-
|
15
|
+
&__table {
|
39
16
|
@include table-styles;
|
40
17
|
@include table-sticky-styles;
|
41
18
|
}
|
@@ -9,11 +9,12 @@ import type {ProblemFilterValue} from '../../store/reducers/settings/types';
|
|
9
9
|
|
10
10
|
import {AccessDenied} from '../../components/Errors/403';
|
11
11
|
import {Illustration} from '../../components/Illustration';
|
12
|
-
import {Loader} from '../../components/Loader';
|
13
12
|
import {Search} from '../../components/Search';
|
14
13
|
import {ProblemFilter} from '../../components/ProblemFilter';
|
15
14
|
import {UptimeFilter} from '../../components/UptimeFIlter';
|
16
15
|
import {EntitiesCount} from '../../components/EntitiesCount';
|
16
|
+
import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout';
|
17
|
+
import {ResponseError} from '../../components/Errors/ResponseError';
|
17
18
|
|
18
19
|
import {DEFAULT_TABLE_SETTINGS, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY} from '../../utils/constants';
|
19
20
|
import {useAutofetcher, useSetting, useTypedSelector} from '../../utils/hooks';
|
@@ -21,12 +22,12 @@ import {AdditionalNodesInfo, isUnavailableNode, NodesUptimeFilterValues} from '.
|
|
21
22
|
|
22
23
|
import {
|
23
24
|
getNodes,
|
24
|
-
getFilteredPreparedNodesList,
|
25
25
|
setNodesUptimeFilter,
|
26
26
|
setSearchValue,
|
27
27
|
resetNodesState,
|
28
28
|
getComputeNodes,
|
29
29
|
} from '../../store/reducers/nodes/nodes';
|
30
|
+
import {selectFilteredNodes} from '../../store/reducers/nodes/selectors';
|
30
31
|
import {changeFilter, ProblemFilterValues} from '../../store/reducers/settings/settings';
|
31
32
|
|
32
33
|
import {isDatabaseEntityType} from '../Tenant/utils/schema';
|
@@ -42,11 +43,10 @@ const b = cn('ydb-nodes');
|
|
42
43
|
interface NodesProps {
|
43
44
|
path?: string;
|
44
45
|
type?: EPathType;
|
45
|
-
className?: string;
|
46
46
|
additionalNodesInfo?: AdditionalNodesInfo;
|
47
47
|
}
|
48
48
|
|
49
|
-
export const Nodes = ({path, type,
|
49
|
+
export const Nodes = ({path, type, additionalNodesInfo = {}}: NodesProps) => {
|
50
50
|
const dispatch = useDispatch();
|
51
51
|
|
52
52
|
const isClusterNodes = !path;
|
@@ -63,7 +63,7 @@ export const Nodes = ({path, type, className, additionalNodesInfo = {}}: NodesPr
|
|
63
63
|
const problemFilter = useTypedSelector((state) => state.settings.problemFilter);
|
64
64
|
const {autorefresh} = useTypedSelector((state) => state.schema);
|
65
65
|
|
66
|
-
const nodes = useTypedSelector(
|
66
|
+
const nodes = useTypedSelector(selectFilteredNodes);
|
67
67
|
|
68
68
|
const [useNodesEndpoint] = useSetting(USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY);
|
69
69
|
|
@@ -93,7 +93,7 @@ export const Nodes = ({path, type, className, additionalNodesInfo = {}}: NodesPr
|
|
93
93
|
|
94
94
|
const renderControls = () => {
|
95
95
|
return (
|
96
|
-
|
96
|
+
<>
|
97
97
|
<Search
|
98
98
|
onChange={handleSearchQueryChange}
|
99
99
|
placeholder="Host name"
|
@@ -108,7 +108,7 @@ export const Nodes = ({path, type, className, additionalNodesInfo = {}}: NodesPr
|
|
108
108
|
label={'Nodes'}
|
109
109
|
loading={loading && !wasLoaded}
|
110
110
|
/>
|
111
|
-
|
111
|
+
</>
|
112
112
|
);
|
113
113
|
};
|
114
114
|
|
@@ -127,44 +127,34 @@ export const Nodes = ({path, type, className, additionalNodesInfo = {}}: NodesPr
|
|
127
127
|
}
|
128
128
|
|
129
129
|
return (
|
130
|
-
<
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
rowClassName={(row) => b('node', {unavailable: isUnavailableNode(row)})}
|
143
|
-
/>
|
144
|
-
</div>
|
145
|
-
</div>
|
130
|
+
<DataTable
|
131
|
+
theme="yandex-cloud"
|
132
|
+
data={nodes || []}
|
133
|
+
columns={columns}
|
134
|
+
settings={DEFAULT_TABLE_SETTINGS}
|
135
|
+
initialSortOrder={{
|
136
|
+
columnId: 'NodeId',
|
137
|
+
order: DataTable.ASCENDING,
|
138
|
+
}}
|
139
|
+
emptyDataMessage={i18n('empty.default')}
|
140
|
+
rowClassName={(row) => b('node', {unavailable: isUnavailableNode(row)})}
|
141
|
+
/>
|
146
142
|
);
|
147
143
|
};
|
148
144
|
|
149
|
-
const renderContent = () => {
|
150
|
-
return (
|
151
|
-
<div className={b(null, className)}>
|
152
|
-
{renderControls()}
|
153
|
-
{renderTable()}
|
154
|
-
</div>
|
155
|
-
);
|
156
|
-
};
|
157
|
-
|
158
|
-
if (loading && !wasLoaded) {
|
159
|
-
return <Loader size={isClusterNodes ? 'l' : 'm'} />;
|
160
|
-
}
|
161
|
-
|
162
145
|
if (error) {
|
163
146
|
if (error.status === 403) {
|
164
147
|
return <AccessDenied />;
|
165
148
|
}
|
166
|
-
return <
|
149
|
+
return <ResponseError error={error} />;
|
167
150
|
}
|
168
151
|
|
169
|
-
return
|
152
|
+
return (
|
153
|
+
<TableWithControlsLayout>
|
154
|
+
<TableWithControlsLayout.Controls>{renderControls()}</TableWithControlsLayout.Controls>
|
155
|
+
<TableWithControlsLayout.Table loading={loading && !wasLoaded} className={b('table')}>
|
156
|
+
{renderTable()}
|
157
|
+
</TableWithControlsLayout.Table>
|
158
|
+
</TableWithControlsLayout>
|
159
|
+
);
|
170
160
|
};
|
@@ -1,24 +1,11 @@
|
|
1
1
|
@import '../../styles/mixins.scss';
|
2
2
|
|
3
3
|
.global-storage {
|
4
|
-
height: 100%;
|
5
|
-
max-height: 100%;
|
6
|
-
@include flex-container;
|
7
|
-
|
8
|
-
&__controls {
|
9
|
-
@include controls();
|
10
|
-
}
|
11
4
|
&__search {
|
12
5
|
@include search();
|
13
6
|
}
|
14
7
|
|
15
|
-
&__table
|
16
|
-
overflow: auto;
|
17
|
-
flex-grow: 1;
|
18
|
-
|
19
|
-
font-size: var(--yc-text-body-2-font-size);
|
20
|
-
line-height: var(--yc-text-body-2-line-height);
|
21
|
-
|
8
|
+
&__table {
|
22
9
|
.yc-tooltip {
|
23
10
|
// stylelint-disable-next-line declaration-no-important
|
24
11
|
height: var(--yc-text-body-2-line-height) !important;
|
@@ -5,10 +5,11 @@ import cn from 'bem-cn-lite';
|
|
5
5
|
import DataTable, {Settings} from '@gravity-ui/react-data-table';
|
6
6
|
|
7
7
|
import {Search} from '../../components/Search';
|
8
|
-
import {TableSkeleton} from '../../components/TableSkeleton/TableSkeleton';
|
9
8
|
import {UptimeFilter} from '../../components/UptimeFIlter';
|
10
9
|
import {AccessDenied} from '../../components/Errors/403';
|
11
10
|
import {EntitiesCount} from '../../components/EntitiesCount';
|
11
|
+
import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout';
|
12
|
+
import {ResponseError} from '../../components/Errors/ResponseError';
|
12
13
|
|
13
14
|
import type {StorageType, VisibleEntities} from '../../store/reducers/storage/types';
|
14
15
|
import {
|
@@ -37,7 +38,7 @@ import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants';
|
|
37
38
|
import {StorageGroups} from './StorageGroups/StorageGroups';
|
38
39
|
import {StorageNodes} from './StorageNodes/StorageNodes';
|
39
40
|
import {StorageTypeFilter} from './StorageTypeFilter/StorageTypeFilter';
|
40
|
-
import {
|
41
|
+
import {StorageVisibleEntitiesFilter} from './StorageVisibleEntitiesFilter/StorageVisibleEntitiesFilter';
|
41
42
|
import {UsageFilter} from './UsageFilter';
|
42
43
|
|
43
44
|
import './Storage.scss';
|
@@ -137,13 +138,9 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
137
138
|
handleUptimeFilterChange(NodesUptimeFilterValues.All);
|
138
139
|
};
|
139
140
|
|
140
|
-
const renderLoader = () => {
|
141
|
-
return <TableSkeleton className={b('loader')} />;
|
142
|
-
};
|
143
|
-
|
144
141
|
const renderDataTable = () => {
|
145
142
|
return (
|
146
|
-
|
143
|
+
<>
|
147
144
|
{storageType === STORAGE_TYPES.groups && (
|
148
145
|
<StorageGroups
|
149
146
|
visibleEntities={visibleEntities}
|
@@ -163,7 +160,7 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
163
160
|
additionalNodesInfo={additionalNodesInfo}
|
164
161
|
/>
|
165
162
|
)}
|
166
|
-
|
163
|
+
</>
|
167
164
|
);
|
168
165
|
};
|
169
166
|
|
@@ -185,7 +182,7 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
185
182
|
|
186
183
|
const renderControls = () => {
|
187
184
|
return (
|
188
|
-
|
185
|
+
<>
|
189
186
|
<div className={b('search')}>
|
190
187
|
<Search
|
191
188
|
placeholder={
|
@@ -199,7 +196,7 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
199
196
|
</div>
|
200
197
|
|
201
198
|
<StorageTypeFilter value={storageType} onChange={handleStorageTypeChange} />
|
202
|
-
<
|
199
|
+
<StorageVisibleEntitiesFilter
|
203
200
|
value={visibleEntities}
|
204
201
|
onChange={handleGroupVisibilityChange}
|
205
202
|
/>
|
@@ -217,24 +214,24 @@ export const Storage = ({additionalNodesInfo, tenant, nodeId}: StorageProps) =>
|
|
217
214
|
/>
|
218
215
|
)}
|
219
216
|
{renderEntitiesCount()}
|
220
|
-
|
217
|
+
</>
|
221
218
|
);
|
222
219
|
};
|
223
220
|
|
224
|
-
const showLoader = loading && !wasLoaded;
|
225
|
-
|
226
221
|
if (error) {
|
227
222
|
if (error.status === 403) {
|
228
223
|
return <AccessDenied />;
|
229
224
|
}
|
230
225
|
|
231
|
-
return <
|
226
|
+
return <ResponseError error={error} />;
|
232
227
|
}
|
233
228
|
|
234
229
|
return (
|
235
|
-
<
|
236
|
-
{renderControls()}
|
237
|
-
{
|
238
|
-
|
230
|
+
<TableWithControlsLayout>
|
231
|
+
<TableWithControlsLayout.Controls>{renderControls()}</TableWithControlsLayout.Controls>
|
232
|
+
<TableWithControlsLayout.Table loading={loading && !wasLoaded} className={b('table')}>
|
233
|
+
{renderDataTable()}
|
234
|
+
</TableWithControlsLayout.Table>
|
235
|
+
</TableWithControlsLayout>
|
239
236
|
);
|
240
237
|
};
|
@@ -13,9 +13,11 @@ interface StorageTypeFilterProps {
|
|
13
13
|
onChange: (value: string) => void;
|
14
14
|
}
|
15
15
|
|
16
|
+
const storageTypeFilterQa = 'storage-type-filter';
|
17
|
+
|
16
18
|
export const StorageTypeFilter = ({value, onChange}: StorageTypeFilterProps) => {
|
17
19
|
return (
|
18
|
-
<RadioButton value={value} onUpdate={onChange}>
|
20
|
+
<RadioButton value={value} onUpdate={onChange} qa={storageTypeFilterQa}>
|
19
21
|
<RadioButton.Option value={STORAGE_TYPES.groups}>
|
20
22
|
{StorageTypesTitles[STORAGE_TYPES.groups]}
|
21
23
|
</RadioButton.Option>
|
@@ -14,9 +14,11 @@ interface StorageProblemFilterProps {
|
|
14
14
|
onChange: (value: string) => void;
|
15
15
|
}
|
16
16
|
|
17
|
-
|
17
|
+
const storageVisibleEntitiesFilterQa = 'storage-visible-entities-filter';
|
18
|
+
|
19
|
+
export const StorageVisibleEntitiesFilter = ({value, onChange}: StorageProblemFilterProps) => {
|
18
20
|
return (
|
19
|
-
<RadioButton value={value} onUpdate={onChange}>
|
21
|
+
<RadioButton value={value} onUpdate={onChange} qa={storageVisibleEntitiesFilterQa}>
|
20
22
|
<RadioButton.Option value={VISIBLE_ENTITIES.missing}>
|
21
23
|
{VisibleEntitiesTitles[VISIBLE_ENTITIES.missing]}
|
22
24
|
</RadioButton.Option>
|
@@ -39,11 +39,15 @@
|
|
39
39
|
width: 100%;
|
40
40
|
padding: 0 20px;
|
41
41
|
|
42
|
-
|
43
|
-
& .ydb-nodes {
|
42
|
+
.ydb-table-with-controls-layout {
|
44
43
|
&__controls {
|
44
|
+
height: 46px;
|
45
45
|
padding-top: 0;
|
46
46
|
}
|
47
|
+
|
48
|
+
.data-table__sticky_moving {
|
49
|
+
top: 46px !important;
|
50
|
+
}
|
47
51
|
}
|
48
52
|
}
|
49
53
|
}
|
@@ -26,7 +26,7 @@
|
|
26
26
|
|
27
27
|
&__action-button {
|
28
28
|
position: absolute;
|
29
|
-
top:
|
29
|
+
top: 19px; // centered relative to the heading
|
30
30
|
right: 5px; // centered relative to the collapsed panel
|
31
31
|
|
32
32
|
background-color: var(--yc-color-base-background);
|
@@ -51,20 +51,11 @@
|
|
51
51
|
flex: 1 1 auto;
|
52
52
|
|
53
53
|
height: 100%;
|
54
|
-
padding: 0 12px 12px;
|
54
|
+
padding: 0 12px 12px 16px;
|
55
55
|
}
|
56
56
|
|
57
57
|
&__tree-header {
|
58
|
-
|
59
|
-
flex: 0 0 auto;
|
60
|
-
justify-content: space-between;
|
61
|
-
align-items: center;
|
62
|
-
|
63
|
-
padding: 12px 12px 8px;
|
64
|
-
}
|
65
|
-
|
66
|
-
&__tree-title {
|
67
|
-
font-weight: 600;
|
58
|
+
padding: 23px 12px 17px 20px;
|
68
59
|
}
|
69
60
|
|
70
61
|
&__sticky-top {
|