ydb-embedded-ui 2.4.1 → 2.4.3
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 +15 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +3 -3
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +8 -6
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +4 -3
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +45 -24
- package/dist/containers/Tenant/utils/schema.ts +2 -3
- package/dist/store/getUrlData.ts +27 -0
- package/dist/store/index.js +11 -35
- package/dist/store/reducers/describe.ts +27 -13
- package/dist/store/reducers/header.ts +4 -1
- package/dist/store/reducers/healthcheckInfo.ts +27 -20
- package/dist/store/reducers/{index.js → index.ts} +7 -5
- package/dist/store/reducers/preview.ts +2 -2
- package/dist/store/reducers/saveQuery.ts +6 -4
- package/dist/store/reducers/singleClusterMode.ts +5 -0
- package/dist/types/api/error.ts +4 -0
- package/dist/types/api/query.ts +22 -28
- package/dist/types/api/schema.ts +163 -9
- package/dist/types/store/describe.ts +14 -0
- package/dist/types/store/healthcheck.ts +12 -0
- package/dist/types/window.d.ts +7 -0
- package/dist/utils/hooks/index.ts +1 -0
- package/dist/utils/hooks/useTypedSelector.ts +5 -0
- package/dist/utils/prepareQueryExplain.ts +41 -6
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [2.4.3](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.2...v2.4.3) (2022-11-14)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* fix app crash on ColumnTable path type ([a1aefa8](https://github.com/ydb-platform/ydb-embedded-ui/commit/a1aefa876600b1b459bf3024f0704883431df5a2))
|
9
|
+
* **schema:** add types for ColumnTable and ColumnStore ([dc13307](https://github.com/ydb-platform/ydb-embedded-ui/commit/dc13307dcea801c05863b7dd5ee19f01aa074c85))
|
10
|
+
|
11
|
+
## [2.4.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.1...v2.4.2) (2022-11-09)
|
12
|
+
|
13
|
+
|
14
|
+
### Bug Fixes
|
15
|
+
|
16
|
+
* **QueryExplain:** apply all node types ([06d26de](https://github.com/ydb-platform/ydb-embedded-ui/commit/06d26def15496f8e2de00d941b39bf6a68382f14))
|
17
|
+
|
3
18
|
## [2.4.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.0...v2.4.1) (2022-11-01)
|
4
19
|
|
5
20
|
|
@@ -1,11 +1,11 @@
|
|
1
1
|
import {useEffect, useState} from 'react';
|
2
|
-
import {useDispatch
|
2
|
+
import {useDispatch} from 'react-redux';
|
3
3
|
import block from 'bem-cn-lite';
|
4
4
|
|
5
5
|
import DataTable, {Column} from '@yandex-cloud/react-data-table';
|
6
6
|
|
7
7
|
import {DEFAULT_TABLE_SETTINGS} from '../../../../utils/constants';
|
8
|
-
import {useAutofetcher} from '../../../../utils/hooks';
|
8
|
+
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
9
9
|
import {Search} from '../../../../components/Search';
|
10
10
|
import {getDescribe, selectConsumers} from '../../../../store/reducers/describe';
|
11
11
|
|
@@ -28,7 +28,7 @@ export const Consumers = ({path}: ConsumersProps) => {
|
|
28
28
|
|
29
29
|
useAutofetcher(fetchData, [path]);
|
30
30
|
|
31
|
-
const consumers =
|
31
|
+
const consumers = useTypedSelector((state) => selectConsumers(state, path));
|
32
32
|
|
33
33
|
const [consumersToRender, setConsumersToRender] = useState(consumers);
|
34
34
|
|
@@ -1,16 +1,16 @@
|
|
1
1
|
import {useCallback} from 'react';
|
2
|
-
import {useDispatch
|
2
|
+
import {useDispatch} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
|
5
5
|
import {Loader} from '@gravity-ui/uikit';
|
6
6
|
|
7
7
|
import {SelfCheckResult} from '../../../../types/api/healthcheck';
|
8
|
+
import {useTypedSelector, useAutofetcher} from '../../../../utils/hooks';
|
8
9
|
import {
|
9
10
|
getHealthcheckInfo,
|
10
11
|
selectIssuesTreeById,
|
11
12
|
selectIssuesTreesRoots,
|
12
13
|
} from '../../../../store/reducers/healthcheckInfo';
|
13
|
-
import {useAutofetcher} from '../../../../utils/hooks';
|
14
14
|
|
15
15
|
import {Details} from './Details';
|
16
16
|
import {Preview} from './Preview';
|
@@ -33,13 +33,15 @@ export const Healthcheck = (props: HealthcheckProps) => {
|
|
33
33
|
|
34
34
|
const dispatch = useDispatch();
|
35
35
|
|
36
|
-
const {data, loading, wasLoaded, error} =
|
36
|
+
const {data, loading, wasLoaded, error} = useTypedSelector((state) => state.healthcheckInfo);
|
37
37
|
const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
|
38
38
|
|
39
|
-
const issuesTreesRoots =
|
40
|
-
const expandedIssueTree =
|
39
|
+
const issuesTreesRoots = useTypedSelector(selectIssuesTreesRoots);
|
40
|
+
const expandedIssueTree = useTypedSelector((state) =>
|
41
|
+
selectIssuesTreeById(state, expandedIssueId),
|
42
|
+
);
|
41
43
|
|
42
|
-
const {autorefresh} =
|
44
|
+
const {autorefresh} = useTypedSelector((state) => state.schema);
|
43
45
|
|
44
46
|
const fetchHealthcheck = useCallback(() => {
|
45
47
|
dispatch(getHealthcheckInfo(tenant));
|
@@ -12,7 +12,7 @@ import {
|
|
12
12
|
PersQueueGroupInfo,
|
13
13
|
} from '../../../../components/InfoViewer/schemaInfo';
|
14
14
|
|
15
|
-
import {EPathType} from '../../../../types/api/schema';
|
15
|
+
import {EPathType, TColumnTableDescription} from '../../../../types/api/schema';
|
16
16
|
import {isColumnEntityType, isTableType} from '../../utils/schema';
|
17
17
|
//@ts-ignore
|
18
18
|
import {getSchema, resetLoadingState} from '../../../../store/reducers/schema';
|
@@ -25,7 +25,7 @@ import {useAutofetcher} from '../../../../utils/hooks';
|
|
25
25
|
|
26
26
|
import './Overview.scss';
|
27
27
|
|
28
|
-
function prepareOlapTableGeneral(tableData:
|
28
|
+
function prepareOlapTableGeneral(tableData: TColumnTableDescription = {}, olapStats?: any[]) {
|
29
29
|
const {ColumnShardCount} = tableData;
|
30
30
|
const Bytes = olapStats?.reduce((acc, el) => {
|
31
31
|
acc += parseInt(el.Bytes) || 0;
|
@@ -103,7 +103,8 @@ function Overview(props: OverviewProps) {
|
|
103
103
|
|
104
104
|
const schemaData = useMemo(() => {
|
105
105
|
return isTableType(type) && isColumnEntityType(type)
|
106
|
-
?
|
106
|
+
? // process data for ColumnTable
|
107
|
+
prepareOlapTableGeneral(tableSchema, olapStats)
|
107
108
|
: currentItem;
|
108
109
|
}, [type, tableSchema, olapStats, currentItem]);
|
109
110
|
|
@@ -20,7 +20,12 @@ import {
|
|
20
20
|
} from '../../../components/InfoViewer/schemaOverview';
|
21
21
|
import Icon from '../../../components/Icon/Icon';
|
22
22
|
|
23
|
-
import {
|
23
|
+
import {
|
24
|
+
EPathSubType,
|
25
|
+
EPathType,
|
26
|
+
TColumnTableDescription,
|
27
|
+
TDirEntry,
|
28
|
+
} from '../../../types/api/schema';
|
24
29
|
import {isColumnEntityType, isIndexTable, isTableType} from '../utils/schema';
|
25
30
|
|
26
31
|
import {
|
@@ -57,19 +62,26 @@ const initialTenantCommonInfoState = {
|
|
57
62
|
collapsed: getInitialIsSummaryCollapsed(),
|
58
63
|
};
|
59
64
|
|
60
|
-
function prepareOlapTableSchema(tableSchema:
|
61
|
-
const {Name, Schema
|
62
|
-
|
63
|
-
|
64
|
-
const
|
65
|
-
|
66
|
-
|
65
|
+
function prepareOlapTableSchema(tableSchema: TColumnTableDescription = {}) {
|
66
|
+
const {Name, Schema} = tableSchema;
|
67
|
+
|
68
|
+
if (Schema) {
|
69
|
+
const {Columns, KeyColumnNames} = Schema;
|
70
|
+
const KeyColumnIds = KeyColumnNames?.map((name: string) => {
|
71
|
+
const column = Columns?.find((el) => el.Name === name);
|
72
|
+
return column?.Id;
|
73
|
+
});
|
74
|
+
|
75
|
+
return {
|
76
|
+
Columns,
|
77
|
+
KeyColumnNames,
|
78
|
+
Name,
|
79
|
+
KeyColumnIds,
|
80
|
+
};
|
81
|
+
}
|
67
82
|
|
68
83
|
return {
|
69
|
-
Columns,
|
70
|
-
KeyColumnNames,
|
71
84
|
Name,
|
72
|
-
KeyColumnIds,
|
73
85
|
};
|
74
86
|
}
|
75
87
|
|
@@ -104,15 +116,23 @@ function ObjectSummary(props: ObjectSummaryProps) {
|
|
104
116
|
});
|
105
117
|
|
106
118
|
const {name: tenantName, info: infoTab} = queryParams;
|
107
|
-
const pathData: TDirEntry | undefined = _.get(
|
108
|
-
|
119
|
+
const pathData: TDirEntry | undefined = _.get(
|
120
|
+
data[tenantName as string],
|
121
|
+
'PathDescription.Self',
|
122
|
+
);
|
123
|
+
const currentSchemaData: TDirEntry | undefined = _.get(
|
124
|
+
data[currentSchemaPath],
|
125
|
+
'PathDescription.Self',
|
126
|
+
);
|
109
127
|
|
110
128
|
const tableSchema =
|
111
129
|
currentItem?.PathDescription?.Table || currentItem?.PathDescription?.ColumnTableDescription;
|
112
130
|
|
113
|
-
const schema =
|
114
|
-
|
115
|
-
|
131
|
+
const schema =
|
132
|
+
isTableType(props.type) && isColumnEntityType(props.type)
|
133
|
+
? // process data for ColumnTable
|
134
|
+
prepareOlapTableSchema(tableSchema)
|
135
|
+
: tableSchema;
|
116
136
|
|
117
137
|
useEffect(() => {
|
118
138
|
const {type} = props;
|
@@ -166,11 +186,16 @@ function ObjectSummary(props: ObjectSummaryProps) {
|
|
166
186
|
[EPathType.EPathTypeExtSubDomain]: undefined,
|
167
187
|
[EPathType.EPathTypeColumnStore]: undefined,
|
168
188
|
[EPathType.EPathTypeColumnTable]: undefined,
|
169
|
-
[EPathType.EPathTypeCdcStream]: () =>
|
170
|
-
|
189
|
+
[EPathType.EPathTypeCdcStream]: () => (
|
190
|
+
<CDCStreamOverview data={data[currentSchemaPath]} />
|
191
|
+
),
|
192
|
+
[EPathType.EPathTypePersQueueGroup]: () => (
|
193
|
+
<PersQueueGroupOverview data={data[currentSchemaPath]} />
|
194
|
+
),
|
171
195
|
};
|
172
196
|
|
173
|
-
let component =
|
197
|
+
let component =
|
198
|
+
currentSchemaData?.PathType && pathTypeToComponent[currentSchemaData.PathType]?.();
|
174
199
|
|
175
200
|
if (!component) {
|
176
201
|
const startTimeInMilliseconds = Number(currentSchemaData?.CreateStep);
|
@@ -182,11 +207,7 @@ function ObjectSummary(props: ObjectSummaryProps) {
|
|
182
207
|
component = <InfoViewer info={[{label: 'Create time', value: createTime}]} />;
|
183
208
|
}
|
184
209
|
|
185
|
-
return (
|
186
|
-
<div className={b('overview-wrapper')}>
|
187
|
-
{component}
|
188
|
-
</div>
|
189
|
-
);
|
210
|
+
return <div className={b('overview-wrapper')}>{component}</div>;
|
190
211
|
};
|
191
212
|
|
192
213
|
const renderTabContent = () => {
|
@@ -35,7 +35,7 @@ const pathTypeToNodeType: Record<EPathType, NavigationTreeNodeType | undefined>
|
|
35
35
|
export const mapPathTypeToNavigationTreeType = (
|
36
36
|
type: EPathType = EPathType.EPathTypeDir,
|
37
37
|
subType?: EPathSubType,
|
38
|
-
defaultType: NavigationTreeNodeType = 'directory'
|
38
|
+
defaultType: NavigationTreeNodeType = 'directory',
|
39
39
|
): NavigationTreeNodeType =>
|
40
40
|
(subType && pathSubTypeToNodeType[subType]) || pathTypeToNodeType[type] || defaultType;
|
41
41
|
|
@@ -87,5 +87,4 @@ const pathTypeToIsColumn: Record<EPathType, boolean> = {
|
|
87
87
|
[EPathType.EPathTypePersQueueGroup]: false,
|
88
88
|
};
|
89
89
|
|
90
|
-
export const isColumnEntityType = (type?: EPathType) =>
|
91
|
-
(type && pathTypeToIsColumn[type]) ?? false;
|
90
|
+
export const isColumnEntityType = (type?: EPathType) => (type && pathTypeToIsColumn[type]) ?? false;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import url from 'url';
|
2
|
+
|
3
|
+
export const getUrlData = (href: string, singleClusterMode: boolean) => {
|
4
|
+
if (!singleClusterMode) {
|
5
|
+
const {backend, clusterName} = url.parse(href, true).query;
|
6
|
+
return {
|
7
|
+
basename: '/',
|
8
|
+
backend,
|
9
|
+
clusterName,
|
10
|
+
};
|
11
|
+
} else if (window.custom_backend) {
|
12
|
+
const {backend} = url.parse(href, true).query;
|
13
|
+
return {
|
14
|
+
basename: '/',
|
15
|
+
backend: backend || window.custom_backend,
|
16
|
+
};
|
17
|
+
} else {
|
18
|
+
const parsedPrefix = window.location.pathname.match(/.*(?=\/monitoring)/) || [];
|
19
|
+
const basenamePrefix = Boolean(parsedPrefix.length) && parsedPrefix[0];
|
20
|
+
const basename = [basenamePrefix, 'monitoring'].filter(Boolean).join('/');
|
21
|
+
|
22
|
+
return {
|
23
|
+
basename,
|
24
|
+
backend: basenamePrefix || '',
|
25
|
+
};
|
26
|
+
}
|
27
|
+
};
|
package/dist/store/index.js
CHANGED
@@ -1,47 +1,16 @@
|
|
1
1
|
import {createStore, applyMiddleware, compose} from 'redux';
|
2
2
|
import thunkMiddleware from 'redux-thunk';
|
3
|
-
import getLocationMiddleware from './state-url-mapping';
|
4
3
|
import {createBrowserHistory} from 'history';
|
5
4
|
import {listenForHistoryChange} from 'redux-location-state';
|
6
5
|
|
6
|
+
import {getUrlData} from './getUrlData';
|
7
|
+
import getLocationMiddleware from './state-url-mapping';
|
7
8
|
import rootReducer from './reducers';
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
export const webVersion = window.web_version;
|
12
|
-
|
13
|
-
export const customBackend = window.custom_backend;
|
14
|
-
|
15
|
-
export const getUrlData = (href, singleClusterMode) => {
|
16
|
-
if (!singleClusterMode) {
|
17
|
-
const {backend, clusterName} = url.parse(href, true).query;
|
18
|
-
return {
|
19
|
-
basename: '/',
|
20
|
-
backend,
|
21
|
-
clusterName,
|
22
|
-
};
|
23
|
-
} else if (customBackend) {
|
24
|
-
const {backend} = url.parse(href, true).query;
|
25
|
-
return {
|
26
|
-
basename: '/',
|
27
|
-
backend: backend || window.custom_backend,
|
28
|
-
};
|
29
|
-
} else {
|
30
|
-
const parsedPrefix = window.location.pathname.match(/.*(?=\/monitoring)/) || [];
|
31
|
-
const basenamePrefix = Boolean(parsedPrefix.length) && parsedPrefix[0];
|
32
|
-
const basename = [basenamePrefix, 'monitoring'].filter(Boolean).join('/');
|
33
|
-
|
34
|
-
return {
|
35
|
-
basename,
|
36
|
-
backend: basenamePrefix || '',
|
37
|
-
};
|
38
|
-
}
|
39
|
-
};
|
10
|
+
export let backend, basename, clusterName;
|
40
11
|
|
41
12
|
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
42
13
|
|
43
|
-
export let backend, basename, clusterName;
|
44
|
-
|
45
14
|
function _configureStore(aRootReducer, history, singleClusterMode) {
|
46
15
|
const {locationMiddleware, reducersWithLocation} = getLocationMiddleware(history, aRootReducer);
|
47
16
|
const middlewares = applyMiddleware(thunkMiddleware, locationMiddleware);
|
@@ -51,7 +20,7 @@ function _configureStore(aRootReducer, history, singleClusterMode) {
|
|
51
20
|
});
|
52
21
|
}
|
53
22
|
|
54
|
-
|
23
|
+
function configureStore(aRootReducer = rootReducer, singleClusterMode = true) {
|
55
24
|
({backend, basename, clusterName} = getUrlData(window.location.href, singleClusterMode));
|
56
25
|
const history = createBrowserHistory({basename});
|
57
26
|
|
@@ -59,3 +28,10 @@ export default function configureStore(aRootReducer = rootReducer, singleCluster
|
|
59
28
|
listenForHistoryChange(store, history);
|
60
29
|
return {history, store};
|
61
30
|
}
|
31
|
+
|
32
|
+
export const webVersion = window.web_version;
|
33
|
+
export const customBackend = window.custom_backend;
|
34
|
+
|
35
|
+
export * from "./reducers"
|
36
|
+
|
37
|
+
export default configureStore;
|
@@ -1,16 +1,25 @@
|
|
1
|
-
import {createSelector} from 'reselect';
|
1
|
+
import {createSelector, Selector} from 'reselect';
|
2
|
+
import {Reducer} from 'redux';
|
2
3
|
|
3
4
|
import '../../services/api';
|
4
5
|
import {TEvDescribeSchemeResult} from '../../types/api/schema';
|
5
6
|
import {IConsumer} from '../../types/api/consumers';
|
7
|
+
import {IDescribeRootStateSlice, IDescribeState} from '../../types/store/describe';
|
8
|
+
import {IResponseError} from '../../types/api/error';
|
6
9
|
import {createRequestActionTypes, createApiRequest, ApiRequestAction} from '../utils';
|
7
10
|
|
8
11
|
const FETCH_DESCRIBE = createRequestActionTypes('describe', 'FETCH_DESCRIBE');
|
9
12
|
|
10
|
-
const
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
const initialState = {
|
14
|
+
loading: false,
|
15
|
+
wasLoaded: false,
|
16
|
+
data: {},
|
17
|
+
};
|
18
|
+
|
19
|
+
const describe: Reducer<
|
20
|
+
IDescribeState,
|
21
|
+
ApiRequestAction<typeof FETCH_DESCRIBE, TEvDescribeSchemeResult, IResponseError>
|
22
|
+
> = (state = initialState, action) => {
|
14
23
|
switch (action.type) {
|
15
24
|
case FETCH_DESCRIBE.REQUEST: {
|
16
25
|
return {
|
@@ -50,16 +59,21 @@ const describe = (
|
|
50
59
|
};
|
51
60
|
|
52
61
|
// Consumers selectors
|
53
|
-
const selectConsumersNames
|
54
|
-
state
|
62
|
+
const selectConsumersNames: Selector<IDescribeRootStateSlice, string[] | undefined, [string]> = (
|
63
|
+
state,
|
64
|
+
path,
|
65
|
+
) => state.describe.data[path]?.PathDescription?.PersQueueGroup?.PQTabletConfig?.ReadRules;
|
55
66
|
|
56
|
-
export const selectConsumers
|
57
|
-
|
58
|
-
|
59
|
-
|
67
|
+
export const selectConsumers: Selector<IDescribeRootStateSlice, IConsumer[]> = createSelector(
|
68
|
+
selectConsumersNames,
|
69
|
+
(names = []) => {
|
70
|
+
const consumers = names.map((name) => {
|
71
|
+
return {name};
|
72
|
+
});
|
60
73
|
|
61
|
-
|
62
|
-
}
|
74
|
+
return consumers;
|
75
|
+
},
|
76
|
+
);
|
63
77
|
|
64
78
|
export function getDescribe({path}: {path: string}) {
|
65
79
|
return createApiRequest({
|
@@ -1,10 +1,13 @@
|
|
1
|
+
import {Reducer} from 'redux';
|
2
|
+
|
1
3
|
const SET_HEADER = 'SET_HEADER';
|
2
4
|
|
5
|
+
type IHeaderAction = ReturnType<typeof setHeader>;
|
3
6
|
export type HeaderItemType = {text: string; link?: string};
|
4
7
|
|
5
8
|
const initialState: HeaderItemType[] = [];
|
6
9
|
|
7
|
-
const header = function (state = initialState, action
|
10
|
+
const header: Reducer<HeaderItemType[], IHeaderAction> = function (state = initialState, action) {
|
8
11
|
switch (action.type) {
|
9
12
|
case SET_HEADER:
|
10
13
|
return action.data;
|
@@ -2,10 +2,16 @@ import _flow from 'lodash/fp/flow';
|
|
2
2
|
import _sortBy from 'lodash/fp/sortBy';
|
3
3
|
import _uniqBy from 'lodash/fp/uniqBy';
|
4
4
|
import _omit from 'lodash/omit';
|
5
|
-
import {createSelector} from 'reselect';
|
6
|
-
|
7
|
-
|
5
|
+
import {createSelector, Selector} from 'reselect';
|
6
|
+
import {Reducer} from 'redux';
|
7
|
+
|
8
|
+
import {
|
9
|
+
IHealthcheckInfoState,
|
10
|
+
IHealthcheckInfoRootStateSlice,
|
11
|
+
IIssuesTree,
|
12
|
+
} from '../../types/store/healthcheck';
|
8
13
|
import {HealthCheckAPIResponse, IssueLog, StatusFlag} from '../../types/api/healthcheck';
|
14
|
+
import {IResponseError} from '../../types/api/error';
|
9
15
|
|
10
16
|
import '../../services/api';
|
11
17
|
import {createRequestActionTypes, createApiRequest, ApiRequestAction} from '../utils';
|
@@ -14,10 +20,10 @@ const FETCH_HEALTHCHECK = createRequestActionTypes('cluster', 'FETCH_HEALTHCHECK
|
|
14
20
|
|
15
21
|
const initialState = {loading: false, wasLoaded: false};
|
16
22
|
|
17
|
-
const healthcheckInfo
|
18
|
-
|
19
|
-
|
20
|
-
) {
|
23
|
+
const healthcheckInfo: Reducer<
|
24
|
+
IHealthcheckInfoState,
|
25
|
+
ApiRequestAction<typeof FETCH_HEALTHCHECK, HealthCheckAPIResponse, IResponseError>
|
26
|
+
> = function (state = initialState, action) {
|
21
27
|
switch (action.type) {
|
22
28
|
case FETCH_HEALTHCHECK.REQUEST: {
|
23
29
|
return {
|
@@ -60,7 +66,7 @@ const getReasonsForIssue = ({issue, data}: {issue: IssueLog; data: IssueLog[]})
|
|
60
66
|
return data.filter((item) => issue.reason && issue.reason.indexOf(item.id) !== -1);
|
61
67
|
};
|
62
68
|
|
63
|
-
const getRoots = (data: IssueLog[]) => {
|
69
|
+
const getRoots = (data: IssueLog[]): IssueLog[] => {
|
64
70
|
let roots = data.filter((item) => {
|
65
71
|
return !data.find((issue) => issue.reason && issue.reason.indexOf(item.id) !== -1);
|
66
72
|
});
|
@@ -95,22 +101,23 @@ const getInvertedConsequencesTree = ({
|
|
95
101
|
: [];
|
96
102
|
};
|
97
103
|
|
98
|
-
const getIssuesLog = (state:
|
104
|
+
const getIssuesLog = (state: IHealthcheckInfoRootStateSlice) =>
|
105
|
+
state.healthcheckInfo.data?.issue_log;
|
99
106
|
|
100
|
-
export const selectIssuesTreesRoots
|
101
|
-
getRoots(issues)
|
102
|
-
);
|
107
|
+
export const selectIssuesTreesRoots: Selector<IHealthcheckInfoRootStateSlice, IssueLog[]> =
|
108
|
+
createSelector(getIssuesLog, (issues = []) => getRoots(issues));
|
103
109
|
|
104
|
-
export const selectIssuesTrees =
|
105
|
-
[getIssuesLog, selectIssuesTreesRoots],
|
106
|
-
(data = [], roots = []) => {
|
110
|
+
export const selectIssuesTrees: Selector<IHealthcheckInfoRootStateSlice, IIssuesTree[]> =
|
111
|
+
createSelector([getIssuesLog, selectIssuesTreesRoots], (data = [], roots = []) => {
|
107
112
|
return getInvertedConsequencesTree({data, roots});
|
108
|
-
}
|
109
|
-
);
|
113
|
+
});
|
110
114
|
|
111
|
-
export const selectIssuesTreeById
|
112
|
-
|
113
|
-
|
115
|
+
export const selectIssuesTreeById: Selector<
|
116
|
+
IHealthcheckInfoRootStateSlice,
|
117
|
+
IIssuesTree | undefined,
|
118
|
+
[string | undefined]
|
119
|
+
> = createSelector([selectIssuesTrees, (_, id: string | undefined) => id], (issuesTrees = [], id) =>
|
120
|
+
issuesTrees.find((issuesTree) => issuesTree.id === id),
|
114
121
|
);
|
115
122
|
|
116
123
|
export function getHealthcheckInfo(database: string) {
|
@@ -34,10 +34,7 @@ import authentication from './authentication';
|
|
34
34
|
import header from './header';
|
35
35
|
import saveQuery from './saveQuery';
|
36
36
|
import fullscreen from './fullscreen';
|
37
|
-
|
38
|
-
function singleClusterMode(state = true) {
|
39
|
-
return state;
|
40
|
-
}
|
37
|
+
import singleClusterMode from './singleClusterMode';
|
41
38
|
|
42
39
|
export const rootReducer = {
|
43
40
|
singleClusterMode,
|
@@ -77,6 +74,11 @@ export const rootReducer = {
|
|
77
74
|
fullscreen,
|
78
75
|
};
|
79
76
|
|
80
|
-
|
77
|
+
const combinedReducer = combineReducers({
|
81
78
|
...rootReducer,
|
82
79
|
});
|
80
|
+
|
81
|
+
export type IRootReducer = typeof combinedReducer;
|
82
|
+
export type IRootState = ReturnType<IRootReducer>;
|
83
|
+
|
84
|
+
export default combinedReducer;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import '../../services/api';
|
2
2
|
|
3
|
-
import type {
|
3
|
+
import type {ErrorResponse, ExecuteActions} from '../../types/api/query';
|
4
4
|
import type {IQueryResult} from '../../types/store/query';
|
5
5
|
import {parseQueryAPIExecuteResponse} from '../../utils/query';
|
6
6
|
|
@@ -16,7 +16,7 @@ const initialState = {
|
|
16
16
|
|
17
17
|
const preview = (
|
18
18
|
state = initialState,
|
19
|
-
action: ApiRequestAction<typeof SEND_QUERY, IQueryResult,
|
19
|
+
action: ApiRequestAction<typeof SEND_QUERY, IQueryResult, ErrorResponse> | ReturnType<typeof setQueryOptions>,
|
20
20
|
) => {
|
21
21
|
switch (action.type) {
|
22
22
|
case SEND_QUERY.REQUEST: {
|
@@ -1,12 +1,14 @@
|
|
1
|
+
import {Reducer} from 'redux';
|
2
|
+
|
1
3
|
const SET_QUERY_NAME_TO_EDIT = 'SET_QUERY_NAME_TO_EDIT';
|
2
4
|
const CLEAR_QUERY_NAME_TO_EDIT = 'CLEAR_QUERY_NAME_TO_EDIT';
|
3
5
|
|
6
|
+
type IAction = ReturnType<typeof setQueryNameToEdit> | ReturnType<typeof clearQueryNameToEdit>;
|
7
|
+
type ISaveQueryState = string | null;
|
8
|
+
|
4
9
|
const initialState = null;
|
5
10
|
|
6
|
-
const saveQuery = function (
|
7
|
-
state = initialState,
|
8
|
-
action: ReturnType<typeof setQueryNameToEdit> | ReturnType<typeof clearQueryNameToEdit>,
|
9
|
-
) {
|
11
|
+
const saveQuery: Reducer<ISaveQueryState, IAction> = function (state = initialState, action) {
|
10
12
|
switch (action.type) {
|
11
13
|
case SET_QUERY_NAME_TO_EDIT:
|
12
14
|
return action.data;
|
package/dist/types/api/query.ts
CHANGED
@@ -8,16 +8,16 @@ export interface CommonFields {
|
|
8
8
|
ast?: AST;
|
9
9
|
plan?: Plan;
|
10
10
|
stats?: Stats;
|
11
|
-
}
|
11
|
+
}
|
12
12
|
|
13
13
|
interface DeprecatedCommonFields {
|
14
14
|
stats?: Stats;
|
15
15
|
}
|
16
16
|
|
17
|
-
export interface
|
17
|
+
export interface ErrorResponse {
|
18
18
|
error?: any;
|
19
19
|
issues?: any;
|
20
|
-
}
|
20
|
+
}
|
21
21
|
|
22
22
|
export type ExecuteActions = 'execute-script' | 'execute' | 'execute-scan' | undefined;
|
23
23
|
export type ExplainActions = 'explain' | 'explain-ast';
|
@@ -34,7 +34,7 @@ type CellValue = string | number | null | undefined;
|
|
34
34
|
|
35
35
|
export type KeyValueRow<T = CellValue> = {
|
36
36
|
[key: string]: T;
|
37
|
-
}
|
37
|
+
};
|
38
38
|
|
39
39
|
export type ArrayRow<T = CellValue> = Array<T>;
|
40
40
|
|
@@ -63,17 +63,15 @@ export type ExecuteYdbResponse = {
|
|
63
63
|
result: KeyValueRow[];
|
64
64
|
} & CommonFields;
|
65
65
|
|
66
|
-
type ExecuteResponse<Schema extends Schemas> =
|
66
|
+
type ExecuteResponse<Schema extends Schemas> =
|
67
67
|
| CommonFields // result can be undefined for queries like `insert into`
|
68
|
-
| (
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
: unknown
|
76
|
-
);
|
68
|
+
| (Schema extends 'modern'
|
69
|
+
? ExecuteModernResponse
|
70
|
+
: Schema extends 'ydb'
|
71
|
+
? ExecuteYdbResponse
|
72
|
+
: Schema extends 'classic' | undefined
|
73
|
+
? ExecuteClassicResponse
|
74
|
+
: unknown);
|
77
75
|
|
78
76
|
// deprecated response from older versions, backward compatibility
|
79
77
|
|
@@ -92,8 +90,9 @@ export type DeprecatedExecuteResponseDeep = {
|
|
92
90
|
// can be undefined for queries like `insert into`
|
93
91
|
export type DeprecatedExecuteResponsePlain = DeprecatedExecuteResponseValue | undefined;
|
94
92
|
|
95
|
-
export type DeprecatedExecuteResponse =
|
96
|
-
|
93
|
+
export type DeprecatedExecuteResponse =
|
94
|
+
| DeprecatedExecuteResponseDeep
|
95
|
+
| DeprecatedExecuteResponsePlain;
|
97
96
|
|
98
97
|
// ==== EXPLAIN ====
|
99
98
|
|
@@ -103,14 +102,12 @@ type ExplainResponse = CommonFields;
|
|
103
102
|
|
104
103
|
// deprecated response from older versions, backward compatibility
|
105
104
|
|
106
|
-
type DeprecatedExplainResponse<Action extends ExplainActions> =
|
105
|
+
type DeprecatedExplainResponse<Action extends ExplainActions> =
|
107
106
|
Action extends 'explain-ast'
|
108
107
|
? ({result: {ast: AST}} & Required<DeprecatedCommonFields>) | {ast: AST}
|
109
108
|
: Action extends 'explain'
|
110
109
|
? ({result: Plan} & Required<DeprecatedCommonFields>) | Plan
|
111
|
-
: unknown
|
112
|
-
);
|
113
|
-
|
110
|
+
: unknown;
|
114
111
|
|
115
112
|
// ==== COMBINED API RESPONSE ====
|
116
113
|
|
@@ -124,15 +121,14 @@ export type QueryAPIExplainResponse<Action extends ExplainActions> =
|
|
124
121
|
| DeprecatedExplainResponse<Action>
|
125
122
|
| null;
|
126
123
|
|
127
|
-
export type QueryAPIResponse<Action extends Actions, Schema extends Schemas = undefined> =
|
124
|
+
export type QueryAPIResponse<Action extends Actions, Schema extends Schemas = undefined> =
|
128
125
|
Action extends ExecuteActions
|
129
126
|
? QueryAPIExecuteResponse<Schema>
|
130
127
|
: Action extends ExplainActions
|
131
128
|
? QueryAPIExplainResponse<Action>
|
132
|
-
: unknown
|
133
|
-
);
|
129
|
+
: unknown;
|
134
130
|
|
135
|
-
export type AnyExecuteResponse =
|
131
|
+
export type AnyExecuteResponse =
|
136
132
|
| ExecuteModernResponse
|
137
133
|
| ExecuteClassicResponse
|
138
134
|
| ExecuteYdbResponse
|
@@ -146,13 +142,11 @@ export type DeepExecuteResponse =
|
|
146
142
|
| ExecuteYdbResponse
|
147
143
|
| DeprecatedExecuteResponseDeep;
|
148
144
|
|
149
|
-
export type AnyExplainResponse =
|
145
|
+
export type AnyExplainResponse =
|
150
146
|
| ExplainResponse
|
151
147
|
| CommonFields
|
152
148
|
| DeprecatedExplainResponse<'explain'>
|
153
149
|
| DeprecatedExplainResponse<'explain-ast'>
|
154
150
|
| null;
|
155
151
|
|
156
|
-
export type AnyResponse =
|
157
|
-
| AnyExecuteResponse
|
158
|
-
| AnyExplainResponse;
|
152
|
+
export type AnyResponse = AnyExecuteResponse | AnyExplainResponse;
|
package/dist/types/api/schema.ts
CHANGED
@@ -52,8 +52,8 @@ interface TPathDescription {
|
|
52
52
|
TabletMetrics?: unknown;
|
53
53
|
TablePartitions?: unknown[];
|
54
54
|
|
55
|
-
ColumnStoreDescription?:
|
56
|
-
ColumnTableDescription?:
|
55
|
+
ColumnStoreDescription?: TColumnStoreDescription;
|
56
|
+
ColumnTableDescription?: TColumnTableDescription;
|
57
57
|
|
58
58
|
TableIndex?: TIndexDescription;
|
59
59
|
|
@@ -85,12 +85,12 @@ export interface TDirEntry {
|
|
85
85
|
Version?: TPathVersion;
|
86
86
|
}
|
87
87
|
|
88
|
-
// incomplete
|
88
|
+
// FIXME: incomplete
|
89
89
|
export interface TTableDescription {
|
90
90
|
PartitionConfig?: TPartitionConfig;
|
91
91
|
}
|
92
92
|
|
93
|
-
// incomplete
|
93
|
+
// FIXME: incomplete
|
94
94
|
export interface TPartitionConfig {
|
95
95
|
/** uint64 */
|
96
96
|
FollowerCount?: string;
|
@@ -263,7 +263,6 @@ export enum EPathType {
|
|
263
263
|
EPathTypeColumnStore = 'EPathTypeColumnStore',
|
264
264
|
EPathTypeColumnTable = 'EPathTypeColumnTable',
|
265
265
|
EPathTypeCdcStream = 'EPathTypeCdcStream',
|
266
|
-
|
267
266
|
}
|
268
267
|
|
269
268
|
export enum EPathSubType {
|
@@ -414,7 +413,7 @@ interface TPQPartitionConfig {
|
|
414
413
|
ExplicitChannelProfiles?: TChannelProfile[];
|
415
414
|
|
416
415
|
MirrorFrom?: TMirrorPartitionConfig;
|
417
|
-
}
|
416
|
+
}
|
418
417
|
|
419
418
|
interface TPQTabletConfig {
|
420
419
|
/** uint64 */
|
@@ -437,7 +436,7 @@ interface TPQTabletConfig {
|
|
437
436
|
ReadFromTimestampsMs?: number[];
|
438
437
|
/** uint64[] */
|
439
438
|
ConsumerFormatVersions?: number[];
|
440
|
-
|
439
|
+
|
441
440
|
ConsumerCodecs?: TCodecs[];
|
442
441
|
ReadRuleServiceTypes?: string;
|
443
442
|
|
@@ -461,7 +460,7 @@ interface TPQTabletConfig {
|
|
461
460
|
PartitionKeySchema?: TKeyComponentSchema[];
|
462
461
|
|
463
462
|
Partitions?: TPartition[];
|
464
|
-
|
463
|
+
|
465
464
|
MeteringMode?: EMeteringMode;
|
466
465
|
}
|
467
466
|
|
@@ -481,7 +480,7 @@ export interface TPersQueueGroupDescription {
|
|
481
480
|
/** uint64 */
|
482
481
|
PathId?: string;
|
483
482
|
TotalGroupCount: number;
|
484
|
-
|
483
|
+
|
485
484
|
PartitionsToAdd?: TPartitionToAdd[];
|
486
485
|
PartitionsToDelete?: number[];
|
487
486
|
NextPartitionId?: number;
|
@@ -497,3 +496,158 @@ export interface TPersQueueGroupDescription {
|
|
497
496
|
|
498
497
|
BootstrapConfig?: TBootstrapConfig;
|
499
498
|
}
|
499
|
+
|
500
|
+
export interface TColumnTableDescription {
|
501
|
+
Name?: string;
|
502
|
+
|
503
|
+
Schema?: TColumnTableSchema;
|
504
|
+
TtlSettings?: TColumnDataLifeCycle;
|
505
|
+
|
506
|
+
SchemaPresetId?: number;
|
507
|
+
SchemaPresetName?: string;
|
508
|
+
|
509
|
+
ColumnStorePathId?: TPathID;
|
510
|
+
|
511
|
+
ColumnShardCount?: number;
|
512
|
+
Sharding?: TColumnTableSharding;
|
513
|
+
|
514
|
+
/** uint64 */
|
515
|
+
SchemaPresetVersionAdj?: string;
|
516
|
+
/** uint64 */
|
517
|
+
TtlSettingsPresetVersionAdj?: string;
|
518
|
+
|
519
|
+
StorageConfig?: TColumnStorageConfig;
|
520
|
+
}
|
521
|
+
|
522
|
+
interface TColumnTableSchema {
|
523
|
+
Columns: TOlapColumnDescription[];
|
524
|
+
KeyColumnNames: string[];
|
525
|
+
Engine?: EColumnTableEngine;
|
526
|
+
NextColumnId?: number;
|
527
|
+
|
528
|
+
/** uint64 */
|
529
|
+
Version?: string;
|
530
|
+
|
531
|
+
DefaultCompression?: TCompressionOptions;
|
532
|
+
EnableTiering?: boolean;
|
533
|
+
}
|
534
|
+
|
535
|
+
interface TOlapColumnDescription {
|
536
|
+
Id?: number;
|
537
|
+
Name?: string;
|
538
|
+
Type?: string;
|
539
|
+
TypeId?: number;
|
540
|
+
TypeInfo?: TTypeInfo;
|
541
|
+
}
|
542
|
+
|
543
|
+
interface TTypeInfo {
|
544
|
+
PgTypeId?: number;
|
545
|
+
}
|
546
|
+
|
547
|
+
enum EColumnTableEngine {
|
548
|
+
COLUMN_ENGINE_NONE = 'COLUMN_ENGINE_NONE',
|
549
|
+
COLUMN_ENGINE_REPLACING_TIMESERIES = 'COLUMN_ENGINE_REPLACING_TIMESERIES',
|
550
|
+
}
|
551
|
+
|
552
|
+
interface TCompressionOptions {
|
553
|
+
CompressionCodec?: EColumnCodec;
|
554
|
+
CompressionLevel?: number;
|
555
|
+
}
|
556
|
+
|
557
|
+
enum EColumnCodec {
|
558
|
+
ColumnCodecPlain = 'ColumnCodecPlain',
|
559
|
+
ColumnCodecLZ4 = 'ColumnCodecLZ4',
|
560
|
+
ColumnCodecZSTD = 'ColumnCodecZSTD',
|
561
|
+
}
|
562
|
+
|
563
|
+
interface TColumnDataLifeCycle {
|
564
|
+
Enabled?: TTtl;
|
565
|
+
Disabled?: {};
|
566
|
+
Tiering?: TStorageTiering;
|
567
|
+
|
568
|
+
/** uint64 */
|
569
|
+
Version?: string;
|
570
|
+
}
|
571
|
+
|
572
|
+
interface TTtl {
|
573
|
+
ColumnName?: string;
|
574
|
+
|
575
|
+
ExpireAfterSeconds?: number;
|
576
|
+
|
577
|
+
/** uint64 */
|
578
|
+
ExpireAfterBytes?: string;
|
579
|
+
|
580
|
+
ColumnUnit?: EUnit;
|
581
|
+
}
|
582
|
+
|
583
|
+
interface TStorageTier {
|
584
|
+
Name?: string;
|
585
|
+
Eviction?: TTtl;
|
586
|
+
}
|
587
|
+
interface TStorageTiering {
|
588
|
+
Tiers: TStorageTier[];
|
589
|
+
}
|
590
|
+
|
591
|
+
enum EUnit {
|
592
|
+
UNIT_AUTO = 'UNIT_AUTO',
|
593
|
+
UNIT_SECONDS = 'UNIT_SECONDS',
|
594
|
+
UNIT_MILLISECONDS = 'UNIT_MILLISECONDS',
|
595
|
+
UNIT_MICROSECONDS = 'UNIT_MICROSECONDS',
|
596
|
+
UNIT_NANOSECONDS = 'UNIT_NANOSECONDS',
|
597
|
+
}
|
598
|
+
|
599
|
+
interface TColumnTableSharding {
|
600
|
+
/** uint64 */
|
601
|
+
Version?: string;
|
602
|
+
|
603
|
+
/** uint64 */
|
604
|
+
ColumnShards: string[];
|
605
|
+
|
606
|
+
/** uint64 */
|
607
|
+
AdditionalColumnShards: string[];
|
608
|
+
|
609
|
+
UniquePrimaryKey?: boolean;
|
610
|
+
|
611
|
+
RandomSharding?: {};
|
612
|
+
HashSharding?: THashSharding;
|
613
|
+
}
|
614
|
+
|
615
|
+
interface THashSharding {
|
616
|
+
Function?: EHashFunction;
|
617
|
+
Columns: string[];
|
618
|
+
UniqueShardKey?: boolean;
|
619
|
+
ActiveShardsCount?: number;
|
620
|
+
}
|
621
|
+
enum EHashFunction {
|
622
|
+
HASH_FUNCTION_MODULO_N = 'HASH_FUNCTION_MODULO_N',
|
623
|
+
HASH_FUNCTION_CLOUD_LOGS = 'HASH_FUNCTION_CLOUD_LOGS',
|
624
|
+
}
|
625
|
+
interface TColumnStorageConfig {
|
626
|
+
SysLog?: TStorageSettings;
|
627
|
+
Log?: TStorageSettings;
|
628
|
+
Data?: TStorageSettings;
|
629
|
+
DataChannelCount?: number;
|
630
|
+
}
|
631
|
+
interface TStorageSettings {
|
632
|
+
PreferredPoolKind?: string;
|
633
|
+
AllowOtherKinds?: boolean;
|
634
|
+
}
|
635
|
+
export interface TColumnStoreDescription {
|
636
|
+
Name?: string;
|
637
|
+
ColumnShardCount?: number;
|
638
|
+
|
639
|
+
/** uint64 */
|
640
|
+
ColumnShards: string[];
|
641
|
+
|
642
|
+
SchemaPresets: TColumnTableSchemaPreset[];
|
643
|
+
StorageConfig?: TColumnStorageConfig;
|
644
|
+
|
645
|
+
NextSchemaPresetId?: number;
|
646
|
+
NextTtlSettingsPresetId?: number;
|
647
|
+
}
|
648
|
+
|
649
|
+
interface TColumnTableSchemaPreset {
|
650
|
+
Id?: number;
|
651
|
+
Name?: string;
|
652
|
+
Schema?: TColumnTableSchema;
|
653
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import {IResponseError} from '../api/error';
|
2
|
+
import {TEvDescribeSchemeResult} from '../api/schema';
|
3
|
+
|
4
|
+
export interface IDescribeState {
|
5
|
+
loading: boolean;
|
6
|
+
wasLoaded: boolean;
|
7
|
+
data: Record<string, TEvDescribeSchemeResult>;
|
8
|
+
currentDescribe?: TEvDescribeSchemeResult;
|
9
|
+
error?: IResponseError;
|
10
|
+
}
|
11
|
+
|
12
|
+
export interface IDescribeRootStateSlice {
|
13
|
+
describe: IDescribeState;
|
14
|
+
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import {IResponseError} from '../api/error';
|
1
2
|
import type {HealthCheckAPIResponse, IssueLog} from '../api/healthcheck';
|
2
3
|
|
3
4
|
export interface IIssuesTree extends IssueLog {
|
@@ -5,3 +6,14 @@ export interface IIssuesTree extends IssueLog {
|
|
5
6
|
}
|
6
7
|
|
7
8
|
export type IHealthCheck = HealthCheckAPIResponse;
|
9
|
+
|
10
|
+
export interface IHealthcheckInfoState {
|
11
|
+
loading: boolean;
|
12
|
+
wasLoaded: boolean;
|
13
|
+
data?: HealthCheckAPIResponse;
|
14
|
+
error?: IResponseError;
|
15
|
+
}
|
16
|
+
|
17
|
+
export interface IHealthcheckInfoRootStateSlice {
|
18
|
+
healthcheckInfo: IHealthcheckInfoState;
|
19
|
+
}
|
package/dist/types/window.d.ts
CHANGED
@@ -30,4 +30,11 @@ interface Window {
|
|
30
30
|
Ya?: {
|
31
31
|
Rum?: RumCounter;
|
32
32
|
};
|
33
|
+
|
34
|
+
// eslint-disable-next-line
|
35
|
+
web_version?: boolean;
|
36
|
+
// eslint-disable-next-line
|
37
|
+
custom_backend?: string;
|
38
|
+
|
39
|
+
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof import('redux').compose;
|
33
40
|
}
|
@@ -4,6 +4,7 @@ import {
|
|
4
4
|
TopologyNodeDataStats,
|
5
5
|
TopologyNodeDataStatsSection,
|
6
6
|
ExplainPlanNodeData,
|
7
|
+
TopologyNodeDataStatsItem,
|
7
8
|
} from '@yandex-cloud/paranoid';
|
8
9
|
|
9
10
|
interface PlanOperator {
|
@@ -25,6 +26,8 @@ export interface RootPlan {
|
|
25
26
|
Plan: Plan;
|
26
27
|
}
|
27
28
|
|
29
|
+
const CONNECTION_NODE_META_FIELDS = new Set(['PlanNodeId', 'PlanNodeType', 'Node Type', 'Plans']);
|
30
|
+
|
28
31
|
function prepareStats(plan: Plan) {
|
29
32
|
const stats: TopologyNodeDataStats[] = [];
|
30
33
|
|
@@ -52,21 +55,52 @@ function prepareStats(plan: Plan) {
|
|
52
55
|
});
|
53
56
|
}
|
54
57
|
|
58
|
+
if (plan.PlanNodeType === 'Connection') {
|
59
|
+
const attrStats: TopologyNodeDataStatsItem[] = [];
|
60
|
+
|
61
|
+
for (const [key, value] of Object.entries(plan)) {
|
62
|
+
if (CONNECTION_NODE_META_FIELDS.has(key)) {
|
63
|
+
continue;
|
64
|
+
}
|
65
|
+
|
66
|
+
attrStats.push({name: key, value: String(value)});
|
67
|
+
}
|
68
|
+
|
69
|
+
if (attrStats.length > 0) {
|
70
|
+
stats.push({
|
71
|
+
group: 'Attributes',
|
72
|
+
stats: attrStats,
|
73
|
+
});
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
55
77
|
return stats;
|
56
78
|
}
|
57
79
|
|
80
|
+
function getNodeType(plan: Plan) {
|
81
|
+
switch (plan.PlanNodeType) {
|
82
|
+
case 'Connection':
|
83
|
+
return 'connection';
|
84
|
+
case 'ResultSet':
|
85
|
+
return 'result';
|
86
|
+
case 'Query':
|
87
|
+
return 'query';
|
88
|
+
default:
|
89
|
+
return 'stage';
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
58
93
|
export function preparePlan(plan: Plan) {
|
59
94
|
const nodes: GraphNode[] = [];
|
60
95
|
const links: Link[] = [];
|
61
96
|
|
62
|
-
function parsePlans(plans: Plan[] = [], from: string
|
63
|
-
const depth = curDepth + 1;
|
97
|
+
function parsePlans(plans: Plan[] = [], from: string) {
|
64
98
|
plans.forEach((p) => {
|
65
99
|
const node: GraphNode<ExplainPlanNodeData> = {
|
66
100
|
name: String(p.PlanNodeId),
|
67
101
|
data: {
|
68
102
|
id: p.PlanNodeId,
|
69
|
-
type: p
|
103
|
+
type: getNodeType(p),
|
70
104
|
name: p['Node Type'],
|
71
105
|
operators: p.Operators?.map((o) => o.Name),
|
72
106
|
stats: prepareStats(p),
|
@@ -75,7 +109,7 @@ export function preparePlan(plan: Plan) {
|
|
75
109
|
};
|
76
110
|
nodes.push(node);
|
77
111
|
links.push({from, to: node.name});
|
78
|
-
parsePlans(p.Plans, node.name
|
112
|
+
parsePlans(p.Plans, node.name);
|
79
113
|
});
|
80
114
|
}
|
81
115
|
|
@@ -84,12 +118,13 @@ export function preparePlan(plan: Plan) {
|
|
84
118
|
name: String(rootPlan.PlanNodeId),
|
85
119
|
data: {
|
86
120
|
id: rootPlan.PlanNodeId,
|
87
|
-
type:
|
121
|
+
type: getNodeType(rootPlan),
|
88
122
|
name: rootPlan['Node Type'],
|
89
123
|
},
|
90
124
|
};
|
91
125
|
nodes.push(rootNode);
|
92
|
-
parsePlans(rootPlan.Plans, rootNode.name
|
126
|
+
parsePlans(rootPlan.Plans, rootNode.name);
|
127
|
+
|
93
128
|
return {
|
94
129
|
nodes,
|
95
130
|
links,
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "ydb-embedded-ui",
|
3
|
-
"version": "2.4.
|
3
|
+
"version": "2.4.3",
|
4
4
|
"files": [
|
5
5
|
"dist"
|
6
6
|
],
|
@@ -10,7 +10,7 @@
|
|
10
10
|
},
|
11
11
|
"dependencies": {
|
12
12
|
"@gravity-ui/i18n": "^1.0.0",
|
13
|
-
"@yandex-cloud/paranoid": "^1.
|
13
|
+
"@yandex-cloud/paranoid": "^1.3.0",
|
14
14
|
"@yandex-cloud/react-data-table": "0.2.1",
|
15
15
|
"axios": "0.19.2",
|
16
16
|
"bem-cn-lite": "4.0.0",
|
@@ -33,7 +33,7 @@
|
|
33
33
|
"redux": "4.0.1",
|
34
34
|
"redux-location-state": "2.6.0",
|
35
35
|
"redux-thunk": "2.3.0",
|
36
|
-
"reselect": "4.
|
36
|
+
"reselect": "4.1.6",
|
37
37
|
"sass": "1.32.8",
|
38
38
|
"web-vitals": "1.1.2",
|
39
39
|
"ydb-ui-components": "3.0.1"
|