ydb-embedded-ui 4.10.1 → 4.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/components/QueryResultTable/Cell/Cell.tsx +8 -8
  3. package/dist/components/QueryResultTable/i18n/en.json +1 -1
  4. package/dist/components/QueryResultTable/i18n/ru.json +1 -1
  5. package/dist/components/ShortyString/ShortyString.tsx +3 -6
  6. package/dist/components/ShortyString/i18n/en.json +8 -8
  7. package/dist/components/ShortyString/i18n/ru.json +8 -8
  8. package/dist/components/SpeedMultiMeter/i18n/index.ts +0 -2
  9. package/dist/components/Stack/Stack.tsx +16 -16
  10. package/dist/components/TableSkeleton/TableSkeleton.tsx +3 -3
  11. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +7 -3
  12. package/dist/containers/Header/Header.tsx +2 -2
  13. package/dist/containers/Header/breadcrumbs.ts +2 -1
  14. package/dist/containers/Heatmap/Heatmap.tsx +4 -3
  15. package/dist/containers/Node/NodeStructure/PDiskTitleBadge.tsx +2 -8
  16. package/dist/containers/Nodes/Nodes.tsx +1 -1
  17. package/dist/containers/Storage/EmptyFilter/i18n/en.json +2 -2
  18. package/dist/containers/Storage/EmptyFilter/i18n/ru.json +2 -2
  19. package/dist/containers/Storage/StorageGroups/i18n/en.json +5 -5
  20. package/dist/containers/Storage/StorageGroups/i18n/ru.json +5 -5
  21. package/dist/containers/Storage/UsageFilter/i18n/en.json +3 -8
  22. package/dist/containers/Storage/UsageFilter/i18n/ru.json +3 -8
  23. package/dist/containers/Tablet/Tablet.tsx +2 -2
  24. package/dist/containers/Tenant/Acl/Acl.scss +1 -9
  25. package/dist/containers/Tenant/Acl/Acl.tsx +137 -0
  26. package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +2 -2
  27. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +6 -0
  28. package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +3 -3
  29. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +2 -0
  30. package/dist/containers/Tenant/Diagnostics/Overview/utils/prepareTopicSchemaInfo.ts +2 -3
  31. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +0 -6
  32. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +95 -83
  33. package/dist/containers/Tenant/Query/Issues/Issues.tsx +27 -23
  34. package/dist/containers/Tenant/Query/Issues/models.ts +0 -11
  35. package/dist/containers/Tenant/Query/Preview/Preview.tsx +3 -3
  36. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +2 -2
  37. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.tsx +99 -0
  38. package/dist/containers/Tenant/Tenant.tsx +1 -5
  39. package/dist/containers/Tenant/TenantPages.tsx +9 -14
  40. package/dist/containers/Tenant/i18n/en.json +11 -0
  41. package/dist/containers/Tenant/i18n/index.ts +11 -0
  42. package/dist/containers/Tenant/i18n/ru.json +11 -0
  43. package/dist/containers/Tenant/utils/schema.ts +24 -0
  44. package/dist/containers/Tenant/utils/schemaActions.ts +28 -24
  45. package/dist/containers/Tenants/Tenants.tsx +1 -4
  46. package/dist/services/api.ts +6 -7
  47. package/dist/store/index.js +1 -1
  48. package/dist/store/reducers/nodes/nodes.ts +14 -5
  49. package/dist/store/reducers/nodes/types.ts +22 -3
  50. package/dist/store/reducers/nodes/utils.ts +23 -10
  51. package/dist/store/reducers/preview.ts +6 -4
  52. package/dist/store/reducers/schemaAcl/schemaAcl.ts +17 -0
  53. package/dist/store/reducers/schemaAcl/types.ts +9 -7
  54. package/dist/store/reducers/tenant/constants.ts +6 -0
  55. package/dist/store/reducers/tenant/tenant.ts +15 -0
  56. package/dist/store/reducers/tenant/types.ts +18 -3
  57. package/dist/store/state-url-mapping.js +3 -0
  58. package/dist/types/api/cluster.ts +1 -1
  59. package/dist/types/api/compute.ts +11 -11
  60. package/dist/types/api/error.ts +2 -2
  61. package/dist/types/api/netInfo.ts +3 -3
  62. package/dist/types/api/nodes.ts +9 -8
  63. package/dist/types/api/query.ts +1 -1
  64. package/dist/types/api/schema/schema.ts +3 -0
  65. package/dist/types/api/schema/shared.ts +3 -3
  66. package/dist/types/api/schema/table.ts +22 -22
  67. package/dist/types/api/storage.ts +1 -1
  68. package/dist/types/assets.d.ts +1 -2
  69. package/dist/types/store/executeQuery.ts +2 -3
  70. package/dist/types/store/executeTopQueries.ts +8 -5
  71. package/dist/types/store/explainQuery.ts +4 -4
  72. package/dist/types/store/query.ts +4 -3
  73. package/dist/types/store/shardsWorkload.ts +8 -5
  74. package/dist/utils/constants.ts +4 -1
  75. package/dist/utils/error.ts +2 -3
  76. package/dist/utils/query.ts +3 -9
  77. package/dist/utils/tests/providers.tsx +6 -9
  78. package/package.json +6 -2
  79. package/dist/containers/Tenant/Acl/Acl.js +0 -153
  80. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +0 -94
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.11.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.10.1...v4.11.0) (2023-07-27)
4
+
5
+
6
+ ### Features
7
+
8
+ * 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))
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **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))
14
+ * 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))
15
+ * **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))
16
+ * **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))
17
+ * **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))
18
+ * **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))
19
+
3
20
  ## [4.10.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.10.0...v4.10.1) (2023-07-14)
4
21
 
5
22
 
@@ -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
- dispatch(hideTooltip());
23
- }, [dispatch]);
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
  });
@@ -1,3 +1,3 @@
1
1
  {
2
- "empty": "Table is empty"
2
+ "empty": "Table is empty"
3
3
  }
@@ -1,3 +1,3 @@
1
1
  {
2
- "empty": "Таблица пустая"
2
+ "empty": "Таблица пустая"
3
3
  }
@@ -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 = displayLength && !expanded
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
- "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
- ]
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
- "default_collapse_label": "Показать меньше",
3
- "default_expand_label": "Показать ещё",
4
- "chars_count": [
5
- " ({{count}} символ)",
6
- " ({{count}} символа)",
7
- " ({{count}} символов)",
8
- " ({{count}} символов)"
9
- ]
2
+ "default_collapse_label": "Показать меньше",
3
+ "default_expand_label": "Показать ещё",
4
+ "chars_count": [
5
+ " ({{count}} символ)",
6
+ " ({{count}} символа)",
7
+ " ({{count}} символов)",
8
+ " ({{count}} символов)"
9
+ ]
10
10
  }
@@ -9,5 +9,3 @@ i18n.registerKeyset(Lang.En, COMPONENT, en);
9
9
  i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
10
10
 
11
11
  export default i18n.keyset(COMPONENT);
12
-
13
-
@@ -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.Children.map(children, (child, index) => {
18
- if (!React.isValidElement(child)) {
19
- return null;
20
- }
16
+ {React.Children.map(children, (child, index) => {
17
+ if (!React.isValidElement(child)) {
18
+ return null;
19
+ }
21
20
 
22
- return (
23
- <div
24
- className={b('layer')}
25
- style={{
21
+ return (
22
+ <div
23
+ className={b('layer')}
24
+ style={
25
+ {
26
26
  [LAYER_CSS_VAR]: index,
27
- } as React.CSSProperties}
28
- >
29
- {child}
30
- </div>
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 { FC } from 'react';
1
+ import {FC} from 'react';
2
2
  import block from 'bem-cn-lite';
3
- import { Skeleton } from '@gravity-ui/uikit';
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> = ({ rows = 2, className }) => (
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 {CLUSTER_INFO_HIDDEN_KEY, DEVELOPER_UI} from '../../../utils/constants';
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: DEVELOPER_UI, url: internalLink},
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 ?? 'Unknown cluster'}
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 {DEVELOPER_UI} from '../../utils/constants';
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={DEVELOPER_UI}
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 || 'Cluster',
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 type {IHeatmapMetricValue} from '../../types/store/heatmap';
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 <div>{prepareQueryError(error)}</div>;
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
- <span className={b('pdisk-title-item-label')}>
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,4 +1,4 @@
1
1
  {
2
- "default_message": "Everything is fine!",
3
- "default_button_label": "Show All"
2
+ "default_message": "Everything is fine!",
3
+ "default_button_label": "Show All"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
- "default_message": "Всё в порядке!",
3
- "default_button_label": "Показать все"
2
+ "default_message": "Всё в порядке!",
3
+ "default_button_label": "Показать все"
4
4
  }
@@ -1,7 +1,7 @@
1
1
  {
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"
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
- "empty.default": "Нет групп",
3
- "empty.out_of_space": "Нет групп, в которых кончается место",
4
- "empty.degraded": "Нет деградировавших групп",
5
- "show_all": "Показать все группы",
6
- "encrypted": "Зашифрованная группа"
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
- "label": "Usage:",
3
- "default_value": "Any",
4
- "groups_count": [
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
- "label": "Использование:",
3
- "default_value": "Любое",
4
- "groups_count": [
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 {DEVELOPER_UI} from '../../utils/constants';
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: `${DEVELOPER_UI} - tablet`,
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
- .kv-acl {
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 <div className={b('message-container', 'error')}>{prepareQueryError(error)}</div>;
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?.map((col, index) => ({
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 prepareQueryError(error);
110
+ return <ResponseError error={error} />;
111
111
  }
112
112
  return data !== null ? (
113
113
  <div className={b('table-content')}>
@@ -124,6 +124,8 @@ function Overview({type, tenantName}: OverviewProps) {
124
124
  <ChangefeedInfo data={data} topic={additionalData?.[0]} />
125
125
  ),
126
126
  [EPathType.EPathTypePersQueueGroup]: () => <TopicInfo data={data} />,
127
+ [EPathType.EPathTypeExternalTable]: undefined,
128
+ [EPathType.EPathTypeExternalDataSource]: undefined,
127
129
  };
128
130
 
129
131
  return (