ydb-embedded-ui 4.6.0 → 4.8.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +27 -0
- package/dist/assets/icons/versions.svg +3 -0
- package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +6 -1
- package/dist/components/Tablet/Tablet.tsx +17 -3
- package/dist/components/TabletsStatistic/TabletsStatistic.tsx +23 -16
- package/dist/containers/App/Content.js +5 -2
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +50 -18
- package/dist/containers/Cluster/Cluster.tsx +6 -13
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +3 -3
- package/dist/containers/Cluster/{utils.ts → utils.tsx} +11 -0
- package/dist/containers/Header/Header.scss +9 -0
- package/dist/containers/Header/Header.tsx +70 -14
- package/dist/containers/Header/breadcrumbs.ts +146 -0
- package/dist/containers/Node/Node.tsx +21 -27
- package/dist/containers/Node/NodePages.ts +10 -6
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +11 -3
- package/dist/containers/Tablet/Tablet.tsx +35 -27
- package/dist/containers/Tablet/TabletInfo/TabletInfo.tsx +2 -2
- package/dist/containers/TabletsFilters/TabletsFilters.js +13 -15
- package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +1 -1
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +5 -1
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +4 -14
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +5 -3
- package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +1 -1
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +2 -1
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +9 -16
- package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +11 -11
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +7 -3
- package/dist/containers/Tenant/{QueryEditor/QueryResult/QueryResult.js → Query/ExecuteResult/ExecuteResult.js} +3 -5
- package/dist/containers/Tenant/{QueryEditor/QueryResult/QueryResult.scss → Query/ExecuteResult/ExecuteResult.scss} +1 -1
- package/dist/containers/Tenant/{QueryEditor/QueryExplain/QueryExplain.js → Query/ExplainResult/ExplainResult.js} +3 -5
- package/dist/containers/Tenant/{QueryEditor/QueryExplain/QueryExplain.scss → Query/ExplainResult/ExplainResult.scss} +1 -1
- package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.scss +20 -0
- package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +60 -0
- package/dist/containers/Tenant/Query/Query.scss +16 -0
- package/dist/containers/Tenant/Query/Query.tsx +73 -0
- package/dist/containers/Tenant/{QueryEditor → Query/QueryEditor}/QueryEditor.js +39 -88
- package/dist/containers/Tenant/{QueryEditor → Query/QueryEditor}/QueryEditor.scss +7 -23
- package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/QueryEditorControls.scss +1 -4
- package/dist/containers/Tenant/Query/QueryTabs/QueryTabs.tsx +59 -0
- package/dist/containers/Tenant/{QueryEditor → Query}/SaveQuery/SaveQuery.js +5 -5
- package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.scss +55 -0
- package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.tsx +150 -0
- package/dist/containers/Tenant/Query/i18n/en.json +12 -0
- package/dist/containers/Tenant/Query/i18n/ru.json +12 -0
- package/dist/containers/Tenant/Query/utils/getPreparedResult.ts +30 -0
- package/dist/containers/Tenant/Tenant.scss +0 -8
- package/dist/containers/Tenant/Tenant.tsx +24 -46
- package/dist/containers/Tenant/TenantPages.tsx +7 -16
- package/dist/containers/Tenant/utils/constants.ts +10 -0
- package/dist/containers/Tenant/utils/schemaActions.ts +9 -4
- package/dist/containers/Tenants/Tenants.js +26 -13
- package/dist/routes.ts +21 -7
- package/dist/services/api.ts +9 -5
- package/dist/store/reducers/executeQuery.ts +18 -4
- package/dist/store/reducers/header/header.ts +31 -0
- package/dist/store/reducers/header/types.ts +54 -0
- package/dist/store/reducers/index.ts +1 -1
- package/dist/store/reducers/node/types.ts +2 -0
- package/dist/store/reducers/settings/settings.ts +8 -3
- package/dist/store/reducers/tablet.ts +18 -1
- package/dist/store/reducers/tenant/constants.ts +9 -1
- package/dist/store/reducers/tenant/tenant.ts +23 -4
- package/dist/store/reducers/tenant/types.ts +9 -5
- package/dist/store/reducers/topic.ts +1 -1
- package/dist/store/state-url-mapping.js +6 -3
- package/dist/types/store/executeQuery.ts +4 -1
- package/dist/types/store/query.ts +5 -0
- package/dist/types/store/tablet.ts +7 -4
- package/dist/utils/constants.ts +5 -1
- package/package.json +2 -1
- package/dist/containers/Tenant/ObjectGeneralTabs/ObjectGeneralTabs.scss +0 -9
- package/dist/containers/Tenant/ObjectGeneralTabs/ObjectGeneralTabs.tsx +0 -68
- package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.scss +0 -85
- package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.tsx +0 -95
- package/dist/containers/Tenant/QueryEditor/SavedQueries/SavedQueries.js +0 -161
- package/dist/containers/Tenant/QueryEditor/SavedQueries/SavedQueries.scss +0 -93
- package/dist/containers/Tenant/QueryEditor/i18n/en.json +0 -3
- package/dist/containers/Tenant/QueryEditor/i18n/ru.json +0 -3
- package/dist/store/reducers/header.ts +0 -26
- /package/dist/containers/Tenant/{QueryEditor → Query}/Issues/Issues.scss +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/Issues/Issues.tsx +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/Issues/models.ts +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/QueryDuration/QueryDuration.scss +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/QueryDuration/QueryDuration.tsx +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/OldQueryEditorControls.tsx +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/QueryEditorControls.tsx +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/shared.ts +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/SaveQuery/SaveQuery.scss +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/i18n/index.ts +0 -0
package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/QueryEditorControls.scss
RENAMED
@@ -5,11 +5,8 @@
|
|
5
5
|
align-items: flex-end;
|
6
6
|
|
7
7
|
min-height: 40px;
|
8
|
-
padding: 5px
|
8
|
+
padding: 5px 0px;
|
9
9
|
|
10
|
-
border-top: 1px solid var(--yc-color-line-generic);
|
11
|
-
border-bottom: 1px solid var(--yc-color-line-generic);
|
12
|
-
background-color: var(--yc-color-base-background);
|
13
10
|
gap: 24px;
|
14
11
|
|
15
12
|
&__left {
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import {useLocation} from 'react-router';
|
2
|
+
|
3
|
+
import {Tabs} from '@gravity-ui/uikit';
|
4
|
+
|
5
|
+
import type {TenantQueryTab} from '../../../../store/reducers/tenant/types';
|
6
|
+
import {TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
|
7
|
+
import {InternalLink} from '../../../../components/InternalLink/InternalLink';
|
8
|
+
import {parseQuery} from '../../../../routes';
|
9
|
+
|
10
|
+
import {TenantTabsGroups, getTenantPath} from '../../TenantPages';
|
11
|
+
|
12
|
+
import i18n from '../i18n';
|
13
|
+
|
14
|
+
const newQuery = {
|
15
|
+
id: TENANT_QUERY_TABS_ID.newQuery,
|
16
|
+
title: i18n('tabs.newQuery'),
|
17
|
+
};
|
18
|
+
const history = {
|
19
|
+
id: TENANT_QUERY_TABS_ID.history,
|
20
|
+
title: i18n('tabs.history'),
|
21
|
+
};
|
22
|
+
const saved = {
|
23
|
+
id: TENANT_QUERY_TABS_ID.saved,
|
24
|
+
title: i18n('tabs.saved'),
|
25
|
+
};
|
26
|
+
|
27
|
+
const queryEditorTabs = [newQuery, history, saved];
|
28
|
+
|
29
|
+
interface QueryEditorTabsProps {
|
30
|
+
className?: string;
|
31
|
+
activeTab?: TenantQueryTab;
|
32
|
+
}
|
33
|
+
|
34
|
+
export const QueryTabs = ({className, activeTab}: QueryEditorTabsProps) => {
|
35
|
+
const location = useLocation();
|
36
|
+
const queryParams = parseQuery(location);
|
37
|
+
|
38
|
+
return (
|
39
|
+
<div className={className}>
|
40
|
+
<Tabs
|
41
|
+
size="l"
|
42
|
+
allowNotSelected={true}
|
43
|
+
activeTab={activeTab}
|
44
|
+
items={queryEditorTabs}
|
45
|
+
wrapTo={({id}, node) => {
|
46
|
+
const path = getTenantPath({
|
47
|
+
...queryParams,
|
48
|
+
[TenantTabsGroups.queryTab]: id,
|
49
|
+
});
|
50
|
+
return (
|
51
|
+
<InternalLink to={path} key={id}>
|
52
|
+
{node}
|
53
|
+
</InternalLink>
|
54
|
+
);
|
55
|
+
}}
|
56
|
+
/>
|
57
|
+
</div>
|
58
|
+
);
|
59
|
+
};
|
@@ -105,21 +105,21 @@ function SaveQuery({savedQueries, onSaveQuery, saveButtonDisabled}) {
|
|
105
105
|
const renderSaveButton = (onClick) => {
|
106
106
|
return (
|
107
107
|
<Button onClick={onClick} disabled={saveButtonDisabled}>
|
108
|
-
Save query
|
108
|
+
{queryNameToEdit ? 'Edit query' : 'Save query'}
|
109
109
|
</Button>
|
110
110
|
);
|
111
111
|
};
|
112
112
|
|
113
113
|
const renderSaveDropdownMenu = () => {
|
114
114
|
const items = [
|
115
|
-
{
|
116
|
-
action: onSaveQueryClick,
|
117
|
-
text: 'Save as new',
|
118
|
-
},
|
119
115
|
{
|
120
116
|
action: onEditQueryClick,
|
121
117
|
text: 'Edit existing',
|
122
118
|
},
|
119
|
+
{
|
120
|
+
action: onSaveQueryClick,
|
121
|
+
text: 'Save as new',
|
122
|
+
},
|
123
123
|
];
|
124
124
|
return (
|
125
125
|
<DropdownMenu items={items} switcher={renderSaveButton()} popupPlacement={['top']} />
|
@@ -0,0 +1,55 @@
|
|
1
|
+
@import '../../../../styles/mixins.scss';
|
2
|
+
|
3
|
+
.ydb-saved-queries {
|
4
|
+
$block: &;
|
5
|
+
|
6
|
+
overflow: auto;
|
7
|
+
|
8
|
+
height: 100%;
|
9
|
+
padding: 0 16px;
|
10
|
+
|
11
|
+
@include flex-container();
|
12
|
+
@include table-styles;
|
13
|
+
|
14
|
+
&__row {
|
15
|
+
cursor: pointer;
|
16
|
+
|
17
|
+
:hover {
|
18
|
+
#{$block}__controls {
|
19
|
+
display: flex;
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
&__query-name {
|
25
|
+
overflow: hidden;
|
26
|
+
|
27
|
+
white-space: pre-wrap;
|
28
|
+
text-overflow: ellipsis;
|
29
|
+
}
|
30
|
+
|
31
|
+
&__query {
|
32
|
+
display: flex;
|
33
|
+
flex-direction: row;
|
34
|
+
justify-content: space-between;
|
35
|
+
align-items: center;
|
36
|
+
}
|
37
|
+
|
38
|
+
&__query-body {
|
39
|
+
overflow: hidden;
|
40
|
+
flex-grow: 1;
|
41
|
+
|
42
|
+
max-width: 100%;
|
43
|
+
|
44
|
+
white-space: pre;
|
45
|
+
text-overflow: ellipsis;
|
46
|
+
}
|
47
|
+
|
48
|
+
&__controls {
|
49
|
+
display: none;
|
50
|
+
}
|
51
|
+
|
52
|
+
&__dialog-query-name {
|
53
|
+
font-weight: 500;
|
54
|
+
}
|
55
|
+
}
|
@@ -0,0 +1,150 @@
|
|
1
|
+
import {MouseEvent, useState} from 'react';
|
2
|
+
import {useDispatch} from 'react-redux';
|
3
|
+
import block from 'bem-cn-lite';
|
4
|
+
|
5
|
+
import {Dialog, Button} from '@gravity-ui/uikit';
|
6
|
+
import DataTable, {Column} from '@gravity-ui/react-data-table';
|
7
|
+
|
8
|
+
import type {SavedQuery} from '../../../../types/store/query';
|
9
|
+
import {setQueryNameToEdit} from '../../../../store/reducers/saveQuery';
|
10
|
+
import {setQueryTab} from '../../../../store/reducers/tenant/tenant';
|
11
|
+
import {TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
|
12
|
+
|
13
|
+
import TruncatedQuery from '../../../../components/TruncatedQuery/TruncatedQuery';
|
14
|
+
import {IconWrapper} from '../../../../components/Icon';
|
15
|
+
|
16
|
+
import {MAX_QUERY_HEIGHT, QUERY_TABLE_SETTINGS} from '../../utils/constants';
|
17
|
+
|
18
|
+
import i18n from '../i18n';
|
19
|
+
|
20
|
+
import './SavedQueries.scss';
|
21
|
+
|
22
|
+
const b = block('ydb-saved-queries');
|
23
|
+
|
24
|
+
interface DeleteDialogProps {
|
25
|
+
visible: boolean;
|
26
|
+
queryName: string;
|
27
|
+
onCancelClick: VoidFunction;
|
28
|
+
onConfirmClick: VoidFunction;
|
29
|
+
}
|
30
|
+
|
31
|
+
const DeleteDialog = ({visible, queryName, onCancelClick, onConfirmClick}: DeleteDialogProps) => {
|
32
|
+
return (
|
33
|
+
<Dialog
|
34
|
+
open={visible}
|
35
|
+
hasCloseButton={false}
|
36
|
+
size="s"
|
37
|
+
onClose={onCancelClick}
|
38
|
+
onEnterKeyDown={onConfirmClick}
|
39
|
+
>
|
40
|
+
<Dialog.Header caption={i18n('delete-dialog.header')} />
|
41
|
+
<Dialog.Body className={b('dialog-body')}>
|
42
|
+
{i18n('delete-dialog.question')}
|
43
|
+
<span className={b('dialog-query-name')}>{` ${queryName}?`}</span>
|
44
|
+
</Dialog.Body>
|
45
|
+
<Dialog.Footer
|
46
|
+
textButtonApply={i18n('delete-dialog.delete')}
|
47
|
+
textButtonCancel={i18n('delete-dialog.cancel')}
|
48
|
+
onClickButtonCancel={onCancelClick}
|
49
|
+
onClickButtonApply={onConfirmClick}
|
50
|
+
/>
|
51
|
+
</Dialog>
|
52
|
+
);
|
53
|
+
};
|
54
|
+
|
55
|
+
interface SavedQueriesProps {
|
56
|
+
savedQueries: SavedQuery[];
|
57
|
+
changeUserInput: (value: {input: string}) => void;
|
58
|
+
onDeleteQuery: (queryName: string) => void;
|
59
|
+
}
|
60
|
+
|
61
|
+
export const SavedQueries = ({savedQueries, changeUserInput, onDeleteQuery}: SavedQueriesProps) => {
|
62
|
+
const dispatch = useDispatch();
|
63
|
+
|
64
|
+
const [isDeleteDialogVisible, setIsDeleteDialogVisible] = useState(false);
|
65
|
+
const [queryNameToDelete, setQueryNameToDelete] = useState<string>('');
|
66
|
+
|
67
|
+
const closeDeleteDialog = () => {
|
68
|
+
setIsDeleteDialogVisible(false);
|
69
|
+
setQueryNameToDelete('');
|
70
|
+
};
|
71
|
+
|
72
|
+
const onCancelDeleteClick = () => {
|
73
|
+
closeDeleteDialog();
|
74
|
+
};
|
75
|
+
|
76
|
+
const onConfirmDeleteClick = () => {
|
77
|
+
closeDeleteDialog();
|
78
|
+
onDeleteQuery(queryNameToDelete);
|
79
|
+
setQueryNameToDelete('');
|
80
|
+
};
|
81
|
+
|
82
|
+
const onQueryClick = (queryText: string, queryName: string) => {
|
83
|
+
changeUserInput({input: queryText});
|
84
|
+
dispatch(setQueryNameToEdit(queryName));
|
85
|
+
dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
|
86
|
+
};
|
87
|
+
|
88
|
+
const onDeleteQueryClick = (queryName: string) => {
|
89
|
+
return (event: MouseEvent) => {
|
90
|
+
event.stopPropagation();
|
91
|
+
setIsDeleteDialogVisible(true);
|
92
|
+
setQueryNameToDelete(queryName);
|
93
|
+
};
|
94
|
+
};
|
95
|
+
|
96
|
+
const columns: Column<SavedQuery>[] = [
|
97
|
+
{
|
98
|
+
name: 'name',
|
99
|
+
header: 'Name',
|
100
|
+
render: ({row: query}) => <div className={b('query-name')}>{query.name}</div>,
|
101
|
+
width: 200,
|
102
|
+
},
|
103
|
+
{
|
104
|
+
name: 'body',
|
105
|
+
header: 'Query Text',
|
106
|
+
render: ({row: query}) => (
|
107
|
+
<div className={b('query')}>
|
108
|
+
<div className={b('query-body')}>
|
109
|
+
<TruncatedQuery value={query.body} maxQueryHeight={MAX_QUERY_HEIGHT} />
|
110
|
+
</div>
|
111
|
+
<span className={b('controls')}>
|
112
|
+
<Button view="flat-secondary">
|
113
|
+
<IconWrapper name="pencil" viewBox="0 0 24 24" />
|
114
|
+
</Button>
|
115
|
+
<Button view="flat-secondary" onClick={onDeleteQueryClick(query.name)}>
|
116
|
+
<IconWrapper name="trash" viewBox="0 0 24 24" />
|
117
|
+
</Button>
|
118
|
+
</span>
|
119
|
+
</div>
|
120
|
+
),
|
121
|
+
sortable: false,
|
122
|
+
},
|
123
|
+
];
|
124
|
+
|
125
|
+
return (
|
126
|
+
<>
|
127
|
+
<div className={b()}>
|
128
|
+
<DataTable
|
129
|
+
theme="yandex-cloud"
|
130
|
+
columns={columns}
|
131
|
+
data={savedQueries}
|
132
|
+
settings={QUERY_TABLE_SETTINGS}
|
133
|
+
emptyDataMessage={i18n('saved.empty')}
|
134
|
+
rowClassName={() => b('row')}
|
135
|
+
onRowClick={(row) => onQueryClick(row.body, row.name)}
|
136
|
+
initialSortOrder={{
|
137
|
+
columnId: 'name',
|
138
|
+
order: DataTable.ASCENDING,
|
139
|
+
}}
|
140
|
+
/>
|
141
|
+
</div>
|
142
|
+
<DeleteDialog
|
143
|
+
visible={isDeleteDialogVisible}
|
144
|
+
queryName={queryNameToDelete}
|
145
|
+
onCancelClick={onCancelDeleteClick}
|
146
|
+
onConfirmClick={onConfirmDeleteClick}
|
147
|
+
/>
|
148
|
+
</>
|
149
|
+
);
|
150
|
+
};
|
@@ -0,0 +1,12 @@
|
|
1
|
+
{
|
2
|
+
"controls.query-mode-selector_type": "Type:",
|
3
|
+
"tabs.newQuery": "New query",
|
4
|
+
"tabs.history": "History",
|
5
|
+
"tabs.saved": "Saved",
|
6
|
+
"history.empty": "History is empty",
|
7
|
+
"saved.empty": "There are no saved queries",
|
8
|
+
"delete-dialog.header": "Delete query",
|
9
|
+
"delete-dialog.question": "Are you sure you want to delete query",
|
10
|
+
"delete-dialog.delete": "Delete",
|
11
|
+
"delete-dialog.cancel": "Cancel"
|
12
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
{
|
2
|
+
"controls.query-mode-selector_type": "Тип:",
|
3
|
+
"tabs.newQuery": "Новый запрос",
|
4
|
+
"tabs.history": "История",
|
5
|
+
"tabs.saved": "Сохраненные",
|
6
|
+
"history.empty": "История пуста",
|
7
|
+
"saved.empty": "Нет сохраненных запросов",
|
8
|
+
"delete-dialog.header": "Удалить запрос",
|
9
|
+
"delete-dialog.question": "Вы уверены что хотите удалить запрос",
|
10
|
+
"delete-dialog.delete": "Удалить",
|
11
|
+
"delete-dialog.cancel": "Отменить"
|
12
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import type {KeyValueRow} from '../../../../types/api/query';
|
2
|
+
import type {IQueryResult} from '../../../../types/store/query';
|
3
|
+
|
4
|
+
export const getPreparedResult = (data: IQueryResult) => {
|
5
|
+
const columnDivider = '\t';
|
6
|
+
const rowDivider = '\n';
|
7
|
+
|
8
|
+
if (!data?.result?.length) {
|
9
|
+
return '';
|
10
|
+
}
|
11
|
+
|
12
|
+
const columnHeaders = Object.keys(data.result[0]);
|
13
|
+
const rows = Array<string[] | KeyValueRow[]>(columnHeaders).concat(data.result);
|
14
|
+
|
15
|
+
return rows
|
16
|
+
.map((item) => {
|
17
|
+
const row = [];
|
18
|
+
|
19
|
+
for (const field in item) {
|
20
|
+
if (typeof item[field] === 'object' || Array.isArray(item[field])) {
|
21
|
+
row.push(JSON.stringify(item[field]));
|
22
|
+
} else {
|
23
|
+
row.push(item[field]);
|
24
|
+
}
|
25
|
+
}
|
26
|
+
|
27
|
+
return row.join(columnDivider);
|
28
|
+
})
|
29
|
+
.join(rowDivider);
|
30
|
+
};
|
@@ -8,17 +8,13 @@ import type {TEvDescribeSchemeResult} from '../../types/api/schema';
|
|
8
8
|
|
9
9
|
import {DEFAULT_IS_TENANT_SUMMARY_COLLAPSED, DEFAULT_SIZE_TENANT_KEY} from '../../utils/constants';
|
10
10
|
import {useTypedSelector} from '../../utils/hooks';
|
11
|
-
import
|
12
|
-
import {setHeader} from '../../store/reducers/header';
|
11
|
+
import {setHeaderBreadcrumbs} from '../../store/reducers/header/header';
|
13
12
|
import {disableAutorefresh, getSchema} from '../../store/reducers/schema/schema';
|
14
13
|
import {getSchemaAcl} from '../../store/reducers/schemaAcl/schemaAcl';
|
15
14
|
|
16
15
|
import SplitPane from '../../components/SplitPane';
|
17
16
|
import {AccessDenied} from '../../components/Errors/403';
|
18
17
|
|
19
|
-
import {getClusterPath} from '../Cluster/utils';
|
20
|
-
|
21
|
-
import ObjectGeneralTabs from './ObjectGeneralTabs/ObjectGeneralTabs';
|
22
18
|
import ObjectSummary from './ObjectSummary/ObjectSummary';
|
23
19
|
import ObjectGeneral from './ObjectGeneral/ObjectGeneral';
|
24
20
|
|
@@ -92,20 +88,7 @@ function Tenant(props: TenantProps) {
|
|
92
88
|
|
93
89
|
useEffect(() => {
|
94
90
|
if (tenantName) {
|
95
|
-
dispatch(
|
96
|
-
setHeader([
|
97
|
-
{
|
98
|
-
text: 'Cluster',
|
99
|
-
link: getClusterPath(),
|
100
|
-
},
|
101
|
-
{
|
102
|
-
text: tenantName.startsWith('/') ? tenantName.slice(1) : tenantName,
|
103
|
-
link: createHref(routes.tenant, undefined, {
|
104
|
-
name: tenantName,
|
105
|
-
}),
|
106
|
-
},
|
107
|
-
]),
|
108
|
-
);
|
91
|
+
dispatch(setHeaderBreadcrumbs('tenant', {tenantName}));
|
109
92
|
}
|
110
93
|
}, [tenantName, dispatch]);
|
111
94
|
|
@@ -127,33 +110,28 @@ function Tenant(props: TenantProps) {
|
|
127
110
|
{showBlockingError ? (
|
128
111
|
<AccessDenied />
|
129
112
|
) : (
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
additionalNodesInfo={props.additionalNodesInfo}
|
153
|
-
/>
|
154
|
-
</SplitPane>
|
155
|
-
</div>
|
156
|
-
</>
|
113
|
+
<SplitPane
|
114
|
+
defaultSizePaneKey={DEFAULT_SIZE_TENANT_KEY}
|
115
|
+
defaultSizes={[25, 75]}
|
116
|
+
triggerCollapse={summaryVisibilityState.triggerCollapse}
|
117
|
+
triggerExpand={summaryVisibilityState.triggerExpand}
|
118
|
+
minSize={[36, 200]}
|
119
|
+
onSplitStartDragAdditional={onSplitStartDragAdditional}
|
120
|
+
>
|
121
|
+
<ObjectSummary
|
122
|
+
type={preloadedPathType || currentPathType}
|
123
|
+
subType={preloadedPathSubType || currentPathSubType}
|
124
|
+
onCollapseSummary={onCollapseSummaryHandler}
|
125
|
+
onExpandSummary={onExpandSummaryHandler}
|
126
|
+
isCollapsed={summaryVisibilityState.collapsed}
|
127
|
+
additionalTenantInfo={props.additionalTenantInfo}
|
128
|
+
/>
|
129
|
+
<ObjectGeneral
|
130
|
+
type={preloadedPathType || currentPathType}
|
131
|
+
additionalTenantInfo={props.additionalTenantInfo}
|
132
|
+
additionalNodesInfo={props.additionalNodesInfo}
|
133
|
+
/>
|
134
|
+
</SplitPane>
|
157
135
|
)}
|
158
136
|
</div>
|
159
137
|
);
|
@@ -1,5 +1,4 @@
|
|
1
|
-
import {
|
2
|
-
import {TENANT_GENERAL_TABS_IDS} from '../../store/reducers/tenant/constants';
|
1
|
+
import routes, {createHref} from '../../routes';
|
3
2
|
|
4
3
|
export enum TenantInfoTabsIds {
|
5
4
|
overview = 'overview',
|
@@ -9,22 +8,10 @@ export enum TenantInfoTabsIds {
|
|
9
8
|
|
10
9
|
export enum TenantTabsGroups {
|
11
10
|
info = 'info',
|
12
|
-
|
13
|
-
|
11
|
+
queryTab = 'queryTab',
|
12
|
+
diagnosticsTab = 'diagnosticsTab',
|
14
13
|
}
|
15
14
|
|
16
|
-
export const TENANT_GENERAL_TABS = [
|
17
|
-
{
|
18
|
-
id: TENANT_GENERAL_TABS_IDS.query,
|
19
|
-
title: 'Query',
|
20
|
-
icon: <Icon name="query" viewBox="0 0 16 16" />,
|
21
|
-
},
|
22
|
-
{
|
23
|
-
id: TENANT_GENERAL_TABS_IDS.diagnostics,
|
24
|
-
title: 'Diagnostics',
|
25
|
-
icon: <Icon name="diagnostics" viewBox="0 0 17 16" />,
|
26
|
-
},
|
27
|
-
];
|
28
15
|
export const TENANT_INFO_TABS = [
|
29
16
|
{
|
30
17
|
id: TenantInfoTabsIds.overview,
|
@@ -42,3 +29,7 @@ export const TENANT_SCHEMA_TAB = [
|
|
42
29
|
title: 'Schema',
|
43
30
|
},
|
44
31
|
];
|
32
|
+
|
33
|
+
export const getTenantPath = (query = {}) => {
|
34
|
+
return createHref(routes.tenant, undefined, query);
|
35
|
+
};
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import type {Settings} from '@gravity-ui/react-data-table';
|
2
|
+
|
3
|
+
import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants';
|
4
|
+
|
5
|
+
export const MAX_QUERY_HEIGHT = 6;
|
6
|
+
|
7
|
+
export const QUERY_TABLE_SETTINGS: Settings = {
|
8
|
+
...DEFAULT_TABLE_SETTINGS,
|
9
|
+
dynamicRenderType: 'variable',
|
10
|
+
};
|
@@ -3,8 +3,11 @@ import type {NavigationTreeNodeType, NavigationTreeProps} from 'ydb-ui-component
|
|
3
3
|
|
4
4
|
import {changeUserInput} from '../../../store/reducers/executeQuery';
|
5
5
|
import {setShowPreview} from '../../../store/reducers/schema/schema';
|
6
|
-
import {
|
7
|
-
import {
|
6
|
+
import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
|
7
|
+
import {
|
8
|
+
TENANT_QUERY_TABS_ID,
|
9
|
+
TENANT_PAGES_IDS,
|
10
|
+
} from '../../../store/reducers/tenant/constants';
|
8
11
|
import createToast from '../../../utils/createToast';
|
9
12
|
|
10
13
|
const createTableTemplate = (path: string) => {
|
@@ -37,7 +40,8 @@ const bindActions = (
|
|
37
40
|
) => {
|
38
41
|
const inputQuery = (tmpl: (path: string) => string) => () => {
|
39
42
|
dispatch(changeUserInput({input: tmpl(path)}));
|
40
|
-
dispatch(
|
43
|
+
dispatch(setTenantPage(TENANT_PAGES_IDS.query));
|
44
|
+
dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
|
41
45
|
setActivePath(path);
|
42
46
|
};
|
43
47
|
|
@@ -66,7 +70,8 @@ const bindActions = (
|
|
66
70
|
},
|
67
71
|
openPreview: () => {
|
68
72
|
dispatch(setShowPreview(true));
|
69
|
-
dispatch(
|
73
|
+
dispatch(setTenantPage(TENANT_PAGES_IDS.query));
|
74
|
+
dispatch(setQueryTab(TENANT_QUERY_TABS_ID.newQuery));
|
70
75
|
setActivePath(path);
|
71
76
|
},
|
72
77
|
};
|
@@ -18,7 +18,8 @@ import {AutoFetcher} from '../../utils/autofetcher';
|
|
18
18
|
import routes, {createHref} from '../../routes';
|
19
19
|
import {formatCPU, formatBytesToGigabyte, formatNumber} from '../../utils';
|
20
20
|
import {withSearch} from '../../HOCS';
|
21
|
-
import {DEFAULT_TABLE_SETTINGS,
|
21
|
+
import {DEFAULT_TABLE_SETTINGS, TENANT_INITIAL_PAGE_KEY} from '../../utils/constants';
|
22
|
+
import {TENANT_PAGES_IDS} from '../../store/reducers/tenant/constants';
|
22
23
|
import {getTenantsInfo} from '../../store/reducers/tenants/tenants';
|
23
24
|
import {
|
24
25
|
changeFilter,
|
@@ -27,7 +28,7 @@ import {
|
|
27
28
|
} from '../../store/reducers/settings/settings';
|
28
29
|
|
29
30
|
import {clusterName} from '../../store';
|
30
|
-
import {TenantTabsGroups,
|
31
|
+
import {TenantTabsGroups, TENANT_INFO_TABS} from '../Tenant/TenantPages';
|
31
32
|
|
32
33
|
import './Tenants.scss';
|
33
34
|
|
@@ -123,18 +124,22 @@ class Tenants extends React.Component {
|
|
123
124
|
});
|
124
125
|
const filteredTenants = Tenants.filterTenants(filteredTenantsBySearch, filter);
|
125
126
|
|
126
|
-
const initialTenantGeneralTab = savedTenantInitialTab ||
|
127
|
+
const initialTenantGeneralTab = savedTenantInitialTab || TENANT_PAGES_IDS.query;
|
127
128
|
const initialTenantInfoTab = TENANT_INFO_TABS[0].id;
|
128
129
|
|
130
|
+
const getTenantBackend = (tenant) => {
|
131
|
+
const backend = tenant.MonitoringEndpoint ?? tenant.backend;
|
132
|
+
return additionalTenantsInfo.tenantBackend
|
133
|
+
? additionalTenantsInfo.tenantBackend(backend)
|
134
|
+
: undefined;
|
135
|
+
};
|
136
|
+
|
129
137
|
const columns = [
|
130
138
|
{
|
131
139
|
name: 'Name',
|
132
140
|
header: 'Database',
|
133
141
|
render: ({value, row}) => {
|
134
|
-
const backend = row
|
135
|
-
const tenantBackend = additionalTenantsInfo.tenantBackend
|
136
|
-
? additionalTenantsInfo.tenantBackend(backend)
|
137
|
-
: undefined;
|
142
|
+
const backend = getTenantBackend(row);
|
138
143
|
const isExternalLink = Boolean(backend);
|
139
144
|
return (
|
140
145
|
<div className={b('name-wrapper')}>
|
@@ -147,7 +152,7 @@ class Tenants extends React.Component {
|
|
147
152
|
hasClipboardButton
|
148
153
|
path={createHref(routes.tenant, undefined, {
|
149
154
|
name: value,
|
150
|
-
backend
|
155
|
+
backend,
|
151
156
|
[TenantTabsGroups.info]: initialTenantInfoTab,
|
152
157
|
[TenantTabsGroups.general]: initialTenantGeneralTab,
|
153
158
|
})}
|
@@ -287,12 +292,20 @@ class Tenants extends React.Component {
|
|
287
292
|
header: 'Tablets States',
|
288
293
|
sortable: false,
|
289
294
|
width: 430,
|
290
|
-
render: ({value, row}) =>
|
291
|
-
|
292
|
-
|
295
|
+
render: ({value, row}) => {
|
296
|
+
const backend = getTenantBackend(row);
|
297
|
+
|
298
|
+
return value ? (
|
299
|
+
<TabletsStatistic
|
300
|
+
path={row.Name}
|
301
|
+
tablets={value}
|
302
|
+
nodeIds={row.NodeIds}
|
303
|
+
backend={backend}
|
304
|
+
/>
|
293
305
|
) : (
|
294
306
|
'—'
|
295
|
-
)
|
307
|
+
);
|
308
|
+
},
|
296
309
|
},
|
297
310
|
];
|
298
311
|
|
@@ -347,7 +360,7 @@ const mapStateToProps = (state) => {
|
|
347
360
|
loading,
|
348
361
|
error,
|
349
362
|
filter: state.settings.problemFilter,
|
350
|
-
savedTenantInitialTab: getSettingValue(state,
|
363
|
+
savedTenantInitialTab: getSettingValue(state, TENANT_INITIAL_PAGE_KEY),
|
351
364
|
};
|
352
365
|
};
|
353
366
|
|