ydb-embedded-ui 4.23.0 → 4.25.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +15 -0
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +11 -79
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +0 -51
- package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +5 -12
- package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +1 -10
- package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.scss +3 -16
- package/dist/containers/Tenant/Query/QueryEditorControls/QueryEditorControls.tsx +4 -27
- package/dist/containers/Tenant/Query/i18n/en.json +0 -2
- package/dist/containers/Tenant/Query/i18n/ru.json +0 -2
- package/dist/containers/Tenant/utils/schemaActions.ts +11 -18
- package/dist/containers/UserSettings/i18n/en.json +1 -7
- package/dist/containers/UserSettings/i18n/ru.json +1 -7
- package/dist/containers/UserSettings/settings.ts +1 -19
- package/dist/services/api.ts +2 -2
- package/dist/store/reducers/settings/settings.ts +14 -16
- package/dist/utils/constants.ts +0 -11
- package/dist/utils/hooks/useQueryModes.ts +3 -32
- package/dist/utils/query.ts +0 -4
- package/dist/utils/settings.ts +4 -1
- package/package.json +1 -1
- package/dist/containers/Tenant/Diagnostics/OldHealthcheck/Details/Details.tsx +0 -64
- package/dist/containers/Tenant/Diagnostics/OldHealthcheck/Details/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/OldHealthcheck/Healthcheck.scss +0 -137
- package/dist/containers/Tenant/Diagnostics/OldHealthcheck/Healthcheck.tsx +0 -92
- package/dist/containers/Tenant/Diagnostics/OldHealthcheck/Preview/Preview.tsx +0 -82
- package/dist/containers/Tenant/Diagnostics/OldHealthcheck/Preview/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/OldHealthcheck/index.ts +0 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/OldTenantOverview.tsx +0 -155
- package/dist/utils/hooks/i18n/en.json +0 -3
- package/dist/utils/hooks/i18n/index.ts +0 -11
- package/dist/utils/hooks/i18n/ru.json +0 -3
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [4.25.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.24.0...v4.25.0) (2023-12-07)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* **Diagnostics:** remove tenant diagnostics cards setting ([#602](https://github.com/ydb-platform/ydb-embedded-ui/issues/602)) ([fe61df8](https://github.com/ydb-platform/ydb-embedded-ui/commit/fe61df86048013432c4e4788d1e621298ecb1fb2))
|
9
|
+
* **Query:** remove query modes setting ([#600](https://github.com/ydb-platform/ydb-embedded-ui/issues/600)) ([78c63e4](https://github.com/ydb-platform/ydb-embedded-ui/commit/78c63e4a2e60950970914eaba49304b68aad0f80))
|
10
|
+
|
11
|
+
## [4.24.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.23.0...v4.24.0) (2023-12-07)
|
12
|
+
|
13
|
+
|
14
|
+
### Features
|
15
|
+
|
16
|
+
* always use localStorage if no settingsApi ([#603](https://github.com/ydb-platform/ydb-embedded-ui/issues/603)) ([ff692df](https://github.com/ydb-platform/ydb-embedded-ui/commit/ff692dffa99d278f6b261bbf1aac0ee24c661a6d))
|
17
|
+
|
3
18
|
## [4.23.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v4.22.0...v4.23.0) (2023-12-06)
|
4
19
|
|
5
20
|
|
@@ -1,18 +1,10 @@
|
|
1
|
-
import React, {useState} from 'react';
|
2
1
|
import {useSelector} from 'react-redux';
|
3
2
|
import cn from 'bem-cn-lite';
|
4
3
|
|
5
|
-
import {Button, Modal} from '@gravity-ui/uikit';
|
6
|
-
|
7
4
|
import type {EPathType} from '../../../../types/api/schema';
|
8
5
|
import type {AdditionalNodesProps, AdditionalTenantsProps} from '../../../../types/additionalProps';
|
9
|
-
import {Icon} from '../../../../components/Icon';
|
10
|
-
import {useSetting} from '../../../../utils/hooks';
|
11
|
-
import {DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS} from '../../../../utils/constants';
|
12
6
|
import Overview from '../Overview/Overview';
|
13
|
-
import {Healthcheck} from '../OldHealthcheck';
|
14
7
|
import {TenantOverview} from '../TenantOverview/TenantOverview';
|
15
|
-
import {OldTenantOverview} from '../TenantOverview/OldTenantOverview';
|
16
8
|
|
17
9
|
import './DetailedOverview.scss';
|
18
10
|
|
@@ -29,86 +21,26 @@ const b = cn('kv-detailed-overview');
|
|
29
21
|
function DetailedOverview(props: DetailedOverviewProps) {
|
30
22
|
const {type, tenantName, additionalTenantProps, additionalNodesProps} = props;
|
31
23
|
|
32
|
-
const [isModalVisible, setIsModalVisible] = useState(false);
|
33
|
-
|
34
24
|
const {currentSchemaPath} = useSelector((state: any) => state.schema);
|
35
25
|
|
36
|
-
const [displayMetricsCards] = useSetting(DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS);
|
37
|
-
|
38
|
-
const openModalHandler = () => {
|
39
|
-
setIsModalVisible(true);
|
40
|
-
};
|
41
|
-
|
42
|
-
const closeModalHandler = () => {
|
43
|
-
setIsModalVisible(false);
|
44
|
-
};
|
45
|
-
|
46
|
-
const renderModal = () => {
|
47
|
-
return (
|
48
|
-
<Modal open={isModalVisible} onClose={closeModalHandler} className={b('modal')}>
|
49
|
-
<Healthcheck tenant={props.tenantName} fetchData={false} />
|
50
|
-
<Button
|
51
|
-
className={b('close-modal-button')}
|
52
|
-
onClick={closeModalHandler}
|
53
|
-
view="flat-secondary"
|
54
|
-
title="Close"
|
55
|
-
>
|
56
|
-
<Icon name="close" viewBox={'0 0 16 16 '} height={20} width={20} />
|
57
|
-
</Button>
|
58
|
-
</Modal>
|
59
|
-
);
|
60
|
-
};
|
61
|
-
|
62
26
|
const renderTenantOverview = () => {
|
63
|
-
if (displayMetricsCards) {
|
64
|
-
return (
|
65
|
-
<div className={b('section')}>
|
66
|
-
<TenantOverview
|
67
|
-
tenantName={tenantName}
|
68
|
-
additionalTenantProps={additionalTenantProps}
|
69
|
-
additionalNodesProps={additionalNodesProps}
|
70
|
-
/>
|
71
|
-
</div>
|
72
|
-
);
|
73
|
-
}
|
74
|
-
|
75
|
-
return (
|
76
|
-
<>
|
77
|
-
<div className={b('section')}>
|
78
|
-
<OldTenantOverview
|
79
|
-
tenantName={tenantName}
|
80
|
-
additionalTenantProps={additionalTenantProps}
|
81
|
-
/>
|
82
|
-
</div>
|
83
|
-
<div className={b('section')}>
|
84
|
-
<Healthcheck
|
85
|
-
tenant={tenantName}
|
86
|
-
preview={true}
|
87
|
-
showMoreHandler={openModalHandler}
|
88
|
-
/>
|
89
|
-
</div>
|
90
|
-
</>
|
91
|
-
);
|
92
|
-
};
|
93
|
-
|
94
|
-
const renderContent = () => {
|
95
|
-
const isTenant = tenantName === currentSchemaPath;
|
96
27
|
return (
|
97
|
-
<div className={b()}>
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
28
|
+
<div className={b('section')}>
|
29
|
+
<TenantOverview
|
30
|
+
tenantName={tenantName}
|
31
|
+
additionalTenantProps={additionalTenantProps}
|
32
|
+
additionalNodesProps={additionalNodesProps}
|
33
|
+
/>
|
103
34
|
</div>
|
104
35
|
);
|
105
36
|
};
|
106
37
|
|
38
|
+
const isTenant = tenantName === currentSchemaPath;
|
39
|
+
|
107
40
|
return (
|
108
|
-
<
|
109
|
-
{
|
110
|
-
|
111
|
-
</React.Fragment>
|
41
|
+
<div className={b()}>
|
42
|
+
{isTenant ? renderTenantOverview() : <Overview type={type} tenantName={tenantName} />}
|
43
|
+
</div>
|
112
44
|
);
|
113
45
|
}
|
114
46
|
|
@@ -33,57 +33,6 @@
|
|
33
33
|
gap: 10px;
|
34
34
|
}
|
35
35
|
|
36
|
-
&__common-info {
|
37
|
-
display: flex;
|
38
|
-
gap: 20px;
|
39
|
-
|
40
|
-
flex-direction: column;
|
41
|
-
justify-content: flex-start;
|
42
|
-
align-items: stretch;
|
43
|
-
}
|
44
|
-
|
45
|
-
&__system-tablets {
|
46
|
-
display: flex;
|
47
|
-
flex-wrap: wrap;
|
48
|
-
align-items: center;
|
49
|
-
|
50
|
-
margin-bottom: 35px;
|
51
|
-
}
|
52
|
-
|
53
|
-
&__collapse-title {
|
54
|
-
font-size: var(--yc-text-body-2-font-size);
|
55
|
-
font-weight: 500;
|
56
|
-
line-height: var(--yc-text-body-2-line-height);
|
57
|
-
}
|
58
|
-
|
59
|
-
&__section {
|
60
|
-
border-radius: 10px;
|
61
|
-
|
62
|
-
&_metrics {
|
63
|
-
.info-viewer__label {
|
64
|
-
min-width: 150px;
|
65
|
-
}
|
66
|
-
.info-viewer__value {
|
67
|
-
min-width: 100px;
|
68
|
-
}
|
69
|
-
}
|
70
|
-
|
71
|
-
&_pools {
|
72
|
-
display: grid;
|
73
|
-
grid-gap: 7px 20px;
|
74
|
-
|
75
|
-
grid-template-columns: 110px 110px;
|
76
|
-
}
|
77
|
-
}
|
78
|
-
|
79
|
-
&__section-title {
|
80
|
-
margin-bottom: 20px;
|
81
|
-
|
82
|
-
font-size: var(--yc-text-body-2-font-size);
|
83
|
-
font-weight: 600;
|
84
|
-
line-height: var(--yc-text-body-2-line-height);
|
85
|
-
}
|
86
|
-
|
87
36
|
&__info {
|
88
37
|
position: sticky;
|
89
38
|
left: 0;
|
@@ -9,7 +9,7 @@ import {setQueryTab} from '../../../../store/reducers/tenant/tenant';
|
|
9
9
|
import {selectQueriesHistory} from '../../../../store/reducers/executeQuery';
|
10
10
|
import {TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
|
11
11
|
import {useQueryModes, useTypedSelector} from '../../../../utils/hooks';
|
12
|
-
import {QUERY_MODES,
|
12
|
+
import {QUERY_MODES, QUERY_SYNTAX} from '../../../../utils/query';
|
13
13
|
import {MAX_QUERY_HEIGHT, QUERY_TABLE_SETTINGS} from '../../utils/constants';
|
14
14
|
|
15
15
|
import i18n from '../i18n';
|
@@ -31,22 +31,15 @@ function QueriesHistory({changeUserInput}: QueriesHistoryProps) {
|
|
31
31
|
const reversedHistory = [...queriesHistory].reverse();
|
32
32
|
|
33
33
|
const onQueryClick = (query: QueryInHistory) => {
|
34
|
-
let isQueryModeSet = true;
|
35
|
-
|
36
34
|
if (query.syntax === QUERY_SYNTAX.pg && queryMode !== QUERY_MODES.pg) {
|
37
|
-
|
38
|
-
QUERY_MODES.pg,
|
39
|
-
i18n('history.cannot-set-mode', {mode: QUERY_MODES_TITLES[QUERY_MODES.pg]}),
|
40
|
-
);
|
35
|
+
setQueryMode(QUERY_MODES.pg);
|
41
36
|
} else if (query.syntax !== QUERY_SYNTAX.pg && queryMode === QUERY_MODES.pg) {
|
42
37
|
// Set query mode for queries with yql syntax
|
43
|
-
|
38
|
+
setQueryMode(QUERY_MODES.script);
|
44
39
|
}
|
45
40
|
|
46
|
-
|
47
|
-
|
48
|
-
dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
|
49
|
-
}
|
41
|
+
changeUserInput({input: query.queryText});
|
42
|
+
dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
|
50
43
|
};
|
51
44
|
|
52
45
|
const columns: Column<QueryInHistory>[] = [
|
@@ -23,12 +23,11 @@ import {
|
|
23
23
|
DEFAULT_IS_QUERY_RESULT_COLLAPSED,
|
24
24
|
DEFAULT_SIZE_RESULT_PANE_KEY,
|
25
25
|
SAVED_QUERIES_KEY,
|
26
|
-
ENABLE_ADDITIONAL_QUERY_MODES,
|
27
26
|
LAST_USED_QUERY_ACTION_KEY,
|
28
27
|
QUERY_USE_MULTI_SCHEMA_KEY,
|
29
28
|
} from '../../../../utils/constants';
|
30
29
|
import {useSetting, useQueryModes} from '../../../../utils/hooks';
|
31
|
-
import {QUERY_ACTIONS
|
30
|
+
import {QUERY_ACTIONS} from '../../../../utils/query';
|
32
31
|
|
33
32
|
import {
|
34
33
|
PaneVisibilityActionTypes,
|
@@ -85,16 +84,9 @@ function QueryEditor(props) {
|
|
85
84
|
|
86
85
|
const [isResultLoaded, setIsResultLoaded] = useState(false);
|
87
86
|
const [queryMode, setQueryMode] = useQueryModes();
|
88
|
-
const [enableAdditionalQueryModes] = useSetting(ENABLE_ADDITIONAL_QUERY_MODES);
|
89
87
|
const [useMultiSchema] = useSetting(QUERY_USE_MULTI_SCHEMA_KEY);
|
90
88
|
const [lastUsedQueryAction, setLastUsedQueryAction] = useSetting(LAST_USED_QUERY_ACTION_KEY);
|
91
89
|
|
92
|
-
useEffect(() => {
|
93
|
-
if (isNewQueryMode(queryMode) && !enableAdditionalQueryModes) {
|
94
|
-
setQueryMode(QUERY_MODES.script);
|
95
|
-
}
|
96
|
-
}, [enableAdditionalQueryModes, queryMode, setQueryMode]);
|
97
|
-
|
98
90
|
useEffect(() => {
|
99
91
|
if (savedPath !== path) {
|
100
92
|
if (savedPath) {
|
@@ -470,7 +462,6 @@ function QueryEditor(props) {
|
|
470
462
|
disabled={!executeQuery.input}
|
471
463
|
onUpdateQueryMode={setQueryMode}
|
472
464
|
queryMode={queryMode}
|
473
|
-
enableAdditionalQueryModes={enableAdditionalQueryModes}
|
474
465
|
highlitedAction={lastUsedQueryAction}
|
475
466
|
/>
|
476
467
|
);
|
@@ -27,7 +27,7 @@
|
|
27
27
|
$b: &;
|
28
28
|
|
29
29
|
&__button {
|
30
|
-
width:
|
30
|
+
width: 241px;
|
31
31
|
margin-left: 2px;
|
32
32
|
}
|
33
33
|
|
@@ -36,24 +36,11 @@
|
|
36
36
|
justify-content: space-between;
|
37
37
|
align-items: center;
|
38
38
|
|
39
|
-
width:
|
39
|
+
width: 215px;
|
40
40
|
}
|
41
41
|
|
42
42
|
&__popup {
|
43
|
-
width:
|
44
|
-
|
45
|
-
&_extended {
|
46
|
-
width: 241px;
|
47
|
-
}
|
48
|
-
}
|
49
|
-
|
50
|
-
&_extended {
|
51
|
-
#{$b}__button {
|
52
|
-
width: 241px;
|
53
|
-
}
|
54
|
-
#{$b}__button-content {
|
55
|
-
width: 215px;
|
56
|
-
}
|
43
|
+
width: 241px;
|
57
44
|
}
|
58
45
|
}
|
59
46
|
|
@@ -19,17 +19,6 @@ const queryModeSelectorPopupQa = 'query-mode-selector-popup';
|
|
19
19
|
|
20
20
|
const b = block('ydb-query-editor-controls');
|
21
21
|
|
22
|
-
const OldQueryModeSelectorOptions = {
|
23
|
-
[QUERY_MODES.script]: {
|
24
|
-
title: QUERY_MODES_TITLES[QUERY_MODES.script],
|
25
|
-
description: i18n('method-description.script'),
|
26
|
-
},
|
27
|
-
[QUERY_MODES.scan]: {
|
28
|
-
title: QUERY_MODES_TITLES[QUERY_MODES.scan],
|
29
|
-
description: i18n('method-description.scan'),
|
30
|
-
},
|
31
|
-
} as const;
|
32
|
-
|
33
22
|
const QueryModeSelectorOptions = {
|
34
23
|
[QUERY_MODES.script]: {
|
35
24
|
title: QUERY_MODES_TITLES[QUERY_MODES.script],
|
@@ -63,7 +52,6 @@ interface QueryEditorControlsProps {
|
|
63
52
|
disabled: boolean;
|
64
53
|
onUpdateQueryMode: (mode: QueryMode) => void;
|
65
54
|
queryMode: QueryMode;
|
66
|
-
enableAdditionalQueryModes: boolean;
|
67
55
|
highlitedAction: QueryAction;
|
68
56
|
}
|
69
57
|
|
@@ -78,14 +66,9 @@ export const QueryEditorControls = ({
|
|
78
66
|
onUpdateQueryMode,
|
79
67
|
queryMode,
|
80
68
|
highlitedAction,
|
81
|
-
enableAdditionalQueryModes,
|
82
69
|
}: QueryEditorControlsProps) => {
|
83
70
|
const querySelectorMenuItems = useMemo(() => {
|
84
|
-
|
85
|
-
? QueryModeSelectorOptions
|
86
|
-
: OldQueryModeSelectorOptions;
|
87
|
-
|
88
|
-
return Object.entries(options).map(([mode, {title, description}]) => {
|
71
|
+
return Object.entries(QueryModeSelectorOptions).map(([mode, {title, description}]) => {
|
89
72
|
return {
|
90
73
|
text: (
|
91
74
|
<LabelWithPopover
|
@@ -100,7 +83,7 @@ export const QueryEditorControls = ({
|
|
100
83
|
},
|
101
84
|
};
|
102
85
|
});
|
103
|
-
}, [onUpdateQueryMode
|
86
|
+
}, [onUpdateQueryMode]);
|
104
87
|
|
105
88
|
const runView: ButtonView | undefined = highlitedAction === 'execute' ? 'action' : undefined;
|
106
89
|
const explainView: ButtonView | undefined =
|
@@ -132,17 +115,11 @@ export const QueryEditorControls = ({
|
|
132
115
|
>
|
133
116
|
Explain
|
134
117
|
</Button>
|
135
|
-
<div
|
136
|
-
className={b('mode-selector', {
|
137
|
-
extended: enableAdditionalQueryModes,
|
138
|
-
})}
|
139
|
-
>
|
118
|
+
<div className={b('mode-selector')}>
|
140
119
|
<DropdownMenu
|
141
120
|
items={querySelectorMenuItems}
|
142
121
|
popupProps={{
|
143
|
-
className: b('mode-selector__popup',
|
144
|
-
extended: enableAdditionalQueryModes,
|
145
|
-
}),
|
122
|
+
className: b('mode-selector__popup'),
|
146
123
|
qa: queryModeSelectorPopupQa,
|
147
124
|
}}
|
148
125
|
switcher={
|
@@ -8,8 +8,6 @@
|
|
8
8
|
"history.empty": "History is empty",
|
9
9
|
"saved.empty": "There are no saved queries",
|
10
10
|
|
11
|
-
"history.cannot-set-mode": "This query is available only with '{{mode}}' query mode. You need to turn in additional query modes in settings to enable it",
|
12
|
-
|
13
11
|
"delete-dialog.header": "Delete query",
|
14
12
|
"delete-dialog.question": "Are you sure you want to delete query",
|
15
13
|
"delete-dialog.delete": "Delete",
|
@@ -8,8 +8,6 @@
|
|
8
8
|
"history.empty": "История пуста",
|
9
9
|
"saved.empty": "Нет сохраненных запросов",
|
10
10
|
|
11
|
-
"history.cannot-set-mode": "Этот запрос доступен только в режиме '{{mode}}'. Вам необходимо включить дополнительные режимы выполнения запросов в настройках",
|
12
|
-
|
13
11
|
"delete-dialog.header": "Удалить запрос",
|
14
12
|
"delete-dialog.question": "Вы уверены что хотите удалить запрос",
|
15
13
|
"delete-dialog.delete": "Удалить",
|
@@ -4,7 +4,6 @@ import copy from 'copy-to-clipboard';
|
|
4
4
|
import type {NavigationTreeNodeType, NavigationTreeProps} from 'ydb-ui-components';
|
5
5
|
|
6
6
|
import type {QueryMode} from '../../../types/store/query';
|
7
|
-
import type {SetQueryModeIfAvailable} from '../../../utils/hooks';
|
8
7
|
import {changeUserInput} from '../../../store/reducers/executeQuery';
|
9
8
|
import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
|
10
9
|
import {TENANT_QUERY_TABS_ID, TENANT_PAGES_IDS} from '../../../store/reducers/tenant/constants';
|
@@ -25,7 +24,7 @@ import {
|
|
25
24
|
} from './queryTemplates';
|
26
25
|
|
27
26
|
interface ActionsAdditionalEffects {
|
28
|
-
setQueryMode:
|
27
|
+
setQueryMode: (mode: QueryMode) => void;
|
29
28
|
setActivePath: (path: string) => void;
|
30
29
|
}
|
31
30
|
|
@@ -36,18 +35,16 @@ const bindActions = (
|
|
36
35
|
) => {
|
37
36
|
const {setActivePath, setQueryMode} = additionalEffects;
|
38
37
|
|
39
|
-
const inputQuery =
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
const inputQuery = (tmpl: (path: string) => string, mode?: QueryMode) => () => {
|
39
|
+
if (mode) {
|
40
|
+
setQueryMode(mode);
|
41
|
+
}
|
43
42
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
}
|
50
|
-
};
|
43
|
+
dispatch(changeUserInput({input: tmpl(path)}));
|
44
|
+
dispatch(setTenantPage(TENANT_PAGES_IDS.query));
|
45
|
+
dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
|
46
|
+
setActivePath(path);
|
47
|
+
};
|
51
48
|
|
52
49
|
return {
|
53
50
|
createTable: inputQuery(createTableTemplate, 'script'),
|
@@ -56,11 +53,7 @@ const bindActions = (
|
|
56
53
|
upsertQuery: inputQuery(upsertQueryTemplate),
|
57
54
|
createExternalTable: inputQuery(createExternalTableTemplate, 'script'),
|
58
55
|
dropExternalTable: inputQuery(dropExternalTableTemplate, 'script'),
|
59
|
-
selectQueryFromExternalTable: inputQuery(
|
60
|
-
selectQueryTemplate,
|
61
|
-
'query',
|
62
|
-
i18n('actions.externalTableSelectUnavailable'),
|
63
|
-
),
|
56
|
+
selectQueryFromExternalTable: inputQuery(selectQueryTemplate, 'query'),
|
64
57
|
createTopic: inputQuery(createTopicTemplate, 'script'),
|
65
58
|
alterTopic: inputQuery(alterTopicTemplate, 'script'),
|
66
59
|
dropTopic: inputQuery(dropTopicTemplate, 'script'),
|
@@ -22,12 +22,6 @@
|
|
22
22
|
"settings.useBackendParamsForTables.title": "Use virtual table for cluster Nodes tab",
|
23
23
|
"settings.useBackendParamsForTables.popover": "Use table with data load on scroll. It will increase performance, but could work unstable",
|
24
24
|
|
25
|
-
"settings.enableAdditionalQueryModes.title": "Enable additional query modes",
|
26
|
-
"settings.enableAdditionalQueryModes.popover": "Adds 'Data', 'YQL - QueryService' and 'PostgreSQL' modes. May not work on some versions",
|
27
|
-
|
28
25
|
"settings.queryUseMultiSchema.title": "Allow queries with multiple result sets",
|
29
|
-
"settings.queryUseMultiSchema.popover": "Use 'multi' schema for queries that enables queries with multiple result sets. Returns nothing on versions 23-3 and older"
|
30
|
-
|
31
|
-
"settings.tenantDiagnostics.title": "Display metrics cards for database diagnostics",
|
32
|
-
"settings.tenantDiagnostics.popover": "Adds indicators of database resources usage. Incomplete data may be displayed for some databases"
|
26
|
+
"settings.queryUseMultiSchema.popover": "Use 'multi' schema for queries that enables queries with multiple result sets. Returns nothing on versions 23-3 and older"
|
33
27
|
}
|
@@ -22,12 +22,6 @@
|
|
22
22
|
"settings.useBackendParamsForTables.title": "Использовать виртуализированную таблицу для вкладки Nodes кластера",
|
23
23
|
"settings.useBackendParamsForTables.popover": "Использовать таблицу с загрузкой данных по скроллу. Это улучшит производительность, но может работать нестабильно",
|
24
24
|
|
25
|
-
"settings.enableAdditionalQueryModes.title": "Включить дополнительные режимы выполнения запросов",
|
26
|
-
"settings.enableAdditionalQueryModes.popover": "Добавляет режимы 'Data', 'YQL - QueryService' и 'PostgreSQL'. Может работать некорректно на некоторых версиях",
|
27
|
-
|
28
25
|
"settings.queryUseMultiSchema.title": "Разрешить запросы с несколькими результатами",
|
29
|
-
"settings.queryUseMultiSchema.popover": "Использовать для запросов схему 'multi', которая позволяет выполнять запросы с несколькими результатами. На версиях 23-3 и старше результат не возвращается вообще"
|
30
|
-
|
31
|
-
"settings.tenantDiagnostics.title": "Показывать карточки с метриками в диагностике базы данных",
|
32
|
-
"settings.tenantDiagnostics.popover": "Добавляет индикаторы использования ресурсов базы данных. Для некоторых баз могут отображаться неполные данные"
|
26
|
+
"settings.queryUseMultiSchema.popover": "Использовать для запросов схему 'multi', которая позволяет выполнять запросы с несколькими результатами. На версиях 23-3 и старше результат не возвращается вообще"
|
33
27
|
}
|
@@ -4,8 +4,6 @@ import favoriteFilledIcon from '../../assets/icons/star.svg';
|
|
4
4
|
import flaskIcon from '../../assets/icons/flask.svg';
|
5
5
|
|
6
6
|
import {
|
7
|
-
ENABLE_ADDITIONAL_QUERY_MODES,
|
8
|
-
DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS,
|
9
7
|
INVERTED_DISKS_KEY,
|
10
8
|
LANGUAGE_KEY,
|
11
9
|
THEME_KEY,
|
@@ -91,21 +89,11 @@ export const useBackendParamsForTables: SettingProps = {
|
|
91
89
|
title: i18n('settings.useBackendParamsForTables.title'),
|
92
90
|
helpPopoverContent: i18n('settings.useBackendParamsForTables.popover'),
|
93
91
|
};
|
94
|
-
export const enableQueryModesForExplainSetting: SettingProps = {
|
95
|
-
settingKey: ENABLE_ADDITIONAL_QUERY_MODES,
|
96
|
-
title: i18n('settings.enableAdditionalQueryModes.title'),
|
97
|
-
helpPopoverContent: i18n('settings.enableAdditionalQueryModes.popover'),
|
98
|
-
};
|
99
92
|
export const queryUseMultiSchemaSetting: SettingProps = {
|
100
93
|
settingKey: QUERY_USE_MULTI_SCHEMA_KEY,
|
101
94
|
title: i18n('settings.queryUseMultiSchema.title'),
|
102
95
|
helpPopoverContent: i18n('settings.queryUseMultiSchema.popover'),
|
103
96
|
};
|
104
|
-
export const enableNewTenantDiagnosticsDesign: SettingProps = {
|
105
|
-
settingKey: DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS,
|
106
|
-
title: i18n('settings.tenantDiagnostics.title'),
|
107
|
-
helpPopoverContent: i18n('settings.tenantDiagnostics.popover'),
|
108
|
-
};
|
109
97
|
|
110
98
|
export const appearanceSection: SettingsSection = {
|
111
99
|
id: 'appearanceSection',
|
@@ -115,13 +103,7 @@ export const appearanceSection: SettingsSection = {
|
|
115
103
|
export const experimentsSection: SettingsSection = {
|
116
104
|
id: 'experimentsSection',
|
117
105
|
title: i18n('section.experiments'),
|
118
|
-
settings: [
|
119
|
-
useNodesEndpointSetting,
|
120
|
-
useBackendParamsForTables,
|
121
|
-
enableQueryModesForExplainSetting,
|
122
|
-
queryUseMultiSchemaSetting,
|
123
|
-
enableNewTenantDiagnosticsDesign,
|
124
|
-
],
|
106
|
+
settings: [useNodesEndpointSetting, useBackendParamsForTables, queryUseMultiSchemaSetting],
|
125
107
|
};
|
126
108
|
|
127
109
|
export const generalPage: SettingsPage = {
|
package/dist/services/api.ts
CHANGED
@@ -34,11 +34,10 @@ import type {StorageApiRequestParams} from '../store/reducers/storage/types';
|
|
34
34
|
|
35
35
|
import {backend as BACKEND} from '../store';
|
36
36
|
import {prepareSortValue} from '../utils/filters';
|
37
|
+
import {settingsApi} from '../utils/settings';
|
37
38
|
|
38
39
|
const config = {withCredentials: !window.custom_backend};
|
39
40
|
|
40
|
-
const settingsApi = window.web_version ? window.systemSettings?.settingsApi : undefined;
|
41
|
-
|
42
41
|
type AxiosOptions = {
|
43
42
|
concurrentId?: string;
|
44
43
|
};
|
@@ -106,6 +105,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
|
|
106
105
|
{concurrentId},
|
107
106
|
);
|
108
107
|
}
|
108
|
+
/** @deprecated use getNodes instead */
|
109
109
|
getCompute(
|
110
110
|
{sortOrder, sortValue, ...params}: ComputeApiRequestParams,
|
111
111
|
{concurrentId}: AxiosOptions = {},
|
@@ -10,18 +10,21 @@ import {
|
|
10
10
|
USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
|
11
11
|
PARTITIONS_HIDDEN_COLUMNS_KEY,
|
12
12
|
QUERY_INITIAL_MODE_KEY,
|
13
|
-
ENABLE_ADDITIONAL_QUERY_MODES,
|
14
13
|
CLUSTER_INFO_HIDDEN_KEY,
|
15
14
|
LAST_USED_QUERY_ACTION_KEY,
|
16
15
|
USE_BACKEND_PARAMS_FOR_TABLES_KEY,
|
17
16
|
LANGUAGE_KEY,
|
18
|
-
DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS,
|
19
17
|
QUERY_USE_MULTI_SCHEMA_KEY,
|
20
18
|
} from '../../../utils/constants';
|
21
19
|
import '../../../services/api';
|
22
20
|
import {parseJson} from '../../../utils/utils';
|
23
21
|
import {QUERY_ACTIONS, QUERY_MODES} from '../../../utils/query';
|
24
|
-
import {
|
22
|
+
import {
|
23
|
+
readSavedSettingsValue,
|
24
|
+
settingsApi,
|
25
|
+
systemSettings,
|
26
|
+
userSettings,
|
27
|
+
} from '../../../utils/settings';
|
25
28
|
|
26
29
|
import {TENANT_PAGES_IDS} from '../tenant/constants';
|
27
30
|
|
@@ -53,15 +56,7 @@ export const initialState = {
|
|
53
56
|
USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
|
54
57
|
'false',
|
55
58
|
),
|
56
|
-
[ENABLE_ADDITIONAL_QUERY_MODES]: readSavedSettingsValue(
|
57
|
-
ENABLE_ADDITIONAL_QUERY_MODES,
|
58
|
-
'true',
|
59
|
-
),
|
60
59
|
[QUERY_USE_MULTI_SCHEMA_KEY]: readSavedSettingsValue(QUERY_USE_MULTI_SCHEMA_KEY, 'false'),
|
61
|
-
[DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS]: readSavedSettingsValue(
|
62
|
-
DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS,
|
63
|
-
'true',
|
64
|
-
),
|
65
60
|
[SAVED_QUERIES_KEY]: readSavedSettingsValue(SAVED_QUERIES_KEY, '[]'),
|
66
61
|
[TENANT_INITIAL_PAGE_KEY]: readSavedSettingsValue(
|
67
62
|
TENANT_INITIAL_PAGE_KEY,
|
@@ -115,13 +110,16 @@ export const setSettingValue = (
|
|
115
110
|
name: string,
|
116
111
|
value: string,
|
117
112
|
): ThunkAction<void, RootState, unknown, SetSettingValueAction> => {
|
118
|
-
return (dispatch
|
113
|
+
return (dispatch) => {
|
119
114
|
dispatch({type: SET_SETTING_VALUE, data: {name, value}});
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
} else {
|
115
|
+
|
116
|
+
// If there is no settingsApi, use localStorage
|
117
|
+
if (settingsApi) {
|
124
118
|
window.api.postSetting(name, value);
|
119
|
+
} else {
|
120
|
+
try {
|
121
|
+
localStorage.setItem(name, value);
|
122
|
+
} catch {}
|
125
123
|
}
|
126
124
|
};
|
127
125
|
};
|
package/dist/utils/constants.ts
CHANGED
@@ -19,14 +19,6 @@ export const DAY_IN_SECONDS = 24 * HOUR_IN_SECONDS;
|
|
19
19
|
|
20
20
|
export const MS_IN_NANOSECONDS = 1000000;
|
21
21
|
|
22
|
-
export const TABLET_STATES = {
|
23
|
-
TABLET_VOLATILE_STATE_UNKNOWN: 'unknown',
|
24
|
-
TABLET_VOLATILE_STATE_STOPPED: 'stopped',
|
25
|
-
TABLET_VOLATILE_STATE_BOOTING: 'booting',
|
26
|
-
TABLET_VOLATILE_STATE_STARTING: 'starting',
|
27
|
-
TABLET_VOLATILE_STATE_RUNNING: 'running',
|
28
|
-
};
|
29
|
-
|
30
22
|
export const TABLET_COLORS = {
|
31
23
|
Created: 'gray',
|
32
24
|
ResolveStateStorage: 'lightgray',
|
@@ -89,9 +81,6 @@ export const THEME_KEY = 'theme';
|
|
89
81
|
export const LANGUAGE_KEY = 'language';
|
90
82
|
export const INVERTED_DISKS_KEY = 'invertedDisks';
|
91
83
|
export const USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY = 'useNodesEndpointInDiagnostics';
|
92
|
-
export const ENABLE_ADDITIONAL_QUERY_MODES = 'enableAdditionalQueryModes';
|
93
|
-
// Remain key name "enableNewTenantDiagnosticsDesign" for backward compatibility
|
94
|
-
export const DISPLAY_METRICS_CARDS_FOR_TENANT_DIAGNOSTICS = 'enableNewTenantDiagnosticsDesign';
|
95
84
|
export const SAVED_QUERIES_KEY = 'saved_queries';
|
96
85
|
export const ASIDE_HEADER_COMPACT_KEY = 'asideHeaderCompact';
|
97
86
|
export const QUERIES_HISTORY_KEY = 'queries_history';
|
@@ -1,36 +1,7 @@
|
|
1
1
|
import type {QueryMode} from '../../types/store/query';
|
2
|
-
import {
|
3
|
-
import {QUERY_MODES_TITLES, isNewQueryMode} from '../query';
|
4
|
-
import createToast from '../createToast';
|
2
|
+
import {QUERY_INITIAL_MODE_KEY} from '../constants';
|
5
3
|
import {useSetting} from './useSetting';
|
6
|
-
import i18n from './i18n';
|
7
4
|
|
8
|
-
export
|
9
|
-
|
10
|
-
errorMessage?: string | undefined,
|
11
|
-
) => boolean;
|
12
|
-
|
13
|
-
export const useQueryModes = (): [QueryMode, SetQueryModeIfAvailable] => {
|
14
|
-
const [queryMode, setQueryMode] = useSetting<QueryMode>(QUERY_INITIAL_MODE_KEY);
|
15
|
-
const [enableAdditionalQueryModes] = useSetting<boolean>(ENABLE_ADDITIONAL_QUERY_MODES);
|
16
|
-
|
17
|
-
const setQueryModeIfAvailable: SetQueryModeIfAvailable = (value, errorMessage) => {
|
18
|
-
if (isNewQueryMode(value) && !enableAdditionalQueryModes) {
|
19
|
-
createToast({
|
20
|
-
name: 'QueryModeCannotBeSet',
|
21
|
-
title:
|
22
|
-
errorMessage ??
|
23
|
-
i18n('useQueryModes.queryModeCannotBeSet', {mode: QUERY_MODES_TITLES[value]}),
|
24
|
-
type: 'error',
|
25
|
-
});
|
26
|
-
|
27
|
-
return false;
|
28
|
-
} else {
|
29
|
-
setQueryMode(value);
|
30
|
-
|
31
|
-
return true;
|
32
|
-
}
|
33
|
-
};
|
34
|
-
|
35
|
-
return [queryMode, setQueryModeIfAvailable];
|
5
|
+
export const useQueryModes = () => {
|
6
|
+
return useSetting<QueryMode>(QUERY_INITIAL_MODE_KEY);
|
36
7
|
};
|
package/dist/utils/query.ts
CHANGED
@@ -38,10 +38,6 @@ export const QUERY_SYNTAX = {
|
|
38
38
|
pg: 'pg',
|
39
39
|
} as const;
|
40
40
|
|
41
|
-
export const isNewQueryMode = (value: QueryMode) => {
|
42
|
-
return value !== QUERY_MODES.script && value !== QUERY_MODES.scan;
|
43
|
-
};
|
44
|
-
|
45
41
|
// eslint-disable-next-line complexity
|
46
42
|
export const getColumnType = (type: string) => {
|
47
43
|
switch (type.replace(/\?$/, '')) {
|
package/dist/utils/settings.ts
CHANGED
@@ -3,8 +3,11 @@ import {getValueFromLS} from './utils';
|
|
3
3
|
export const userSettings = window.userSettings || {};
|
4
4
|
export const systemSettings = window.systemSettings || {};
|
5
5
|
|
6
|
+
export const settingsApi = window.web_version ? systemSettings.settingsApi : undefined;
|
7
|
+
|
6
8
|
export function readSavedSettingsValue(key: string, defaultValue?: string) {
|
7
|
-
|
9
|
+
// If there is no settingsApi, use localStorage
|
10
|
+
const savedValue = settingsApi ? userSettings[key] : getValueFromLS(key);
|
8
11
|
|
9
12
|
return savedValue ?? defaultValue;
|
10
13
|
}
|
package/package.json
CHANGED
@@ -1,64 +0,0 @@
|
|
1
|
-
import cn from 'bem-cn-lite';
|
2
|
-
|
3
|
-
import {Button, Icon} from '@gravity-ui/uikit';
|
4
|
-
|
5
|
-
import updateArrow from '../../../../../assets/icons/update-arrow.svg';
|
6
|
-
|
7
|
-
import type {IResponseError} from '../../../../../types/api/error';
|
8
|
-
import type {IIssuesTree} from '../../../../../types/store/healthcheck';
|
9
|
-
import {ResponseError} from '../../../../../components/Errors/ResponseError';
|
10
|
-
|
11
|
-
import IssueTree from '../../TenantOverview/Healthcheck/IssuesViewer/IssueTree';
|
12
|
-
|
13
|
-
import i18n from '../../TenantOverview/Healthcheck/i18n';
|
14
|
-
|
15
|
-
const b = cn('old-healthcheck');
|
16
|
-
|
17
|
-
interface DetailsProps {
|
18
|
-
issueTrees?: IIssuesTree[];
|
19
|
-
loading?: boolean;
|
20
|
-
onUpdate: VoidFunction;
|
21
|
-
error?: IResponseError;
|
22
|
-
}
|
23
|
-
|
24
|
-
export const Details = (props: DetailsProps) => {
|
25
|
-
const {loading, onUpdate, issueTrees, error} = props;
|
26
|
-
|
27
|
-
const renderHealthcheckHeader = () => {
|
28
|
-
return (
|
29
|
-
<div className={b('details-header')}>
|
30
|
-
<h3 className={b('details-header-title')}>{i18n('title.healthcheck')}</h3>
|
31
|
-
<div className={b('details-header-update')}>
|
32
|
-
<Button size="s" onClick={onUpdate} loading={loading} view="flat-secondary">
|
33
|
-
<Icon data={updateArrow} height={20} width={20} />
|
34
|
-
</Button>
|
35
|
-
</div>
|
36
|
-
</div>
|
37
|
-
);
|
38
|
-
};
|
39
|
-
|
40
|
-
const renderContent = () => {
|
41
|
-
if (error) {
|
42
|
-
return <ResponseError error={error} defaultMessage={i18n('no-data')} />;
|
43
|
-
}
|
44
|
-
|
45
|
-
if (!issueTrees || !issueTrees.length) {
|
46
|
-
return i18n('status_message.ok');
|
47
|
-
}
|
48
|
-
|
49
|
-
return (
|
50
|
-
<>
|
51
|
-
{issueTrees.map((issueTree) => (
|
52
|
-
<IssueTree key={issueTree.id} issueTree={issueTree} />
|
53
|
-
))}
|
54
|
-
</>
|
55
|
-
);
|
56
|
-
};
|
57
|
-
|
58
|
-
return (
|
59
|
-
<div className={b('details')}>
|
60
|
-
{renderHealthcheckHeader()}
|
61
|
-
<div className={b('details-content-wrapper')}>{renderContent()}</div>
|
62
|
-
</div>
|
63
|
-
);
|
64
|
-
};
|
@@ -1 +0,0 @@
|
|
1
|
-
export * from './Details';
|
@@ -1,137 +0,0 @@
|
|
1
|
-
@import '../../../../styles/mixins.scss';
|
2
|
-
@import '@gravity-ui/uikit/styles/mixins.scss';
|
3
|
-
|
4
|
-
.old-healthcheck {
|
5
|
-
display: flex;
|
6
|
-
|
7
|
-
&_expanded {
|
8
|
-
// Since most of the inner containers have fixed width, we can set fixed width here as well
|
9
|
-
// Thus we will get rid of unneeded layout shift when scrollbar appear
|
10
|
-
min-width: 885px;
|
11
|
-
}
|
12
|
-
|
13
|
-
&__details {
|
14
|
-
width: 860px;
|
15
|
-
padding: 25px 20px 20px;
|
16
|
-
}
|
17
|
-
|
18
|
-
&__issue-preview {
|
19
|
-
margin-bottom: 15px;
|
20
|
-
}
|
21
|
-
|
22
|
-
&__details-content-wrapper {
|
23
|
-
overflow-x: hidden;
|
24
|
-
overflow-y: auto;
|
25
|
-
|
26
|
-
height: 70vh;
|
27
|
-
max-height: 70vh;
|
28
|
-
}
|
29
|
-
|
30
|
-
&__message-container {
|
31
|
-
padding: 15px 0;
|
32
|
-
}
|
33
|
-
|
34
|
-
&__details-header {
|
35
|
-
display: flex;
|
36
|
-
align-items: center;
|
37
|
-
|
38
|
-
margin-bottom: 20px;
|
39
|
-
}
|
40
|
-
|
41
|
-
&__details-header-title {
|
42
|
-
margin: 0 10px 0 0;
|
43
|
-
|
44
|
-
@include text-header-1();
|
45
|
-
}
|
46
|
-
|
47
|
-
&__details-header-update {
|
48
|
-
margin-left: 10px;
|
49
|
-
}
|
50
|
-
|
51
|
-
&__preview {
|
52
|
-
width: 206px;
|
53
|
-
padding: 16px;
|
54
|
-
padding-bottom: 28px;
|
55
|
-
|
56
|
-
border: 1px solid var(--yc-color-line-generic);
|
57
|
-
border-radius: 8px;
|
58
|
-
background-color: transparent;
|
59
|
-
}
|
60
|
-
|
61
|
-
&__preview-header {
|
62
|
-
margin-bottom: var(--diagnostics-section-title-margin);
|
63
|
-
gap: 8px;
|
64
|
-
}
|
65
|
-
|
66
|
-
&__preview-title {
|
67
|
-
font-weight: 600;
|
68
|
-
@include lead-typography();
|
69
|
-
}
|
70
|
-
|
71
|
-
&__preview-content {
|
72
|
-
line-height: 24px;
|
73
|
-
}
|
74
|
-
|
75
|
-
&__preview-title-wrapper {
|
76
|
-
display: flex;
|
77
|
-
align-items: center;
|
78
|
-
|
79
|
-
margin-bottom: 4px;
|
80
|
-
|
81
|
-
gap: 8px;
|
82
|
-
}
|
83
|
-
|
84
|
-
&__issues-statistics {
|
85
|
-
display: flex;
|
86
|
-
flex-wrap: wrap;
|
87
|
-
align-items: center;
|
88
|
-
|
89
|
-
margin: 8px 0;
|
90
|
-
|
91
|
-
gap: 10px;
|
92
|
-
}
|
93
|
-
|
94
|
-
&__self-check-status-indicator {
|
95
|
-
display: inline-block;
|
96
|
-
|
97
|
-
padding: 0 8px;
|
98
|
-
|
99
|
-
font-size: 13px;
|
100
|
-
line-height: 24px;
|
101
|
-
|
102
|
-
border-radius: 4px;
|
103
|
-
|
104
|
-
&_good,
|
105
|
-
&_green {
|
106
|
-
color: var(--yc-color-text-positive);
|
107
|
-
background-color: var(--yc-color-base-positive);
|
108
|
-
}
|
109
|
-
&_degraded,
|
110
|
-
&_yellow {
|
111
|
-
color: var(--yc-color-text-warning);
|
112
|
-
background-color: var(--yc-color-base-warning);
|
113
|
-
}
|
114
|
-
|
115
|
-
&_blue {
|
116
|
-
color: var(--yc-color-text-info);
|
117
|
-
background-color: var(--yc-color-base-info);
|
118
|
-
}
|
119
|
-
|
120
|
-
&_emergency,
|
121
|
-
&_red {
|
122
|
-
color: var(--yc-color-text-danger);
|
123
|
-
background-color: var(--yc-color-base-danger);
|
124
|
-
}
|
125
|
-
&_unspecified,
|
126
|
-
&_gray,
|
127
|
-
&_grey {
|
128
|
-
color: var(--yc-color-text-misc);
|
129
|
-
background-color: var(--yc-color-base-misc);
|
130
|
-
}
|
131
|
-
&_maintenance_required,
|
132
|
-
&_orange {
|
133
|
-
color: var(--yc-color-text-warning-heavy);
|
134
|
-
background-color: var(--yc-color-infographics-warning-light);
|
135
|
-
}
|
136
|
-
}
|
137
|
-
}
|
@@ -1,92 +0,0 @@
|
|
1
|
-
import {useCallback} from 'react';
|
2
|
-
import {useDispatch} from 'react-redux';
|
3
|
-
import cn from 'bem-cn-lite';
|
4
|
-
|
5
|
-
import {Loader} from '@gravity-ui/uikit';
|
6
|
-
|
7
|
-
import {SelfCheckResult} from '../../../../types/api/healthcheck';
|
8
|
-
import {useTypedSelector, useAutofetcher} from '../../../../utils/hooks';
|
9
|
-
import {
|
10
|
-
getHealthcheckInfo,
|
11
|
-
selectIssuesStatistics,
|
12
|
-
selectIssuesTrees,
|
13
|
-
setDataWasNotLoaded,
|
14
|
-
} from '../../../../store/reducers/healthcheckInfo';
|
15
|
-
|
16
|
-
import {Details} from './Details';
|
17
|
-
import {Preview} from './Preview';
|
18
|
-
|
19
|
-
import './Healthcheck.scss';
|
20
|
-
|
21
|
-
interface HealthcheckProps {
|
22
|
-
tenant: string;
|
23
|
-
preview?: boolean;
|
24
|
-
fetchData?: boolean;
|
25
|
-
showMoreHandler?: VoidFunction;
|
26
|
-
}
|
27
|
-
|
28
|
-
const b = cn('old-healthcheck');
|
29
|
-
|
30
|
-
export const Healthcheck = (props: HealthcheckProps) => {
|
31
|
-
const {tenant, preview, fetchData = true, showMoreHandler} = props;
|
32
|
-
|
33
|
-
const dispatch = useDispatch();
|
34
|
-
|
35
|
-
const {data, loading, wasLoaded, error} = useTypedSelector((state) => state.healthcheckInfo);
|
36
|
-
const issuesStatistics = useTypedSelector(selectIssuesStatistics);
|
37
|
-
const issueTrees = useTypedSelector(selectIssuesTrees);
|
38
|
-
const {autorefresh} = useTypedSelector((state) => state.schema);
|
39
|
-
|
40
|
-
const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
|
41
|
-
|
42
|
-
const fetchHealthcheck = useCallback(
|
43
|
-
(isBackground = true) => {
|
44
|
-
if (!isBackground) {
|
45
|
-
dispatch(setDataWasNotLoaded());
|
46
|
-
}
|
47
|
-
|
48
|
-
dispatch(getHealthcheckInfo(tenant));
|
49
|
-
},
|
50
|
-
[dispatch, tenant],
|
51
|
-
);
|
52
|
-
|
53
|
-
useAutofetcher(
|
54
|
-
(isBackground) => {
|
55
|
-
if (fetchData) {
|
56
|
-
fetchHealthcheck(isBackground);
|
57
|
-
}
|
58
|
-
},
|
59
|
-
[fetchData, fetchHealthcheck],
|
60
|
-
autorefresh,
|
61
|
-
);
|
62
|
-
|
63
|
-
const renderContent = () => {
|
64
|
-
if (loading && !wasLoaded) {
|
65
|
-
return (
|
66
|
-
<div className={b('old-preview', {loader: true})}>
|
67
|
-
<Loader size="m" />
|
68
|
-
</div>
|
69
|
-
);
|
70
|
-
}
|
71
|
-
|
72
|
-
return preview ? (
|
73
|
-
<Preview
|
74
|
-
issuesStatistics={issuesStatistics}
|
75
|
-
selfCheckResult={selfCheckResult}
|
76
|
-
loading={loading}
|
77
|
-
onShowMore={showMoreHandler}
|
78
|
-
onUpdate={fetchHealthcheck}
|
79
|
-
error={error}
|
80
|
-
/>
|
81
|
-
) : (
|
82
|
-
<Details
|
83
|
-
loading={loading}
|
84
|
-
onUpdate={fetchHealthcheck}
|
85
|
-
issueTrees={issueTrees}
|
86
|
-
error={error}
|
87
|
-
/>
|
88
|
-
);
|
89
|
-
};
|
90
|
-
|
91
|
-
return <div className={b({expanded: !preview})}>{renderContent()}</div>;
|
92
|
-
};
|
@@ -1,82 +0,0 @@
|
|
1
|
-
import cn from 'bem-cn-lite';
|
2
|
-
|
3
|
-
import {Button, Icon, Link} from '@gravity-ui/uikit';
|
4
|
-
|
5
|
-
import updateArrow from '../../../../../assets/icons/update-arrow.svg';
|
6
|
-
|
7
|
-
import {SelfCheckResult, type StatusFlag} from '../../../../../types/api/healthcheck';
|
8
|
-
import type {IResponseError} from '../../../../../types/api/error';
|
9
|
-
import EntityStatus from '../../../../../components/EntityStatus/EntityStatus';
|
10
|
-
import {ResponseError} from '../../../../../components/Errors/ResponseError';
|
11
|
-
|
12
|
-
import i18n from '../../TenantOverview/Healthcheck/i18n';
|
13
|
-
|
14
|
-
const b = cn('old-healthcheck');
|
15
|
-
|
16
|
-
interface PreviewProps {
|
17
|
-
selfCheckResult: SelfCheckResult;
|
18
|
-
issuesStatistics?: [StatusFlag, number][];
|
19
|
-
loading?: boolean;
|
20
|
-
onShowMore?: VoidFunction;
|
21
|
-
onUpdate: VoidFunction;
|
22
|
-
error?: IResponseError;
|
23
|
-
}
|
24
|
-
|
25
|
-
export const Preview = (props: PreviewProps) => {
|
26
|
-
const {selfCheckResult, issuesStatistics, loading, onShowMore, onUpdate, error} = props;
|
27
|
-
|
28
|
-
const renderHeader = () => {
|
29
|
-
const modifier = selfCheckResult.toLowerCase();
|
30
|
-
|
31
|
-
return (
|
32
|
-
<div className={b('preview-header')}>
|
33
|
-
<div className={b('preview-title-wrapper')}>
|
34
|
-
<div className={b('preview-title')}>{i18n('title.healthcheck')}</div>
|
35
|
-
<Button size="s" onClick={onUpdate} loading={loading} view="flat-secondary">
|
36
|
-
<Icon data={updateArrow} width={20} height={20} />
|
37
|
-
</Button>
|
38
|
-
</div>
|
39
|
-
<div className={b('self-check-status-indicator', {[modifier]: true})}>
|
40
|
-
{selfCheckResult}
|
41
|
-
</div>
|
42
|
-
</div>
|
43
|
-
);
|
44
|
-
};
|
45
|
-
|
46
|
-
const renderContent = () => {
|
47
|
-
if (error) {
|
48
|
-
return <ResponseError error={error} defaultMessage={i18n('no-data')} />;
|
49
|
-
}
|
50
|
-
|
51
|
-
return (
|
52
|
-
<div className={b('preview-content')}>
|
53
|
-
{!issuesStatistics || !issuesStatistics.length ? (
|
54
|
-
i18n('status_message.ok')
|
55
|
-
) : (
|
56
|
-
<>
|
57
|
-
<div>{i18n('label.issues')}</div>
|
58
|
-
<div className={b('issues-statistics')}>
|
59
|
-
{issuesStatistics.map(([status, count]) => (
|
60
|
-
<EntityStatus
|
61
|
-
key={status}
|
62
|
-
mode="icons"
|
63
|
-
status={status}
|
64
|
-
label={count.toString()}
|
65
|
-
size="l"
|
66
|
-
/>
|
67
|
-
))}
|
68
|
-
</div>
|
69
|
-
<Link onClick={() => onShowMore?.()}>{i18n('label.show-details')}</Link>
|
70
|
-
</>
|
71
|
-
)}
|
72
|
-
</div>
|
73
|
-
);
|
74
|
-
};
|
75
|
-
|
76
|
-
return (
|
77
|
-
<div className={b('preview')}>
|
78
|
-
{renderHeader()}
|
79
|
-
{renderContent()}
|
80
|
-
</div>
|
81
|
-
);
|
82
|
-
};
|
@@ -1 +0,0 @@
|
|
1
|
-
export * from './Preview';
|
@@ -1 +0,0 @@
|
|
1
|
-
export * from './Healthcheck';
|
@@ -1,155 +0,0 @@
|
|
1
|
-
import cn from 'bem-cn-lite';
|
2
|
-
import {useCallback} from 'react';
|
3
|
-
import {useDispatch} from 'react-redux';
|
4
|
-
|
5
|
-
import {Loader} from '@gravity-ui/uikit';
|
6
|
-
|
7
|
-
import {InfoViewer} from '../../../../components/InfoViewer';
|
8
|
-
import {PoolUsage} from '../../../../components/PoolUsage/PoolUsage';
|
9
|
-
import {Tablet} from '../../../../components/Tablet';
|
10
|
-
import EntityStatus from '../../../../components/EntityStatus/EntityStatus';
|
11
|
-
import {formatCPU} from '../../../../utils/dataFormatters/dataFormatters';
|
12
|
-
import {TABLET_STATES, TENANT_DEFAULT_TITLE} from '../../../../utils/constants';
|
13
|
-
import {bytesToGB} from '../../../../utils/utils';
|
14
|
-
import {mapDatabaseTypeToDBName} from '../../utils/schema';
|
15
|
-
import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
|
16
|
-
import type {ETabletVolatileState} from '../../../../types/api/tenant';
|
17
|
-
import type {AdditionalTenantsProps} from '../../../../types/additionalProps';
|
18
|
-
import {getTenantInfo, setDataWasNotLoaded} from '../../../../store/reducers/tenant/tenant';
|
19
|
-
|
20
|
-
import i18n from './i18n';
|
21
|
-
import './TenantOverview.scss';
|
22
|
-
|
23
|
-
const b = cn('tenant-overview');
|
24
|
-
|
25
|
-
interface OldTenantOverviewProps {
|
26
|
-
tenantName: string;
|
27
|
-
additionalTenantProps?: AdditionalTenantsProps;
|
28
|
-
}
|
29
|
-
|
30
|
-
export function OldTenantOverview({tenantName, additionalTenantProps}: OldTenantOverviewProps) {
|
31
|
-
const {tenant, loading, wasLoaded} = useTypedSelector((state) => state.tenant);
|
32
|
-
const {autorefresh} = useTypedSelector((state) => state.schema);
|
33
|
-
const dispatch = useDispatch();
|
34
|
-
const fetchTenant = useCallback(
|
35
|
-
(isBackground = true) => {
|
36
|
-
if (!isBackground) {
|
37
|
-
dispatch(setDataWasNotLoaded());
|
38
|
-
}
|
39
|
-
dispatch(getTenantInfo({path: tenantName}));
|
40
|
-
},
|
41
|
-
[dispatch, tenantName],
|
42
|
-
);
|
43
|
-
|
44
|
-
useAutofetcher(fetchTenant, [fetchTenant], autorefresh);
|
45
|
-
|
46
|
-
const {
|
47
|
-
Metrics = {},
|
48
|
-
PoolStats,
|
49
|
-
StateStats = [],
|
50
|
-
MemoryUsed,
|
51
|
-
Name,
|
52
|
-
State,
|
53
|
-
CoresUsed,
|
54
|
-
StorageGroups,
|
55
|
-
StorageAllocatedSize,
|
56
|
-
Type,
|
57
|
-
SystemTablets,
|
58
|
-
} = tenant || {};
|
59
|
-
|
60
|
-
const tenantType = mapDatabaseTypeToDBName(Type);
|
61
|
-
const memoryRaw = MemoryUsed ?? Metrics.Memory;
|
62
|
-
|
63
|
-
const memory = (memoryRaw && bytesToGB(memoryRaw)) || i18n('no-data');
|
64
|
-
const storage = (Metrics.Storage && bytesToGB(Metrics.Storage)) || i18n('no-data');
|
65
|
-
const storageGroups = StorageGroups ?? i18n('no-data');
|
66
|
-
const blobStorage =
|
67
|
-
(StorageAllocatedSize && bytesToGB(StorageAllocatedSize)) || i18n('no-data');
|
68
|
-
const storageEfficiency =
|
69
|
-
Metrics.Storage && StorageAllocatedSize
|
70
|
-
? `${((parseInt(Metrics.Storage) * 100) / parseInt(StorageAllocatedSize)).toFixed(2)}%`
|
71
|
-
: i18n('no-data');
|
72
|
-
|
73
|
-
const cpuRaw = CoresUsed !== undefined ? Number(CoresUsed) * 1_000_000 : Metrics.CPU;
|
74
|
-
|
75
|
-
const cpu = formatCPU(cpuRaw);
|
76
|
-
|
77
|
-
const metricsInfo = [
|
78
|
-
{label: 'Type', value: Type},
|
79
|
-
{label: 'Memory', value: memory},
|
80
|
-
{label: 'CPU', value: cpu},
|
81
|
-
{label: 'Tablet storage', value: storage},
|
82
|
-
{label: 'Storage groups', value: storageGroups},
|
83
|
-
{label: 'Blob storage', value: blobStorage},
|
84
|
-
{label: 'Storage efficiency', value: storageEfficiency},
|
85
|
-
];
|
86
|
-
|
87
|
-
const tabletsInfo = StateStats.filter(
|
88
|
-
(item): item is {VolatileState: ETabletVolatileState; Count: number} => {
|
89
|
-
return item.VolatileState !== undefined && item.Count !== undefined;
|
90
|
-
},
|
91
|
-
).map((info) => {
|
92
|
-
return {label: TABLET_STATES[info.VolatileState], value: info.Count};
|
93
|
-
});
|
94
|
-
|
95
|
-
const renderName = () => {
|
96
|
-
return (
|
97
|
-
<div className={b('tenant-name-wrapper')}>
|
98
|
-
<EntityStatus
|
99
|
-
status={State}
|
100
|
-
name={Name || TENANT_DEFAULT_TITLE}
|
101
|
-
withLeftTrim
|
102
|
-
hasClipboardButton={Boolean(tenant)}
|
103
|
-
clipboardButtonAlwaysVisible
|
104
|
-
/>
|
105
|
-
</div>
|
106
|
-
);
|
107
|
-
};
|
108
|
-
|
109
|
-
if (loading && !wasLoaded) {
|
110
|
-
return (
|
111
|
-
<div className={b('loader')}>
|
112
|
-
<Loader size="m" />
|
113
|
-
</div>
|
114
|
-
);
|
115
|
-
}
|
116
|
-
|
117
|
-
return (
|
118
|
-
<div className={b()}>
|
119
|
-
<div className={b('top-label')}>{tenantType}</div>
|
120
|
-
<div className={b('top')}>
|
121
|
-
{renderName()}
|
122
|
-
{additionalTenantProps?.getMonitoringLink?.(Name, Type)}
|
123
|
-
</div>
|
124
|
-
<div className={b('system-tablets')}>
|
125
|
-
{SystemTablets &&
|
126
|
-
SystemTablets.map((tablet, tabletIndex) => (
|
127
|
-
<Tablet key={tabletIndex} tablet={tablet} tenantName={Name} />
|
128
|
-
))}
|
129
|
-
</div>
|
130
|
-
<div className={b('common-info')}>
|
131
|
-
<div>
|
132
|
-
<div className={b('section-title')}>{i18n('title.pools')}</div>
|
133
|
-
{PoolStats ? (
|
134
|
-
<div className={b('section', {pools: true})}>
|
135
|
-
{PoolStats.map((pool, poolIndex) => (
|
136
|
-
<PoolUsage key={poolIndex} data={pool} />
|
137
|
-
))}
|
138
|
-
</div>
|
139
|
-
) : (
|
140
|
-
<div className="error">{i18n('no-pools-data')}</div>
|
141
|
-
)}
|
142
|
-
</div>
|
143
|
-
<InfoViewer
|
144
|
-
title={i18n('title.metrics')}
|
145
|
-
className={b('section', {metrics: true})}
|
146
|
-
info={metricsInfo}
|
147
|
-
/>
|
148
|
-
|
149
|
-
<div className={b('section')}>
|
150
|
-
<InfoViewer info={tabletsInfo} title="Tablets" />
|
151
|
-
</div>
|
152
|
-
</div>
|
153
|
-
</div>
|
154
|
-
);
|
155
|
-
}
|
@@ -1,11 +0,0 @@
|
|
1
|
-
import {i18n, Lang} from '../../../utils/i18n';
|
2
|
-
|
3
|
-
import en from './en.json';
|
4
|
-
import ru from './ru.json';
|
5
|
-
|
6
|
-
const COMPONENT = 'ydb-hooks';
|
7
|
-
|
8
|
-
i18n.registerKeyset(Lang.En, COMPONENT, en);
|
9
|
-
i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
|
10
|
-
|
11
|
-
export default i18n.keyset(COMPONENT);
|