ydb-embedded-ui 4.15.1 → 4.16.1
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +21 -0
- package/dist/components/BasicNodeViewer/BasicNodeViewer.tsx +2 -2
- package/dist/components/DiagnosticCard/DiagnosticCard.scss +5 -0
- package/dist/components/DiagnosticCard/DiagnosticCard.tsx +17 -0
- package/dist/components/EntityStatus/EntityStatus.js +2 -2
- package/dist/components/EntityStatus/EntityStatus.scss +15 -0
- package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +2 -1
- package/dist/containers/Cluster/Cluster.tsx +2 -2
- package/dist/containers/Node/Node.tsx +3 -1
- package/dist/containers/Node/NodeStructure/NodeStructure.tsx +3 -1
- package/dist/containers/Node/NodeStructure/Pdisk.tsx +2 -2
- package/dist/containers/Nodes/Nodes.tsx +3 -2
- package/dist/containers/Nodes/getNodesColumns.tsx +3 -1
- package/dist/containers/Storage/Storage.tsx +3 -2
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +2 -2
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +5 -12
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -2
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/Details.tsx +20 -11
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +14 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +26 -37
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/Preview.tsx +37 -25
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +155 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +7 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/index.ts +11 -0
- package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +7 -0
- package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +3 -2
- package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.scss +4 -1
- package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +42 -11
- package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +1 -1
- package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.tsx +11 -7
- package/dist/containers/Tenant/Query/i18n/en.json +3 -0
- package/dist/containers/Tenant/Query/i18n/ru.json +3 -0
- package/dist/containers/Tenant/Tenant.tsx +3 -2
- package/dist/containers/UserSettings/Setting.tsx +9 -2
- package/dist/containers/UserSettings/i18n/en.json +5 -1
- package/dist/containers/UserSettings/i18n/ru.json +5 -1
- package/dist/containers/UserSettings/settings.ts +25 -0
- package/dist/services/api.ts +16 -16
- package/dist/store/reducers/executeQuery.ts +33 -7
- package/dist/store/reducers/explainQuery.ts +12 -4
- package/dist/store/reducers/healthcheckInfo.ts +27 -11
- package/dist/store/reducers/settings/settings.ts +4 -10
- package/dist/store/reducers/tenant/tenant.ts +19 -1
- package/dist/store/reducers/tenant/types.ts +3 -1
- package/dist/store/reducers/tenants/selectors.ts +1 -1
- package/dist/store/reducers/tenants/utils.ts +2 -2
- package/dist/types/additionalProps.ts +8 -1
- package/dist/types/api/tenant.ts +19 -20
- package/dist/types/store/executeQuery.ts +11 -1
- package/dist/types/store/query.ts +2 -1
- package/dist/utils/autofetcher.ts +7 -7
- package/dist/utils/constants.ts +2 -1
- package/dist/utils/hooks/i18n/en.json +1 -1
- package/dist/utils/hooks/i18n/ru.json +1 -1
- package/dist/utils/hooks/useQueryModes.ts +4 -2
- package/dist/utils/i18n/i18n.ts +10 -4
- package/dist/utils/nodes.ts +0 -6
- package/dist/utils/query.ts +14 -0
- package/dist/utils/settings.ts +10 -0
- package/package.json +1 -1
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/PreviewItem/PreviewItem.tsx +0 -33
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/PreviewItem/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +0 -213
package/dist/services/api.ts
CHANGED
@@ -28,6 +28,7 @@ import type {DescribeTopicResult} from '../types/api/topic';
|
|
28
28
|
import type {TEvPDiskStateResponse} from '../types/api/pdisk';
|
29
29
|
import type {TEvVDiskStateResponse} from '../types/api/vdisk';
|
30
30
|
import type {TUserToken} from '../types/api/whoami';
|
31
|
+
import type {QuerySyntax} from '../types/store/query';
|
31
32
|
import type {ComputeApiRequestParams, NodesApiRequestParams} from '../store/reducers/nodes/types';
|
32
33
|
import type {StorageApiRequestParams} from '../store/reducers/storage/types';
|
33
34
|
|
@@ -75,12 +76,16 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
75
76
|
cluster_name: clusterName,
|
76
77
|
});
|
77
78
|
}
|
78
|
-
getTenantInfo({path}: {path: string}) {
|
79
|
-
return this.get<TTenantInfo>(
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
getTenantInfo({path}: {path: string}, {concurrentId}: AxiosOptions = {}) {
|
80
|
+
return this.get<TTenantInfo>(
|
81
|
+
this.getPath('/viewer/json/tenantinfo'),
|
82
|
+
{
|
83
|
+
path,
|
84
|
+
tablets: true,
|
85
|
+
storage: true,
|
86
|
+
},
|
87
|
+
{concurrentId: concurrentId || `getTenantInfo|${path}`},
|
88
|
+
);
|
84
89
|
}
|
85
90
|
getNodes(
|
86
91
|
{
|
@@ -281,17 +286,15 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
281
286
|
}
|
282
287
|
sendQuery<Action extends Actions, Schema extends Schemas = undefined>(
|
283
288
|
{
|
284
|
-
query,
|
285
|
-
database,
|
286
|
-
action,
|
287
|
-
stats,
|
288
289
|
schema,
|
290
|
+
...params
|
289
291
|
}: {
|
290
292
|
query?: string;
|
291
293
|
database?: string;
|
292
294
|
action?: Action;
|
293
295
|
stats?: string;
|
294
296
|
schema?: Schema;
|
297
|
+
syntax?: QuerySyntax;
|
295
298
|
},
|
296
299
|
{concurrentId}: AxiosOptions = {},
|
297
300
|
) {
|
@@ -303,12 +306,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
303
306
|
this.getPath(
|
304
307
|
`/viewer/json/query?timeout=${backendTimeout}${schema ? `&schema=${schema}` : ''}`,
|
305
308
|
),
|
306
|
-
|
307
|
-
query,
|
308
|
-
database,
|
309
|
-
action,
|
310
|
-
stats,
|
311
|
-
},
|
309
|
+
params,
|
312
310
|
{},
|
313
311
|
{
|
314
312
|
concurrentId,
|
@@ -320,6 +318,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
320
318
|
query: string,
|
321
319
|
database: string,
|
322
320
|
action: Action,
|
321
|
+
syntax?: QuerySyntax,
|
323
322
|
) {
|
324
323
|
return this.post<ExplainResponse<Action>>(
|
325
324
|
this.getPath('/viewer/json/query'),
|
@@ -327,6 +326,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
327
326
|
query,
|
328
327
|
database,
|
329
328
|
action: action || 'explain',
|
329
|
+
syntax,
|
330
330
|
timeout: 600000,
|
331
331
|
},
|
332
332
|
{},
|
@@ -4,12 +4,14 @@ import type {ExecuteActions} from '../../types/api/query';
|
|
4
4
|
import type {
|
5
5
|
ExecuteQueryAction,
|
6
6
|
ExecuteQueryState,
|
7
|
+
ExecuteQueryStateSlice,
|
7
8
|
MonacoHotKeyAction,
|
9
|
+
QueryInHistory,
|
8
10
|
} from '../../types/store/executeQuery';
|
9
|
-
import type {QueryRequestParams, QueryMode} from '../../types/store/query';
|
11
|
+
import type {QueryRequestParams, QueryMode, QuerySyntax} from '../../types/store/query';
|
10
12
|
import {getValueFromLS, parseJson} from '../../utils/utils';
|
11
13
|
import {QUERIES_HISTORY_KEY} from '../../utils/constants';
|
12
|
-
import {parseQueryAPIExecuteResponse} from '../../utils/query';
|
14
|
+
import {QUERY_MODES, QUERY_SYNTAX, parseQueryAPIExecuteResponse} from '../../utils/query';
|
13
15
|
import {parseQueryError} from '../../utils/error';
|
14
16
|
import '../../services/api';
|
15
17
|
|
@@ -87,8 +89,12 @@ const executeQuery: Reducer<ExecuteQueryState, ExecuteQueryAction> = (
|
|
87
89
|
}
|
88
90
|
|
89
91
|
case SAVE_QUERY_TO_HISTORY: {
|
90
|
-
const
|
91
|
-
|
92
|
+
const queryText = action.data.queryText;
|
93
|
+
|
94
|
+
// Do not save explicit yql syntax value for easier further support (use yql by default)
|
95
|
+
const syntax = action.data.mode === QUERY_MODES.pg ? QUERY_SYNTAX.pg : undefined;
|
96
|
+
|
97
|
+
const newQueries = [...state.history.queries, {queryText, syntax}].slice(
|
92
98
|
state.history.queries.length >= MAXIMUM_QUERIES_IN_HISTORY ? 1 : 0,
|
93
99
|
);
|
94
100
|
window.localStorage.setItem(QUERIES_HISTORY_KEY, JSON.stringify(newQueries));
|
@@ -151,7 +157,15 @@ interface SendQueryParams extends QueryRequestParams {
|
|
151
157
|
}
|
152
158
|
|
153
159
|
export const sendExecuteQuery = ({query, database, mode}: SendQueryParams) => {
|
154
|
-
|
160
|
+
let action: ExecuteActions = 'execute';
|
161
|
+
let syntax: QuerySyntax = QUERY_SYNTAX.yql;
|
162
|
+
|
163
|
+
if (mode === 'pg') {
|
164
|
+
action = 'execute-query';
|
165
|
+
syntax = QUERY_SYNTAX.pg;
|
166
|
+
} else if (mode) {
|
167
|
+
action = `execute-${mode}`;
|
168
|
+
}
|
155
169
|
|
156
170
|
return createApiRequest({
|
157
171
|
request: window.api.sendQuery({
|
@@ -159,6 +173,7 @@ export const sendExecuteQuery = ({query, database, mode}: SendQueryParams) => {
|
|
159
173
|
query,
|
160
174
|
database,
|
161
175
|
action,
|
176
|
+
syntax,
|
162
177
|
stats: 'profile',
|
163
178
|
}),
|
164
179
|
actions: SEND_QUERY,
|
@@ -166,10 +181,10 @@ export const sendExecuteQuery = ({query, database, mode}: SendQueryParams) => {
|
|
166
181
|
});
|
167
182
|
};
|
168
183
|
|
169
|
-
export const saveQueryToHistory = (
|
184
|
+
export const saveQueryToHistory = (queryText: string, mode: QueryMode) => {
|
170
185
|
return {
|
171
186
|
type: SAVE_QUERY_TO_HISTORY,
|
172
|
-
data:
|
187
|
+
data: {queryText, mode},
|
173
188
|
} as const;
|
174
189
|
};
|
175
190
|
|
@@ -206,4 +221,15 @@ export const setTenantPath = (value: string) => {
|
|
206
221
|
} as const;
|
207
222
|
};
|
208
223
|
|
224
|
+
export const selectQueriesHistory = (state: ExecuteQueryStateSlice): QueryInHistory[] => {
|
225
|
+
return state.executeQuery.history.queries.map((rawQuery) => {
|
226
|
+
if (typeof rawQuery === 'string') {
|
227
|
+
return {
|
228
|
+
queryText: rawQuery,
|
229
|
+
};
|
230
|
+
}
|
231
|
+
return rawQuery;
|
232
|
+
});
|
233
|
+
};
|
234
|
+
|
209
235
|
export default executeQuery;
|
@@ -9,10 +9,10 @@ import type {
|
|
9
9
|
ExplainQueryState,
|
10
10
|
PreparedExplainResponse,
|
11
11
|
} from '../../types/store/explainQuery';
|
12
|
-
import type {QueryRequestParams, QueryMode} from '../../types/store/query';
|
12
|
+
import type {QueryRequestParams, QueryMode, QuerySyntax} from '../../types/store/query';
|
13
13
|
|
14
14
|
import {preparePlan} from '../../utils/prepareQueryExplain';
|
15
|
-
import {parseQueryAPIExplainResponse, parseQueryExplainPlan} from '../../utils/query';
|
15
|
+
import {QUERY_SYNTAX, parseQueryAPIExplainResponse, parseQueryExplainPlan} from '../../utils/query';
|
16
16
|
import {parseQueryError} from '../../utils/error';
|
17
17
|
|
18
18
|
import {createRequestActionTypes, createApiRequest} from '../utils';
|
@@ -103,10 +103,18 @@ interface ExplainQueryParams extends QueryRequestParams {
|
|
103
103
|
}
|
104
104
|
|
105
105
|
export const getExplainQuery = ({query, database, mode}: ExplainQueryParams) => {
|
106
|
-
|
106
|
+
let action: ExplainActions = 'explain';
|
107
|
+
let syntax: QuerySyntax = QUERY_SYNTAX.yql;
|
108
|
+
|
109
|
+
if (mode === 'pg') {
|
110
|
+
action = 'explain-query';
|
111
|
+
syntax = QUERY_SYNTAX.pg;
|
112
|
+
} else if (mode) {
|
113
|
+
action = `explain-${mode}`;
|
114
|
+
}
|
107
115
|
|
108
116
|
return createApiRequest({
|
109
|
-
request: window.api.getExplainQuery(query, database, action),
|
117
|
+
request: window.api.getExplainQuery(query, database, action, syntax),
|
110
118
|
actions: GET_EXPLAIN_QUERY,
|
111
119
|
dataHandler: (response): PreparedExplainResponse => {
|
112
120
|
const {plan: rawPlan, ast} = parseQueryAPIExplainResponse(response);
|
@@ -1,17 +1,16 @@
|
|
1
1
|
import _flow from 'lodash/fp/flow';
|
2
2
|
import _sortBy from 'lodash/fp/sortBy';
|
3
3
|
import _uniqBy from 'lodash/fp/uniqBy';
|
4
|
-
import _omit from 'lodash/omit';
|
5
4
|
import {createSelector, Selector} from 'reselect';
|
6
5
|
import {Reducer} from 'redux';
|
7
6
|
|
8
|
-
import {
|
9
|
-
|
7
|
+
import type {
|
8
|
+
IHealthCheckInfoAction,
|
10
9
|
IHealthcheckInfoRootStateSlice,
|
10
|
+
IHealthcheckInfoState,
|
11
11
|
IIssuesTree,
|
12
|
-
IHealthCheckInfoAction,
|
13
12
|
} from '../../types/store/healthcheck';
|
14
|
-
import {IssueLog, StatusFlag} from '../../types/api/healthcheck';
|
13
|
+
import type {IssueLog, StatusFlag} from '../../types/api/healthcheck';
|
15
14
|
|
16
15
|
import '../../services/api';
|
17
16
|
import {createRequestActionTypes, createApiRequest} from '../utils';
|
@@ -49,6 +48,8 @@ const healthcheckInfo: Reducer<IHealthcheckInfoState, IHealthCheckInfoAction> =
|
|
49
48
|
...state,
|
50
49
|
error: action.error,
|
51
50
|
loading: false,
|
51
|
+
wasLoaded: true,
|
52
|
+
data: undefined,
|
52
53
|
};
|
53
54
|
}
|
54
55
|
|
@@ -110,6 +111,24 @@ const getInvertedConsequencesTree = ({
|
|
110
111
|
: [];
|
111
112
|
};
|
112
113
|
|
114
|
+
const getIssuesStatistics = (data: IssueLog[]): [StatusFlag, number][] => {
|
115
|
+
const issuesMap = {} as Record<StatusFlag, number>;
|
116
|
+
|
117
|
+
for (const issue of data) {
|
118
|
+
if (!issuesMap[issue.status]) {
|
119
|
+
issuesMap[issue.status] = 0;
|
120
|
+
}
|
121
|
+
issuesMap[issue.status]++;
|
122
|
+
}
|
123
|
+
|
124
|
+
return (Object.entries(issuesMap) as [StatusFlag, number][]).sort(([aStatus], [bStatus]) => {
|
125
|
+
const bPriority = mapStatusToPriority[bStatus] || 0;
|
126
|
+
const aPriority = mapStatusToPriority[aStatus] || 0;
|
127
|
+
|
128
|
+
return aPriority - bPriority;
|
129
|
+
});
|
130
|
+
};
|
131
|
+
|
113
132
|
const getIssuesLog = (state: IHealthcheckInfoRootStateSlice) =>
|
114
133
|
state.healthcheckInfo.data?.issue_log;
|
115
134
|
|
@@ -121,13 +140,10 @@ export const selectIssuesTrees: Selector<IHealthcheckInfoRootStateSlice, IIssues
|
|
121
140
|
return getInvertedConsequencesTree({data, roots});
|
122
141
|
});
|
123
142
|
|
124
|
-
export const
|
143
|
+
export const selectIssuesStatistics: Selector<
|
125
144
|
IHealthcheckInfoRootStateSlice,
|
126
|
-
|
127
|
-
|
128
|
-
> = createSelector([selectIssuesTrees, (_, id: string | undefined) => id], (issuesTrees = [], id) =>
|
129
|
-
issuesTrees.find((issuesTree) => issuesTree.id === id),
|
130
|
-
);
|
145
|
+
[StatusFlag, number][]
|
146
|
+
> = createSelector(getIssuesLog, (issues = []) => getIssuesStatistics(issues));
|
131
147
|
|
132
148
|
export function getHealthcheckInfo(database: string) {
|
133
149
|
return createApiRequest({
|
@@ -14,10 +14,12 @@ import {
|
|
14
14
|
CLUSTER_INFO_HIDDEN_KEY,
|
15
15
|
LAST_USED_QUERY_ACTION_KEY,
|
16
16
|
USE_BACKEND_PARAMS_FOR_TABLES_KEY,
|
17
|
+
LANGUAGE_KEY,
|
17
18
|
} from '../../../utils/constants';
|
18
19
|
import '../../../services/api';
|
19
|
-
import {
|
20
|
+
import {parseJson} from '../../../utils/utils';
|
20
21
|
import {QUERY_ACTIONS, QUERY_MODES} from '../../../utils/query';
|
22
|
+
import {readSavedSettingsValue, systemSettings, userSettings} from '../../../utils/settings';
|
21
23
|
|
22
24
|
import {TENANT_PAGES_IDS} from '../tenant/constants';
|
23
25
|
|
@@ -38,20 +40,12 @@ export const ProblemFilterValues = {
|
|
38
40
|
PROBLEMS: 'With problems',
|
39
41
|
} as const;
|
40
42
|
|
41
|
-
const userSettings = window.userSettings || {};
|
42
|
-
const systemSettings = window.systemSettings || {};
|
43
|
-
|
44
|
-
export function readSavedSettingsValue(key: string, defaultValue?: string) {
|
45
|
-
const savedValue = window.web_version ? userSettings[key] : getValueFromLS(key);
|
46
|
-
|
47
|
-
return savedValue ?? defaultValue;
|
48
|
-
}
|
49
|
-
|
50
43
|
export const initialState = {
|
51
44
|
problemFilter: ProblemFilterValues.ALL,
|
52
45
|
userSettings: {
|
53
46
|
...userSettings,
|
54
47
|
[THEME_KEY]: readSavedSettingsValue(THEME_KEY, 'system'),
|
48
|
+
[LANGUAGE_KEY]: readSavedSettingsValue(LANGUAGE_KEY),
|
55
49
|
[INVERTED_DISKS_KEY]: readSavedSettingsValue(INVERTED_DISKS_KEY, 'false'),
|
56
50
|
[USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY]: readSavedSettingsValue(
|
57
51
|
USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
|
@@ -20,6 +20,7 @@ const SET_QUERY_TAB = 'tenant/SET_QUERY_TAB';
|
|
20
20
|
const SET_DIAGNOSTICS_TAB = 'tenant/SET_DIAGNOSTICS_TAB';
|
21
21
|
const SET_SUMMARY_TAB = 'tenant/SET_SUMMARY_TAB';
|
22
22
|
const CLEAR_TENANT = 'tenant/CLEAR_TENANT';
|
23
|
+
const SET_DATA_WAS_NOT_LOADED = 'tenant/SET_DATA_WAS_NOT_LOADED';
|
23
24
|
|
24
25
|
const initialState = {loading: false, wasLoaded: false};
|
25
26
|
|
@@ -43,6 +44,10 @@ const tenantReducer: Reducer<TenantState, TenantAction> = (state = initialState,
|
|
43
44
|
}
|
44
45
|
|
45
46
|
case FETCH_TENANT.FAILURE: {
|
47
|
+
if (action.error?.isCancelled) {
|
48
|
+
return state;
|
49
|
+
}
|
50
|
+
|
46
51
|
return {
|
47
52
|
...state,
|
48
53
|
error: action.error,
|
@@ -84,6 +89,13 @@ const tenantReducer: Reducer<TenantState, TenantAction> = (state = initialState,
|
|
84
89
|
};
|
85
90
|
}
|
86
91
|
|
92
|
+
case SET_DATA_WAS_NOT_LOADED: {
|
93
|
+
return {
|
94
|
+
...state,
|
95
|
+
wasLoaded: false,
|
96
|
+
};
|
97
|
+
}
|
98
|
+
|
87
99
|
default:
|
88
100
|
return state;
|
89
101
|
}
|
@@ -91,7 +103,7 @@ const tenantReducer: Reducer<TenantState, TenantAction> = (state = initialState,
|
|
91
103
|
|
92
104
|
export const getTenantInfo = ({path}: {path: string}) => {
|
93
105
|
return createApiRequest({
|
94
|
-
request: window.api.getTenantInfo({path}),
|
106
|
+
request: window.api.getTenantInfo({path}, {concurrentId: 'getTenantInfo'}),
|
95
107
|
actions: FETCH_TENANT,
|
96
108
|
dataHandler: (tenantData): TTenant | undefined => {
|
97
109
|
return tenantData.TenantInfo?.[0];
|
@@ -131,4 +143,10 @@ export function setSummaryTab(tab: TenantSummaryTab) {
|
|
131
143
|
} as const;
|
132
144
|
}
|
133
145
|
|
146
|
+
export const setDataWasNotLoaded = () => {
|
147
|
+
return {
|
148
|
+
type: SET_DATA_WAS_NOT_LOADED,
|
149
|
+
} as const;
|
150
|
+
};
|
151
|
+
|
134
152
|
export default tenantReducer;
|
@@ -16,6 +16,7 @@ import {
|
|
16
16
|
setQueryTab,
|
17
17
|
setSummaryTab,
|
18
18
|
setTenantPage,
|
19
|
+
setDataWasNotLoaded,
|
19
20
|
} from './tenant';
|
20
21
|
|
21
22
|
export type TenantPage = ValueOf<typeof TENANT_PAGES_IDS>;
|
@@ -41,4 +42,5 @@ export type TenantAction =
|
|
41
42
|
| ReturnType<typeof setTenantPage>
|
42
43
|
| ReturnType<typeof setQueryTab>
|
43
44
|
| ReturnType<typeof setDiagnosticsTab>
|
44
|
-
| ReturnType<typeof setSummaryTab
|
45
|
+
| ReturnType<typeof setSummaryTab>
|
46
|
+
| ReturnType<typeof setDataWasNotLoaded>;
|
@@ -24,7 +24,7 @@ const filterTenantsByProblems = (tenants: PreparedTenant[], problemFilter: Probl
|
|
24
24
|
const filteredTenantsBySearch = (tenants: PreparedTenant[], searchQuery: string) => {
|
25
25
|
return tenants.filter((item) => {
|
26
26
|
const re = new RegExp(escapeRegExp(searchQuery), 'i');
|
27
|
-
return re.test(item.Name) || re.test(item.controlPlaneName);
|
27
|
+
return re.test(item.Name || '') || re.test(item.controlPlaneName);
|
28
28
|
});
|
29
29
|
};
|
30
30
|
|
@@ -2,8 +2,8 @@ import type {TTenant} from '../../../types/api/tenant';
|
|
2
2
|
import {isNumeric} from '../../../utils/utils';
|
3
3
|
|
4
4
|
const getControlPlaneValue = (tenant: TTenant) => {
|
5
|
-
const parts = tenant.Name
|
6
|
-
const defaultValue = parts
|
5
|
+
const parts = tenant.Name?.split('/');
|
6
|
+
const defaultValue = parts?.length ? parts[parts.length - 1] : '—';
|
7
7
|
const controlPlaneName = tenant.ControlPlane?.name;
|
8
8
|
|
9
9
|
return controlPlaneName ?? defaultValue;
|
@@ -2,6 +2,7 @@ import type {ReactNode} from 'react';
|
|
2
2
|
|
3
3
|
import type {InfoViewerItem} from '../components/InfoViewer';
|
4
4
|
import type {ETenantType} from './api/tenant';
|
5
|
+
import type {TSystemStateInfo} from './api/nodes';
|
5
6
|
import type {VersionToColorMap} from './versions';
|
6
7
|
|
7
8
|
export interface AdditionalVersionsProps {
|
@@ -20,5 +21,11 @@ export interface AdditionalClusterProps {
|
|
20
21
|
|
21
22
|
export interface AdditionalTenantsProps {
|
22
23
|
prepareTenantBackend?: (backend: string | undefined) => string | undefined;
|
23
|
-
getMonitoringLink?: (name
|
24
|
+
getMonitoringLink?: (name?: string, type?: ETenantType) => ReactNode;
|
25
|
+
}
|
26
|
+
|
27
|
+
export type NodeAddress = Pick<TSystemStateInfo, 'Host' | 'Endpoints'>;
|
28
|
+
|
29
|
+
export interface AdditionalNodesProps extends Record<string, unknown> {
|
30
|
+
getNodeRef?: (node?: NodeAddress) => string | null;
|
24
31
|
}
|
package/dist/types/api/tenant.ts
CHANGED
@@ -22,38 +22,38 @@ export interface TTenantInfo {
|
|
22
22
|
}
|
23
23
|
|
24
24
|
export interface TTenant {
|
25
|
-
Name
|
26
|
-
Id
|
27
|
-
Type
|
28
|
-
State
|
25
|
+
Name?: string;
|
26
|
+
Id?: string;
|
27
|
+
Type?: ETenantType;
|
28
|
+
State?: State;
|
29
29
|
StateStats?: THiveDomainStatsStateCount[];
|
30
|
-
Metrics
|
30
|
+
Metrics?: TMetrics;
|
31
31
|
NodeIds?: number[];
|
32
|
-
AliveNodes
|
33
|
-
Resources
|
32
|
+
AliveNodes?: number;
|
33
|
+
Resources?: TTenantResources;
|
34
34
|
/** uint64 */
|
35
|
-
CreateTime
|
36
|
-
Owner
|
35
|
+
CreateTime?: string;
|
36
|
+
Owner?: string;
|
37
37
|
Users?: string[];
|
38
38
|
PoolStats?: TPoolStats[];
|
39
|
-
UserAttributes
|
40
|
-
Overall
|
39
|
+
UserAttributes?: Record<string, string>;
|
40
|
+
Overall?: EFlag;
|
41
41
|
SystemTablets?: TTabletStateInfo[];
|
42
|
-
ResourceId
|
42
|
+
ResourceId?: string;
|
43
43
|
Tablets?: TTabletStateInfo[];
|
44
44
|
/** uint64 */
|
45
|
-
StorageAllocatedSize
|
45
|
+
StorageAllocatedSize?: string;
|
46
46
|
/** uint64 */
|
47
|
-
StorageMinAvailableSize
|
47
|
+
StorageMinAvailableSize?: string;
|
48
48
|
Nodes?: TSystemStateInfo[];
|
49
49
|
/** uint64 */
|
50
|
-
MemoryUsed
|
50
|
+
MemoryUsed?: string;
|
51
51
|
/** uint64 */
|
52
|
-
MemoryLimit
|
52
|
+
MemoryLimit?: string;
|
53
53
|
/** double */
|
54
|
-
CoresUsed
|
54
|
+
CoresUsed?: number;
|
55
55
|
/** uint64 */
|
56
|
-
StorageGroups
|
56
|
+
StorageGroups?: string;
|
57
57
|
|
58
58
|
MonitoringEndpoint?: string; // additional
|
59
59
|
ControlPlane?: ControlPlane; // additional
|
@@ -139,11 +139,10 @@ enum State {
|
|
139
139
|
'CONFIGURING' = 'CONFIGURING',
|
140
140
|
}
|
141
141
|
|
142
|
-
enum ETabletVolatileState {
|
142
|
+
export enum ETabletVolatileState {
|
143
143
|
'TABLET_VOLATILE_STATE_UNKNOWN' = 'TABLET_VOLATILE_STATE_UNKNOWN',
|
144
144
|
'TABLET_VOLATILE_STATE_STOPPED' = 'TABLET_VOLATILE_STATE_STOPPED',
|
145
145
|
'TABLET_VOLATILE_STATE_BOOTING' = 'TABLET_VOLATILE_STATE_BOOTING',
|
146
146
|
'TABLET_VOLATILE_STATE_STARTING' = 'TABLET_VOLATILE_STATE_STARTING',
|
147
147
|
'TABLET_VOLATILE_STATE_RUNNING' = 'TABLET_VOLATILE_STATE_RUNNING',
|
148
|
-
'_TABLET_VOLATILE_STATE_BLOCKED' = '_TABLET_VOLATILE_STATE_BLOCKED',
|
149
148
|
}
|
@@ -14,11 +14,17 @@ import type {IQueryResult, QueryError, QueryErrorResponse} from './query';
|
|
14
14
|
|
15
15
|
export type MonacoHotKeyAction = ValueOf<typeof MONACO_HOT_KEY_ACTIONS>;
|
16
16
|
|
17
|
+
export interface QueryInHistory {
|
18
|
+
queryText: string;
|
19
|
+
syntax?: string;
|
20
|
+
}
|
21
|
+
|
17
22
|
export interface ExecuteQueryState {
|
18
23
|
loading: boolean;
|
19
24
|
input: string;
|
20
25
|
history: {
|
21
|
-
|
26
|
+
// String type for backward compatibility
|
27
|
+
queries: (QueryInHistory | string)[];
|
22
28
|
currentIndex: number;
|
23
29
|
};
|
24
30
|
monacoHotKey: null | MonacoHotKeyAction;
|
@@ -38,3 +44,7 @@ export type ExecuteQueryAction =
|
|
38
44
|
| ReturnType<typeof saveQueryToHistory>
|
39
45
|
| ReturnType<typeof setMonacoHotKey>
|
40
46
|
| ReturnType<typeof setTenantPath>;
|
47
|
+
|
48
|
+
export interface ExecuteQueryStateSlice {
|
49
|
+
executeQuery: ExecuteQueryState;
|
50
|
+
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import {QUERY_ACTIONS, QUERY_MODES} from '../../utils/query';
|
1
|
+
import {QUERY_ACTIONS, QUERY_MODES, QUERY_SYNTAX} from '../../utils/query';
|
2
2
|
|
3
3
|
import type {IResponseError, NetworkError} from '../api/error';
|
4
4
|
import type {
|
@@ -29,6 +29,7 @@ export type QueryError = NetworkError | QueryErrorResponse;
|
|
29
29
|
|
30
30
|
export type QueryAction = ValueOf<typeof QUERY_ACTIONS>;
|
31
31
|
export type QueryMode = ValueOf<typeof QUERY_MODES>;
|
32
|
+
export type QuerySyntax = ValueOf<typeof QUERY_SYNTAX>;
|
32
33
|
|
33
34
|
export interface SavedQuery {
|
34
35
|
name: string;
|
@@ -1,4 +1,11 @@
|
|
1
1
|
export class AutoFetcher {
|
2
|
+
static DEFAULT_TIMEOUT = 30000;
|
3
|
+
static MIN_TIMEOUT = 30000;
|
4
|
+
timeout: number;
|
5
|
+
active: boolean;
|
6
|
+
timer: undefined | ReturnType<typeof setTimeout>;
|
7
|
+
launchCounter: number;
|
8
|
+
|
2
9
|
constructor() {
|
3
10
|
this.timeout = AutoFetcher.DEFAULT_TIMEOUT;
|
4
11
|
this.active = true;
|
@@ -52,11 +59,4 @@ export class AutoFetcher {
|
|
52
59
|
this.launchCounter++;
|
53
60
|
this.active = true;
|
54
61
|
}
|
55
|
-
|
56
|
-
static DEFAULT_TIMEOUT = 30000;
|
57
|
-
static MIN_TIMEOUT = 30000;
|
58
|
-
timeout: number;
|
59
|
-
active: boolean;
|
60
|
-
timer: undefined | ReturnType<typeof setTimeout>;
|
61
|
-
launchCounter: number;
|
62
62
|
}
|
package/dist/utils/constants.ts
CHANGED
@@ -25,7 +25,6 @@ export const TABLET_STATES = {
|
|
25
25
|
TABLET_VOLATILE_STATE_BOOTING: 'booting',
|
26
26
|
TABLET_VOLATILE_STATE_STARTING: 'starting',
|
27
27
|
TABLET_VOLATILE_STATE_RUNNING: 'running',
|
28
|
-
TABLET_VOLATILE_STATE_BLOCKED: 'blocked',
|
29
28
|
};
|
30
29
|
|
31
30
|
export const TABLET_COLORS = {
|
@@ -81,9 +80,11 @@ export const COLORS_PRIORITY = {
|
|
81
80
|
// ==== Titles ====
|
82
81
|
export const DEVELOPER_UI_TITLE = 'Developer UI';
|
83
82
|
export const CLUSTER_DEFAULT_TITLE = 'Cluster';
|
83
|
+
export const TENANT_DEFAULT_TITLE = 'Database';
|
84
84
|
|
85
85
|
// ==== Settings ====
|
86
86
|
export const THEME_KEY = 'theme';
|
87
|
+
export const LANGUAGE_KEY = 'language';
|
87
88
|
export const INVERTED_DISKS_KEY = 'invertedDisks';
|
88
89
|
export const USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY = 'useNodesEndpointInDiagnostics';
|
89
90
|
export const ENABLE_ADDITIONAL_QUERY_MODES = 'enableAdditionalQueryModes';
|
@@ -1,3 +1,3 @@
|
|
1
1
|
{
|
2
|
-
"useQueryModes.queryModeCannotBeSet": "Query mode
|
2
|
+
"useQueryModes.queryModeCannotBeSet": "Query mode '{{mode}}' cannot be set. You need to turn in additional query modes in settings to enable it"
|
3
3
|
}
|
@@ -1,3 +1,3 @@
|
|
1
1
|
{
|
2
|
-
"useQueryModes.queryModeCannotBeSet": "Режим выполнения запроса
|
2
|
+
"useQueryModes.queryModeCannotBeSet": "Режим выполнения запроса '{{mode}}' недоступен. Вам необходимо включить дополнительные режимы выполнения запросов в настройках"
|
3
3
|
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import type {QueryMode} from '../../types/store/query';
|
2
2
|
import {ENABLE_ADDITIONAL_QUERY_MODES, QUERY_INITIAL_MODE_KEY} from '../constants';
|
3
|
-
import {isNewQueryMode} from '../query';
|
3
|
+
import {QUERY_MODES_TITLES, isNewQueryMode} from '../query';
|
4
4
|
import createToast from '../createToast';
|
5
5
|
import {useSetting} from './useSetting';
|
6
6
|
import i18n from './i18n';
|
@@ -18,7 +18,9 @@ export const useQueryModes = (): [QueryMode, SetQueryModeIfAvailable] => {
|
|
18
18
|
if (isNewQueryMode(value) && !enableAdditionalQueryModes) {
|
19
19
|
createToast({
|
20
20
|
name: 'QueryModeCannotBeSet',
|
21
|
-
title:
|
21
|
+
title:
|
22
|
+
errorMessage ??
|
23
|
+
i18n('useQueryModes.queryModeCannotBeSet', {mode: QUERY_MODES_TITLES[value]}),
|
22
24
|
type: 'error',
|
23
25
|
});
|
24
26
|
|
package/dist/utils/i18n/i18n.ts
CHANGED
@@ -2,15 +2,21 @@ import {I18N} from '@gravity-ui/i18n';
|
|
2
2
|
import {configure as configureUiKit} from '@gravity-ui/uikit';
|
3
3
|
import {configure as configureYdbUiComponents} from 'ydb-ui-components';
|
4
4
|
|
5
|
+
import {LANGUAGE_KEY} from '../constants';
|
6
|
+
import {readSavedSettingsValue} from '../settings';
|
7
|
+
|
5
8
|
enum Lang {
|
6
9
|
En = 'en',
|
7
10
|
Ru = 'ru',
|
8
11
|
}
|
9
12
|
|
13
|
+
const defaultLang = Lang.En;
|
14
|
+
const currentLang = readSavedSettingsValue(LANGUAGE_KEY, defaultLang);
|
15
|
+
|
10
16
|
const i18n = new I18N();
|
11
17
|
|
12
|
-
i18n.setLang(
|
13
|
-
configureYdbUiComponents({lang:
|
14
|
-
configureUiKit({lang:
|
18
|
+
i18n.setLang(currentLang);
|
19
|
+
configureYdbUiComponents({lang: currentLang});
|
20
|
+
configureUiKit({lang: currentLang});
|
15
21
|
|
16
|
-
export {i18n, Lang};
|
22
|
+
export {i18n, Lang, currentLang, defaultLang};
|
package/dist/utils/nodes.ts
CHANGED
@@ -18,12 +18,6 @@ export const NodesUptimeFilterTitles = {
|
|
18
18
|
export const isUnavailableNode = (node: NodesPreparedEntity | TSystemStateInfo) =>
|
19
19
|
!node.SystemState || node.SystemState === EFlag.Grey;
|
20
20
|
|
21
|
-
export type NodeAddress = Pick<TSystemStateInfo, 'Host' | 'Endpoints'>;
|
22
|
-
|
23
|
-
export interface AdditionalNodesInfo extends Record<string, unknown> {
|
24
|
-
getNodeRef?: (node?: NodeAddress) => string | null;
|
25
|
-
}
|
26
|
-
|
27
21
|
export const prepareNodesMap = (nodesList?: TNodeInfo[]) => {
|
28
22
|
return nodesList?.reduce<NodesMap>((nodesMap, node) => {
|
29
23
|
if (node.Id && node.Host) {
|