ydb-embedded-ui 1.0.0 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +23 -0
- package/dist/containers/Header/Header.scss +12 -0
- package/dist/containers/Header/Header.tsx +28 -6
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +4 -1
- package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +6 -1
- package/dist/containers/Tenant/Acl/Acl.scss +4 -4
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +10 -0
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +12 -4
- package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.tsx +3 -2
- package/dist/containers/Tenant/QueryEditor/QueryEditor.js +2 -9
- package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +25 -21
- package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.scss +1 -0
- package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +1 -0
- package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +1 -1
- package/dist/store/reducers/executeQuery.js +17 -3
- package/dist/store/reducers/storage.js +2 -2
- package/dist/utils/constants.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
@@ -1,5 +1,28 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
### [1.0.3](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.0.2...v1.0.3) (2022-03-21)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* query status should not be shown when query is loading ([d214eee](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/d214eee575b63341082f0be33163e3fce520df88))
|
9
|
+
* should set correct initial current index in queries history ([c3228d7](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/c3228d7a6a0c810982db1bdbec7762889ac44ffa))
|
10
|
+
* **Storage:** wording fixed [YDB-1552] ([3f487ff](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/3f487ff01117963760b676d14281e93e5f3002c0))
|
11
|
+
|
12
|
+
### [1.0.2](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.0.1...v1.0.2) (2022-03-11)
|
13
|
+
|
14
|
+
|
15
|
+
### Bug Fixes
|
16
|
+
|
17
|
+
* **Header:** add link to internal viewer ([64af24f](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/64af24f8d78cf0d34466ac129be10c0764cce3d4))
|
18
|
+
|
19
|
+
### [1.0.1](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v1.0.0...v1.0.1) (2022-03-05)
|
20
|
+
|
21
|
+
|
22
|
+
### Bug Fixes
|
23
|
+
|
24
|
+
* **QueriesHistory:** should save history to local storage ([#8](https://www.github.com/ydb-platform/ydb-embedded-ui/issues/8)) ([57031ab](https://www.github.com/ydb-platform/ydb-embedded-ui/commit/57031ab16900e9d1112bbf506d5c777f94f883bb))
|
25
|
+
|
3
26
|
## [1.0.0](https://www.github.com/ydb-platform/ydb-embedded-ui/compare/v0.2.0...v1.0.0) (2022-03-01)
|
4
27
|
|
5
28
|
|
@@ -1,15 +1,19 @@
|
|
1
|
-
import {useEffect} from 'react';
|
1
|
+
import React, {useEffect} from 'react';
|
2
2
|
import {useDispatch, useSelector} from 'react-redux';
|
3
3
|
import cn from 'bem-cn-lite';
|
4
4
|
import {useHistory, useLocation} from 'react-router';
|
5
|
+
import {Breadcrumbs, BreadcrumbsItem, Link} from '@yandex-cloud/uikit';
|
5
6
|
|
6
|
-
import
|
7
|
+
import Divider from '../../components/Divider/Divider';
|
8
|
+
//@ts-ignore
|
9
|
+
import Icon from '../../components/Icon/Icon';
|
10
|
+
|
11
|
+
import {clusterName as clusterNameLocation, backend, customBackend} from '../../store';
|
7
12
|
import {getClusterInfo} from '../../store/reducers/cluster';
|
8
13
|
import {getHostInfo} from '../../store/reducers/host';
|
14
|
+
import {HeaderItemType} from '../../store/reducers/header';
|
9
15
|
|
10
16
|
import './Header.scss';
|
11
|
-
import {Breadcrumbs, BreadcrumbsItem} from '@yandex-cloud/uikit';
|
12
|
-
import {HeaderItemType} from '../../store/reducers/header';
|
13
17
|
|
14
18
|
const b = cn('header');
|
15
19
|
|
@@ -49,6 +53,12 @@ function Header() {
|
|
49
53
|
const renderHeader = () => {
|
50
54
|
const clusterNameFinal = singleClusterMode ? host.ClusterName : clusterName;
|
51
55
|
|
56
|
+
let link = backend + '/internal';
|
57
|
+
|
58
|
+
if (singleClusterMode && !customBackend) {
|
59
|
+
link = `/internal`;
|
60
|
+
}
|
61
|
+
|
52
62
|
const breadcrumbItems = header.reduce((acc, el) => {
|
53
63
|
acc.push({text: el.text, action: () => history.push(el.link)});
|
54
64
|
return acc;
|
@@ -63,8 +73,20 @@ function Header() {
|
|
63
73
|
firstDisplayedItemsCount={1}
|
64
74
|
/>
|
65
75
|
</div>
|
66
|
-
|
67
|
-
|
76
|
+
|
77
|
+
<div className={b('cluster-name-wrapper')}>
|
78
|
+
<Link href={link} target="_blank">
|
79
|
+
Internal viewer{' '}
|
80
|
+
<Icon name="external" viewBox={'0 0 16 16'} width={16} height={16} />
|
81
|
+
</Link>
|
82
|
+
{clusterNameFinal && (
|
83
|
+
<React.Fragment>
|
84
|
+
<div className={b('divider')}>
|
85
|
+
<Divider />
|
86
|
+
</div>
|
87
|
+
<ClusterName name={clusterNameFinal} />
|
88
|
+
</React.Fragment>
|
89
|
+
)}
|
68
90
|
</div>
|
69
91
|
</header>
|
70
92
|
);
|
@@ -210,13 +210,16 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes}: StorageGro
|
|
210
210
|
];
|
211
211
|
|
212
212
|
let columns = allColumns;
|
213
|
+
let emptyMessage = 'No such groups.';
|
213
214
|
|
214
215
|
if (visibleEntities === VisibleEntities.Space) {
|
215
216
|
columns = allColumns.filter((col) => col.name !== TableColumnsIds.Missing);
|
217
|
+
emptyMessage = 'No storage groups with space problems.';
|
216
218
|
}
|
217
219
|
|
218
220
|
if (visibleEntities === VisibleEntities.Missing) {
|
219
221
|
columns = allColumns.filter((col) => col.name !== TableColumnsIds.UsedSpaceFlag);
|
222
|
+
emptyMessage = 'No degraded groups.';
|
220
223
|
}
|
221
224
|
return data ? (
|
222
225
|
<DataTable
|
@@ -226,7 +229,7 @@ function StorageGroups({data, tableSettings, visibleEntities, nodes}: StorageGro
|
|
226
229
|
columns={columns}
|
227
230
|
settings={tableSettings}
|
228
231
|
initialSortOrder={setSortOrder(visibleEntities)}
|
229
|
-
emptyDataMessage=
|
232
|
+
emptyDataMessage={emptyMessage}
|
230
233
|
/>
|
231
234
|
) : null;
|
232
235
|
}
|
@@ -114,9 +114,14 @@ function StorageNodes({data, tableSettings, visibleEntities}: StorageGroupsProps
|
|
114
114
|
];
|
115
115
|
|
116
116
|
let columns = allColumns;
|
117
|
+
let emptyMessage = 'No such nodes.';
|
117
118
|
|
118
119
|
if (visibleEntities === VisibleEntities.Space) {
|
119
120
|
columns = allColumns.filter((col) => col.name !== TableColumnsIds.Missing);
|
121
|
+
emptyMessage = 'No nodes with space problems.';
|
122
|
+
}
|
123
|
+
if (visibleEntities === VisibleEntities.Missing) {
|
124
|
+
emptyMessage = 'No degraded nodes.';
|
120
125
|
}
|
121
126
|
|
122
127
|
return data ? (
|
@@ -127,7 +132,7 @@ function StorageNodes({data, tableSettings, visibleEntities}: StorageGroupsProps
|
|
127
132
|
columns={columns}
|
128
133
|
settings={tableSettings}
|
129
134
|
initialSortOrder={setSortOrder(visibleEntities)}
|
130
|
-
emptyDataMessage=
|
135
|
+
emptyDataMessage={emptyMessage}
|
131
136
|
/>
|
132
137
|
) : null;
|
133
138
|
}
|
@@ -1,6 +1,10 @@
|
|
1
1
|
@import '../../../styles/mixins.scss';
|
2
2
|
|
3
3
|
.kv-acl {
|
4
|
+
display: flex;
|
5
|
+
overflow: auto;
|
6
|
+
flex-grow: 1;
|
7
|
+
|
4
8
|
padding: 0 12px 16px;
|
5
9
|
@include query-data-table;
|
6
10
|
&__message-container {
|
@@ -38,8 +42,4 @@
|
|
38
42
|
color: var(--yc-color-text-danger);
|
39
43
|
}
|
40
44
|
}
|
41
|
-
|
42
|
-
&__result {
|
43
|
-
overflow: auto;
|
44
|
-
}
|
45
45
|
}
|
@@ -13,7 +13,9 @@
|
|
13
13
|
max-height: 100%;
|
14
14
|
|
15
15
|
&__overview-wrapper {
|
16
|
+
display: flex;
|
16
17
|
overflow: auto;
|
18
|
+
flex-grow: 1;
|
17
19
|
|
18
20
|
padding: 0 12px 16px;
|
19
21
|
}
|
@@ -91,7 +93,15 @@
|
|
91
93
|
}
|
92
94
|
|
93
95
|
&__info {
|
96
|
+
display: flex;
|
94
97
|
overflow: hidden;
|
98
|
+
flex-direction: column;
|
99
|
+
}
|
100
|
+
|
101
|
+
&__schema {
|
102
|
+
display: flex;
|
103
|
+
overflow: auto;
|
104
|
+
flex-grow: 1;
|
95
105
|
}
|
96
106
|
|
97
107
|
&__info-controls {
|
@@ -78,7 +78,7 @@ interface ObjectSummaryProps {
|
|
78
78
|
onCollapseSummary: VoidFunction;
|
79
79
|
onExpandSummary: VoidFunction;
|
80
80
|
isCollapsed: boolean;
|
81
|
-
additionalTenantInfo?: any
|
81
|
+
additionalTenantInfo?: any;
|
82
82
|
}
|
83
83
|
|
84
84
|
function ObjectSummary(props: ObjectSummaryProps) {
|
@@ -168,10 +168,16 @@ function ObjectSummary(props: ObjectSummaryProps) {
|
|
168
168
|
const renderTabContent = () => {
|
169
169
|
switch (infoTab) {
|
170
170
|
case TenantInfoTabsIds.acl: {
|
171
|
-
return <Acl additionalTenantInfo={props.additionalTenantInfo}/>;
|
171
|
+
return <Acl additionalTenantInfo={props.additionalTenantInfo} />;
|
172
172
|
}
|
173
173
|
case TenantInfoTabsIds.schema: {
|
174
|
-
return loadingSchema ?
|
174
|
+
return loadingSchema ? (
|
175
|
+
renderLoader()
|
176
|
+
) : (
|
177
|
+
<div className={b('schema')}>
|
178
|
+
<SchemaViewer data={schema} />
|
179
|
+
</div>
|
180
|
+
);
|
175
181
|
}
|
176
182
|
default: {
|
177
183
|
return renderObjectOverview();
|
@@ -194,7 +200,9 @@ function ObjectSummary(props: ObjectSummaryProps) {
|
|
194
200
|
<div className={b('tree-title')}>Navigation</div>
|
195
201
|
</div>
|
196
202
|
<div className={b('tree')}>
|
197
|
-
{tenantData &&
|
203
|
+
{tenantData && (
|
204
|
+
<SchemaNode fullPath={tenantName as string} data={tenantData} isRoot />
|
205
|
+
)}
|
198
206
|
</div>
|
199
207
|
</div>
|
200
208
|
);
|
@@ -38,6 +38,7 @@ function QueriesHistory(props: QueriesHistoryProps) {
|
|
38
38
|
};
|
39
39
|
|
40
40
|
const renderSavedQueries = () => {
|
41
|
+
const reversedHistory = ([] as string[]).concat(history).reverse();
|
41
42
|
return (
|
42
43
|
<Popup
|
43
44
|
className={b('popup-wrapper')}
|
@@ -47,7 +48,7 @@ function QueriesHistory(props: QueriesHistoryProps) {
|
|
47
48
|
onClose={onCloseHistory}
|
48
49
|
>
|
49
50
|
<div className={b()}>
|
50
|
-
{
|
51
|
+
{reversedHistory.length === 0 ? (
|
51
52
|
<div className={b('empty')}>History is empty</div>
|
52
53
|
) : (
|
53
54
|
<React.Fragment>
|
@@ -57,7 +58,7 @@ function QueriesHistory(props: QueriesHistoryProps) {
|
|
57
58
|
</div>
|
58
59
|
</div>
|
59
60
|
<div>
|
60
|
-
{
|
61
|
+
{reversedHistory.map((query, index) => {
|
61
62
|
return (
|
62
63
|
<div
|
63
64
|
className={b('saved-queries-row')}
|
@@ -154,7 +154,7 @@ function QueryEditor(props) {
|
|
154
154
|
useEffect(() => {
|
155
155
|
const {monacoHotKey, setMonacoHotKey} = props;
|
156
156
|
if (monacoHotKey === null) {
|
157
|
-
return
|
157
|
+
return;
|
158
158
|
}
|
159
159
|
setMonacoHotKey(null);
|
160
160
|
switch (monacoHotKey) {
|
@@ -464,19 +464,12 @@ function QueryEditor(props) {
|
|
464
464
|
};
|
465
465
|
|
466
466
|
const getExecuteResult = () => {
|
467
|
-
const {
|
468
|
-
data = [],
|
469
|
-
error,
|
470
|
-
loading,
|
471
|
-
history: {queries},
|
472
|
-
} = props.executeQuery;
|
467
|
+
const {data = [], error} = props.executeQuery;
|
473
468
|
|
474
469
|
if (error) {
|
475
470
|
return error.data || error;
|
476
471
|
} else if (data.length > 0) {
|
477
472
|
return data;
|
478
|
-
} else if (!loading && queries.length) {
|
479
|
-
return 'The request was successful';
|
480
473
|
} else {
|
481
474
|
return '';
|
482
475
|
}
|
@@ -252,28 +252,32 @@ function QueryExplain(props) {
|
|
252
252
|
return (
|
253
253
|
<React.Fragment>
|
254
254
|
<div className={b('controls')}>
|
255
|
-
|
256
|
-
<
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
255
|
+
{!props.loading && (
|
256
|
+
<React.Fragment>
|
257
|
+
<div className={b('controls-right')}>
|
258
|
+
<QueryExecutionStatus hasError={Boolean(props.error)} />
|
259
|
+
{!props.error && (
|
260
|
+
<React.Fragment>
|
261
|
+
<Divider />
|
262
|
+
<RadioButton
|
263
|
+
options={explainOptions}
|
264
|
+
value={activeOption}
|
265
|
+
onUpdate={onSelectOption}
|
266
|
+
/>
|
267
|
+
</React.Fragment>
|
268
|
+
)}
|
269
|
+
</div>
|
270
|
+
<div className={b('controls-left')}>
|
271
|
+
<EnableFullscreenButton disabled={Boolean(props.error)} />
|
272
|
+
<PaneVisibilityToggleButtons
|
273
|
+
onCollapse={props.onCollapseResults}
|
274
|
+
onExpand={props.onExpandResults}
|
275
|
+
isCollapsed={props.isResultsCollapsed}
|
276
|
+
initialDirection="bottom"
|
264
277
|
/>
|
265
|
-
</
|
266
|
-
|
267
|
-
|
268
|
-
<div className={b('controls-left')}>
|
269
|
-
<EnableFullscreenButton disabled={Boolean(props.error)} />
|
270
|
-
<PaneVisibilityToggleButtons
|
271
|
-
onCollapse={props.onCollapseResults}
|
272
|
-
onExpand={props.onExpandResults}
|
273
|
-
isCollapsed={props.isResultsCollapsed}
|
274
|
-
initialDirection="bottom"
|
275
|
-
/>
|
276
|
-
</div>
|
278
|
+
</div>
|
279
|
+
</React.Fragment>
|
280
|
+
)}
|
277
281
|
</div>
|
278
282
|
<div className={b('result')}>{renderContent()}</div>
|
279
283
|
</React.Fragment>
|
@@ -67,7 +67,7 @@ class SchemaViewer extends React.Component {
|
|
67
67
|
theme="yandex-cloud"
|
68
68
|
data={tableData}
|
69
69
|
columns={columns}
|
70
|
-
settings={
|
70
|
+
settings={DEFAULT_TABLE_SETTINGS}
|
71
71
|
dynamicRender={true}
|
72
72
|
initialSortOrder={{columnId: SchemaViewerColumns.key, order: DataTable.DESCENDING}}
|
73
73
|
/>
|
@@ -1,5 +1,9 @@
|
|
1
1
|
import {createRequestActionTypes, createApiRequest} from '../utils';
|
2
2
|
import '../../services/api';
|
3
|
+
import {getValueFromLS, parseJson} from '../../utils/utils';
|
4
|
+
import {QUERIES_HISTORY_KEY} from '../../utils/constants';
|
5
|
+
|
6
|
+
const MAXIMUM_QUERIES_IN_HISTORY = 20;
|
3
7
|
|
4
8
|
const SEND_QUERY = createRequestActionTypes('query', 'SEND_QUERY');
|
5
9
|
const CHANGE_USER_INPUT = 'query/CHANGE_USER_INPUT';
|
@@ -9,6 +13,10 @@ const GO_TO_NEXT_QUERY = 'query/GO_TO_NEXT_QUERY';
|
|
9
13
|
const SELECT_RUN_ACTION = 'query/SELECT_RUN_ACTION';
|
10
14
|
const MONACO_HOT_KEY = 'query/MONACO_HOT_KEY';
|
11
15
|
|
16
|
+
const queriesHistoryInitial = parseJson(getValueFromLS(QUERIES_HISTORY_KEY, []));
|
17
|
+
|
18
|
+
const sliceLimit = queriesHistoryInitial.length - MAXIMUM_QUERIES_IN_HISTORY;
|
19
|
+
|
12
20
|
export const RUN_ACTIONS_VALUES = {
|
13
21
|
script: 'execute-script',
|
14
22
|
scan: 'execute-scan',
|
@@ -25,8 +33,11 @@ const initialState = {
|
|
25
33
|
loading: false,
|
26
34
|
input: '',
|
27
35
|
history: {
|
28
|
-
queries:
|
29
|
-
currentIndex:
|
36
|
+
queries: queriesHistoryInitial.slice(sliceLimit < 0 ? 0 : sliceLimit),
|
37
|
+
currentIndex:
|
38
|
+
queriesHistoryInitial.length > MAXIMUM_QUERIES_IN_HISTORY
|
39
|
+
? MAXIMUM_QUERIES_IN_HISTORY - 1
|
40
|
+
: queriesHistoryInitial.length - 1,
|
30
41
|
},
|
31
42
|
runAction: RUN_ACTIONS_VALUES.script,
|
32
43
|
monacoHotKey: null,
|
@@ -76,7 +87,10 @@ const executeQuery = (state = initialState, action) => {
|
|
76
87
|
|
77
88
|
case SAVE_QUERY_TO_HISTORY: {
|
78
89
|
const query = action.data;
|
79
|
-
const newQueries = [...state.history.queries, query]
|
90
|
+
const newQueries = [...state.history.queries, query].slice(
|
91
|
+
state.history.queries.length >= MAXIMUM_QUERIES_IN_HISTORY ? 1 : 0,
|
92
|
+
);
|
93
|
+
window.localStorage.setItem(QUERIES_HISTORY_KEY, JSON.stringify(newQueries));
|
80
94
|
const currentIndex = newQueries.length - 1;
|
81
95
|
|
82
96
|
return {
|
package/dist/utils/constants.js
CHANGED
@@ -120,6 +120,7 @@ export const PROBLEMS = 'With problems';
|
|
120
120
|
|
121
121
|
export const THEME_KEY = 'theme';
|
122
122
|
export const SAVED_QUERIES_KEY = 'saved_queries';
|
123
|
+
export const QUERIES_HISTORY_KEY = 'queries_history';
|
123
124
|
export const DATA_QA_TUNE_COLUMNS_POPUP = 'tune-columns-popup';
|
124
125
|
|
125
126
|
export const defaultUserSettings = {
|