ydb-embedded-ui 2.4.1 → 2.4.2
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 +7 -0
- package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +3 -3
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +8 -6
- 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/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 +2 -2
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [2.4.2](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.1...v2.4.2) (2022-11-09)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* **QueryExplain:** apply all node types ([06d26de](https://github.com/ydb-platform/ydb-embedded-ui/commit/06d26def15496f8e2de00d941b39bf6a68382f14))
|
9
|
+
|
3
10
|
## [2.4.1](https://github.com/ydb-platform/ydb-embedded-ui/compare/v2.4.0...v2.4.1) (2022-11-01)
|
4
11
|
|
5
12
|
|
@@ -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));
|
@@ -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;
|
@@ -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.2",
|
4
4
|
"files": [
|
5
5
|
"dist"
|
6
6
|
],
|
@@ -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"
|