ydb-embedded-ui 1.4.2 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/components/GroupTreeViewer/GroupTreeViewer.js +3 -2
  3. package/dist/components/GroupTreeViewer/GroupTreeViewer.scss +0 -2
  4. package/dist/components/SplitPane/SplitPane.tsx +8 -8
  5. package/dist/containers/App/App.js +1 -0
  6. package/dist/containers/App/App.scss +0 -26
  7. package/dist/containers/Authentication/Authentication.tsx +1 -0
  8. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +14 -21
  9. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueViewer.scss +11 -23
  10. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssuesViewer.js +7 -7
  11. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +9 -15
  12. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +18 -21
  13. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +2 -2
  14. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +62 -0
  15. package/dist/containers/Tenant/Tenant.tsx +2 -2
  16. package/dist/containers/Tenant/utils/schema.ts +17 -0
  17. package/dist/containers/Tenant/utils/schemaActions.ts +115 -0
  18. package/dist/services/api.d.ts +3 -0
  19. package/dist/services/api.js +2 -2
  20. package/dist/store/reducers/tenant.js +30 -0
  21. package/dist/store/state-url-mapping.js +6 -0
  22. package/package.json +8 -4
  23. package/dist/components/TreeView/TreeView.js +0 -60
  24. package/dist/components/TreeView/TreeView.scss +0 -39
  25. package/dist/containers/Tenant/Schema/SchemaNode/SchemaNode.js +0 -170
  26. package/dist/containers/Tenant/Schema/SchemaNode/SchemaNode.scss +0 -62
  27. package/dist/containers/Tenant/Schema/SchemaNodeActions/SchemaNodeActions.scss +0 -17
  28. package/dist/containers/Tenant/Schema/SchemaNodeActions/SchemaNodeActions.tsx +0 -125
  29. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.js +0 -116
  30. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.scss +0 -17
  31. package/dist/styles/react-treeview.scss +0 -45
@@ -0,0 +1,115 @@
1
+ import {Dispatch} from 'react';
2
+ import type {NavigationTreeNodeType} from 'ydb-ui-components';
3
+
4
+ import {changeUserInput} from '../../../store/reducers/executeQuery';
5
+ import {setShowPreview} from '../../../store/reducers/schema';
6
+ import {setTopLevelTab} from '../../../store/reducers/tenant';
7
+ import createToast from '../../../utils/createToast';
8
+ import {TenantGeneralTabsIds} from '../TenantPages';
9
+
10
+ const createTableTemplate = (path: string) => {
11
+ return `CREATE TABLE \`${path}/my_table\`
12
+ (
13
+ \`id\` Uint64,
14
+ \`name\` String,
15
+ PRIMARY KEY (\`id\`)
16
+ );`;
17
+ };
18
+
19
+ const alterTableTemplate = (path: string) => {
20
+ return `ALTER TABLE \`${path}\`
21
+ ADD COLUMN is_deleted Bool;`;
22
+ };
23
+ const selectQueryTemplate = (path: string) => {
24
+ return `SELECT \`id\`, \`name\`
25
+ FROM \`${path}\`
26
+ ORDER BY \`id\`
27
+ LIMIT 10;`;
28
+ };
29
+ const upsertQueryTemplate = (path: string) => {
30
+ return `UPSERT INTO \`${path}\`
31
+ ( \`id\`, \`name\` )
32
+ VALUES ( );`;
33
+ };
34
+
35
+ export const getActions = (
36
+ dispatch: Dispatch<any>,
37
+ setActivePath: (path: string) => void,
38
+ ) =>
39
+ (path: string, type: NavigationTreeNodeType) => {
40
+ const switchTabToQuery = () => {
41
+ dispatch(setTopLevelTab(TenantGeneralTabsIds.query));
42
+ };
43
+
44
+ const onCreateTableClick = () => {
45
+ dispatch(changeUserInput({input: createTableTemplate(path)}));
46
+ switchTabToQuery();
47
+ setActivePath(path);
48
+ };
49
+
50
+ const onAlterTableClick = () => {
51
+ dispatch(changeUserInput({input: alterTableTemplate(path)}));
52
+ switchTabToQuery();
53
+ setActivePath(path);
54
+ };
55
+
56
+ const onSelectQueryClick = () => {
57
+ dispatch(changeUserInput({input: selectQueryTemplate(path)}));
58
+ switchTabToQuery();
59
+ setActivePath(path);
60
+ };
61
+
62
+ const onUpsertQueryClick = () => {
63
+ dispatch(changeUserInput({input: upsertQueryTemplate(path)}));
64
+ switchTabToQuery();
65
+ setActivePath(path);
66
+ };
67
+
68
+ const onCopyPathClick = () => {
69
+ navigator.clipboard
70
+ .writeText(path)
71
+ .then(() => {
72
+ createToast({
73
+ name: 'Copied',
74
+ title: 'The path is copied to the clipboard',
75
+ type: 'success',
76
+ });
77
+ })
78
+ .catch(() => {
79
+ createToast({
80
+ name: 'Not copied',
81
+ title: 'Couldn’t copy the path',
82
+ type: 'error',
83
+ });
84
+ });
85
+ };
86
+
87
+ const onOpenPreviewClick = () => {
88
+ dispatch(setShowPreview(true));
89
+ switchTabToQuery();
90
+ setActivePath(path);
91
+ };
92
+
93
+ const copyItem = {text: 'Copy path', action: onCopyPathClick};
94
+
95
+ return type === 'table'
96
+ ? [
97
+ [
98
+ {text: 'Open preview', action: onOpenPreviewClick},
99
+ copyItem,
100
+ ],
101
+ [
102
+ {text: 'Alter table...', action: onAlterTableClick},
103
+ {text: 'Select query...', action: onSelectQueryClick},
104
+ {text: 'Upsert query...', action: onUpsertQueryClick},
105
+ ],
106
+ ]
107
+ : [
108
+ [
109
+ copyItem,
110
+ ],
111
+ [
112
+ {text: 'Create table...', action: onCreateTableClick},
113
+ ],
114
+ ];
115
+ };
@@ -0,0 +1,3 @@
1
+ interface Window {
2
+ api: any;
3
+ }
@@ -76,7 +76,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
76
76
  enums: true,
77
77
  });
78
78
  }
79
- getSchema({path}) {
79
+ getSchema({path}, {concurrentId} = {}) {
80
80
  return this.get(
81
81
  this.getPath('/viewer/json/describe'),
82
82
  {
@@ -88,7 +88,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
88
88
  partition_stats: false,
89
89
  partitioning_info: false,
90
90
  },
91
- {concurrentId: `getSchema|${path}`},
91
+ {concurrentId: concurrentId || `getSchema|${path}`},
92
92
  );
93
93
  }
94
94
  getDescribe({path}) {
@@ -3,6 +3,8 @@ import '../../services/api';
3
3
  import _ from 'lodash';
4
4
 
5
5
  const FETCH_TENANT = createRequestActionTypes('tenant', 'FETCH_TENANT');
6
+ const SET_TOP_LEVEL_TAB = 'tenant/SET_TOP_LEVEL_TAB';
7
+ const SET_DIAGNOSTICS_TAB = 'tenant/SET_DIAGNOSTICS_TAB';
6
8
 
7
9
  const tenantReducer = (state = {loading: false, tenant: {}}, action) => {
8
10
  switch (action.type) {
@@ -41,6 +43,20 @@ const tenantReducer = (state = {loading: false, tenant: {}}, action) => {
41
43
  };
42
44
  }
43
45
 
46
+ case SET_TOP_LEVEL_TAB: {
47
+ return {
48
+ ...state,
49
+ topLevelTab: action.data,
50
+ };
51
+ }
52
+
53
+ case SET_DIAGNOSTICS_TAB: {
54
+ return {
55
+ ...state,
56
+ diagnosticsTab: action.data,
57
+ };
58
+ }
59
+
44
60
  default:
45
61
  return state;
46
62
  }
@@ -73,4 +89,18 @@ export const getTenantInfo = ({path}) => {
73
89
  });
74
90
  };
75
91
 
92
+ export function setTopLevelTab(tab) {
93
+ return {
94
+ type: SET_TOP_LEVEL_TAB,
95
+ data: tab,
96
+ };
97
+ }
98
+
99
+ export function setDiagnosticsTab(tab) {
100
+ return {
101
+ type: SET_DIAGNOSTICS_TAB,
102
+ data: tab,
103
+ };
104
+ }
105
+
76
106
  export default tenantReducer;
@@ -42,6 +42,12 @@ const paramSetup = {
42
42
  stateKey: 'tablets.typeFilter',
43
43
  type: 'array',
44
44
  },
45
+ general: {
46
+ stateKey: 'tenant.topLevelTab',
47
+ },
48
+ generalTab: {
49
+ stateKey: 'tenant.diagnosticsTab',
50
+ },
45
51
  },
46
52
  };
47
53
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "1.4.2",
3
+ "version": "1.5.2",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -13,7 +13,7 @@
13
13
  "@testing-library/react": "11.2.7",
14
14
  "@testing-library/user-event": "12.8.3",
15
15
  "@types/qs": "6.9.7",
16
- "@yandex-cloud/i18n": "0.2.0",
16
+ "@yandex-cloud/i18n": "0.4.0",
17
17
  "@yandex-cloud/paranoid": "1.0.0",
18
18
  "@yandex-cloud/react-data-table": "0.2.1",
19
19
  "axios": "0.19.2",
@@ -34,13 +34,13 @@
34
34
  "react-scripts": "4.0.3",
35
35
  "react-split": "2.0.14",
36
36
  "react-transition-group": "4.4.2",
37
- "react-treeview": "0.4.7",
38
37
  "redux": "4.0.1",
39
38
  "redux-location-state": "2.6.0",
40
39
  "redux-thunk": "2.3.0",
41
40
  "reselect": "4.0.0",
42
41
  "sass": "1.32.8",
43
- "web-vitals": "1.1.2"
42
+ "web-vitals": "1.1.2",
43
+ "ydb-ui-components": "1.2.3"
44
44
  },
45
45
  "scripts": {
46
46
  "start": "react-app-rewired start",
@@ -88,6 +88,7 @@
88
88
  "@types/react-transition-group": "^4.4.4",
89
89
  "@types/react-virtualized-auto-sizer": "^1.0.1",
90
90
  "@yandex-cloud/axios-wrapper": "^1.0.2",
91
+ "@yandex-cloud/browserslist-config": "1.0.1",
91
92
  "@yandex-cloud/eslint-config": "^1.0.0",
92
93
  "@yandex-cloud/prettier-config": "^1.0.0",
93
94
  "@yandex-cloud/stylelint-config": "^1.1.0",
@@ -104,5 +105,8 @@
104
105
  "react-dom": "^17.0.2",
105
106
  "stylelint": "^14.3.0",
106
107
  "typescript": "^4.5.5"
108
+ },
109
+ "peerDependencies": {
110
+ "@yandex-cloud/browserslist-config": "^1.0.1"
107
111
  }
108
112
  }
@@ -1,60 +0,0 @@
1
- import PropTypes from 'prop-types';
2
- import cn from 'bem-cn-lite';
3
- import TreeViewBase from 'react-treeview';
4
- import Icon from '../Icon/Icon';
5
-
6
- import './TreeView.scss';
7
-
8
- const b = cn('km-tree-view');
9
-
10
- const TreeView = (props) => {
11
- const {
12
- children,
13
- nodeLabel,
14
- onClick,
15
- collapsed,
16
- clickableLabel = false,
17
- className,
18
- hasArrow = true,
19
- ...rest
20
- } = props;
21
-
22
- const newNodeLabel = (
23
- <div
24
- className={b('node-wrapper', {clickable: clickableLabel})}
25
- onClick={clickableLabel ? onClick : undefined}
26
- >
27
- {hasArrow ? (
28
- <span
29
- className={b('arrow-icon', {extended: !collapsed})}
30
- onClick={clickableLabel ? undefined : onClick}
31
- >
32
- <Icon name="arrow-right" viewBox="0 0 6 11" width={6} height={11} />
33
- </span>
34
- ) : null}
35
- {nodeLabel}
36
- </div>
37
- );
38
-
39
- return (
40
- <TreeViewBase
41
- {...rest}
42
- treeViewClassName={b(null, className)}
43
- nodeLabel={newNodeLabel}
44
- collapsed={collapsed}
45
- >
46
- {children}
47
- </TreeViewBase>
48
- );
49
- };
50
-
51
- TreeView.propTypes = {
52
- children: PropTypes.any,
53
- nodeLabel: PropTypes.node,
54
- onClick: PropTypes.func,
55
- collapsed: PropTypes.bool,
56
- clickableLabel: PropTypes.bool,
57
- className: PropTypes.string,
58
- };
59
-
60
- export default TreeView;
@@ -1,39 +0,0 @@
1
- .km-tree-view {
2
- & .tree-view_arrow {
3
- display: none;
4
- }
5
-
6
- &__node-wrapper {
7
- display: flex;
8
- overflow: hidden;
9
- align-items: center;
10
-
11
- width: 100%;
12
-
13
- &_clickable {
14
- cursor: pointer;
15
- }
16
- }
17
-
18
- &__arrow-icon {
19
- display: flex;
20
- justify-content: center;
21
-
22
- width: 11px;
23
- margin-right: 8px;
24
-
25
- cursor: pointer;
26
-
27
- &_extended {
28
- transform: rotate(90deg);
29
- }
30
-
31
- & .yc-icon {
32
- vertical-align: middle;
33
- }
34
- }
35
- .yc-icon {
36
- display: flex;
37
- flex-shrink: 0;
38
- }
39
- }
@@ -1,170 +0,0 @@
1
- import React from 'react';
2
- import {connect} from 'react-redux';
3
- import PropTypes from 'prop-types';
4
- import cn from 'bem-cn-lite';
5
-
6
- import TreeView from '../../../../components/TreeView/TreeView';
7
- import SchemaTree from '../../../Tenant/Schema/SchemaTree/SchemaTree';
8
- import Icon from '../../../../components/Icon/Icon';
9
-
10
- import {getSchema, setCurrentSchemaPath} from '../../../../store/reducers/schema';
11
- import {getDescribe} from '../../../../store/reducers/describe';
12
- import {getSchemaAcl} from '../../../../store/reducers/schemaAcl';
13
-
14
- import './SchemaNode.scss';
15
- import SchemaNodeActions from '../SchemaNodeActions/SchemaNodeActions';
16
- import {isTableType} from '../../Tenant';
17
-
18
- const b = cn('schema-node');
19
-
20
- export const SUBDOMAIN_FOLDER_TYPE = 'EPathTypeSubDomain';
21
- export const TABLE_TYPE = 'EPathTypeTable';
22
- export const OLAP_TABLE_TYPE = 'EPathTypeOlapTable';
23
-
24
- export const FOLDERS_TYPE = ['EPathTypeDir', 'EPathTypeExtSubDomain', 'EPathTypeOlapStore'];
25
-
26
- class SchemaNode extends React.Component {
27
- static propTypes = {
28
- data: PropTypes.object.isRequired,
29
- fullPath: PropTypes.string.isRequired,
30
- getSchema: PropTypes.func.isRequired,
31
- setCurrentSchemaPath: PropTypes.func,
32
- currentSchemaPath: PropTypes.string,
33
- isRoot: PropTypes.bool,
34
- };
35
-
36
- state = {
37
- collapsed: true,
38
- active: false,
39
- };
40
-
41
- schemaNodeRef = React.createRef();
42
-
43
- componentDidMount() {
44
- const {currentSchemaPath, isRoot} = this.props;
45
- const schemaPath = this.getSchemaPath();
46
-
47
- if (schemaPath === currentSchemaPath && !this.state.active) {
48
- this.addActiveClass();
49
- }
50
-
51
- if (
52
- (currentSchemaPath &&
53
- currentSchemaPath.startsWith(schemaPath) &&
54
- currentSchemaPath !== schemaPath) ||
55
- isRoot
56
- ) {
57
- this.setState({collapsed: false});
58
- }
59
- }
60
-
61
- componentDidUpdate() {
62
- const {currentSchemaPath} = this.props;
63
- const schemaPath = this.getSchemaPath();
64
-
65
- if (schemaPath === currentSchemaPath && !this.state.active) {
66
- this.addActiveClass();
67
- }
68
- }
69
-
70
- getSchemaPath = () => {
71
- const {data, fullPath, isRoot} = this.props;
72
-
73
- return isRoot ? fullPath : `${fullPath}/${data.Name}`;
74
- };
75
-
76
- invertCollapsed = () => {
77
- this.setState({collapsed: !this.state.collapsed});
78
- };
79
-
80
- setIcon = (data) => {
81
- const viewBox = '0 0 16 16';
82
- const {collapsed} = this.state;
83
- if (FOLDERS_TYPE.indexOf(data.PathType) !== -1) {
84
- return collapsed ? (
85
- <Icon name="folder" viewBox={viewBox} width={16} height={16} />
86
- ) : (
87
- <Icon name="openFolder" viewBox={viewBox} width={16} height={16} />
88
- );
89
- } else if (data.PathType === TABLE_TYPE || data.PathType === OLAP_TABLE_TYPE) {
90
- return <Icon name="table" viewBox={viewBox} width={16} height={16} />;
91
- } else if (data.PathType === SUBDOMAIN_FOLDER_TYPE) {
92
- return <Icon name="subdomain" viewBox={viewBox} width={16} height={16} />;
93
- }
94
- };
95
-
96
- addActiveClass = () => {
97
- const activeClass = 'schema-node_active';
98
- const currentActiveSchemaNode = document.querySelector(`.${activeClass}`);
99
- if (currentActiveSchemaNode) {
100
- currentActiveSchemaNode.classList.remove(activeClass);
101
- }
102
- const activeNode = this.schemaNodeRef.current;
103
- if (activeNode) {
104
- this.setState({active: true});
105
- activeNode.classList.add(activeClass);
106
- }
107
- };
108
-
109
- handleClick = (e) => {
110
- const {getSchema, getDescribe, getSchemaAcl, setCurrentSchemaPath} = this.props;
111
- e.stopPropagation();
112
- this.addActiveClass();
113
-
114
- const schemaPath = this.getSchemaPath();
115
- setCurrentSchemaPath(schemaPath);
116
- getSchema({path: schemaPath});
117
- getDescribe({path: schemaPath});
118
- getSchemaAcl({path: schemaPath});
119
- };
120
-
121
- render() {
122
- const {data, fullPath, isRoot = false, currentSchemaPath, currentItem = {}} = this.props;
123
- const {collapsed} = this.state;
124
-
125
- if (!data) {
126
- return null;
127
- }
128
- const currentPathType = currentItem.PathDescription?.Self?.PathType;
129
- const type = isTableType(currentPathType);
130
-
131
- const hasArrow = data.PathType !== TABLE_TYPE;
132
- const label = (
133
- <div className={b('label')}>
134
- {this.setIcon(data)}
135
- <div className={b('name-wrapper')}>
136
- <div className={b('name')}>{data.Name}</div>
137
- <SchemaNodeActions name={currentSchemaPath} isTableType={type} />
138
- </div>
139
- </div>
140
- );
141
- return (
142
- <div onClick={this.handleClick} ref={this.schemaNodeRef}>
143
- <TreeView
144
- nodeLabel={label}
145
- collapsed={collapsed}
146
- onClick={this.invertCollapsed}
147
- hasArrow={hasArrow}
148
- >
149
- <SchemaTree path={isRoot ? fullPath : `${fullPath}/${data.Name}`} />
150
- </TreeView>
151
- </div>
152
- );
153
- }
154
- }
155
-
156
- function mapStateToProps(state) {
157
- return {
158
- currentSchemaPath: state.schema.currentSchemaPath,
159
- currentItem: state.schema.currentSchema,
160
- };
161
- }
162
-
163
- const mapDispatchToProps = {
164
- getSchema,
165
- getDescribe,
166
- getSchemaAcl,
167
- setCurrentSchemaPath,
168
- };
169
-
170
- export default connect(mapStateToProps, mapDispatchToProps)(SchemaNode);
@@ -1,62 +0,0 @@
1
- .schema-node {
2
- display: flex;
3
- align-items: center;
4
-
5
- .tree-view_item {
6
- flex-wrap: wrap;
7
-
8
- margin: 0;
9
- padding: 5px 0;
10
- }
11
-
12
- .tree-view_children {
13
- margin: 0;
14
- padding-left: 15px;
15
- }
16
-
17
- &__label {
18
- display: flex;
19
- overflow: hidden;
20
- align-items: center;
21
-
22
- width: 100%;
23
- height: 20px;
24
- padding: 0 5px;
25
-
26
- cursor: pointer;
27
-
28
- & > svg {
29
- color: var(--yc-color-text-hint);
30
- }
31
- }
32
-
33
- &_active > .tree-view > .tree-view_item {
34
- font-weight: 600;
35
-
36
- background-color: var(--yc-color-base-info);
37
- }
38
-
39
- &__name-wrapper {
40
- display: inline-flex;
41
- justify-content: space-between;
42
-
43
- width: 100%;
44
- }
45
-
46
- &__name {
47
- display: inline;
48
- overflow: hidden;
49
-
50
- margin-left: 6px;
51
-
52
- white-space: nowrap;
53
- text-overflow: ellipsis;
54
- }
55
- }
56
-
57
- .tree-view_item {
58
- border-bottom: 1px solid var(--yc-color-line-generic);
59
- &:hover {
60
- background-color: var(--yc-color-base-simple-hover);
61
- }
62
- }
@@ -1,17 +0,0 @@
1
- .kv-schema-node-actions {
2
- visibility: hidden;
3
-
4
- &__popup {
5
- .yc-menu__list-item {
6
- line-height: 36px;
7
- }
8
- }
9
- }
10
-
11
- .tree-view_item {
12
- &:hover {
13
- .kv-schema-node-actions {
14
- visibility: visible;
15
- }
16
- }
17
- }