ydb-embedded-ui 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/dist/components/GroupTreeViewer/GroupTreeViewer.js +3 -2
- package/dist/components/GroupTreeViewer/GroupTreeViewer.scss +0 -2
- package/dist/components/SplitPane/SplitPane.tsx +8 -8
- package/dist/containers/App/App.js +1 -0
- package/dist/containers/App/App.scss +0 -26
- package/dist/containers/App/NodesTable.scss +0 -2
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueViewer.scss +11 -23
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssuesViewer.js +7 -7
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +9 -15
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +16 -15
- package/dist/containers/Tenant/QueryEditor/QueryEditor.js +2 -2
- package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +36 -54
- package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.scss +7 -5
- package/dist/containers/Tenant/QueryEditor/SavedQueries/SavedQueries.js +1 -0
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +64 -0
- package/dist/containers/Tenant/Tenant.tsx +2 -2
- package/dist/containers/Tenant/utils/schema.ts +17 -0
- package/dist/containers/Tenant/utils/schemaActions.ts +130 -0
- package/dist/containers/Tenants/Tenants.js +2 -2
- package/dist/containers/Tenants/Tenants.scss +7 -1
- package/dist/services/api.d.ts +3 -0
- package/dist/services/api.js +2 -2
- package/package.json +8 -4
- package/dist/components/TreeView/TreeView.js +0 -60
- package/dist/components/TreeView/TreeView.scss +0 -39
- package/dist/containers/Tenant/Schema/SchemaNode/SchemaNode.js +0 -170
- package/dist/containers/Tenant/Schema/SchemaNode/SchemaNode.scss +0 -62
- package/dist/containers/Tenant/Schema/SchemaNodeActions/SchemaNodeActions.scss +0 -17
- package/dist/containers/Tenant/Schema/SchemaNodeActions/SchemaNodeActions.tsx +0 -125
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.js +0 -116
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.scss +0 -17
- package/dist/styles/react-treeview.scss +0 -45
@@ -0,0 +1,64 @@
|
|
1
|
+
import {useDispatch} from 'react-redux';
|
2
|
+
import {useHistory} from 'react-router';
|
3
|
+
|
4
|
+
import {NavigationTree} from 'ydb-ui-components';
|
5
|
+
|
6
|
+
import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema';
|
7
|
+
import {getDescribe} from '../../../../store/reducers/describe';
|
8
|
+
import {getSchemaAcl} from '../../../../store/reducers/schemaAcl';
|
9
|
+
|
10
|
+
import {calcNavigationTreeType} from '../../utils/schema';
|
11
|
+
import {getActions} from '../../utils/schemaActions';
|
12
|
+
|
13
|
+
interface SchemaTreeProps {
|
14
|
+
rootPath: string;
|
15
|
+
rootName: string;
|
16
|
+
rootType: string;
|
17
|
+
currentPath: string;
|
18
|
+
}
|
19
|
+
|
20
|
+
export function SchemaTree(props: SchemaTreeProps) {
|
21
|
+
const {
|
22
|
+
rootPath,
|
23
|
+
rootName,
|
24
|
+
rootType,
|
25
|
+
currentPath,
|
26
|
+
} = props;
|
27
|
+
|
28
|
+
const dispatch = useDispatch();
|
29
|
+
const history = useHistory();
|
30
|
+
|
31
|
+
const fetchPath = (path: string) => window.api.getSchema(
|
32
|
+
{path},
|
33
|
+
{concurrentId: `NavigationTree.getSchema|${path}`},
|
34
|
+
)
|
35
|
+
.then(({PathDescription: {Children = []} = {}}) => {
|
36
|
+
return Children.map(({Name, PathType}) => ({
|
37
|
+
name: Name,
|
38
|
+
type: calcNavigationTreeType(PathType),
|
39
|
+
}));
|
40
|
+
});
|
41
|
+
|
42
|
+
const handleActivePathUpdate = (activePath: string) => {
|
43
|
+
dispatch(setCurrentSchemaPath(activePath));
|
44
|
+
dispatch(getSchema({path: activePath}));
|
45
|
+
dispatch(getDescribe({path: activePath}));
|
46
|
+
dispatch(getSchemaAcl({path: activePath}));
|
47
|
+
};
|
48
|
+
|
49
|
+
return (
|
50
|
+
<NavigationTree
|
51
|
+
rootState={{
|
52
|
+
path: rootPath,
|
53
|
+
name: rootName,
|
54
|
+
type: calcNavigationTreeType(rootType),
|
55
|
+
collapsed: false,
|
56
|
+
}}
|
57
|
+
fetchPath={fetchPath}
|
58
|
+
getActions={getActions(dispatch, history, handleActivePathUpdate)}
|
59
|
+
activePath={currentPath}
|
60
|
+
onActivePathUpdate={handleActivePathUpdate}
|
61
|
+
cache={false}
|
62
|
+
/>
|
63
|
+
);
|
64
|
+
}
|
@@ -127,7 +127,7 @@ function Tenant(props: TenantProps) {
|
|
127
127
|
dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.triggerExpand);
|
128
128
|
};
|
129
129
|
|
130
|
-
const
|
130
|
+
const onSplitStartDragAdditional = () => {
|
131
131
|
dispatchSummaryVisibilityAction(PaneVisibilityActionTypes.clear);
|
132
132
|
};
|
133
133
|
|
@@ -139,7 +139,7 @@ function Tenant(props: TenantProps) {
|
|
139
139
|
triggerCollapse={summaryVisibilityState.triggerCollapse}
|
140
140
|
triggerExpand={summaryVisibilityState.triggerExpand}
|
141
141
|
minSize={[36, 200]}
|
142
|
-
|
142
|
+
onSplitStartDragAdditional={onSplitStartDragAdditional}
|
143
143
|
>
|
144
144
|
<ObjectSummary
|
145
145
|
type={entityType as string}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import type {NavigationTreeNodeType} from "ydb-ui-components";
|
2
|
+
|
3
|
+
const DB_TYPES = new Set(['EPathTypeSubDomain']);
|
4
|
+
const TABLE_TYPES = new Set(['EPathTypeTable', 'EPathTypeOlapTable']);
|
5
|
+
const DIR_TYPES = new Set(['EPathTypeDir', 'EPathTypeOlapStore']);
|
6
|
+
|
7
|
+
export const calcNavigationTreeType = (type: string): NavigationTreeNodeType => {
|
8
|
+
if (DIR_TYPES.has(type)) {
|
9
|
+
return 'directory';
|
10
|
+
} else if (TABLE_TYPES.has(type)) {
|
11
|
+
return 'table';
|
12
|
+
} else if (DB_TYPES.has(type)) {
|
13
|
+
return 'database';
|
14
|
+
}
|
15
|
+
|
16
|
+
return 'directory';
|
17
|
+
};
|
@@ -0,0 +1,130 @@
|
|
1
|
+
import qs from 'qs';
|
2
|
+
import {Dispatch} from 'react';
|
3
|
+
import {History} from 'history';
|
4
|
+
import type {NavigationTreeNodeType} from 'ydb-ui-components';
|
5
|
+
|
6
|
+
import routes, {createHref} from '../../../routes';
|
7
|
+
import {changeUserInput} from '../../../store/reducers/executeQuery';
|
8
|
+
import {setShowPreview} from '../../../store/reducers/schema';
|
9
|
+
import createToast from '../../../utils/createToast';
|
10
|
+
import {TenantGeneralTabsIds, TenantTabsGroups} from '../TenantPages';
|
11
|
+
|
12
|
+
const createTableTemplate = (path: string) => {
|
13
|
+
return `CREATE TABLE \`${path}/my_table\`
|
14
|
+
(
|
15
|
+
\`id\` Uint64,
|
16
|
+
\`name\` String,
|
17
|
+
PRIMARY KEY (\`id\`)
|
18
|
+
);`;
|
19
|
+
};
|
20
|
+
|
21
|
+
const alterTableTemplate = (path: string) => {
|
22
|
+
return `ALTER TABLE \`${path}\`
|
23
|
+
ADD COLUMN is_deleted Bool;`;
|
24
|
+
};
|
25
|
+
const selectQueryTemplate = (path: string) => {
|
26
|
+
return `SELECT \`id\`, \`name\`
|
27
|
+
FROM \`${path}\`
|
28
|
+
ORDER BY \`id\`
|
29
|
+
LIMIT 10;`;
|
30
|
+
};
|
31
|
+
const upsertQueryTemplate = (path: string) => {
|
32
|
+
return `UPSERT INTO \`${path}\`
|
33
|
+
( \`id\`, \`name\` )
|
34
|
+
VALUES ( );`;
|
35
|
+
};
|
36
|
+
|
37
|
+
export const getActions = (
|
38
|
+
dispatch: Dispatch<any>,
|
39
|
+
history: History<unknown>,
|
40
|
+
setActivePath: (path: string) => void,
|
41
|
+
) =>
|
42
|
+
(path: string, type: NavigationTreeNodeType) => {
|
43
|
+
const queryParams = qs.parse(location.search, {
|
44
|
+
ignoreQueryPrefix: true,
|
45
|
+
});
|
46
|
+
|
47
|
+
const switchTabToQuery = () => {
|
48
|
+
history.push(
|
49
|
+
createHref(routes.tenant, undefined, {
|
50
|
+
...queryParams,
|
51
|
+
[TenantTabsGroups.general]: TenantGeneralTabsIds.query,
|
52
|
+
}),
|
53
|
+
);
|
54
|
+
};
|
55
|
+
|
56
|
+
const onCreateTableClick = () => {
|
57
|
+
dispatch(changeUserInput({input: createTableTemplate(path)}));
|
58
|
+
switchTabToQuery();
|
59
|
+
// here and in the other handlers this should be called after switching tab:
|
60
|
+
// redux-location-state catches the history.push event from the tab switching
|
61
|
+
// before active path updates in url, preventing its update at all
|
62
|
+
setActivePath(path);
|
63
|
+
};
|
64
|
+
|
65
|
+
const onAlterTableClick = () => {
|
66
|
+
dispatch(changeUserInput({input: alterTableTemplate(path)}));
|
67
|
+
switchTabToQuery();
|
68
|
+
setActivePath(path);
|
69
|
+
};
|
70
|
+
|
71
|
+
const onSelectQueryClick = () => {
|
72
|
+
dispatch(changeUserInput({input: selectQueryTemplate(path)}));
|
73
|
+
switchTabToQuery();
|
74
|
+
setActivePath(path);
|
75
|
+
};
|
76
|
+
|
77
|
+
const onUpsertQueryClick = () => {
|
78
|
+
dispatch(changeUserInput({input: upsertQueryTemplate(path)}));
|
79
|
+
switchTabToQuery();
|
80
|
+
setActivePath(path);
|
81
|
+
};
|
82
|
+
|
83
|
+
const onCopyPathClick = () => {
|
84
|
+
navigator.clipboard
|
85
|
+
.writeText(path)
|
86
|
+
.then(() => {
|
87
|
+
createToast({
|
88
|
+
name: 'Copied',
|
89
|
+
title: 'The path is copied to the clipboard',
|
90
|
+
type: 'success',
|
91
|
+
});
|
92
|
+
})
|
93
|
+
.catch(() => {
|
94
|
+
createToast({
|
95
|
+
name: 'Not copied',
|
96
|
+
title: 'Couldn’t copy the path',
|
97
|
+
type: 'error',
|
98
|
+
});
|
99
|
+
});
|
100
|
+
};
|
101
|
+
|
102
|
+
const onOpenPreviewClick = () => {
|
103
|
+
dispatch(setShowPreview(true));
|
104
|
+
switchTabToQuery();
|
105
|
+
setActivePath(path);
|
106
|
+
};
|
107
|
+
|
108
|
+
const copyItem = {text: 'Copy path', action: onCopyPathClick};
|
109
|
+
|
110
|
+
return type === 'table'
|
111
|
+
? [
|
112
|
+
[
|
113
|
+
{text: 'Open preview', action: onOpenPreviewClick},
|
114
|
+
copyItem,
|
115
|
+
],
|
116
|
+
[
|
117
|
+
{text: 'Alter table...', action: onAlterTableClick},
|
118
|
+
{text: 'Select query...', action: onSelectQueryClick},
|
119
|
+
{text: 'Upsert query...', action: onUpsertQueryClick},
|
120
|
+
],
|
121
|
+
]
|
122
|
+
: [
|
123
|
+
[
|
124
|
+
copyItem,
|
125
|
+
],
|
126
|
+
[
|
127
|
+
{text: 'Create table...', action: onCreateTableClick},
|
128
|
+
],
|
129
|
+
];
|
130
|
+
};
|
@@ -144,7 +144,7 @@ class Tenants extends React.Component {
|
|
144
144
|
: undefined;
|
145
145
|
const isExternalLink = Boolean(backend);
|
146
146
|
return (
|
147
|
-
<
|
147
|
+
<div className={b('name-wrapper')}>
|
148
148
|
<EntityStatus
|
149
149
|
externalLink={isExternalLink}
|
150
150
|
className={b('name')}
|
@@ -159,7 +159,7 @@ class Tenants extends React.Component {
|
|
159
159
|
})}
|
160
160
|
/>
|
161
161
|
{additionalTenantsInfo.name && additionalTenantsInfo.name(value, row)}
|
162
|
-
</
|
162
|
+
</div>
|
163
163
|
);
|
164
164
|
},
|
165
165
|
width: 440,
|
package/dist/services/api.js
CHANGED
@@ -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}) {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "ydb-embedded-ui",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.5.0",
|
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.
|
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
|
-
}
|