ydb-embedded-ui 2.2.1 → 2.4.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 +37 -0
- package/dist/assets/icons/shield.svg +3 -0
- package/dist/components/Errors/403/AccessDenied.tsx +19 -0
- package/dist/components/Errors/403/index.ts +1 -0
- package/dist/components/Errors/i18n/en.json +4 -0
- package/dist/components/Errors/i18n/index.ts +11 -0
- package/dist/components/Errors/i18n/ru.json +4 -0
- package/dist/components/NodesViewer/NodesViewer.js +1 -1
- package/dist/components/QueryResultTable/QueryResultTable.tsx +16 -21
- package/dist/{containers/Storage/StorageFilter/StorageFilter.tsx → components/Search/Search.tsx} +22 -22
- package/dist/components/Search/index.ts +1 -0
- package/dist/containers/App/App.scss +5 -1
- package/dist/containers/Nodes/Nodes.js +6 -1
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +7 -5
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -11
- package/dist/containers/Storage/Pdisk/Pdisk.scss +15 -8
- package/dist/containers/Storage/Pdisk/Pdisk.tsx +22 -14
- package/dist/containers/Storage/Storage.js +39 -50
- package/dist/containers/Storage/StorageGroups/StorageGroups.scss +1 -4
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +27 -2
- package/dist/containers/Storage/StorageGroups/i18n/en.json +2 -1
- package/dist/containers/Storage/StorageGroups/i18n/ru.json +2 -1
- package/dist/containers/Storage/StorageNodes/StorageNodes.scss +14 -12
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -5
- package/dist/containers/Storage/Vdisk/Vdisk.js +36 -23
- package/dist/containers/Storage/Vdisk/Vdisk.scss +6 -0
- package/dist/containers/TabletsFilters/TabletsFilters.js +5 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.scss +6 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +82 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/en.json +6 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/i18n/ru.json +6 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +7 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +29 -11
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -8
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/Details.tsx +55 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +5 -5
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +16 -6
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/{IssueViewer.scss → IssueTree.scss} +3 -54
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTree.tsx +87 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +50 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +25 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/Preview.tsx +13 -16
- package/dist/containers/Tenant/Diagnostics/Healthcheck/{IssuePreview/IssuePreview.tsx → Preview/PreviewItem/PreviewItem.tsx} +6 -8
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/PreviewItem/index.ts +1 -0
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +34 -19
- package/dist/containers/Tenant/Preview/Preview.scss +6 -0
- package/dist/containers/Tenant/QueryEditor/QueryEditor.js +1 -9
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
- package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +1 -1
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +27 -20
- package/dist/containers/Tenant/Tenant.tsx +14 -16
- package/dist/containers/Tenants/Tenants.js +1 -1
- package/dist/store/reducers/describe.ts +71 -0
- package/dist/store/reducers/healthcheckInfo.ts +123 -0
- package/dist/store/reducers/olapStats.js +13 -0
- package/dist/store/reducers/schema.js +43 -1
- package/dist/store/reducers/storage.js +27 -17
- package/dist/store/reducers/tenant.js +3 -1
- package/dist/store/utils.ts +21 -13
- package/dist/styles/mixins.scss +1 -1
- package/dist/types/api/consumers.ts +3 -0
- package/dist/types/api/healthcheck.ts +1 -1
- package/dist/types/api/storage.ts +35 -10
- package/dist/types/store/healthcheck.ts +5 -1
- package/dist/types/store/storage.ts +1 -0
- package/dist/utils/hooks/useAutofetcher.ts +9 -3
- package/package.json +1 -1
- package/dist/containers/Storage/StorageFilter/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuePreview/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/IssuesList.tsx +0 -62
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssuesViewer.js +0 -151
- package/dist/store/reducers/describe.js +0 -45
- package/dist/store/reducers/healthcheckInfo.js +0 -45
|
@@ -4,10 +4,15 @@ import cn from 'bem-cn-lite';
|
|
|
4
4
|
|
|
5
5
|
import {Loader} from '@gravity-ui/uikit';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import {SelfCheckResult} from '../../../../types/api/healthcheck';
|
|
8
|
+
import {
|
|
9
|
+
getHealthcheckInfo,
|
|
10
|
+
selectIssuesTreeById,
|
|
11
|
+
selectIssuesTreesRoots,
|
|
12
|
+
} from '../../../../store/reducers/healthcheckInfo';
|
|
8
13
|
import {useAutofetcher} from '../../../../utils/hooks';
|
|
9
14
|
|
|
10
|
-
import {
|
|
15
|
+
import {Details} from './Details';
|
|
11
16
|
import {Preview} from './Preview';
|
|
12
17
|
|
|
13
18
|
import i18n from './i18n';
|
|
@@ -29,6 +34,11 @@ export const Healthcheck = (props: HealthcheckProps) => {
|
|
|
29
34
|
const dispatch = useDispatch();
|
|
30
35
|
|
|
31
36
|
const {data, loading, wasLoaded, error} = useSelector((state: any) => state.healthcheckInfo);
|
|
37
|
+
const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
|
|
38
|
+
|
|
39
|
+
const issuesTreesRoots = useSelector(selectIssuesTreesRoots);
|
|
40
|
+
const expandedIssueTree = useSelector((state) => selectIssuesTreeById(state, expandedIssueId));
|
|
41
|
+
|
|
32
42
|
const {autorefresh} = useSelector((state: any) => state.schema);
|
|
33
43
|
|
|
34
44
|
const fetchHealthcheck = useCallback(() => {
|
|
@@ -61,15 +71,15 @@ export const Healthcheck = (props: HealthcheckProps) => {
|
|
|
61
71
|
if (data && data['self_check_result']) {
|
|
62
72
|
return preview ? (
|
|
63
73
|
<Preview
|
|
64
|
-
|
|
74
|
+
issuesTrees={issuesTreesRoots}
|
|
75
|
+
selfCheckResult={selfCheckResult}
|
|
65
76
|
loading={loading}
|
|
66
77
|
onShowMore={showMoreHandler}
|
|
67
78
|
onUpdate={fetchHealthcheck}
|
|
68
79
|
/>
|
|
69
80
|
) : (
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
expandedIssueId={expandedIssueId}
|
|
81
|
+
<Details
|
|
82
|
+
issueTree={expandedIssueTree}
|
|
73
83
|
loading={loading}
|
|
74
84
|
onUpdate={fetchHealthcheck}
|
|
75
85
|
/>
|
|
@@ -1,56 +1,5 @@
|
|
|
1
1
|
@import '../../../../../styles/mixins.scss';
|
|
2
2
|
|
|
3
|
-
.issue {
|
|
4
|
-
display: flex;
|
|
5
|
-
justify-content: space-between;
|
|
6
|
-
align-items: center;
|
|
7
|
-
|
|
8
|
-
height: 40px;
|
|
9
|
-
|
|
10
|
-
cursor: pointer;
|
|
11
|
-
|
|
12
|
-
&__field {
|
|
13
|
-
display: flex;
|
|
14
|
-
overflow: hidden;
|
|
15
|
-
|
|
16
|
-
&_status {
|
|
17
|
-
display: flex;
|
|
18
|
-
|
|
19
|
-
white-space: nowrap;
|
|
20
|
-
}
|
|
21
|
-
&_additional {
|
|
22
|
-
width: max-content;
|
|
23
|
-
|
|
24
|
-
cursor: pointer;
|
|
25
|
-
|
|
26
|
-
color: var(--yc-color-text-link);
|
|
27
|
-
|
|
28
|
-
&:hover {
|
|
29
|
-
color: var(--yc-color-text-link-hover);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
&_message {
|
|
33
|
-
overflow: hidden;
|
|
34
|
-
flex-shrink: 0;
|
|
35
|
-
|
|
36
|
-
width: 300px;
|
|
37
|
-
|
|
38
|
-
white-space: normal;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
&__field-tooltip {
|
|
43
|
-
&#{&} {
|
|
44
|
-
min-width: 500px;
|
|
45
|
-
max-width: 500px;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
&__field-label {
|
|
50
|
-
color: var(--yc-color-text-secondary);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
3
|
.indicator {
|
|
55
4
|
width: 12px;
|
|
56
5
|
height: 12px;
|
|
@@ -86,12 +35,12 @@
|
|
|
86
35
|
}
|
|
87
36
|
}
|
|
88
37
|
|
|
89
|
-
.issue-
|
|
38
|
+
.issue-tree {
|
|
90
39
|
display: flex;
|
|
91
40
|
|
|
92
41
|
width: 820px;
|
|
93
42
|
|
|
94
|
-
&
|
|
43
|
+
&__block {
|
|
95
44
|
width: 100%;
|
|
96
45
|
}
|
|
97
46
|
|
|
@@ -163,7 +112,7 @@
|
|
|
163
112
|
padding-left: 0 !important;
|
|
164
113
|
}
|
|
165
114
|
|
|
166
|
-
.issue-
|
|
115
|
+
.issue-tree__info-panel {
|
|
167
116
|
margin-left: $calculated-margin;
|
|
168
117
|
}
|
|
169
118
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {useCallback, useState} from 'react';
|
|
2
|
+
import cn from 'bem-cn-lite';
|
|
3
|
+
import _omit from 'lodash/omit';
|
|
4
|
+
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
import JSONTree from 'react-json-inspector';
|
|
7
|
+
|
|
8
|
+
import {TreeView} from 'ydb-ui-components';
|
|
9
|
+
|
|
10
|
+
import {IIssuesTree} from '../../../../../types/store/healthcheck';
|
|
11
|
+
|
|
12
|
+
import {IssueTreeItem} from './IssueTreeItem';
|
|
13
|
+
|
|
14
|
+
import './IssueTree.scss';
|
|
15
|
+
|
|
16
|
+
const b = cn('issue-tree');
|
|
17
|
+
|
|
18
|
+
interface IssuesViewerProps {
|
|
19
|
+
issueTree: IIssuesTree;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const IssueTree = ({issueTree}: IssuesViewerProps) => {
|
|
23
|
+
const [collapsedIssues, setCollapsedIssues] = useState<Record<string, boolean>>({});
|
|
24
|
+
|
|
25
|
+
const renderTree = useCallback(
|
|
26
|
+
(data: IIssuesTree[]) => {
|
|
27
|
+
return data.map((item) => {
|
|
28
|
+
const {id} = item;
|
|
29
|
+
const {status, message, type, reasonsItems, level, ...rest} = item;
|
|
30
|
+
|
|
31
|
+
const isCollapsed =
|
|
32
|
+
typeof collapsedIssues[id] === 'undefined' || collapsedIssues[id];
|
|
33
|
+
|
|
34
|
+
const toggleCollapsed = () => {
|
|
35
|
+
setCollapsedIssues((collapsedIssues) => ({
|
|
36
|
+
...collapsedIssues,
|
|
37
|
+
[id]: !isCollapsed,
|
|
38
|
+
}));
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<TreeView
|
|
43
|
+
key={id}
|
|
44
|
+
name={<IssueTreeItem status={status} message={message} type={type} />}
|
|
45
|
+
collapsed={isCollapsed}
|
|
46
|
+
hasArrow={true}
|
|
47
|
+
onClick={toggleCollapsed}
|
|
48
|
+
onArrowClick={toggleCollapsed}
|
|
49
|
+
level={level - 1}
|
|
50
|
+
>
|
|
51
|
+
{renderInfoPanel(_omit(rest, ['reason']))}
|
|
52
|
+
{renderTree(reasonsItems || [])}
|
|
53
|
+
</TreeView>
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
},
|
|
57
|
+
[issueTree, collapsedIssues],
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const renderInfoPanel = useCallback(
|
|
61
|
+
(info) => {
|
|
62
|
+
if (!info) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div className={b('info-panel')}>
|
|
68
|
+
<JSONTree
|
|
69
|
+
data={info}
|
|
70
|
+
search={false}
|
|
71
|
+
isExpanded={() => true}
|
|
72
|
+
className={b('inspector')}
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
},
|
|
77
|
+
[issueTree],
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div className={b()}>
|
|
82
|
+
<div className={b('block')}>{renderTree([issueTree])}</div>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export default IssueTree;
|
package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.scss
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
.issue-tree-item {
|
|
2
|
+
display: flex;
|
|
3
|
+
justify-content: space-between;
|
|
4
|
+
align-items: center;
|
|
5
|
+
|
|
6
|
+
height: 40px;
|
|
7
|
+
|
|
8
|
+
cursor: pointer;
|
|
9
|
+
|
|
10
|
+
&__field {
|
|
11
|
+
display: flex;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
|
|
14
|
+
&_status {
|
|
15
|
+
display: flex;
|
|
16
|
+
|
|
17
|
+
white-space: nowrap;
|
|
18
|
+
}
|
|
19
|
+
&_additional {
|
|
20
|
+
width: max-content;
|
|
21
|
+
|
|
22
|
+
cursor: pointer;
|
|
23
|
+
|
|
24
|
+
color: var(--yc-color-text-link);
|
|
25
|
+
|
|
26
|
+
&:hover {
|
|
27
|
+
color: var(--yc-color-text-link-hover);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
&_message {
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
flex-shrink: 0;
|
|
33
|
+
|
|
34
|
+
width: 300px;
|
|
35
|
+
|
|
36
|
+
white-space: normal;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&__field-tooltip {
|
|
41
|
+
&#{&} {
|
|
42
|
+
min-width: 500px;
|
|
43
|
+
max-width: 500px;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
&__field-label {
|
|
48
|
+
color: var(--yc-color-text-secondary);
|
|
49
|
+
}
|
|
50
|
+
}
|
package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import cn from 'bem-cn-lite';
|
|
2
|
+
|
|
3
|
+
import EntityStatus from '../../../../../../components/EntityStatus/EntityStatus';
|
|
4
|
+
|
|
5
|
+
import './IssueTreeItem.scss';
|
|
6
|
+
|
|
7
|
+
const b = cn('issue-tree-item');
|
|
8
|
+
|
|
9
|
+
interface IssueRowProps {
|
|
10
|
+
status: string;
|
|
11
|
+
message: string;
|
|
12
|
+
type: string;
|
|
13
|
+
onClick?: VoidFunction;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const IssueTreeItem = ({status, message, type, onClick}: IssueRowProps) => {
|
|
17
|
+
return (
|
|
18
|
+
<div className={b()} onClick={onClick}>
|
|
19
|
+
<div className={b('field', {status: true})}>
|
|
20
|
+
<EntityStatus mode="icons" status={status} name={type} />
|
|
21
|
+
</div>
|
|
22
|
+
<div className={b('field', {message: true})}>{message}</div>
|
|
23
|
+
</div>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './IssueTreeItem';
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {useMemo} from 'react';
|
|
2
1
|
import cn from 'bem-cn-lite';
|
|
3
2
|
|
|
4
3
|
import {Button, Icon} from '@gravity-ui/uikit';
|
|
@@ -6,34 +5,28 @@ import {Button, Icon} from '@gravity-ui/uikit';
|
|
|
6
5
|
import updateArrow from '../../../../../assets/icons/update-arrow.svg';
|
|
7
6
|
|
|
8
7
|
import {SelfCheckResult} from '../../../../../types/api/healthcheck';
|
|
9
|
-
import type {
|
|
8
|
+
import type {IIssuesTree} from '../../../../../types/store/healthcheck';
|
|
10
9
|
|
|
11
|
-
import {
|
|
10
|
+
import {PreviewItem} from './PreviewItem';
|
|
12
11
|
|
|
13
12
|
import i18n from '../i18n';
|
|
14
13
|
|
|
15
14
|
const b = cn('healthcheck');
|
|
16
15
|
|
|
17
16
|
interface PreviewProps {
|
|
18
|
-
|
|
17
|
+
selfCheckResult: SelfCheckResult;
|
|
18
|
+
issuesTrees?: IIssuesTree[];
|
|
19
19
|
loading?: boolean;
|
|
20
|
-
onUpdate: VoidFunction;
|
|
21
20
|
onShowMore?: (id: string) => void;
|
|
21
|
+
onUpdate: VoidFunction;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export const Preview = (props: PreviewProps) => {
|
|
25
|
-
const {
|
|
25
|
+
const {selfCheckResult, issuesTrees, loading, onShowMore, onUpdate} = props;
|
|
26
26
|
|
|
27
|
-
const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
|
|
28
27
|
const isStatusOK = selfCheckResult === SelfCheckResult.GOOD;
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
const firstLevelIssues = useMemo(
|
|
32
|
-
() => issuesLog?.filter(({level}) => level === 1),
|
|
33
|
-
[issuesLog],
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
if (!data) {
|
|
29
|
+
if (!issuesTrees) {
|
|
37
30
|
return null;
|
|
38
31
|
}
|
|
39
32
|
|
|
@@ -58,8 +51,12 @@ export const Preview = (props: PreviewProps) => {
|
|
|
58
51
|
<div className={b('preview-content')}>
|
|
59
52
|
{isStatusOK
|
|
60
53
|
? i18n('status_message.ok')
|
|
61
|
-
:
|
|
62
|
-
<
|
|
54
|
+
: issuesTrees?.map((issueTree) => (
|
|
55
|
+
<PreviewItem
|
|
56
|
+
key={issueTree.id}
|
|
57
|
+
data={issueTree}
|
|
58
|
+
onShowMore={onShowMore}
|
|
59
|
+
/>
|
|
63
60
|
))}
|
|
64
61
|
</div>
|
|
65
62
|
);
|
|
@@ -2,19 +2,19 @@ import cn from 'bem-cn-lite';
|
|
|
2
2
|
|
|
3
3
|
import {Link, Text} from '@gravity-ui/uikit';
|
|
4
4
|
|
|
5
|
-
import EntityStatus from '
|
|
6
|
-
import {IssueLog} from '
|
|
5
|
+
import EntityStatus from '../../../../../../components/EntityStatus/EntityStatus';
|
|
6
|
+
import {IssueLog} from '../../../../../../types/api/healthcheck';
|
|
7
7
|
|
|
8
|
-
import i18n from '
|
|
8
|
+
import i18n from '../../i18n';
|
|
9
9
|
|
|
10
10
|
const b = cn('healthcheck');
|
|
11
11
|
|
|
12
|
-
interface
|
|
12
|
+
interface PreviewItemProps {
|
|
13
13
|
data?: IssueLog;
|
|
14
14
|
onShowMore?: (id: string) => void;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export const
|
|
17
|
+
export const PreviewItem = (props: PreviewItemProps) => {
|
|
18
18
|
const {data, onShowMore} = props;
|
|
19
19
|
|
|
20
20
|
if (!data) {
|
|
@@ -27,9 +27,7 @@ export const IssuePreview = (props: IssuePreviewProps) => {
|
|
|
27
27
|
<Text as="div" color="secondary" variant="body-2">
|
|
28
28
|
{data.message}
|
|
29
29
|
</Text>
|
|
30
|
-
<Link onClick={() => onShowMore
|
|
31
|
-
{i18n('label.show-details')}
|
|
32
|
-
</Link>
|
|
30
|
+
<Link onClick={() => onShowMore?.(data.id)}>{i18n('label.show-details')}</Link>
|
|
33
31
|
</div>
|
|
34
32
|
);
|
|
35
33
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './PreviewItem';
|
|
@@ -15,9 +15,12 @@ import {
|
|
|
15
15
|
import {EPathType} from '../../../../types/api/schema';
|
|
16
16
|
import {isColumnEntityType, isTableType} from '../../utils/schema';
|
|
17
17
|
//@ts-ignore
|
|
18
|
-
import {getSchema} from '../../../../store/reducers/schema';
|
|
18
|
+
import {getSchema, resetLoadingState} from '../../../../store/reducers/schema';
|
|
19
19
|
//@ts-ignore
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
getOlapStats,
|
|
22
|
+
resetLoadingState as resetOlapLoadingState,
|
|
23
|
+
} from '../../../../store/reducers/olapStats';
|
|
21
24
|
import {useAutofetcher} from '../../../../utils/hooks';
|
|
22
25
|
|
|
23
26
|
import './Overview.scss';
|
|
@@ -64,24 +67,36 @@ function Overview(props: OverviewProps) {
|
|
|
64
67
|
|
|
65
68
|
const {
|
|
66
69
|
currentSchema: currentItem = {},
|
|
67
|
-
loading,
|
|
70
|
+
loading: schemaLoading,
|
|
68
71
|
wasLoaded,
|
|
69
72
|
autorefresh,
|
|
70
73
|
currentSchemaPath,
|
|
71
74
|
} = useSelector((state: any) => state.schema);
|
|
72
75
|
|
|
73
|
-
const {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
const {data: {result: olapStats} = {result: undefined}, loading: olapStatsLoading} =
|
|
77
|
+
useSelector((state: any) => state.olapStats);
|
|
78
|
+
|
|
79
|
+
const loading = schemaLoading || olapStatsLoading;
|
|
76
80
|
|
|
77
|
-
useAutofetcher(
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
useAutofetcher(
|
|
82
|
+
(isBackground) => {
|
|
83
|
+
if (!isBackground) {
|
|
84
|
+
dispatch(resetLoadingState());
|
|
85
|
+
}
|
|
80
86
|
|
|
81
|
-
|
|
82
|
-
dispatch(
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
const schemaPath = currentSchemaPath || tenantName;
|
|
88
|
+
dispatch(getSchema({path: schemaPath}));
|
|
89
|
+
|
|
90
|
+
if (isTableType(type) && isColumnEntityType(type)) {
|
|
91
|
+
if (!isBackground) {
|
|
92
|
+
dispatch(resetOlapLoadingState());
|
|
93
|
+
}
|
|
94
|
+
dispatch(getOlapStats({path: schemaPath}));
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
[currentSchemaPath, dispatch, tenantName, type],
|
|
98
|
+
autorefresh,
|
|
99
|
+
);
|
|
85
100
|
|
|
86
101
|
const tableSchema =
|
|
87
102
|
currentItem?.PathDescription?.Table || currentItem?.PathDescription?.ColumnTableDescription;
|
|
@@ -116,17 +131,17 @@ function Overview(props: OverviewProps) {
|
|
|
116
131
|
[EPathType.EPathTypePersQueueGroup]: () => <PersQueueGroupInfo data={schemaData} />,
|
|
117
132
|
};
|
|
118
133
|
|
|
119
|
-
return (
|
|
120
|
-
|
|
134
|
+
return (
|
|
135
|
+
(type && pathTypeToComponent[type]?.()) || (
|
|
136
|
+
<SchemaInfoViewer fullPath={currentItem.Path} data={schemaData} />
|
|
137
|
+
)
|
|
121
138
|
);
|
|
122
|
-
}
|
|
139
|
+
};
|
|
123
140
|
|
|
124
141
|
return loading && !wasLoaded ? (
|
|
125
142
|
renderLoader()
|
|
126
143
|
) : (
|
|
127
|
-
<div className={props.className}>
|
|
128
|
-
{renderContent()}
|
|
129
|
-
</div>
|
|
144
|
+
<div className={props.className}>{renderContent()}</div>
|
|
130
145
|
);
|
|
131
146
|
}
|
|
132
147
|
|
|
@@ -52,7 +52,13 @@
|
|
|
52
52
|
&__result {
|
|
53
53
|
overflow: auto;
|
|
54
54
|
|
|
55
|
+
// This fixes last row display for ordinary preview (not fullscreen)
|
|
55
56
|
height: calc(100% - 40px);
|
|
56
57
|
padding: 0 10px;
|
|
58
|
+
|
|
59
|
+
// Fix white space footer block for fullscreen preview
|
|
60
|
+
.kv-fullscreen & {
|
|
61
|
+
height: 100%;
|
|
62
|
+
}
|
|
57
63
|
}
|
|
58
64
|
}
|
|
@@ -54,8 +54,6 @@ export const RUN_ACTIONS = [
|
|
|
54
54
|
|
|
55
55
|
const TABLE_SETTINGS = {
|
|
56
56
|
sortable: false,
|
|
57
|
-
dynamicItemSizeGetter: () => 40,
|
|
58
|
-
dynamicRenderType: 'variable',
|
|
59
57
|
};
|
|
60
58
|
|
|
61
59
|
const EDITOR_OPTIONS = {
|
|
@@ -511,13 +509,7 @@ function QueryEditor(props) {
|
|
|
511
509
|
};
|
|
512
510
|
|
|
513
511
|
const renderControls = () => {
|
|
514
|
-
const {
|
|
515
|
-
executeQuery,
|
|
516
|
-
explainQuery,
|
|
517
|
-
savedQueries,
|
|
518
|
-
selectRunAction,
|
|
519
|
-
setSettingValue,
|
|
520
|
-
} = props;
|
|
512
|
+
const {executeQuery, explainQuery, savedQueries, selectRunAction, setSettingValue} = props;
|
|
521
513
|
const {runAction} = executeQuery;
|
|
522
514
|
const runIsDisabled = !executeQuery.input || executeQuery.loading;
|
|
523
515
|
const runText = _.find(RUN_ACTIONS, {value: runAction}).content;
|
|
@@ -3,7 +3,7 @@ import {useDispatch} from 'react-redux';
|
|
|
3
3
|
|
|
4
4
|
import {NavigationTree} from 'ydb-ui-components';
|
|
5
5
|
|
|
6
|
-
import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema';
|
|
6
|
+
import {setCurrentSchemaPath, getSchema, preloadSchema} from '../../../../store/reducers/schema';
|
|
7
7
|
import {getDescribe} from '../../../../store/reducers/describe';
|
|
8
8
|
import {getSchemaAcl} from '../../../../store/reducers/schemaAcl';
|
|
9
9
|
import type {EPathType} from '../../../../types/api/schema';
|
|
@@ -19,28 +19,35 @@ interface SchemaTreeProps {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export function SchemaTree(props: SchemaTreeProps) {
|
|
22
|
-
const {
|
|
23
|
-
rootPath,
|
|
24
|
-
rootName,
|
|
25
|
-
rootType,
|
|
26
|
-
currentPath,
|
|
27
|
-
} = props;
|
|
22
|
+
const {rootPath, rootName, rootType, currentPath} = props;
|
|
28
23
|
|
|
29
24
|
const dispatch = useDispatch();
|
|
30
25
|
|
|
31
|
-
const fetchPath = (path: string) =>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
26
|
+
const fetchPath = (path: string) =>
|
|
27
|
+
window.api
|
|
28
|
+
.getSchema({path}, {concurrentId: `NavigationTree.getSchema|${path}`})
|
|
29
|
+
.then((data) => {
|
|
30
|
+
const {PathDescription: {Children = []} = {}} = data;
|
|
31
|
+
|
|
32
|
+
dispatch(preloadSchema(path, data));
|
|
33
|
+
|
|
34
|
+
return Children.map((childData) => {
|
|
35
|
+
const {Name = '', PathType, PathSubType} = childData;
|
|
36
|
+
|
|
37
|
+
// not full data, but it contains PathType, which ensures seamless switch between nodes
|
|
38
|
+
dispatch(
|
|
39
|
+
preloadSchema(`${path}/${Name}`, {PathDescription: {Self: childData}}),
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
name: Name,
|
|
44
|
+
type: mapPathTypeToNavigationTreeType(PathType, PathSubType),
|
|
45
|
+
// FIXME: should only be explicitly set to true for tables with indexes
|
|
46
|
+
// at the moment of writing there is no property to determine this, fix later
|
|
47
|
+
expandable: true,
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
});
|
|
44
51
|
|
|
45
52
|
const handleActivePathUpdate = (activePath: string) => {
|
|
46
53
|
dispatch(setCurrentSchemaPath(activePath));
|