ydb-embedded-ui 1.6.4 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.8.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.7.1...v1.8.0) (2022-07-05)
4
+
5
+
6
+ ### Features
7
+
8
+ * add Illustration component ([7d10880](https://github.com/ydb-platform/ydb-embedded-ui/commit/7d10880cd4d9f945e7c8a7232327d8db68f0865c))
9
+ * **Tenant:** proper 403 error page ([d822a2b](https://github.com/ydb-platform/ydb-embedded-ui/commit/d822a2b6e3e18c24882ecf30db399087053b83b3))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * fix empty state illustration layout ([7cfd97e](https://github.com/ydb-platform/ydb-embedded-ui/commit/7cfd97e13ebcaa703478bd7b4e29774150bd569e))
15
+
16
+ ## [1.7.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.7.0...v1.7.1) (2022-07-05)
17
+
18
+
19
+ ### Performance Improvements
20
+
21
+ * **Tenant:** use api call viewer/json/acl instead of metainfo ([c3603c4](https://github.com/ydb-platform/ydb-embedded-ui/commit/c3603c4b364cef79cb4790c7e9e4378d5b66e0ed))
22
+
23
+ ## [1.7.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.6.4...v1.7.0) (2022-06-29)
24
+
25
+
26
+ ### Features
27
+
28
+ * **Storage:** show total groups count ([5e31cfe](https://github.com/ydb-platform/ydb-embedded-ui/commit/5e31cfee9edc50fa4bc0770c443b136291a3536e))
29
+ * **Storage:** show total nodes count ([b438f70](https://github.com/ydb-platform/ydb-embedded-ui/commit/b438f7075961e878a1412ca185743c4374dd9178))
30
+ * **Tenant:** display tables indexes ([693a100](https://github.com/ydb-platform/ydb-embedded-ui/commit/693a1001db6487b2d43aeca7d8168afcd06f5cbd))
31
+
3
32
  ## [1.6.4](https://github.com/ydb-platform/ydb-embedded-ui/compare/v1.6.3...v1.6.4) (2022-06-24)
4
33
 
5
34
 
@@ -0,0 +1 @@
1
+ <svg width="349" height="356" fill="none" xmlns="http://www.w3.org/2000/svg"><g opacity=".8"><path d="M275.008 84.928c0 24.7-9.9 83.9-9.9 117.1 0 33.2 0 106.3-27.8 134.1-27.8 27.8-61.9 16.1-61.9 16.1s-46.7 13-76.3-14.8c-29.6-27.8-60.1-83.5-69.1-115.3-9.9-35-26.5-49.3-27.8-56.5-1.3-7.2 3.6-12.1 12.1-12.6 8.5-.4 22.9 4 34.5 22 11.6 18 17.5 26 23.8 35.9 6.3 9.9 20.6 23.3 20.6 23.3s.4-44.9 1.3-64.1c.9-19.3-1.8-111.7 1.8-132.3 3.6-20.6 26.5-20.2 28.7-4 2.2 16.1 8.8 66.8 9.8 79.8s3.7 44.4 3.7 44.4l7.6-2.7s-.9-105.8-.9-132.9c0-29.2 28.7-29.2 32.3-4 3.6 25.2 6.7 142.8 6.7 142.8l6.7 2.7s2.2-111.7 5.8-129.6c3.6-17.9 26.5-17.5 30.1 4.9 3.6 22.4 1.3 72.2.9 94.2s-.9 43.5-.9 43.5l5.4 4s11-73.3 14.4-99.1c3.7-27.8 28.4-21.5 28.4 3.1z" fill="#fff" fill-opacity=".07"/><path d="M279.207 266.428l-216.9 12c-7.3.4-13.3-5.2-13.3-12.5v-167.4c0-7.3 6-12.9 13.3-12.5l216.9 12c5.6.3 10.1 5.7 10.1 12v144.4c0 6.3-4.5 11.7-10.1 12z" fill="#FF4645"/><path d="M191.308 139.226l-32.3-1.4c-1.9-.1-3.8.6-5.2 1.9l-24.3 22.8c-1.4 1.3-2.2 3.2-2.2 5.2v33.7c0 2 .8 3.8 2.2 5.2l24.3 22.8c1.4 1.3 3.3 2 5.2 1.9l32.3-1.4c1.8-.1 3.6-.9 4.9-2.2l21.5-22.8c1.2-1.3 1.9-3.1 1.9-4.9v-31c0-1.8-.7-3.6-1.9-4.9l-21.5-22.8c-1.3-1.3-3.1-2.1-4.9-2.1z" fill="#fff"/><path d="M203.408 195.526l-58.1.6c-1.6 0-3-1.3-3-3v-17.2c0-1.6 1.3-3 3-3l58.1.6c1.6 0 2.9 1.3 2.9 3v16c0 1.7-1.3 3-2.9 3z" fill="#FF4645"/><path fill-rule="evenodd" clip-rule="evenodd" d="M74.707 103.727c0 3.4-2.7 6-6.1 5.8-3.4-.1-6.1-3-6.1-6.4 0-3.4 2.8-6 6.1-5.8 3.4.2 6.1 3 6.1 6.4zm19.7.9c0 3.3-2.7 5.9-6 5.8-3.3-.1-6-3-6-6.3s2.7-5.9 6-5.8c3.3.1 6 2.9 6 6.3zm13.4 6.499c3.2.2 5.8-2.4 5.8-5.7 0-3.3-2.6-6.1-5.8-6.2-3.3-.2-5.9 2.4-5.9 5.7 0 3.3 2.7 6.1 5.9 6.2z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M248.707 247.329h84.6v-62c0-22.5-18.3-40.7-40.7-40.7h-3.2c-22.5 0-40.7 18.3-40.7 40.7v62zm70.2-14.3h-56v-47.7c0-14.6 11.9-26.4 26.4-26.4h3.2c14.6 0 26.4 11.9 26.4 26.4v47.7z" fill="#DEB700"/><path d="M340.507 205.528s-16.3-2.7-17.3-2.7l-78.6 1.1c-7 .1-13.7 6.5-13.7 13.1v58.6c0 4.7 2.9 8.5 7 10.1 1.5.6 3.1.9 4.8.9l12.5 2.3 7.6-3.7 60.4-4.3c6.2-.4 11.2-5.8 11.2-11.9v-43.3l6.1-20.2z" fill="#DEB700"/><path d="M337.607 283.43l-79.6 5.7c-7 .5-12.7-4.4-12.7-11v-59.6c0-6.6 5.7-12 12.7-12.1l79.6-1.1c6.2-.1 11.2 4.8 11.2 10.9v55.4c-.1 6-5 11.3-11.2 11.8z" fill="#FBC900"/><path d="M313.007 236.029c0-6.3-5.2-11.4-11.7-11.4-6.7 0-12.3 5.4-12.3 12 0 5 3.2 9.1 7.6 10.7v15.5c0 2.5 2.1 4.4 4.7 4.2 2.6-.2 4.6-2.5 4.6-4.9v-15.1c4.3-2.1 7.1-6.3 7.1-11z" fill="#00236B"/><path d="M308.307 236.028c0-5.5-4-10.1-9.3-11.2-5.6 1.1-10 6-10 11.8 0 5 3.2 9.1 7.6 10.7v15.5c0 1.5.8 2.8 2 3.5 1.6-.9 2.6-2.5 2.6-4.3v-15.1c4.2-2 7.1-6.2 7.1-10.9z" fill="#18123D"/><path d="M21.708 40.727a2 2 0 1 0-4 0h4zm-4 8.2a2 2 0 0 0 4 0h-4zm4 17.198a2 2 0 0 0-4 0h4zm-4 8.9a2 2 0 1 0 4 0h-4zm19.2-15.197a2 2 0 1 0 0-4v4zm-8.3-4a2 2 0 0 0 0 4v-4zm-17.8 4a2 2 0 1 0 0-4v4zm-8.3-4a2 2 0 0 0 0 4v-4zm15.2-15.101v8.2h4v-8.2h-4zm0 25.398v8.9h4v-8.9h-4zm19.2-10.297h-8.3v4h8.3v-4zm-26.1 0h-8.3v4h8.3v-4zm284.199 259.098a2 2 0 1 0-4 0h4zm-4 6.2a2 2 0 0 0 4 0h-4zm4 13.1a2 2 0 1 0-4 0h4zm-4 6.8a2 2 0 0 0 4 0h-4zm15-11.1a2 2 0 0 0 0-4v4zm-6.2-4a2 2 0 0 0 0 4v-4zm-13.6 4a2 2 0 0 0 0-4v4zm-6.3-4a2 2 0 0 0 0 4v-4zm11.1-11v6.2h4v-6.2h-4zm0 19.3v6.8h4v-6.8h-4zm15-8.3h-6.2v4h6.2v-4zm-19.8 0h-6.3v4h6.3v-4z" fill="#2EE5C0"/><path clip-rule="evenodd" d="M15.207 325.426c7.18 0 13-5.821 13-13 0-7.18-5.82-13-13-13s-13 5.82-13 13c0 7.179 5.82 13 13 13z" stroke="#2EE5C0" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M28.207 310.426a2 2 0 1 0 0 4v-4zm35.2 2h2a2 2 0 0 0-2-2v2zm-2 12.2a2 2 0 0 0 4 0h-4zm-17.1 0a2 2 0 0 0 4 0h-4zm4-12.2a2 2 0 1 0-4 0h4zm-20.1 2h35.2v-4h-35.2v4zm33.2-2v12.2h4v-12.2h-4zm-13.1 12.2v-12.2h-4v12.2h4z" fill="#2EE5C0"/></g></svg>
@@ -0,0 +1 @@
1
+ <svg width="349" height="357" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M275.033 85.83c0 24.7-9.9 83.9-9.9 117.1 0 33.2 0 106.3-27.8 134.1-27.8 27.8-61.9 16.1-61.9 16.1s-46.7 13-76.3-14.8c-29.6-27.8-60.1-83.5-69.1-115.3-9.9-35-26.5-49.3-27.8-56.5-1.3-7.2 3.6-12.1 12.1-12.6 8.5-.4 22.9 4 34.5 22 11.6 18 17.5 26 23.8 35.9 6.3 9.9 20.6 23.3 20.6 23.3s.4-44.9 1.3-64.1c.9-19.3-1.8-111.7 1.8-132.3 3.6-20.6 26.5-20.2 28.7-4 2.2 16.1 8.8 66.8 9.8 79.8s3.7 44.4 3.7 44.4l7.6-2.7s-.9-105.8-.9-132.9c0-29.2 28.7-29.2 32.3-4 3.6 25.2 6.7 142.8 6.7 142.8l6.7 2.7s2.2-111.7 5.8-129.6c3.6-17.9 26.5-17.5 30.1 4.9 3.6 22.4 1.3 72.2.9 94.2s-.9 43.5-.9 43.5l5.4 4s11-73.3 14.4-99.1c3.7-27.8 28.4-21.5 28.4 3.1z" fill="#ECF2F9"/><path d="M279.233 267.33l-216.9 12c-7.3.4-13.3-5.2-13.3-12.5V99.43c0-7.3 6-12.9 13.3-12.5l216.9 12c5.6.3 10.1 5.7 10.1 12v144.4c0 6.3-4.5 11.7-10.1 12z" fill="#FF4645"/><path d="M191.333 140.128l-32.3-1.4c-1.9-.1-3.8.6-5.2 1.9l-24.3 22.8c-1.4 1.3-2.2 3.2-2.2 5.2v33.7c0 2 .8 3.8 2.2 5.2l24.3 22.8c1.4 1.3 3.3 2 5.2 1.9l32.3-1.4c1.8-.1 3.6-.9 4.9-2.2l21.5-22.8c1.2-1.3 1.9-3.1 1.9-4.9v-31c0-1.8-.7-3.6-1.9-4.9l-21.5-22.8c-1.3-1.3-3.1-2.1-4.9-2.1z" fill="#fff"/><path d="M203.433 196.428l-58.1.6c-1.6 0-3-1.3-3-3v-17.2c0-1.6 1.3-3 3-3l58.1.6c1.6 0 2.9 1.3 2.9 3v16c0 1.7-1.3 3-2.9 3z" fill="#FF4645"/><path fill-rule="evenodd" clip-rule="evenodd" d="M74.733 104.63c0 3.4-2.7 6-6.1 5.8-3.4-.1-6.1-3-6.1-6.4 0-3.4 2.8-6 6.1-5.8 3.4.2 6.1 3 6.1 6.4zm19.7.9c0 3.3-2.7 5.9-6 5.8-3.3-.1-6-3-6-6.3s2.7-5.9 6-5.8c3.3.1 6 2.9 6 6.3zm13.4 6.498c3.2.2 5.8-2.4 5.8-5.7 0-3.3-2.6-6.1-5.8-6.2-3.3-.2-5.9 2.4-5.9 5.7 0 3.3 2.7 6.1 5.9 6.2z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M248.733 248.231h84.6v-62c0-22.5-18.3-40.7-40.7-40.7h-3.2c-22.5 0-40.7 18.3-40.7 40.7v62zm70.2-14.3h-56v-47.7c0-14.6 11.9-26.4 26.4-26.4h3.2c14.6 0 26.4 11.9 26.4 26.4v47.7z" fill="#DEB700"/><path d="M340.533 206.43s-16.3-2.7-17.3-2.7l-78.6 1.1c-7 .1-13.7 6.5-13.7 13.1v58.6c0 4.7 2.9 8.5 7 10.1 1.5.6 3.1.9 4.8.9l12.5 2.3 7.6-3.7 60.4-4.3c6.2-.4 11.2-5.8 11.2-11.9v-43.3l6.1-20.2z" fill="#DEB700"/><path d="M337.633 284.332l-79.6 5.7c-7 .5-12.7-4.4-12.7-11v-59.6c0-6.6 5.7-12 12.7-12.1l79.6-1.1c6.2-.1 11.2 4.8 11.2 10.9v55.4c-.1 6-5 11.3-11.2 11.8z" fill="#FBC900"/><path d="M313.033 236.931c0-6.3-5.2-11.4-11.7-11.4-6.7 0-12.3 5.4-12.3 12 0 5 3.2 9.1 7.6 10.7v15.5c0 2.5 2.1 4.4 4.7 4.2 2.6-.2 4.6-2.5 4.6-4.9v-15.1c4.3-2.1 7.1-6.3 7.1-11z" fill="#00236B"/><path d="M308.333 236.93c0-5.5-4-10.1-9.3-11.2-5.6 1.1-10 6-10 11.8 0 5 3.2 9.1 7.6 10.7v15.5c0 1.5.8 2.8 2 3.5 1.6-.9 2.6-2.5 2.6-4.3v-15.1c4.2-2 7.1-6.2 7.1-10.9z" fill="#18123D"/><path d="M21.733 41.629a2 2 0 0 0-4 0h4zm-4 8.2a2 2 0 1 0 4 0h-4zm4 17.198a2 2 0 0 0-4 0h4zm-4 8.9a2 2 0 1 0 4 0h-4zm19.2-15.197a2 2 0 0 0 0-4v4zm-8.3-4a2 2 0 1 0 0 4v-4zm-17.8 4a2 2 0 0 0 0-4v4zm-8.3-4a2 2 0 1 0 0 4v-4zm15.2-15.101v8.2h4v-8.2h-4zm0 25.398v8.9h4v-8.9h-4zm19.2-10.297h-8.3v4h8.3v-4zm-26.1 0h-8.3v4h8.3v-4zm284.2 259.098a2 2 0 0 0-4 0h4zm-4 6.2a2 2 0 1 0 4 0h-4zm4 13.1a2 2 0 0 0-4 0h4zm-4 6.8a2 2 0 1 0 4 0h-4zm15-11.1a2 2 0 0 0 0-4v4zm-6.2-4a2 2 0 0 0 0 4v-4zm-13.6 4a2 2 0 0 0 0-4v4zm-6.3-4a2 2 0 0 0 0 4v-4zm11.1-11v6.2h4v-6.2h-4zm0 19.3v6.8h4v-6.8h-4zm15-8.3h-6.2v4h6.2v-4zm-19.8 0h-6.3v4h6.3v-4z" fill="#2EE5C0"/><path clip-rule="evenodd" d="M15.233 326.328c7.18 0 13-5.82 13-13s-5.82-13-13-13-13 5.82-13 13 5.82 13 13 13z" stroke="#2EE5C0" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M28.233 311.328a2 2 0 0 0 0 4v-4zm35.2 2h2a2 2 0 0 0-2-2v2zm-2 12.2a2 2 0 1 0 4 0h-4zm-17.1 0a2 2 0 1 0 4 0h-4zm4-12.2a2 2 0 0 0-4 0h4zm-20.1 2h35.2v-4h-35.2v4zm33.2-2v12.2h4v-12.2h-4zm-13.1 12.2v-12.2h-4v12.2h4z" fill="#2EE5C0"/></svg>
@@ -16,16 +16,18 @@ export default function EmptyState({image, title, description, actions, size}) {
16
16
  return (
17
17
  <div className={block({size})}>
18
18
  <div className={block('wrapper', {size})}>
19
- {image ? (
20
- image
21
- ) : (
22
- <Icon
23
- viewBox="0 0 383 396"
24
- name="emptyState"
25
- width={sizes[size]}
26
- height={sizes[size]}
27
- />
28
- )}
19
+ <div className={block('image')}>
20
+ {image ? (
21
+ image
22
+ ) : (
23
+ <Icon
24
+ viewBox="0 0 383 396"
25
+ name="emptyState"
26
+ width={sizes[size]}
27
+ height={sizes[size]}
28
+ />
29
+ )}
30
+ </div>
29
31
 
30
32
  <div className={block('title', {size})}>{title}</div>
31
33
  <div className={block('description')}>{description}</div>
@@ -0,0 +1,47 @@
1
+ import {useEffect, useState} from 'react';
2
+ import cn from 'bem-cn-lite';
3
+ import {useThemeValue} from '@yandex-cloud/uikit';
4
+
5
+ export interface IllustrationProps {
6
+ name: string;
7
+ className?: string;
8
+ }
9
+
10
+ type IllustrationStore = Record<string, Record<string, () => Promise<{default: any}>>>;
11
+
12
+ const store: IllustrationStore = {
13
+ light: {
14
+ 403: () => import('../../assets/illustrations/light/403.svg'),
15
+ },
16
+ dark: {
17
+ 403: () => import('../../assets/illustrations/dark/403.svg'),
18
+ },
19
+ };
20
+
21
+ const b = cn('kv-illustration');
22
+
23
+ export const Illustration = ({name, className, ...props}: IllustrationProps) => {
24
+ const theme = useThemeValue();
25
+ const [src, setSrc] = useState('');
26
+ const srcGetter = store[theme] && store[theme][name];
27
+
28
+ useEffect(() => {
29
+ if (typeof srcGetter === 'function') {
30
+ srcGetter()
31
+ .then((svg) => setSrc(svg.default))
32
+ .catch((e) => {
33
+ console.error(e);
34
+ setSrc('');
35
+ });
36
+ }
37
+ }, [srcGetter]);
38
+
39
+ return (
40
+ <img
41
+ alt={name}
42
+ src={src}
43
+ className={b(null, className)}
44
+ {...props}
45
+ />
46
+ );
47
+ }
@@ -0,0 +1 @@
1
+ export * from './Illustration';
@@ -20,6 +20,8 @@ import {
20
20
  StorageTypes,
21
21
  setStorageType,
22
22
  VisibleEntitiesTitles,
23
+ getStoragePoolsGroupsCount,
24
+ getStorageNodesCount,
23
25
  } from '../../store/reducers/storage';
24
26
  import {getNodesList} from '../../store/reducers/clusterNodes';
25
27
  import StorageGroups from './StorageGroups/StorageGroups';
@@ -52,6 +54,8 @@ class Storage extends React.Component {
52
54
  getStorageInfo: PropTypes.func,
53
55
  setInitialState: PropTypes.func,
54
56
  flatListStorageEntities: PropTypes.array,
57
+ groupsCount: PropTypes.object,
58
+ nodesCount: PropTypes.object,
55
59
  setStorageFilter: PropTypes.func,
56
60
  setVisibleEntities: PropTypes.func,
57
61
  visibleEntities: PropTypes.string,
@@ -199,10 +203,39 @@ class Storage extends React.Component {
199
203
  setStorageType(value);
200
204
  };
201
205
 
206
+ renderEntitiesCount() {
207
+ const {
208
+ storageType,
209
+ groupsCount,
210
+ nodesCount,
211
+ loading,
212
+ wasLoaded,
213
+ } = this.props;
214
+
215
+ let label = `${storageType === StorageTypes.groups ? 'Groups' : 'Nodes'}: `;
216
+ const count = storageType === StorageTypes.groups ? groupsCount : nodesCount;
217
+
218
+ if (loading && !wasLoaded) {
219
+ label += '...';
220
+ return label;
221
+ }
222
+
223
+ if (count.total === count.found) {
224
+ label += count.total;
225
+ } else {
226
+ label += `${count.found} of ${count.total}`;
227
+ }
228
+
229
+ return label;
230
+ }
231
+
202
232
  renderControls() {
203
- const {setStorageFilter, visibleEntities, storageType, flatListStorageEntities, loading, wasLoaded} =
204
- this.props;
205
- const showLoader = loading && !wasLoaded;
233
+ const {
234
+ setStorageFilter,
235
+ visibleEntities,
236
+ storageType,
237
+ } = this.props;
238
+
206
239
  return (
207
240
  <div className={b('controls')}>
208
241
  <div className={b('search')}>
@@ -231,9 +264,9 @@ class Storage extends React.Component {
231
264
  {StorageTypes.nodes}
232
265
  </RadioButton.Option>
233
266
  </RadioButton>
234
- <Label theme="info" size="m">{`${
235
- storageType === StorageTypes.groups ? 'Groups' : 'Nodes'
236
- }: ${(showLoader) ? '...' : flatListStorageEntities.length}`}</Label>
267
+ <Label theme="info" size="m">
268
+ {this.renderEntitiesCount()}
269
+ </Label>
237
270
  </div>
238
271
  );
239
272
  }
@@ -270,8 +303,10 @@ function mapStateToProps(state) {
270
303
 
271
304
  return {
272
305
  flatListStorageEntities: getFilteredEntities(state),
306
+ groupsCount: getStoragePoolsGroupsCount(state),
273
307
  autorefresh: state.schema.autorefresh,
274
308
  nodes: getNodesObject(state),
309
+ nodesCount: getStorageNodesCount(state),
275
310
  loading,
276
311
  wasLoaded,
277
312
  error,
@@ -3,6 +3,8 @@ import {useSelector} from 'react-redux';
3
3
  import cn from 'bem-cn-lite';
4
4
 
5
5
  import {Button, Modal} from '@yandex-cloud/uikit';
6
+
7
+ import type {EPathType} from '../../../../types/api/schema';
6
8
  //@ts-ignore
7
9
  import Icon from '../../../../components/Icon/Icon';
8
10
  import Overview from '../Overview/Overview';
@@ -14,7 +16,7 @@ import TenantOverview from '../TenantOverview/TenantOverview';
14
16
  import './DetailedOverview.scss';
15
17
 
16
18
  interface DetailedOverviewProps {
17
- type: string;
19
+ type?: EPathType;
18
20
  className?: string;
19
21
  tenantName: string;
20
22
  additionalTenantInfo?: any;
@@ -29,7 +29,8 @@ import Compute from './Compute/Compute';
29
29
  import Tablets from '../../Tablets/Tablets';
30
30
 
31
31
  import routes, {createHref} from '../../../routes';
32
- import {OLAP_TABLE_TYPE, TABLE_TYPE} from '../Tenant';
32
+ import type {EPathType} from '../../../types/api/schema';
33
+ import {isTableType} from '../utils/schema';
33
34
  import {TenantGeneralTabsIds, TenantTabsGroups} from '../TenantPages';
34
35
  import {GeneralPagesIds, DATABASE_PAGES, TABLE_PAGES, DIR_PAGES} from './DiagnosticsPages';
35
36
  //@ts-ignore
@@ -39,7 +40,7 @@ import {setTopLevelTab, setDiagnosticsTab} from '../../../store/reducers/tenant'
39
40
  import './Diagnostics.scss';
40
41
 
41
42
  interface DiagnosticsProps {
42
- type: string;
43
+ type?: EPathType;
43
44
  additionalTenantInfo?: any;
44
45
  additionalNodesInfo?: any;
45
46
  }
@@ -68,8 +69,7 @@ function Diagnostics(props: DiagnosticsProps) {
68
69
  const isDatabase = currentSchemaPath === tenantName;
69
70
 
70
71
  const pages = useMemo(() => {
71
- const {type} = props;
72
- const isTable = type === TABLE_TYPE || type === OLAP_TABLE_TYPE;
72
+ const isTable = isTableType(props.type);
73
73
 
74
74
  let pages = DIR_PAGES;
75
75
 
@@ -8,7 +8,7 @@ import Icon from '../../../../components/Icon/Icon';
8
8
 
9
9
  import {AutoFetcher} from '../../../../utils/autofetcher';
10
10
  import {getHotKeys, setHotKeysOptions} from '../../../../store/reducers/hotKeys';
11
- import {TABLE_TYPE} from '../../Tenant';
11
+ import {EPathType} from '../../../../types/api/schema';
12
12
  import {prepareQueryError} from '../../../../utils';
13
13
 
14
14
  import './HotKeys.scss';
@@ -42,7 +42,8 @@ function HotKeys({
42
42
  type,
43
43
  }) {
44
44
  const fetchData = () => {
45
- if (type === TABLE_TYPE) {
45
+ // ColumnTables excluded intentionally
46
+ if (type === EPathType.EPathTypeTable) {
46
47
  getHotKeys(currentSchemaPath);
47
48
  }
48
49
  };
@@ -7,7 +7,8 @@ import {Loader} from '@yandex-cloud/uikit';
7
7
  //@ts-ignore
8
8
  import SchemaInfoViewer from '../../Schema/SchemaInfoViewer/SchemaInfoViewer';
9
9
 
10
- import {OLAP_TABLE_TYPE} from '../../Tenant';
10
+ import type {EPathType} from '../../../../types/api/schema';
11
+ import {isColumnEntityType, isTableType} from '../../utils/schema';
11
12
  import {AutoFetcher} from '../../../../utils/autofetcher';
12
13
  //@ts-ignore
13
14
  import {getSchema} from '../../../../store/reducers/schema';
@@ -44,7 +45,7 @@ function prepareOlapTableGeneral(tableData: any, olapStats: any[]) {
44
45
  }
45
46
 
46
47
  interface OverviewProps {
47
- type: string;
48
+ type?: EPathType;
48
49
  className?: string;
49
50
  tenantName?: string;
50
51
  }
@@ -70,7 +71,7 @@ function Overview(props: OverviewProps) {
70
71
  const schemaPath = currentSchemaPath || tenantName;
71
72
  dispatch(getSchema({path: schemaPath}));
72
73
 
73
- if (type === OLAP_TABLE_TYPE) {
74
+ if (isTableType(type) && isColumnEntityType(type)) {
74
75
  dispatch(getOlapStats({path: schemaPath}));
75
76
  }
76
77
  };
@@ -98,7 +99,7 @@ function Overview(props: OverviewProps) {
98
99
  currentItem?.PathDescription?.Table || currentItem?.PathDescription?.ColumnTableDescription;
99
100
 
100
101
  const schemaData = useMemo(() => {
101
- return props.type === OLAP_TABLE_TYPE
102
+ return isTableType(props.type) && isColumnEntityType(props.type)
102
103
  ? prepareOlapTableGeneral(tableSchema, olapStats)
103
104
  : currentItem;
104
105
  }, [props.type, tableSchema, olapStats, currentItem]);
@@ -9,7 +9,7 @@ import {changeUserInput} from '../../../../store/reducers/executeQuery';
9
9
  import {sendQuery, setQueryOptions} from '../../../../store/reducers/executeTopQueries';
10
10
  import TruncatedQuery from '../../../../components/TruncatedQuery/TruncatedQuery';
11
11
  import {AutoFetcher} from '../../../../utils/autofetcher';
12
- import {OLAP_STORE_TYPE, OLAP_TABLE_TYPE} from '../../Tenant';
12
+ import {isColumnEntityType} from '../../utils/schema';
13
13
 
14
14
  import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
15
15
  import {TenantGeneralTabsIds} from '../../TenantPages';
@@ -149,7 +149,7 @@ class TopQueries extends React.Component {
149
149
 
150
150
  let message;
151
151
 
152
- if (type === OLAP_STORE_TYPE || type === OLAP_TABLE_TYPE) {
152
+ if (isColumnEntityType(type)) {
153
153
  message = 'No data';
154
154
  } else if (error && !error.isCancelled) {
155
155
  message = prepareQueryError(error).slice(0, 300);
@@ -12,7 +12,7 @@ import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema
12
12
  import {AutoFetcher} from '../../../../utils/autofetcher';
13
13
  import HistoryContext from '../../../../contexts/HistoryContext';
14
14
  import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
15
- import {OLAP_STORE_TYPE, OLAP_TABLE_TYPE} from '../../Tenant';
15
+ import {isColumnEntityType} from '../../utils/schema';
16
16
  import {prepareQueryError} from '../../../../utils';
17
17
 
18
18
  import './TopShards.scss';
@@ -120,7 +120,7 @@ function TopShards({
120
120
  };
121
121
 
122
122
  const renderContent = () => {
123
- if (type === OLAP_STORE_TYPE || type === OLAP_TABLE_TYPE) {
123
+ if (isColumnEntityType(type)) {
124
124
  return 'No data';
125
125
  }
126
126
  if (error) {
@@ -14,13 +14,14 @@ import {TenantGeneralTabsIds, TenantTabsGroups, TENANT_GENERAL_TABS} from '../Te
14
14
  import routes, {createHref} from '../../../routes';
15
15
  import {setSettingValue} from '../../../store/reducers/settings';
16
16
  import {TENANT_INITIAL_TAB_KEY} from '../../../utils/constants';
17
+ import type {EPathType} from '../../../types/api/schema';
17
18
 
18
19
  import './ObjectGeneral.scss';
19
20
 
20
21
  const b = cn('object-general');
21
22
 
22
23
  interface ObjectGeneralProps {
23
- type: string;
24
+ type?: EPathType;
24
25
  additionalTenantInfo?: any;
25
26
  additionalNodesInfo?: any;
26
27
  setSettingValue: (name: string, value: string) => void;
@@ -16,7 +16,8 @@ import CopyToClipboard from '../../../components/CopyToClipboard/CopyToClipboard
16
16
  import InfoViewer from '../../../components/InfoViewer/InfoViewer';
17
17
  import Icon from '../../../components/Icon/Icon';
18
18
 
19
- import {OLAP_TABLE_TYPE, TABLE_TYPE} from '../Tenant';
19
+ import type {EPathType} from '../../../types/api/schema';
20
+ import {isColumnEntityType, isTableType} from '../utils/schema';
20
21
 
21
22
  import {
22
23
  DEFAULT_IS_TENANT_COMMON_INFO_COLLAPSED,
@@ -69,7 +70,7 @@ function prepareOlapTableSchema(tableSchema: any) {
69
70
  }
70
71
 
71
72
  interface ObjectSummaryProps {
72
- type: string;
73
+ type?: EPathType;
73
74
  onCollapseSummary: VoidFunction;
74
75
  onExpandSummary: VoidFunction;
75
76
  isCollapsed: boolean;
@@ -104,12 +105,13 @@ function ObjectSummary(props: ObjectSummaryProps) {
104
105
  const tableSchema =
105
106
  currentItem?.PathDescription?.Table || currentItem?.PathDescription?.ColumnTableDescription;
106
107
 
107
- const schema =
108
- props.type === OLAP_TABLE_TYPE ? prepareOlapTableSchema(tableSchema) : tableSchema;
108
+ const schema = isTableType(props.type) && isColumnEntityType(props.type)
109
+ ? prepareOlapTableSchema(tableSchema)
110
+ : tableSchema;
109
111
 
110
112
  useEffect(() => {
111
113
  const {type} = props;
112
- const isTable = type === TABLE_TYPE || type === OLAP_TABLE_TYPE;
114
+ const isTable = isTableType(type);
113
115
 
114
116
  if (type && !isTable && !TENANT_INFO_TABS.find((el) => el.id === infoTab)) {
115
117
  history.push({
@@ -120,8 +122,7 @@ function ObjectSummary(props: ObjectSummaryProps) {
120
122
  }, [props.type]);
121
123
 
122
124
  const renderTabs = () => {
123
- const {type} = props;
124
- const isTable = type === TABLE_TYPE || type === OLAP_TABLE_TYPE;
125
+ const isTable = isTableType(props.type);
125
126
  const tabsItems = isTable ? [...TENANT_INFO_TABS, ...TENANT_SCHEMA_TAB] : TENANT_INFO_TABS;
126
127
 
127
128
  return (
@@ -228,8 +229,7 @@ function ObjectSummary(props: ObjectSummaryProps) {
228
229
  };
229
230
 
230
231
  const renderCommonInfoControls = () => {
231
- const {type} = props;
232
- const isTable = type === TABLE_TYPE || type === OLAP_TABLE_TYPE;
232
+ const isTable = isTableType(props.type);
233
233
  return (
234
234
  <React.Fragment>
235
235
  {isTable && (
@@ -257,8 +257,8 @@ function ObjectSummary(props: ObjectSummaryProps) {
257
257
  message = `${Status}: ${Reason}`;
258
258
  }
259
259
 
260
- return props.type ? (
261
- <div className={b('entity-type')}>{type}</div>
260
+ return type ? (
261
+ <div className={b('entity-type')}>{type.replace('EPathType', '')}</div>
262
262
  ) : (
263
263
  <div className={b('entity-type', {error: true})}>
264
264
  <HelpPopover content={message} offset={{left: 0}} />
@@ -13,7 +13,7 @@ import {sendQuery, setQueryOptions} from '../../../store/reducers/preview';
13
13
  import {showTooltip, hideTooltip} from '../../../store/reducers/tooltip';
14
14
  import {prepareQueryError, prepareQueryResponse} from '../../../utils/index';
15
15
 
16
- import {OLAP_TABLE_TYPE, TABLE_TYPE} from '../Tenant';
16
+ import {isTableType} from '../utils/schema';
17
17
  import {AutoFetcher} from '../../../utils/autofetcher';
18
18
  import EnableFullscreenButton from '../../../components/EnableFullscreenButton/EnableFullscreenButton';
19
19
  import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
@@ -82,7 +82,7 @@ class Preview extends React.Component {
82
82
  sendQueryForPreview = () => {
83
83
  const {sendQuery, database, table, type} = this.props;
84
84
 
85
- if (type !== TABLE_TYPE && type !== OLAP_TABLE_TYPE) {
85
+ if (!isTableType(type)) {
86
86
  return;
87
87
  }
88
88
 
@@ -150,7 +150,7 @@ class Preview extends React.Component {
150
150
 
151
151
  let message;
152
152
 
153
- if (type !== TABLE_TYPE && type !== OLAP_TABLE_TYPE) {
153
+ if (!isTableType(type)) {
154
154
  message = <div className={b('message-container')}>Not available</div>;
155
155
  }
156
156
 
@@ -35,6 +35,9 @@ export function SchemaTree(props: SchemaTreeProps) {
35
35
  return Children.map(({Name = '', PathType}) => ({
36
36
  name: Name,
37
37
  type: mapPathTypeToNavigationTreeType(PathType),
38
+ // FIXME: should only be explicitly set to true for tables with indexes
39
+ // at the moment of writing there is no property to determine this, fix later
40
+ expandable: true,
38
41
  }));
39
42
  });
40
43
 
@@ -1,9 +1,12 @@
1
- import {useEffect, useMemo, useReducer} from 'react';
1
+ import {useEffect, useReducer} from 'react';
2
2
  import {useDispatch, useSelector} from 'react-redux';
3
3
  import cn from 'bem-cn-lite';
4
4
  import {useLocation} from 'react-router';
5
5
  import qs from 'qs';
6
6
 
7
+ import EmptyState from '../../components/EmptyState/EmptyState';
8
+ import {Illustration} from '../../components/Illustration';
9
+
7
10
  import ObjectSummary from './ObjectSummary/ObjectSummary';
8
11
  import {setHeader} from '../../store/reducers/header';
9
12
  import ObjectGeneral from './ObjectGeneral/ObjectGeneral';
@@ -22,28 +25,12 @@ import {
22
25
  //@ts-ignore
23
26
  import {getTenantInfo, clearTenant} from '../../store/reducers/tenant';
24
27
  import routes, {CLUSTER_PAGES, createHref} from '../../routes';
28
+ import type {TEvDescribeSchemeResult} from '../../types/api/schema';
25
29
 
26
30
  import './Tenant.scss';
27
31
 
28
32
  const b = cn('tenant-page');
29
33
 
30
- export const TABLE_TYPE = 'Table';
31
- export const OLAP_TABLE_TYPE = 'ColumnTable';
32
- export const OLAP_STORE_TYPE = 'ColumnStore';
33
-
34
- export function calcEntityType(currentPathType?: string) {
35
- return currentPathType && currentPathType.replace('EPathType', '');
36
- }
37
-
38
- export function isTableType(currentPathType?: string) {
39
- const type = calcEntityType(currentPathType);
40
-
41
- if (type === TABLE_TYPE || type === OLAP_TABLE_TYPE) {
42
- return true;
43
- }
44
- return false;
45
- }
46
-
47
34
  const getInitialIsSummaryCollapsed = () => {
48
35
  return Boolean(localStorage.getItem(DEFAULT_IS_TENANT_SUMMARY_COLLAPSED));
49
36
  };
@@ -69,6 +56,9 @@ function Tenant(props: TenantProps) {
69
56
  (state: any) => state.schema,
70
57
  );
71
58
 
59
+ const {data: {status: tenantStatus = 200} = {}} = useSelector((state: any) => state.tenant);
60
+ const {error: {status: schemaStatus = 200} = {}} = useSelector((state: any) => state.schema);
61
+
72
62
  const dispatch = useDispatch();
73
63
 
74
64
  const location = useLocation();
@@ -114,11 +104,7 @@ function Tenant(props: TenantProps) {
114
104
  };
115
105
  }, [tenantName, dispatch]);
116
106
 
117
- const currentPathType = currentItem.PathDescription?.Self?.PathType;
118
-
119
- const entityType = useMemo(() => {
120
- return calcEntityType(currentPathType);
121
- }, [currentPathType]);
107
+ const currentPathType = (currentItem as TEvDescribeSchemeResult).PathDescription?.Self?.PathType;
122
108
 
123
109
  const onCollapseSummaryHandler = () => {
124
110
  dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.triggerCollapse);
@@ -131,29 +117,39 @@ function Tenant(props: TenantProps) {
131
117
  dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.clear);
132
118
  };
133
119
 
120
+ const showBlockingError = tenantStatus === 403 || schemaStatus === 403;
121
+
134
122
  return (
135
123
  <div className={b()}>
136
- <SplitPane
137
- defaultSizePaneKey={DEFAULT_SIZE_TENANT_KEY}
138
- defaultSizes={[25, 75]}
139
- triggerCollapse={summaryVisibilityState.triggerCollapse}
140
- triggerExpand={summaryVisibilityState.triggerExpand}
141
- minSize={[36, 200]}
142
- onSplitStartDragAdditional={onSplitStartDragAdditional}
143
- >
144
- <ObjectSummary
145
- type={entityType as string}
146
- onCollapseSummary={onCollapseSummaryHandler}
147
- onExpandSummary={onExpandSummaryHandler}
148
- isCollapsed={summaryVisibilityState.collapsed}
149
- additionalTenantInfo={props.additionalTenantInfo}
150
- />
151
- <ObjectGeneral
152
- type={entityType as string}
153
- additionalTenantInfo={props.additionalTenantInfo}
154
- additionalNodesInfo={props.additionalNodesInfo}
124
+ {showBlockingError ? (
125
+ <EmptyState
126
+ image={<Illustration name="403" />}
127
+ title="Access denied"
128
+ description="You don’t have the necessary roles to view this page."
155
129
  />
156
- </SplitPane>
130
+ ) : (
131
+ <SplitPane
132
+ defaultSizePaneKey={DEFAULT_SIZE_TENANT_KEY}
133
+ defaultSizes={[25, 75]}
134
+ triggerCollapse={summaryVisibilityState.triggerCollapse}
135
+ triggerExpand={summaryVisibilityState.triggerExpand}
136
+ minSize={[36, 200]}
137
+ onSplitStartDragAdditional={onSplitStartDragAdditional}
138
+ >
139
+ <ObjectSummary
140
+ type={currentPathType}
141
+ onCollapseSummary={onCollapseSummaryHandler}
142
+ onExpandSummary={onExpandSummaryHandler}
143
+ isCollapsed={summaryVisibilityState.collapsed}
144
+ additionalTenantInfo={props.additionalTenantInfo}
145
+ />
146
+ <ObjectGeneral
147
+ type={currentPathType}
148
+ additionalTenantInfo={props.additionalTenantInfo}
149
+ additionalNodesInfo={props.additionalNodesInfo}
150
+ />
151
+ </SplitPane>
152
+ )}
157
153
  </div>
158
154
  );
159
155
  }
@@ -13,8 +13,16 @@ export const mapPathTypeToNavigationTreeType = (
13
13
  return 'table';
14
14
  case EPathType.EPathTypeDir:
15
15
  case EPathType.EPathTypeColumnStore:
16
+ case EPathType.EPathTypeTableIndex:
16
17
  return 'directory';
17
18
  default:
18
19
  return defaultType;
19
20
  }
20
21
  };
22
+
23
+ export const isTableType = (type?: EPathType) =>
24
+ mapPathTypeToNavigationTreeType(type) === 'table';
25
+
26
+ export const isColumnEntityType = (type?: EPathType) =>
27
+ type === EPathType.EPathTypeColumnStore ||
28
+ type === EPathType.EPathTypeColumnTable;
@@ -83,7 +83,6 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
83
83
  path,
84
84
  enums: true,
85
85
  backup: false,
86
- private: false,
87
86
  partition_config: false,
88
87
  partition_stats: false,
89
88
  partitioning_info: false,
@@ -99,7 +98,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
99
98
  }
100
99
  getSchemaAcl({path}) {
101
100
  return this.get(
102
- this.getPath('/viewer/json/metainfo'),
101
+ this.getPath('/viewer/json/acl'),
103
102
  {
104
103
  path,
105
104
  },
@@ -111,7 +110,6 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
111
110
  path,
112
111
  enums: true,
113
112
  backup: false,
114
- private: false,
115
113
  children: false,
116
114
  partition_config: false,
117
115
  partition_stats: true,
@@ -125,7 +125,15 @@ export function setVisibleEntities(value) {
125
125
  }
126
126
 
127
127
  export const getStoragePools = (state) => state.storage.data?.StoragePools;
128
+ export const getStoragePoolsGroupsCount = (state) => ({
129
+ total: state.storage.data?.TotalGroups || 0,
130
+ found: state.storage.data?.FoundGroups || 0,
131
+ });
128
132
  export const getStorageNodes = (state) => state.storage.data?.Nodes;
133
+ export const getStorageNodesCount = (state) => ({
134
+ total: state.storage.data?.TotalNodes || 0,
135
+ found: state.storage.data?.FoundNodes || 0,
136
+ });
129
137
  export const getStorageFilter = (state) => state.storage.filter;
130
138
  export const getVisibleEntities = (state) => state.storage.visible;
131
139
  export const getStorageType = (state) => state.storage.type;
@@ -88,6 +88,7 @@ export enum EPathType {
88
88
  EPathTypeSubDomain = 'EPathTypeSubDomain',
89
89
  EPathTypeColumnStore = 'EPathTypeColumnStore',
90
90
  EPathTypeColumnTable = 'EPathTypeColumnTable',
91
+ EPathTypeTableIndex = 'EPathTypeTableIndex',
91
92
  }
92
93
 
93
94
  enum EPathSubType {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "1.6.4",
3
+ "version": "1.8.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -40,7 +40,7 @@
40
40
  "reselect": "4.0.0",
41
41
  "sass": "1.32.8",
42
42
  "web-vitals": "1.1.2",
43
- "ydb-ui-components": "2.0.2"
43
+ "ydb-ui-components": "2.1.0"
44
44
  },
45
45
  "scripts": {
46
46
  "start": "react-app-rewired start",