ydb-embedded-ui 1.13.2 → 1.14.1
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 +40 -0
- package/dist/assets/icons/flask.svg +3 -0
- package/dist/components/InfoViewer/formatters/common.ts +15 -0
- package/dist/components/InfoViewer/formatters/index.ts +2 -0
- package/dist/components/InfoViewer/formatters/schema.ts +43 -0
- package/dist/components/InfoViewer/schemaInfo/CDCStreamInfo.tsx +44 -0
- package/dist/components/InfoViewer/schemaInfo/PersQueueGroupInfo.tsx +34 -0
- package/dist/components/{IndexInfoViewer/IndexInfoViewer.tsx → InfoViewer/schemaInfo/TableIndexInfo.tsx} +7 -18
- package/dist/components/InfoViewer/schemaInfo/index.ts +3 -0
- package/dist/components/InfoViewer/schemaOverview/CDCStreamOverview.tsx +44 -0
- package/dist/components/InfoViewer/schemaOverview/PersQueueGroupOverview.tsx +35 -0
- package/dist/components/InfoViewer/schemaOverview/index.ts +2 -0
- package/dist/components/QueryResultTable/Cell/Cell.tsx +33 -0
- package/dist/components/QueryResultTable/Cell/index.ts +1 -0
- package/dist/components/QueryResultTable/QueryResultTable.scss +11 -0
- package/dist/components/QueryResultTable/QueryResultTable.tsx +115 -0
- package/dist/components/QueryResultTable/i18n/en.json +3 -0
- package/dist/components/QueryResultTable/i18n/index.ts +11 -0
- package/dist/components/QueryResultTable/i18n/ru.json +3 -0
- package/dist/components/QueryResultTable/index.ts +1 -0
- package/dist/containers/App/App.scss +1 -0
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +39 -14
- package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +18 -7
- package/dist/containers/Storage/Pdisk/__tests__/colors.tsx +4 -3
- package/dist/containers/Storage/Vdisk/__tests__/colors.tsx +7 -7
- package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +6 -2
- package/dist/containers/Tenant/Diagnostics/HotKeys/HotKeys.js +1 -1
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +8 -3
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +1 -1
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.js +1 -1
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +36 -10
- package/dist/containers/Tenant/Preview/Preview.js +15 -57
- package/dist/containers/Tenant/Preview/Preview.scss +4 -8
- package/dist/containers/Tenant/QueryEditor/QueryEditor.js +12 -41
- package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +0 -4
- package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.scss +1 -2
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
- package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +1 -1
- package/dist/containers/Tenant/utils/schema.ts +3 -0
- package/dist/containers/Tenant/utils/schemaActions.ts +1 -2
- package/dist/containers/Tenants/Tenants.js +12 -2
- package/dist/containers/UserSettings/UserSettings.tsx +26 -3
- package/dist/services/api.d.ts +19 -2
- package/dist/services/api.js +2 -2
- package/dist/setupTests.js +4 -0
- package/dist/store/reducers/executeQuery.js +4 -9
- package/dist/store/reducers/{preview.js → preview.ts} +22 -18
- package/dist/store/reducers/settings.js +3 -1
- package/dist/store/utils.ts +88 -0
- package/dist/types/api/query.ts +147 -0
- package/dist/types/api/schema.ts +235 -2
- package/dist/types/index.ts +33 -0
- package/dist/types/store/query.ts +9 -0
- package/dist/utils/{constants.js → constants.ts} +11 -6
- package/dist/utils/index.js +0 -24
- package/dist/utils/query.test.ts +189 -0
- package/dist/utils/query.ts +156 -0
- package/dist/utils/tests/providers.tsx +29 -0
- package/package.json +2 -2
- package/dist/store/utils.js +0 -51
@@ -1,7 +1,12 @@
|
|
1
1
|
import React from 'react';
|
2
|
-
import
|
2
|
+
import {useSelector} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
|
5
|
+
import {INVERTED_DISKS_KEY} from '../../../utils/constants';
|
6
|
+
import {getSettingValue} from '../../../store/reducers/settings';
|
7
|
+
|
8
|
+
import InternalLink from '../../../components/InternalLink/InternalLink';
|
9
|
+
|
5
10
|
import './DiskStateProgressBar.scss';
|
6
11
|
|
7
12
|
const b = cn('storage-disk-progress-bar');
|
@@ -26,11 +31,16 @@ function DiskStateProgressBar({
|
|
26
31
|
severity,
|
27
32
|
href,
|
28
33
|
}: DiskStateProgressBarProps) {
|
34
|
+
const inverted = useSelector((state) => getSettingValue(state, INVERTED_DISKS_KEY));
|
35
|
+
|
29
36
|
const renderAllocatedPercent = () => {
|
30
37
|
return (
|
31
38
|
diskAllocatedPercent >= 0 && (
|
32
39
|
<React.Fragment>
|
33
|
-
<div
|
40
|
+
<div
|
41
|
+
className={b('filled')}
|
42
|
+
style={{width: `${inverted ? 100 - diskAllocatedPercent : diskAllocatedPercent}%`}}
|
43
|
+
/>
|
34
44
|
<div className={b('filled-title')}>
|
35
45
|
{`${Math.round(diskAllocatedPercent)}%`}
|
36
46
|
</div>
|
@@ -39,13 +49,14 @@ function DiskStateProgressBar({
|
|
39
49
|
);
|
40
50
|
};
|
41
51
|
|
52
|
+
const mods: Record<string, boolean | undefined> = {inverted};
|
53
|
+
if (severity !== undefined && severity in diskProgressColors) {
|
54
|
+
mods[diskProgressColors[severity].toLocaleLowerCase()] = true;
|
55
|
+
}
|
56
|
+
|
42
57
|
return (
|
43
58
|
<div
|
44
|
-
className={
|
45
|
-
severity !== undefined
|
46
|
-
? b({[diskProgressColors[severity].toLowerCase()]: true})
|
47
|
-
: undefined
|
48
|
-
}
|
59
|
+
className={b(mods)}
|
49
60
|
role="meter"
|
50
61
|
aria-label="Disk allocated space"
|
51
62
|
aria-valuemin={0}
|
@@ -1,13 +1,14 @@
|
|
1
|
-
import {render} from '@testing-library/react'
|
2
1
|
import {MemoryRouter} from 'react-router-dom';
|
3
2
|
|
3
|
+
import {renderWithStore} from '../../../../utils/tests/providers';
|
4
|
+
|
4
5
|
import {TPDiskState} from '../../../../types/api/storage'
|
5
6
|
|
6
7
|
import PDisk from '../Pdisk'
|
7
8
|
|
8
9
|
describe('PDisk state', () => {
|
9
10
|
it('Should determine severity based on State', () => {
|
10
|
-
const {getAllByRole} =
|
11
|
+
const {getAllByRole} = renderWithStore(
|
11
12
|
<MemoryRouter>
|
12
13
|
<PDisk
|
13
14
|
NodeId={1}
|
@@ -26,7 +27,7 @@ describe('PDisk state', () => {
|
|
26
27
|
});
|
27
28
|
|
28
29
|
it('Should display as unavailabe when no State is provided', () => {
|
29
|
-
const {getByRole} =
|
30
|
+
const {getByRole} = renderWithStore(
|
30
31
|
<MemoryRouter>
|
31
32
|
<PDisk NodeId={1} />
|
32
33
|
</MemoryRouter>
|
@@ -1,10 +1,10 @@
|
|
1
|
-
import {
|
1
|
+
import {renderWithStore} from '../../../../utils/tests/providers';
|
2
2
|
|
3
3
|
import VDisk from '../Vdisk'
|
4
4
|
|
5
5
|
describe('VDisk state', () => {
|
6
6
|
it('Should determine severity based on the highest value among VDiskState, DiskSpace and FrontQueues', () => {
|
7
|
-
const {getAllByRole} =
|
7
|
+
const {getAllByRole} = renderWithStore(
|
8
8
|
<>
|
9
9
|
<VDisk
|
10
10
|
VDiskId={{Domain: 1}}
|
@@ -35,7 +35,7 @@ describe('VDisk state', () => {
|
|
35
35
|
});
|
36
36
|
|
37
37
|
it('Should not pick the highest severity based on FrontQueues value', () => {
|
38
|
-
const {getAllByRole} =
|
38
|
+
const {getAllByRole} = renderWithStore(
|
39
39
|
<>
|
40
40
|
<VDisk
|
41
41
|
VDiskId={{Domain: 1}}
|
@@ -59,7 +59,7 @@ describe('VDisk state', () => {
|
|
59
59
|
});
|
60
60
|
|
61
61
|
it('Should display as unavailable when no VDiskState is provided', () => {
|
62
|
-
const {getAllByRole} =
|
62
|
+
const {getAllByRole} = renderWithStore(
|
63
63
|
<>
|
64
64
|
<VDisk VDiskId={{Domain: 1}} />
|
65
65
|
<VDisk VDiskId={{Domain: 2}} VDiskState="OK" />
|
@@ -86,7 +86,7 @@ describe('VDisk state', () => {
|
|
86
86
|
});
|
87
87
|
|
88
88
|
it('Should display replicating VDisks in OK state with a distinct color', () => {
|
89
|
-
const {getAllByRole} =
|
89
|
+
const {getAllByRole} = renderWithStore(
|
90
90
|
<>
|
91
91
|
<VDisk
|
92
92
|
VDiskId={{Domain: 1}}
|
@@ -108,7 +108,7 @@ describe('VDisk state', () => {
|
|
108
108
|
});
|
109
109
|
|
110
110
|
it('Should display replicating VDisks in a not-OK state with a regular color', () => {
|
111
|
-
const {getAllByRole} =
|
111
|
+
const {getAllByRole} = renderWithStore(
|
112
112
|
<>
|
113
113
|
<VDisk
|
114
114
|
VDiskId={{Domain: 1}}
|
@@ -130,7 +130,7 @@ describe('VDisk state', () => {
|
|
130
130
|
});
|
131
131
|
|
132
132
|
it('Should always display donor VDisks with a regular color', () => {
|
133
|
-
const {getAllByRole} =
|
133
|
+
const {getAllByRole} = renderWithStore(
|
134
134
|
<>
|
135
135
|
<VDisk
|
136
136
|
VDiskId={{Domain: 1}}
|
@@ -20,7 +20,7 @@ type Page = {
|
|
20
20
|
|
21
21
|
const overview = {
|
22
22
|
id: GeneralPagesIds.overview,
|
23
|
-
title: '
|
23
|
+
title: 'Info',
|
24
24
|
};
|
25
25
|
|
26
26
|
const topQueries = {
|
@@ -81,6 +81,8 @@ export const TABLE_PAGES = [overview, topShards, graph, tablets, hotKeys, descri
|
|
81
81
|
|
82
82
|
export const DIR_PAGES = [overview, topShards, describe];
|
83
83
|
|
84
|
+
export const TOPIC_PAGES = [overview, describe];
|
85
|
+
|
84
86
|
// verbose mapping to guarantee correct tabs for new path types
|
85
87
|
// TS will error when a new type is added but not mapped here
|
86
88
|
const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
|
@@ -95,7 +97,9 @@ const pathTypeToPages: Record<EPathType, Page[] | undefined> = {
|
|
95
97
|
|
96
98
|
[EPathType.EPathTypeDir]: DIR_PAGES,
|
97
99
|
[EPathType.EPathTypeTableIndex]: DIR_PAGES,
|
98
|
-
|
100
|
+
|
101
|
+
[EPathType.EPathTypeCdcStream]: TOPIC_PAGES,
|
102
|
+
[EPathType.EPathTypePersQueueGroup]: TOPIC_PAGES,
|
99
103
|
};
|
100
104
|
|
101
105
|
export const getPagesByType = (type?: EPathType) =>
|
@@ -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 {prepareQueryError} from '../../../../utils';
|
11
|
+
import {prepareQueryError} from '../../../../utils/query';
|
12
12
|
|
13
13
|
import {isColumnEntityType, isTableType} from '../../utils/schema';
|
14
14
|
|
@@ -6,7 +6,11 @@ import {Loader} from '@yandex-cloud/uikit';
|
|
6
6
|
|
7
7
|
//@ts-ignore
|
8
8
|
import SchemaInfoViewer from '../../Schema/SchemaInfoViewer/SchemaInfoViewer';
|
9
|
-
import {
|
9
|
+
import {
|
10
|
+
CDCStreamInfo,
|
11
|
+
TableIndexInfo,
|
12
|
+
PersQueueGroupInfo,
|
13
|
+
} from '../../../../components/InfoViewer/schemaInfo';
|
10
14
|
|
11
15
|
import {EPathType} from '../../../../types/api/schema';
|
12
16
|
import {isColumnEntityType, isTableType} from '../../utils/schema';
|
@@ -121,11 +125,12 @@ function Overview(props: OverviewProps) {
|
|
121
125
|
[EPathType.EPathTypeDir]: undefined,
|
122
126
|
[EPathType.EPathTypeTable]: undefined,
|
123
127
|
[EPathType.EPathTypeSubDomain]: undefined,
|
124
|
-
[EPathType.EPathTypeTableIndex]: () => <
|
128
|
+
[EPathType.EPathTypeTableIndex]: () => <TableIndexInfo data={schemaData} />,
|
125
129
|
[EPathType.EPathTypeExtSubDomain]: undefined,
|
126
130
|
[EPathType.EPathTypeColumnStore]: undefined,
|
127
131
|
[EPathType.EPathTypeColumnTable]: undefined,
|
128
|
-
[EPathType.EPathTypeCdcStream]:
|
132
|
+
[EPathType.EPathTypeCdcStream]: () => <CDCStreamInfo data={schemaData} />,
|
133
|
+
[EPathType.EPathTypePersQueueGroup]: () => <PersQueueGroupInfo data={schemaData} />,
|
129
134
|
};
|
130
135
|
|
131
136
|
return (props.type && pathTypeToComponent[props.type]?.()) || (
|
@@ -13,7 +13,7 @@ import {isColumnEntityType} from '../../utils/schema';
|
|
13
13
|
|
14
14
|
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
|
15
15
|
import {TenantGeneralTabsIds} from '../../TenantPages';
|
16
|
-
import {prepareQueryError} from '../../../../utils';
|
16
|
+
import {prepareQueryError} from '../../../../utils/query';
|
17
17
|
|
18
18
|
import './TopQueries.scss';
|
19
19
|
|
@@ -13,7 +13,7 @@ import {AutoFetcher} from '../../../../utils/autofetcher';
|
|
13
13
|
import HistoryContext from '../../../../contexts/HistoryContext';
|
14
14
|
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
|
15
15
|
import {isColumnEntityType} from '../../utils/schema';
|
16
|
-
import {prepareQueryError} from '../../../../utils';
|
16
|
+
import {prepareQueryError} from '../../../../utils/query';
|
17
17
|
import {i18n} from '../../../../utils/i18n';
|
18
18
|
|
19
19
|
import './TopShards.scss';
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, {useEffect, useReducer} from 'react';
|
1
|
+
import React, {ReactNode, useEffect, useReducer} from 'react';
|
2
2
|
import {useDispatch, useSelector} from 'react-redux';
|
3
3
|
import {Link} from 'react-router-dom';
|
4
4
|
import cn from 'bem-cn-lite';
|
@@ -14,9 +14,13 @@ import Acl from '../Acl/Acl';
|
|
14
14
|
import SchemaViewer from '../Schema/SchemaViewer/SchemaViewer';
|
15
15
|
import CopyToClipboard from '../../../components/CopyToClipboard/CopyToClipboard';
|
16
16
|
import InfoViewer from '../../../components/InfoViewer/InfoViewer';
|
17
|
+
import {
|
18
|
+
CDCStreamOverview,
|
19
|
+
PersQueueGroupOverview,
|
20
|
+
} from '../../../components/InfoViewer/schemaOverview';
|
17
21
|
import Icon from '../../../components/Icon/Icon';
|
18
22
|
|
19
|
-
import
|
23
|
+
import {EPathSubType, EPathType, TDirEntry} from '../../../types/api/schema';
|
20
24
|
import {isColumnEntityType, isIndexTable, isTableType} from '../utils/schema';
|
21
25
|
|
22
26
|
import {
|
@@ -100,8 +104,8 @@ function ObjectSummary(props: ObjectSummaryProps) {
|
|
100
104
|
});
|
101
105
|
|
102
106
|
const {name: tenantName, info: infoTab} = queryParams;
|
103
|
-
const pathData = _.get(data[tenantName as string], 'PathDescription.Self');
|
104
|
-
const currentSchemaData = _.get(data[currentSchemaPath], 'PathDescription.Self');
|
107
|
+
const pathData: TDirEntry | undefined = _.get(data[tenantName as string], 'PathDescription.Self');
|
108
|
+
const currentSchemaData: TDirEntry | undefined = _.get(data[currentSchemaPath], 'PathDescription.Self');
|
105
109
|
|
106
110
|
const tableSchema =
|
107
111
|
currentItem?.PathDescription?.Table || currentItem?.PathDescription?.ColumnTableDescription;
|
@@ -151,14 +155,36 @@ function ObjectSummary(props: ObjectSummaryProps) {
|
|
151
155
|
};
|
152
156
|
|
153
157
|
const renderObjectOverview = () => {
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
+
// verbose mapping to guarantee a correct render for new path types
|
159
|
+
// TS will error when a new type is added but not mapped here
|
160
|
+
const pathTypeToComponent: Record<EPathType, (() => ReactNode) | undefined> = {
|
161
|
+
[EPathType.EPathTypeInvalid]: undefined,
|
162
|
+
[EPathType.EPathTypeDir]: undefined,
|
163
|
+
[EPathType.EPathTypeTable]: undefined,
|
164
|
+
[EPathType.EPathTypeSubDomain]: undefined,
|
165
|
+
[EPathType.EPathTypeTableIndex]: undefined,
|
166
|
+
[EPathType.EPathTypeExtSubDomain]: undefined,
|
167
|
+
[EPathType.EPathTypeColumnStore]: undefined,
|
168
|
+
[EPathType.EPathTypeColumnTable]: undefined,
|
169
|
+
[EPathType.EPathTypeCdcStream]: () => <CDCStreamOverview data={data[currentSchemaPath]} />,
|
170
|
+
[EPathType.EPathTypePersQueueGroup]: () => <PersQueueGroupOverview data={data[currentSchemaPath]} />,
|
171
|
+
};
|
172
|
+
|
173
|
+
let component = currentSchemaData?.PathType && pathTypeToComponent[currentSchemaData.PathType]?.();
|
174
|
+
|
175
|
+
if (!component) {
|
176
|
+
const startTimeInMilliseconds = Number(currentSchemaData?.CreateStep);
|
177
|
+
let createTime = '';
|
178
|
+
if (startTimeInMilliseconds) {
|
179
|
+
createTime = new Date(startTimeInMilliseconds).toUTCString();
|
180
|
+
}
|
181
|
+
|
182
|
+
component = <InfoViewer info={[{label: 'Create time', value: createTime}]} />;
|
158
183
|
}
|
184
|
+
|
159
185
|
return (
|
160
186
|
<div className={b('overview-wrapper')}>
|
161
|
-
|
187
|
+
{component}
|
162
188
|
</div>
|
163
189
|
);
|
164
190
|
};
|
@@ -203,7 +229,7 @@ function ObjectSummary(props: ObjectSummaryProps) {
|
|
203
229
|
rootPath={tenantName as string}
|
204
230
|
// for the root pathData.Name contains the same string as tenantName,
|
205
231
|
// but without the leading slash
|
206
|
-
rootName={pathData
|
232
|
+
rootName={pathData.Name || String(tenantName)}
|
207
233
|
rootType={pathData.PathType}
|
208
234
|
currentPath={currentSchemaPath}
|
209
235
|
/>
|
@@ -3,30 +3,22 @@ import PropTypes from 'prop-types';
|
|
3
3
|
import {connect} from 'react-redux';
|
4
4
|
import cn from 'bem-cn-lite';
|
5
5
|
|
6
|
-
import DataTable from '@yandex-cloud/react-data-table';
|
7
6
|
import {Loader, Button} from '@yandex-cloud/uikit';
|
8
7
|
|
9
8
|
import Icon from '../../../components/Icon/Icon';
|
10
9
|
import Fullscreen from '../../../components/Fullscreen/Fullscreen';
|
10
|
+
import {QueryResultTable} from '../../../components/QueryResultTable';
|
11
11
|
|
12
12
|
import {sendQuery, setQueryOptions} from '../../../store/reducers/preview';
|
13
|
-
import {
|
14
|
-
import {prepareQueryError, prepareQueryResponse} from '../../../utils/index';
|
15
|
-
import {isNumeric} from '../../../utils/utils';
|
13
|
+
import {prepareQueryError} from '../../../utils/query';
|
16
14
|
|
17
15
|
import {isTableType} from '../utils/schema';
|
18
16
|
import {AutoFetcher} from '../../../utils/autofetcher';
|
19
17
|
import EnableFullscreenButton from '../../../components/EnableFullscreenButton/EnableFullscreenButton';
|
20
|
-
import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
|
21
18
|
import {setShowPreview} from '../../../store/reducers/schema';
|
22
19
|
|
23
20
|
import './Preview.scss';
|
24
21
|
|
25
|
-
const TABLE_SETTINGS = {
|
26
|
-
...DEFAULT_TABLE_SETTINGS,
|
27
|
-
stripedRows: true,
|
28
|
-
};
|
29
|
-
|
30
22
|
const b = cn('kv-preview');
|
31
23
|
|
32
24
|
class Preview extends React.Component {
|
@@ -38,8 +30,6 @@ class Preview extends React.Component {
|
|
38
30
|
data: PropTypes.array,
|
39
31
|
loading: PropTypes.bool,
|
40
32
|
type: PropTypes.string,
|
41
|
-
showTooltip: PropTypes.func,
|
42
|
-
hideTooltip: PropTypes.func,
|
43
33
|
partCount: PropTypes.string,
|
44
34
|
};
|
45
35
|
|
@@ -55,11 +45,10 @@ class Preview extends React.Component {
|
|
55
45
|
}
|
56
46
|
|
57
47
|
componentDidUpdate(prevProps) {
|
58
|
-
const {table,
|
48
|
+
const {table, autorefresh, setQueryOptions} = this.props;
|
59
49
|
|
60
50
|
if (prevProps.table !== table) {
|
61
51
|
this.sendQueryForPreview();
|
62
|
-
hideTooltip();
|
63
52
|
setQueryOptions({
|
64
53
|
wasLoaded: false,
|
65
54
|
data: undefined,
|
@@ -121,41 +110,8 @@ class Preview extends React.Component {
|
|
121
110
|
);
|
122
111
|
};
|
123
112
|
|
124
|
-
renderTable = () => {
|
125
|
-
const {data, showTooltip} = this.props;
|
126
|
-
|
127
|
-
let columns = [];
|
128
|
-
if (data && data.length > 0) {
|
129
|
-
columns = Object.keys(data[0]).map((key) => ({
|
130
|
-
name: key,
|
131
|
-
align: isNumeric(data[0][key]) ? DataTable.RIGHT : DataTable.LEFT,
|
132
|
-
sortAccessor: (row) => isNumeric(row[key]) ? Number(row[key]) : row[key],
|
133
|
-
render: ({value}) => {
|
134
|
-
return (
|
135
|
-
<span
|
136
|
-
className={b('cell')}
|
137
|
-
onClick={(e) => showTooltip(e.target, value, 'cell')}
|
138
|
-
>
|
139
|
-
{value}
|
140
|
-
</span>
|
141
|
-
);
|
142
|
-
},
|
143
|
-
}));
|
144
|
-
}
|
145
|
-
|
146
|
-
const preparedData = prepareQueryResponse(data);
|
147
|
-
|
148
|
-
return <DataTable columns={columns} data={preparedData} settings={TABLE_SETTINGS} />;
|
149
|
-
};
|
150
|
-
|
151
113
|
render() {
|
152
|
-
const {error, loading, data
|
153
|
-
|
154
|
-
let message;
|
155
|
-
|
156
|
-
if (!isTableType(type)) {
|
157
|
-
message = <div className={b('message-container')}>Not available</div>;
|
158
|
-
}
|
114
|
+
const {error, loading, data, type, wasLoaded, isFullscreen} = this.props;
|
159
115
|
|
160
116
|
if (loading && !wasLoaded) {
|
161
117
|
return (
|
@@ -165,15 +121,19 @@ class Preview extends React.Component {
|
|
165
121
|
);
|
166
122
|
}
|
167
123
|
|
168
|
-
|
169
|
-
message = <div className={b('message-container')}>{prepareQueryError(error)}</div>;
|
170
|
-
}
|
124
|
+
let message;
|
171
125
|
|
172
|
-
if (!
|
173
|
-
message = <div className={b('message-container')}>
|
126
|
+
if (!isTableType(type)) {
|
127
|
+
message = <div className={b('message-container')}>Not available</div>;
|
128
|
+
} else if (error) {
|
129
|
+
message = <div className={b('message-container')}>{prepareQueryError(error)}</div>;
|
174
130
|
}
|
175
131
|
|
176
|
-
const content = message ??
|
132
|
+
const content = message ?? (
|
133
|
+
<div className={b('result')}>
|
134
|
+
<QueryResultTable data={data.result} columns={data.columns} />
|
135
|
+
</div>
|
136
|
+
);
|
177
137
|
|
178
138
|
return (
|
179
139
|
<div className={b()}>
|
@@ -185,7 +145,7 @@ class Preview extends React.Component {
|
|
185
145
|
}
|
186
146
|
|
187
147
|
const mapStateToProps = (state) => {
|
188
|
-
const {data =
|
148
|
+
const {data = {}, loading, error, wasLoaded} = state.preview;
|
189
149
|
const {autorefresh, currentSchemaPath} = state.schema;
|
190
150
|
|
191
151
|
return {
|
@@ -201,8 +161,6 @@ const mapStateToProps = (state) => {
|
|
201
161
|
|
202
162
|
const mapDispatchToProps = {
|
203
163
|
sendQuery,
|
204
|
-
showTooltip,
|
205
|
-
hideTooltip,
|
206
164
|
setQueryOptions,
|
207
165
|
setShowPreview,
|
208
166
|
};
|
@@ -16,8 +16,8 @@
|
|
16
16
|
justify-content: space-between;
|
17
17
|
align-items: center;
|
18
18
|
|
19
|
-
height:
|
20
|
-
padding: 0
|
19
|
+
height: 53px;
|
20
|
+
padding: 0 20px;
|
21
21
|
|
22
22
|
border-bottom: 1px solid var(--yc-color-line-generic);
|
23
23
|
background-color: var(--yc-color-base-background);
|
@@ -38,7 +38,7 @@
|
|
38
38
|
gap: 5px;
|
39
39
|
}
|
40
40
|
&__message-container {
|
41
|
-
padding: 15px
|
41
|
+
padding: 15px 20px;
|
42
42
|
}
|
43
43
|
|
44
44
|
&__loader-container {
|
@@ -49,14 +49,10 @@
|
|
49
49
|
height: 100%;
|
50
50
|
}
|
51
51
|
|
52
|
-
&__cell {
|
53
|
-
@include cell-container;
|
54
|
-
}
|
55
|
-
|
56
52
|
&__result {
|
57
53
|
overflow: auto;
|
58
54
|
|
59
55
|
height: calc(100% - 40px);
|
60
|
-
padding: 0
|
56
|
+
padding: 0 10px;
|
61
57
|
}
|
62
58
|
}
|
@@ -4,9 +4,10 @@ import {connect} from 'react-redux';
|
|
4
4
|
import cn from 'bem-cn-lite';
|
5
5
|
import _ from 'lodash';
|
6
6
|
import MonacoEditor from 'react-monaco-editor';
|
7
|
-
import DataTable from '@yandex-cloud/react-data-table';
|
8
7
|
import {Button, DropdownMenu} from '@yandex-cloud/uikit';
|
8
|
+
|
9
9
|
import SplitPane from '../../../components/SplitPane';
|
10
|
+
import {QueryResultTable} from '../../../components/QueryResultTable';
|
10
11
|
|
11
12
|
import SaveQuery from './SaveQuery/SaveQuery';
|
12
13
|
import SavedQueries from './SavedQueries/SavedQueries';
|
@@ -26,16 +27,13 @@ import {
|
|
26
27
|
setMonacoHotKey,
|
27
28
|
} from '../../../store/reducers/executeQuery';
|
28
29
|
import {getExplainQuery, getExplainQueryAst} from '../../../store/reducers/explainQuery';
|
29
|
-
import {showTooltip} from '../../../store/reducers/tooltip';
|
30
30
|
import {getSettingValue, setSettingValue} from '../../../store/reducers/settings';
|
31
31
|
import {
|
32
32
|
DEFAULT_IS_QUERY_RESULT_COLLAPSED,
|
33
33
|
DEFAULT_SIZE_RESULT_PANE_KEY,
|
34
|
-
DEFAULT_TABLE_SETTINGS,
|
35
34
|
SAVED_QUERIES_KEY,
|
36
35
|
QUERY_INITIAL_RUN_ACTION_KEY,
|
37
36
|
} from '../../../utils/constants';
|
38
|
-
import {prepareQueryResponse} from '../../../utils/index';
|
39
37
|
|
40
38
|
import {parseJson} from '../../../utils/utils';
|
41
39
|
|
@@ -55,11 +53,9 @@ export const RUN_ACTIONS = [
|
|
55
53
|
];
|
56
54
|
|
57
55
|
const TABLE_SETTINGS = {
|
58
|
-
...DEFAULT_TABLE_SETTINGS,
|
59
56
|
sortable: false,
|
60
57
|
dynamicItemSizeGetter: () => 40,
|
61
58
|
dynamicRenderType: 'variable',
|
62
|
-
stripedRows: true,
|
63
59
|
};
|
64
60
|
|
65
61
|
const EDITOR_OPTIONS = {
|
@@ -84,7 +80,6 @@ const propTypes = {
|
|
84
80
|
response: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]),
|
85
81
|
executeQuery: PropTypes.object,
|
86
82
|
explainQuery: PropTypes.object,
|
87
|
-
showTooltip: PropTypes.func,
|
88
83
|
setMonacoHotKey: PropTypes.func,
|
89
84
|
theme: PropTypes.string,
|
90
85
|
type: PropTypes.string,
|
@@ -306,40 +301,17 @@ function QueryEditor(props) {
|
|
306
301
|
const renderExecuteQuery = () => {
|
307
302
|
const {
|
308
303
|
executeQuery: {data, error, stats},
|
309
|
-
showTooltip,
|
310
304
|
} = props;
|
311
305
|
|
312
306
|
let content;
|
313
307
|
if (data) {
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
className={b('cell')}
|
322
|
-
onClick={(e) => showTooltip(e.target, value, 'cell')}
|
323
|
-
>
|
324
|
-
{value}
|
325
|
-
</span>
|
326
|
-
);
|
327
|
-
},
|
328
|
-
}));
|
329
|
-
const preparedData = prepareQueryResponse(data);
|
330
|
-
|
331
|
-
content = columns.length ? (
|
332
|
-
<DataTable
|
333
|
-
columns={columns}
|
334
|
-
data={preparedData}
|
335
|
-
settings={TABLE_SETTINGS}
|
336
|
-
theme="yandex-cloud"
|
337
|
-
rowKey={(_, index) => index}
|
338
|
-
/>
|
339
|
-
) : (
|
340
|
-
<div>{data}</div>
|
341
|
-
);
|
342
|
-
}
|
308
|
+
content = (
|
309
|
+
<QueryResultTable
|
310
|
+
data={data.result}
|
311
|
+
columns={data.columns}
|
312
|
+
settings={TABLE_SETTINGS}
|
313
|
+
/>
|
314
|
+
);
|
343
315
|
}
|
344
316
|
const textResults = getPreparedResult();
|
345
317
|
const disabled = !textResults.length || resultType !== RESULT_TYPES.EXECUTE;
|
@@ -469,12 +441,12 @@ function QueryEditor(props) {
|
|
469
441
|
const columnDivider = '\t';
|
470
442
|
const rowDivider = '\n';
|
471
443
|
|
472
|
-
if (!data?.length) {
|
444
|
+
if (!data?.result?.length) {
|
473
445
|
return '';
|
474
446
|
}
|
475
447
|
|
476
|
-
const columnHeaders = Object.keys(data[0]);
|
477
|
-
const rows = [columnHeaders].concat(data);
|
448
|
+
const columnHeaders = Object.keys(data.result[0]);
|
449
|
+
const rows = [columnHeaders].concat(data.result);
|
478
450
|
|
479
451
|
return rows
|
480
452
|
.map((item) => {
|
@@ -675,7 +647,6 @@ const mapDispatchToProps = {
|
|
675
647
|
saveQueryToHistory,
|
676
648
|
goToPreviousQuery,
|
677
649
|
goToNextQuery,
|
678
|
-
showTooltip,
|
679
650
|
getExplainQuery,
|
680
651
|
getExplainQueryAst,
|
681
652
|
setSettingValue,
|
@@ -29,6 +29,7 @@ const pathTypeToNodeType: Record<EPathType, NavigationTreeNodeType | undefined>
|
|
29
29
|
[EPathType.EPathTypeColumnTable]: 'column_table',
|
30
30
|
|
31
31
|
[EPathType.EPathTypeCdcStream]: 'topic',
|
32
|
+
[EPathType.EPathTypePersQueueGroup]: 'topic',
|
32
33
|
};
|
33
34
|
|
34
35
|
export const mapPathTypeToNavigationTreeType = (
|
@@ -51,6 +52,7 @@ const pathTypeToIsTable: Record<EPathType, boolean> = {
|
|
51
52
|
[EPathType.EPathTypeExtSubDomain]: false,
|
52
53
|
[EPathType.EPathTypeColumnStore]: false,
|
53
54
|
[EPathType.EPathTypeCdcStream]: false,
|
55
|
+
[EPathType.EPathTypePersQueueGroup]: false,
|
54
56
|
};
|
55
57
|
|
56
58
|
export const isTableType = (pathType?: EPathType) =>
|
@@ -82,6 +84,7 @@ const pathTypeToIsColumn: Record<EPathType, boolean> = {
|
|
82
84
|
[EPathType.EPathTypeTableIndex]: false,
|
83
85
|
[EPathType.EPathTypeExtSubDomain]: false,
|
84
86
|
[EPathType.EPathTypeCdcStream]: false,
|
87
|
+
[EPathType.EPathTypePersQueueGroup]: false,
|
85
88
|
};
|
86
89
|
|
87
90
|
export const isColumnEntityType = (type?: EPathType) =>
|