ydb-embedded-ui 4.10.1 → 4.11.1
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +24 -0
- package/dist/components/QueryResultTable/Cell/Cell.tsx +8 -8
- package/dist/components/QueryResultTable/i18n/en.json +1 -1
- package/dist/components/QueryResultTable/i18n/ru.json +1 -1
- package/dist/components/ShortyString/ShortyString.tsx +3 -6
- package/dist/components/ShortyString/i18n/en.json +8 -8
- package/dist/components/ShortyString/i18n/ru.json +8 -8
- package/dist/components/SpeedMultiMeter/i18n/index.ts +0 -2
- package/dist/components/Stack/Stack.tsx +16 -16
- package/dist/components/TableSkeleton/TableSkeleton.tsx +3 -3
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +7 -3
- package/dist/containers/Header/Header.tsx +2 -2
- package/dist/containers/Header/breadcrumbs.ts +2 -1
- package/dist/containers/Heatmap/Heatmap.tsx +4 -3
- package/dist/containers/Node/NodeStructure/PDiskTitleBadge.tsx +2 -8
- package/dist/containers/Nodes/Nodes.tsx +1 -1
- package/dist/containers/Storage/EmptyFilter/i18n/en.json +2 -2
- package/dist/containers/Storage/EmptyFilter/i18n/ru.json +2 -2
- package/dist/containers/Storage/StorageGroups/i18n/en.json +5 -5
- package/dist/containers/Storage/StorageGroups/i18n/ru.json +5 -5
- package/dist/containers/Storage/UsageFilter/i18n/en.json +3 -8
- package/dist/containers/Storage/UsageFilter/i18n/ru.json +3 -8
- package/dist/containers/Tablet/Tablet.tsx +2 -2
- package/dist/containers/Tenant/Acl/Acl.scss +1 -9
- package/dist/containers/Tenant/Acl/Acl.tsx +137 -0
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +6 -0
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +3 -3
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +2 -0
- package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +2 -3
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +0 -6
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +95 -83
- package/dist/containers/Tenant/Query/Issues/Issues.tsx +27 -23
- package/dist/containers/Tenant/Query/Issues/models.ts +0 -11
- package/dist/containers/Tenant/Query/Preview/Preview.tsx +3 -3
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +2 -2
- package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx +99 -0
- package/dist/containers/Tenant/Tenant.tsx +1 -5
- package/dist/containers/Tenant/TenantPages.tsx +9 -14
- package/dist/containers/Tenant/i18n/en.json +11 -0
- package/dist/containers/Tenant/i18n/index.ts +11 -0
- package/dist/containers/Tenant/i18n/ru.json +11 -0
- package/dist/containers/Tenant/utils/schema.ts +24 -0
- package/dist/containers/Tenant/utils/schemaActions.ts +28 -24
- package/dist/containers/Tenants/Tenants.tsx +1 -4
- package/dist/services/api.ts +6 -7
- package/dist/store/index.js +1 -1
- package/dist/store/reducers/nodes/nodes.ts +14 -5
- package/dist/store/reducers/nodes/types.ts +22 -3
- package/dist/store/reducers/nodes/utils.ts +23 -10
- package/dist/store/reducers/preview.ts +6 -4
- package/dist/store/reducers/schemaAcl/schemaAcl.ts +17 -0
- package/dist/store/reducers/schemaAcl/types.ts +9 -7
- package/dist/store/reducers/tenant/constants.ts +6 -0
- package/dist/store/reducers/tenant/tenant.ts +15 -0
- package/dist/store/reducers/tenant/types.ts +18 -3
- package/dist/store/state-url-mapping.js +3 -0
- package/dist/types/api/cluster.ts +1 -1
- package/dist/types/api/compute.ts +11 -11
- package/dist/types/api/error.ts +2 -2
- package/dist/types/api/netInfo.ts +3 -3
- package/dist/types/api/nodes.ts +9 -8
- package/dist/types/api/query.ts +1 -1
- package/dist/types/api/schema/schema.ts +3 -0
- package/dist/types/api/schema/shared.ts +3 -3
- package/dist/types/api/schema/table.ts +22 -22
- package/dist/types/api/storage.ts +1 -1
- package/dist/types/assets.d.ts +1 -2
- package/dist/types/store/executeQuery.ts +2 -3
- package/dist/types/store/executeTopQueries.ts +8 -5
- package/dist/types/store/explainQuery.ts +4 -4
- package/dist/types/store/query.ts +4 -3
- package/dist/types/store/shardsWorkload.ts +8 -5
- package/dist/utils/constants.ts +4 -1
- package/dist/utils/error.ts +2 -3
- package/dist/utils/query.ts +3 -9
- package/dist/utils/tests/providers.tsx +6 -9
- package/package.json +6 -2
- package/dist/containers/Tenant/Acl/Acl.js +0 -153
- package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +0 -94
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,29 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [4.11.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.11.0...v4.11.1) (2023-07-27)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* **Issues:** fix types ([#488](https://github.com/ydb-platform/ydb-embedded-ui/issues/488)) ([e2fe731](https://github.com/ydb-platform/ydb-embedded-ui/commit/e2fe731ae23db6703f21179668582d5657de9550))
|
9
|
+
|
10
|
+
## [4.11.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.10.1...v4.11.0) (2023-07-27)
|
11
|
+
|
12
|
+
|
13
|
+
### Features
|
14
|
+
|
15
|
+
* support external objects in schema tree ([#485](https://github.com/ydb-platform/ydb-embedded-ui/issues/485)) ([cf96f9a](https://github.com/ydb-platform/ydb-embedded-ui/commit/cf96f9af02db1352f3990f21f8a84c1282229517))
|
16
|
+
|
17
|
+
|
18
|
+
### Bug Fixes
|
19
|
+
|
20
|
+
* **ClusterInfo:** change cluster default name ([#478](https://github.com/ydb-platform/ydb-embedded-ui/issues/478)) ([398df6e](https://github.com/ydb-platform/ydb-embedded-ui/commit/398df6e3a5778c245653f61b41ba2e1bd0ea3a51))
|
21
|
+
* fix copy schema action ([#483](https://github.com/ydb-platform/ydb-embedded-ui/issues/483)) ([f6b01c3](https://github.com/ydb-platform/ydb-embedded-ui/commit/f6b01c3cc2808337d5597f990f65ff3e7c010b05))
|
22
|
+
* **Nodes:** support v2 compute ([#476](https://github.com/ydb-platform/ydb-embedded-ui/issues/476)) ([696d43a](https://github.com/ydb-platform/ydb-embedded-ui/commit/696d43a04109c7fc68986e036e66767593af8d00))
|
23
|
+
* **ObjectSummary:** fix issue on object change with active schema tab ([#482](https://github.com/ydb-platform/ydb-embedded-ui/issues/482)) ([b50db5f](https://github.com/ydb-platform/ydb-embedded-ui/commit/b50db5ff742c5c7fc27e292309831b937e5d40bd))
|
24
|
+
* **ObjectSummary:** fix wrong tree alignment bug ([#486](https://github.com/ydb-platform/ydb-embedded-ui/issues/486)) ([e8bfe99](https://github.com/ydb-platform/ydb-embedded-ui/commit/e8bfe99657870c735a41d24febaa907ac1383479))
|
25
|
+
* **Query:** process null issues error ([#480](https://github.com/ydb-platform/ydb-embedded-ui/issues/480)) ([4c4e684](https://github.com/ydb-platform/ydb-embedded-ui/commit/4c4e6845e539296ecbdefa930bc63d3321f277dc))
|
26
|
+
|
3
27
|
## [4.10.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.10.0...v4.10.1) (2023-07-14)
|
4
28
|
|
5
29
|
|
@@ -11,16 +11,16 @@ interface CellProps {
|
|
11
11
|
}
|
12
12
|
|
13
13
|
export const Cell = React.memo(function Cell(props: CellProps) {
|
14
|
-
const {
|
15
|
-
className,
|
16
|
-
value,
|
17
|
-
} = props;
|
14
|
+
const {className, value} = props;
|
18
15
|
|
19
16
|
const dispatch = useDispatch();
|
20
17
|
|
21
|
-
useEffect(
|
22
|
-
|
23
|
-
|
18
|
+
useEffect(
|
19
|
+
() => () => {
|
20
|
+
dispatch(hideTooltip());
|
21
|
+
},
|
22
|
+
[dispatch],
|
23
|
+
);
|
24
24
|
|
25
25
|
return (
|
26
26
|
<span
|
@@ -29,5 +29,5 @@ export const Cell = React.memo(function Cell(props: CellProps) {
|
|
29
29
|
>
|
30
30
|
{value}
|
31
31
|
</span>
|
32
|
-
)
|
32
|
+
);
|
33
33
|
});
|
@@ -33,18 +33,15 @@ export default function ShortyString({
|
|
33
33
|
const [expanded, setExpanded] = React.useState(false);
|
34
34
|
|
35
35
|
const toggleLabelAction = expanded ? collapseLabel : expandLabel;
|
36
|
-
const toggleLabelSymbolsCount =
|
37
|
-
? i18n('chars_count', {count: value.length})
|
38
|
-
: '';
|
36
|
+
const toggleLabelSymbolsCount =
|
37
|
+
displayLength && !expanded ? i18n('chars_count', {count: value.length}) : '';
|
39
38
|
const toggleLabel = toggleLabelAction + toggleLabelSymbolsCount;
|
40
39
|
|
41
40
|
// showing toogle button with a label that is longer than the hidden part is pointless,
|
42
41
|
// hence compare to limit + length in the not-strict mode
|
43
42
|
const hasToggle = value.length > limit + (strict ? 0 : toggleLabel.length);
|
44
43
|
|
45
|
-
const text = expanded || !hasToggle
|
46
|
-
? value
|
47
|
-
: value.slice(0, limit - 4) + '\u00a0...';
|
44
|
+
const text = expanded || !hasToggle ? value : value.slice(0, limit - 4) + '\u00a0...';
|
48
45
|
|
49
46
|
return (
|
50
47
|
<div className={block()}>
|
@@ -1,10 +1,10 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
"default_collapse_label": "Show less",
|
3
|
+
"default_expand_label": "Show more",
|
4
|
+
"chars_count": [
|
5
|
+
" ({{count}} symbol)",
|
6
|
+
" ({{count}} symbols)",
|
7
|
+
" ({{count}} symbols)",
|
8
|
+
" ({{count}} symbols)"
|
9
|
+
]
|
10
10
|
}
|
@@ -1,10 +1,10 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
"default_collapse_label": "Показать меньше",
|
3
|
+
"default_expand_label": "Показать ещё",
|
4
|
+
"chars_count": [
|
5
|
+
" ({{count}} символ)",
|
6
|
+
" ({{count}} символа)",
|
7
|
+
" ({{count}} символов)",
|
8
|
+
" ({{count}} символов)"
|
9
|
+
]
|
10
10
|
}
|
@@ -13,23 +13,23 @@ const b = cn('stack');
|
|
13
13
|
|
14
14
|
export const Stack: React.FC<StackProps> = ({children, className}) => (
|
15
15
|
<div className={b(null, className)}>
|
16
|
-
{
|
17
|
-
React.
|
18
|
-
|
19
|
-
|
20
|
-
}
|
16
|
+
{React.Children.map(children, (child, index) => {
|
17
|
+
if (!React.isValidElement(child)) {
|
18
|
+
return null;
|
19
|
+
}
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
return (
|
22
|
+
<div
|
23
|
+
className={b('layer')}
|
24
|
+
style={
|
25
|
+
{
|
26
26
|
[LAYER_CSS_VAR]: index,
|
27
|
-
} as React.CSSProperties
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
}
|
27
|
+
} as React.CSSProperties
|
28
|
+
}
|
29
|
+
>
|
30
|
+
{child}
|
31
|
+
</div>
|
32
|
+
);
|
33
|
+
})}
|
34
34
|
</div>
|
35
35
|
);
|
@@ -1,6 +1,6 @@
|
|
1
|
-
import {
|
1
|
+
import {FC} from 'react';
|
2
2
|
import block from 'bem-cn-lite';
|
3
|
-
import {
|
3
|
+
import {Skeleton} from '@gravity-ui/uikit';
|
4
4
|
|
5
5
|
import './TableSkeleton.scss';
|
6
6
|
|
@@ -11,7 +11,7 @@ interface TableSkeletonProps {
|
|
11
11
|
rows?: number;
|
12
12
|
}
|
13
13
|
|
14
|
-
export const TableSkeleton: FC<TableSkeletonProps> = ({
|
14
|
+
export const TableSkeleton: FC<TableSkeletonProps> = ({rows = 2, className}) => (
|
15
15
|
<div className={b(null, className)}>
|
16
16
|
<div className={b('row')}>
|
17
17
|
<Skeleton className={b('col-1')} />
|
@@ -18,7 +18,11 @@ 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 {
|
21
|
+
import {
|
22
|
+
CLUSTER_DEFAULT_TITLE,
|
23
|
+
CLUSTER_INFO_HIDDEN_KEY,
|
24
|
+
DEVELOPER_UI_TITLE,
|
25
|
+
} from '../../../utils/constants';
|
22
26
|
|
23
27
|
import {VersionsBar} from '../VersionsBar/VersionsBar';
|
24
28
|
import {ClusterInfoSkeleton} from '../ClusterInfoSkeleton/ClusterInfoSkeleton';
|
@@ -148,7 +152,7 @@ export const ClusterInfo = ({
|
|
148
152
|
const {info = [], links = []} = additionalClusterProps;
|
149
153
|
|
150
154
|
const clusterInfo = getInfo(cluster, versionsValues, info, [
|
151
|
-
{title:
|
155
|
+
{title: DEVELOPER_UI_TITLE, url: internalLink},
|
152
156
|
...links,
|
153
157
|
]);
|
154
158
|
|
@@ -173,7 +177,7 @@ export const ClusterInfo = ({
|
|
173
177
|
<EntityStatus
|
174
178
|
size="m"
|
175
179
|
status={cluster?.Overall}
|
176
|
-
name={cluster?.Name ??
|
180
|
+
name={cluster?.Name ?? CLUSTER_DEFAULT_TITLE}
|
177
181
|
className={b('title')}
|
178
182
|
/>
|
179
183
|
);
|
@@ -10,7 +10,7 @@ import {ExternalLinkWithIcon} from '../../components/ExternalLinkWithIcon/Extern
|
|
10
10
|
import {backend, customBackend} from '../../store';
|
11
11
|
import {getClusterInfo} from '../../store/reducers/cluster/cluster';
|
12
12
|
import {useTypedSelector} from '../../utils/hooks';
|
13
|
-
import {
|
13
|
+
import {DEVELOPER_UI_TITLE} from '../../utils/constants';
|
14
14
|
import {parseQuery} from '../../routes';
|
15
15
|
|
16
16
|
import {RawBreadcrumbItem, getBreadcrumbs} from './breadcrumbs';
|
@@ -105,7 +105,7 @@ function Header({mainPage}: HeaderProps) {
|
|
105
105
|
</div>
|
106
106
|
|
107
107
|
<ExternalLinkWithIcon
|
108
|
-
title={
|
108
|
+
title={DEVELOPER_UI_TITLE}
|
109
109
|
url={getInternalLink(singleClusterMode)}
|
110
110
|
/>
|
111
111
|
</header>
|
@@ -16,6 +16,7 @@ import {
|
|
16
16
|
TENANT_PAGES_IDS,
|
17
17
|
} from '../../store/reducers/tenant/constants';
|
18
18
|
import routes, {createHref} from '../../routes';
|
19
|
+
import {CLUSTER_DEFAULT_TITLE} from '../../utils/constants';
|
19
20
|
|
20
21
|
import {getClusterPath} from '../Cluster/utils';
|
21
22
|
import {TenantTabsGroups, getTenantPath} from '../Tenant/TenantPages';
|
@@ -39,7 +40,7 @@ const getClusterBreadcrumbs = (
|
|
39
40
|
|
40
41
|
return [
|
41
42
|
{
|
42
|
-
text: clusterName ||
|
43
|
+
text: clusterName || CLUSTER_DEFAULT_TITLE,
|
43
44
|
link: getClusterPath(clusterTab, query),
|
44
45
|
icon: nodesRightIcon,
|
45
46
|
},
|
@@ -4,13 +4,14 @@ import cn from 'bem-cn-lite';
|
|
4
4
|
|
5
5
|
import {Checkbox, Select} from '@gravity-ui/uikit';
|
6
6
|
|
7
|
+
import type {IHeatmapMetricValue} from '../../types/store/heatmap';
|
7
8
|
import {getTabletsInfo, setHeatmapOptions} from '../../store/reducers/heatmap';
|
8
9
|
import {showTooltip, hideTooltip} from '../../store/reducers/tooltip';
|
9
10
|
import {formatNumber} from '../../utils';
|
10
|
-
import {prepareQueryError} from '../../utils/query';
|
11
11
|
import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
|
12
|
+
|
12
13
|
import {Loader} from '../../components/Loader';
|
13
|
-
import
|
14
|
+
import {ResponseError} from '../../components/Errors/ResponseError';
|
14
15
|
|
15
16
|
import {COLORS_RANGE_SIZE, getColorRange, getColorIndex, getCurrentMetricLimits} from './util';
|
16
17
|
import {HeatmapCanvas} from './HeatmapCanvas/HeatmapCanvas';
|
@@ -196,7 +197,7 @@ export const Heatmap = ({path}: HeatmapProps) => {
|
|
196
197
|
}
|
197
198
|
|
198
199
|
if (error) {
|
199
|
-
return <
|
200
|
+
return <ResponseError error={error} />;
|
200
201
|
}
|
201
202
|
|
202
203
|
return renderContent();
|
@@ -12,14 +12,8 @@ interface PDiskTitleBadgeProps {
|
|
12
12
|
export function PDiskTitleBadge({label, value, className}: PDiskTitleBadgeProps) {
|
13
13
|
return (
|
14
14
|
<span className={b('pdisk-title-item', className)}>
|
15
|
-
{label && (
|
16
|
-
|
17
|
-
{label}:
|
18
|
-
</span>
|
19
|
-
)}
|
20
|
-
<span className={b('pdisk-title-item-value')}>
|
21
|
-
{value}
|
22
|
-
</span>
|
15
|
+
{label && <span className={b('pdisk-title-item-label')}>{label}:</span>}
|
16
|
+
<span className={b('pdisk-title-item-value')}>{value}</span>
|
23
17
|
</span>
|
24
18
|
);
|
25
19
|
}
|
@@ -71,7 +71,7 @@ export const Nodes = ({path, type, additionalNodesInfo = {}}: NodesProps) => {
|
|
71
71
|
// For not DB entities we always use /compute endpoint instead of /nodes
|
72
72
|
// since /nodes can return data only for tenants
|
73
73
|
if (path && (!useNodesEndpoint || !isDatabaseEntityType(type))) {
|
74
|
-
dispatch(getComputeNodes(path));
|
74
|
+
dispatch(getComputeNodes({path}));
|
75
75
|
} else {
|
76
76
|
dispatch(getNodes({tenant: path}));
|
77
77
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
"empty.default": "No such groups",
|
3
|
+
"empty.out_of_space": "No groups with out of space errors",
|
4
|
+
"empty.degraded": "No degraded groups",
|
5
|
+
"show_all": "Show all groups",
|
6
|
+
"encrypted": "Encrypted group"
|
7
7
|
}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
"empty.default": "Нет групп",
|
3
|
+
"empty.out_of_space": "Нет групп, в которых кончается место",
|
4
|
+
"empty.degraded": "Нет деградировавших групп",
|
5
|
+
"show_all": "Показать все группы",
|
6
|
+
"encrypted": "Зашифрованная группа"
|
7
7
|
}
|
@@ -1,10 +1,5 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
"{{count}} group",
|
6
|
-
"{{count}} groups",
|
7
|
-
"{{count}} groups",
|
8
|
-
"No groups"
|
9
|
-
]
|
2
|
+
"label": "Usage:",
|
3
|
+
"default_value": "Any",
|
4
|
+
"groups_count": ["{{count}} group", "{{count}} groups", "{{count}} groups", "No groups"]
|
10
5
|
}
|
@@ -1,10 +1,5 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
"{{count}} группа",
|
6
|
-
"{{count}} группы",
|
7
|
-
"{{count}} групп",
|
8
|
-
"Нет групп"
|
9
|
-
]
|
2
|
+
"label": "Использование:",
|
3
|
+
"default_value": "Любое",
|
4
|
+
"groups_count": ["{{count}} группа", "{{count}} группы", "{{count}} групп", "Нет групп"]
|
10
5
|
}
|
@@ -9,7 +9,7 @@ import {getTablet, getTabletDescribe, clearTabletData} from '../../store/reducer
|
|
9
9
|
import {setHeaderBreadcrumbs} from '../../store/reducers/header/header';
|
10
10
|
|
11
11
|
import {useAutofetcher, useTypedSelector} from '../../utils/hooks';
|
12
|
-
import {
|
12
|
+
import {DEVELOPER_UI_TITLE} from '../../utils/constants';
|
13
13
|
import '../../services/api';
|
14
14
|
import {parseQuery} from '../../routes';
|
15
15
|
|
@@ -113,7 +113,7 @@ export const Tablet = () => {
|
|
113
113
|
|
114
114
|
const externalLinks = [
|
115
115
|
{
|
116
|
-
name: `${
|
116
|
+
name: `${DEVELOPER_UI_TITLE} - tablet`,
|
117
117
|
path: `/tablets?TabletID=${TabletId}`,
|
118
118
|
},
|
119
119
|
];
|
@@ -1,6 +1,6 @@
|
|
1
1
|
@import '../../../styles/mixins.scss';
|
2
2
|
|
3
|
-
.
|
3
|
+
.ydb-acl {
|
4
4
|
display: flex;
|
5
5
|
overflow: auto;
|
6
6
|
flex-grow: 1;
|
@@ -16,14 +16,6 @@
|
|
16
16
|
padding: 0 12px 16px;
|
17
17
|
}
|
18
18
|
|
19
|
-
&__loader-container {
|
20
|
-
display: flex;
|
21
|
-
justify-content: center;
|
22
|
-
align-items: center;
|
23
|
-
|
24
|
-
height: 100%;
|
25
|
-
}
|
26
|
-
|
27
19
|
&__owner-container {
|
28
20
|
position: sticky;
|
29
21
|
z-index: 2;
|
@@ -0,0 +1,137 @@
|
|
1
|
+
import {useDispatch} from 'react-redux';
|
2
|
+
import {useEffect} from 'react';
|
3
|
+
import cn from 'bem-cn-lite';
|
4
|
+
|
5
|
+
import DataTable, {Column} from '@gravity-ui/react-data-table';
|
6
|
+
|
7
|
+
import type {TACE} from '../../../types/api/acl';
|
8
|
+
import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
|
9
|
+
import {useTypedSelector} from '../../../utils/hooks';
|
10
|
+
import {getSchemaAcl, setAclWasNotLoaded} from '../../../store/reducers/schemaAcl/schemaAcl';
|
11
|
+
|
12
|
+
import {ResponseError} from '../../../components/Errors/ResponseError';
|
13
|
+
import {Loader} from '../../../components/Loader';
|
14
|
+
|
15
|
+
import './Acl.scss';
|
16
|
+
import i18n from '../i18n';
|
17
|
+
|
18
|
+
const b = cn('ydb-acl');
|
19
|
+
|
20
|
+
const TABLE_SETTINGS = {
|
21
|
+
...DEFAULT_TABLE_SETTINGS,
|
22
|
+
dynamicRender: false,
|
23
|
+
stickyTop: 36,
|
24
|
+
};
|
25
|
+
|
26
|
+
const prepareLogin = (value: string | undefined) => {
|
27
|
+
if (value && value.endsWith('@staff') && !value.startsWith('svc_')) {
|
28
|
+
const login = value.split('@')[0];
|
29
|
+
return login;
|
30
|
+
}
|
31
|
+
|
32
|
+
return value;
|
33
|
+
};
|
34
|
+
|
35
|
+
const columns: Column<TACE>[] = [
|
36
|
+
{
|
37
|
+
name: 'AccessType',
|
38
|
+
header: 'Access Type',
|
39
|
+
sortable: false,
|
40
|
+
render: ({row}) => row.AccessType,
|
41
|
+
},
|
42
|
+
{
|
43
|
+
name: 'AccessRights',
|
44
|
+
header: 'Access Rights',
|
45
|
+
render: ({row}) => {
|
46
|
+
return row.AccessRights?.map((item, index) => {
|
47
|
+
return <div key={index}>{item}</div>;
|
48
|
+
});
|
49
|
+
},
|
50
|
+
sortable: false,
|
51
|
+
},
|
52
|
+
{
|
53
|
+
name: 'Subject',
|
54
|
+
sortable: false,
|
55
|
+
render: ({row}) => {
|
56
|
+
return prepareLogin(row.Subject);
|
57
|
+
},
|
58
|
+
width: 140,
|
59
|
+
},
|
60
|
+
{
|
61
|
+
name: 'InheritanceType',
|
62
|
+
header: 'Inheritance Type',
|
63
|
+
render: ({row}) => {
|
64
|
+
return row.InheritanceType?.map((item, index) => {
|
65
|
+
return <div key={index}>{item}</div>;
|
66
|
+
});
|
67
|
+
},
|
68
|
+
sortable: false,
|
69
|
+
},
|
70
|
+
];
|
71
|
+
|
72
|
+
export const Acl = () => {
|
73
|
+
const dispatch = useDispatch();
|
74
|
+
|
75
|
+
const {currentSchemaPath} = useTypedSelector((state) => state.schema);
|
76
|
+
const {loading, error, acl, owner, wasLoaded} = useTypedSelector((state) => state.schemaAcl);
|
77
|
+
|
78
|
+
useEffect(() => {
|
79
|
+
if (currentSchemaPath) {
|
80
|
+
dispatch(getSchemaAcl({path: currentSchemaPath}));
|
81
|
+
}
|
82
|
+
|
83
|
+
return () => {
|
84
|
+
// Ensures correct acl on path change
|
85
|
+
dispatch(setAclWasNotLoaded());
|
86
|
+
};
|
87
|
+
}, [currentSchemaPath, dispatch]);
|
88
|
+
|
89
|
+
const renderTable = () => {
|
90
|
+
if (!acl || !acl.length) {
|
91
|
+
return null;
|
92
|
+
}
|
93
|
+
|
94
|
+
return (
|
95
|
+
<DataTable
|
96
|
+
theme="yandex-cloud"
|
97
|
+
columns={columns}
|
98
|
+
data={acl}
|
99
|
+
settings={TABLE_SETTINGS}
|
100
|
+
/>
|
101
|
+
);
|
102
|
+
};
|
103
|
+
|
104
|
+
const renderOwner = () => {
|
105
|
+
if (!owner) {
|
106
|
+
return null;
|
107
|
+
}
|
108
|
+
|
109
|
+
return (
|
110
|
+
<div className={b('owner-container')}>
|
111
|
+
<span className={b('owner-label')}>{`${i18n('acl.owner')}: `}</span>
|
112
|
+
{prepareLogin(owner)}
|
113
|
+
</div>
|
114
|
+
);
|
115
|
+
};
|
116
|
+
|
117
|
+
if (loading && !wasLoaded) {
|
118
|
+
return <Loader />;
|
119
|
+
}
|
120
|
+
|
121
|
+
if (error) {
|
122
|
+
return <ResponseError error={error} className={b('message-container')} />;
|
123
|
+
}
|
124
|
+
|
125
|
+
if (!loading && !acl && !owner) {
|
126
|
+
return <div className={b('message-container')}>{i18n('acl.empty')}</div>;
|
127
|
+
}
|
128
|
+
|
129
|
+
return (
|
130
|
+
<div className={b()}>
|
131
|
+
<div className={b('result')}>
|
132
|
+
{renderOwner()}
|
133
|
+
{renderTable()}
|
134
|
+
</div>
|
135
|
+
</div>
|
136
|
+
);
|
137
|
+
};
|
@@ -6,8 +6,8 @@ import JSONTree from 'react-json-inspector';
|
|
6
6
|
import 'react-json-inspector/json-inspector.css';
|
7
7
|
|
8
8
|
import {Loader} from '../../../../components/Loader';
|
9
|
+
import {ResponseError} from '../../../../components/Errors/ResponseError';
|
9
10
|
|
10
|
-
import {prepareQueryError} from '../../../../utils/query';
|
11
11
|
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
12
12
|
import {
|
13
13
|
getDescribe,
|
@@ -86,7 +86,7 @@ const Describe = ({tenant, type}: IDescribeProps) => {
|
|
86
86
|
}
|
87
87
|
|
88
88
|
if (error) {
|
89
|
-
return <
|
89
|
+
return <ResponseError error={error} className={b('message-container')} />;
|
90
90
|
}
|
91
91
|
|
92
92
|
if (!loading && !preparedDescribeData) {
|
@@ -83,6 +83,9 @@ export const DIR_PAGES = [overview, topShards, nodes, describe];
|
|
83
83
|
export const CDC_STREAM_PAGES = [overview, consumers, partitions, nodes, describe];
|
84
84
|
export const TOPIC_PAGES = [overview, consumers, partitions, nodes, describe];
|
85
85
|
|
86
|
+
export const EXTERNAL_DATA_SOURCE_PAGES = [overview, describe];
|
87
|
+
export const EXTERNAL_TABLE_PAGES = [overview, describe];
|
88
|
+
|
86
89
|
// verbose mapping to guarantee correct tabs for new path types
|
87
90
|
// TS will error when a new type is added but not mapped here
|
88
91
|
const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
|
@@ -101,6 +104,9 @@ const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
|
|
101
104
|
[EPathType.EPathTypeCdcStream]: CDC_STREAM_PAGES,
|
102
105
|
|
103
106
|
[EPathType.EPathTypePersQueueGroup]: TOPIC_PAGES,
|
107
|
+
|
108
|
+
[EPathType.EPathTypeExternalDataSource]: EXTERNAL_DATA_SOURCE_PAGES,
|
109
|
+
[EPathType.EPathTypeExternalTable]: EXTERNAL_TABLE_PAGES,
|
104
110
|
};
|
105
111
|
|
106
112
|
export const getPagesByType = (type?: EPathType) => (type && pathTypeToPages[type]) || DIR_PAGES;
|
@@ -5,10 +5,10 @@ import {Loader} from '@gravity-ui/uikit';
|
|
5
5
|
import DataTable from '@gravity-ui/react-data-table';
|
6
6
|
|
7
7
|
import {Icon} from '../../../../components/Icon';
|
8
|
+
import {ResponseError} from '../../../../components/Errors/ResponseError';
|
8
9
|
|
9
10
|
import {AutoFetcher} from '../../../../utils/autofetcher';
|
10
11
|
import {getHotKeys, setHotKeysOptions} from '../../../../store/reducers/hotKeys';
|
11
|
-
import {prepareQueryError} from '../../../../utils/query';
|
12
12
|
|
13
13
|
import {isColumnEntityType, isTableType} from '../../utils/schema';
|
14
14
|
|
@@ -86,7 +86,7 @@ function HotKeys({
|
|
86
86
|
sortable: false,
|
87
87
|
align: DataTable.RIGHT,
|
88
88
|
},
|
89
|
-
...keyColumnsIds
|
89
|
+
...keyColumnsIds.map((col, index) => ({
|
90
90
|
name: col,
|
91
91
|
header: (
|
92
92
|
<div className={b('primary-key-column')}>
|
@@ -107,7 +107,7 @@ function HotKeys({
|
|
107
107
|
|
108
108
|
const renderContent = () => {
|
109
109
|
if (error) {
|
110
|
-
return
|
110
|
+
return <ResponseError error={error} />;
|
111
111
|
}
|
112
112
|
return data !== null ? (
|
113
113
|
<div className={b('table-content')}>
|