ydb-embedded-ui 4.5.2 → 4.7.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +33 -0
- package/dist/assets/icons/versions.svg +3 -0
- package/dist/components/NodeHostWrapper/NodeHostWrapper.tsx +7 -2
- package/dist/components/Tablet/Tablet.tsx +17 -3
- package/dist/components/TabletsStatistic/TabletsStatistic.tsx +23 -16
- package/dist/containers/App/Content.js +8 -4
- package/dist/containers/AsideNavigation/AsideNavigation.tsx +4 -50
- package/dist/containers/Cluster/Cluster.scss +7 -48
- package/dist/containers/Cluster/Cluster.tsx +129 -20
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +34 -17
- package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +58 -92
- package/dist/containers/Cluster/ClusterInfoSkeleton/ClusterInfoSkeleton.scss +48 -0
- package/dist/containers/Cluster/ClusterInfoSkeleton/ClusterInfoSkeleton.tsx +34 -0
- package/dist/containers/Cluster/utils.tsx +45 -0
- package/dist/containers/Header/Header.scss +4 -19
- package/dist/containers/Header/Header.tsx +72 -46
- package/dist/containers/Header/breadcrumbs.ts +146 -0
- package/dist/containers/Node/Node.tsx +25 -29
- package/dist/containers/Node/NodePages.ts +10 -6
- package/dist/containers/Nodes/Nodes.tsx +0 -16
- package/dist/containers/Nodes/getNodesColumns.tsx +1 -1
- package/dist/containers/Storage/Storage.js +1 -11
- package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +11 -3
- package/dist/containers/Tablet/Tablet.tsx +40 -4
- package/dist/containers/Tablet/TabletInfo/TabletInfo.tsx +2 -2
- package/dist/containers/TabletsFilters/TabletsFilters.js +15 -2
- package/dist/containers/Tenant/Diagnostics/Consumers/columns/columns.tsx +1 -1
- package/dist/containers/Tenant/Diagnostics/Describe/Describe.tsx +1 -1
- package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +7 -0
- package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +4 -4
- 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/Overview/ChangefeedInfo/ChangefeedInfo.tsx +4 -6
- package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +56 -53
- package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +2 -1
- package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +11 -13
- package/dist/containers/Tenant/Diagnostics/TopShards/TopShards.tsx +1 -1
- package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +2 -2
- package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +7 -3
- package/dist/containers/Tenant/Preview/Preview.js +1 -1
- 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 +43 -100
- package/dist/containers/Tenant/{QueryEditor → Query/QueryEditor}/QueryEditor.scss +7 -23
- package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/OldQueryEditorControls.tsx +10 -3
- package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/QueryEditorControls.scss +1 -4
- package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/QueryEditorControls.tsx +8 -1
- package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/shared.ts +1 -6
- 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/Schema/SchemaTree/SchemaTree.tsx +1 -1
- package/dist/containers/Tenant/Tenant.tsx +4 -25
- package/dist/containers/Tenant/TenantPages.tsx +8 -2
- package/dist/containers/Tenant/utils/constants.ts +10 -0
- package/dist/containers/Tenant/utils/schemaActions.ts +8 -3
- package/dist/containers/Tenants/Tenants.js +39 -37
- package/dist/containers/Tenants/Tenants.scss +2 -4
- package/dist/containers/UserSettings/i18n/en.json +2 -2
- package/dist/containers/UserSettings/i18n/ru.json +2 -2
- package/dist/containers/UserSettings/settings.ts +4 -4
- package/dist/containers/Versions/Versions.scss +0 -4
- package/dist/containers/Versions/Versions.tsx +74 -66
- package/dist/routes.ts +8 -6
- package/dist/services/api.ts +15 -7
- package/dist/store/reducers/clusterNodes/clusterNodes.tsx +4 -0
- package/dist/store/reducers/executeQuery.ts +1 -1
- package/dist/store/reducers/header/header.ts +31 -0
- package/dist/store/reducers/header/types.ts +54 -0
- package/dist/store/reducers/index.ts +4 -2
- package/dist/store/reducers/node/types.ts +2 -0
- package/dist/store/reducers/overview/overview.ts +109 -0
- package/dist/store/reducers/overview/types.ts +24 -0
- package/dist/store/reducers/{schema.ts → schema/schema.ts} +24 -50
- package/dist/{types/store/schema.ts → store/reducers/schema/types.ts} +16 -15
- package/dist/store/reducers/settings/settings.ts +5 -3
- package/dist/store/reducers/tablet.ts +18 -1
- package/dist/store/reducers/tenant/constants.ts +6 -0
- package/dist/store/reducers/tenant/tenant.ts +21 -2
- package/dist/store/reducers/tenant/types.ts +9 -2
- package/dist/store/reducers/topic.ts +1 -1
- package/dist/store/state-url-mapping.js +4 -1
- package/dist/types/api/query.ts +78 -44
- package/dist/types/store/explainQuery.ts +2 -2
- package/dist/types/store/query.ts +9 -2
- package/dist/types/store/tablet.ts +7 -4
- package/dist/utils/constants.ts +5 -1
- package/dist/utils/nodes.ts +1 -1
- package/dist/utils/query.ts +3 -3
- package/package.json +2 -1
- 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}/SaveQuery/SaveQuery.scss +0 -0
- /package/dist/containers/Tenant/{QueryEditor → Query}/i18n/index.ts +0 -0
@@ -5,42 +5,44 @@ import cn from 'bem-cn-lite';
|
|
5
5
|
import _ from 'lodash';
|
6
6
|
import MonacoEditor from 'react-monaco-editor';
|
7
7
|
|
8
|
-
import SplitPane from '
|
9
|
-
import {QueryResultTable} from '
|
10
|
-
|
11
|
-
import SavedQueries from './SavedQueries/SavedQueries';
|
12
|
-
import QueryResult from './QueryResult/QueryResult';
|
13
|
-
import QueryExplain from './QueryExplain/QueryExplain';
|
14
|
-
import {QueryEditorControls} from './QueryEditorControls/QueryEditorControls';
|
15
|
-
import {OldQueryEditorControls} from './QueryEditorControls/OldQueryEditorControls';
|
8
|
+
import SplitPane from '../../../../components/SplitPane';
|
9
|
+
import {QueryResultTable} from '../../../../components/QueryResultTable';
|
16
10
|
|
17
11
|
import {
|
18
12
|
sendExecuteQuery,
|
19
|
-
changeUserInput,
|
20
13
|
saveQueryToHistory,
|
21
14
|
goToPreviousQuery,
|
22
15
|
goToNextQuery,
|
23
16
|
MONACO_HOT_KEY_ACTIONS,
|
24
17
|
setMonacoHotKey,
|
25
|
-
} from '
|
26
|
-
import {getExplainQuery, getExplainQueryAst} from '
|
27
|
-
import {getParsedSettingValue, setSettingValue} from '
|
18
|
+
} from '../../../../store/reducers/executeQuery';
|
19
|
+
import {getExplainQuery, getExplainQueryAst} from '../../../../store/reducers/explainQuery';
|
20
|
+
import {getParsedSettingValue, setSettingValue} from '../../../../store/reducers/settings/settings';
|
21
|
+
import {setShowPreview} from '../../../../store/reducers/schema/schema';
|
28
22
|
import {
|
29
23
|
DEFAULT_IS_QUERY_RESULT_COLLAPSED,
|
30
24
|
DEFAULT_SIZE_RESULT_PANE_KEY,
|
31
25
|
SAVED_QUERIES_KEY,
|
32
26
|
QUERY_INITIAL_MODE_KEY,
|
33
|
-
|
34
|
-
} from '
|
27
|
+
ENABLE_ADDITIONAL_QUERY_MODES,
|
28
|
+
} from '../../../../utils/constants';
|
29
|
+
import {useSetting} from '../../../../utils/hooks';
|
30
|
+
import {QueryModes} from '../../../../types/store/query';
|
35
31
|
|
36
|
-
import './QueryEditor.scss';
|
37
|
-
import QueriesHistory from './QueriesHistory/QueriesHistory';
|
38
32
|
import {
|
39
33
|
PaneVisibilityActionTypes,
|
40
34
|
paneVisibilityToggleReducerCreator,
|
41
|
-
} from '
|
42
|
-
import Preview from '
|
43
|
-
|
35
|
+
} from '../../utils/paneVisibilityToggleHelpers';
|
36
|
+
import Preview from '../../Preview/Preview';
|
37
|
+
|
38
|
+
import {ExecuteResult} from '../ExecuteResult/ExecuteResult';
|
39
|
+
import {ExplainResult} from '../ExplainResult/ExplainResult';
|
40
|
+
import {QueryEditorControls} from '../QueryEditorControls/QueryEditorControls';
|
41
|
+
import {OldQueryEditorControls} from '../QueryEditorControls/OldQueryEditorControls';
|
42
|
+
|
43
|
+
import {getPreparedResult} from '../utils/getPreparedResult';
|
44
|
+
|
45
|
+
import './QueryEditor.scss';
|
44
46
|
|
45
47
|
const TABLE_SETTINGS = {
|
46
48
|
sortable: false,
|
@@ -64,6 +66,7 @@ const b = cn('query-editor');
|
|
64
66
|
|
65
67
|
const propTypes = {
|
66
68
|
sendExecuteQuery: PropTypes.func,
|
69
|
+
changeUserInput: PropTypes.func,
|
67
70
|
path: PropTypes.string,
|
68
71
|
response: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]),
|
69
72
|
executeQuery: PropTypes.object,
|
@@ -83,7 +86,15 @@ function QueryEditor(props) {
|
|
83
86
|
const [resultType, setResultType] = useState(RESULT_TYPES.EXECUTE);
|
84
87
|
|
85
88
|
const [isResultLoaded, setIsResultLoaded] = useState(false);
|
86
|
-
const [queryMode, setQueryMode] =
|
89
|
+
const [queryMode, setQueryMode] = useSetting(QUERY_INITIAL_MODE_KEY);
|
90
|
+
const [enableAdditionalQueryModes] = useSetting(ENABLE_ADDITIONAL_QUERY_MODES);
|
91
|
+
|
92
|
+
useEffect(() => {
|
93
|
+
const isNewQueryMode = queryMode !== QueryModes.script && queryMode !== QueryModes.scan;
|
94
|
+
if (!enableAdditionalQueryModes && isNewQueryMode) {
|
95
|
+
setQueryMode(QueryModes.script);
|
96
|
+
}
|
97
|
+
}, [enableAdditionalQueryModes, queryMode, setQueryMode]);
|
87
98
|
|
88
99
|
const [resultVisibilityState, dispatchResultVisibilityState] = useReducer(
|
89
100
|
paneVisibilityToggleReducerCreator(DEFAULT_IS_QUERY_RESULT_COLLAPSED),
|
@@ -313,11 +324,11 @@ function QueryEditor(props) {
|
|
313
324
|
/>
|
314
325
|
);
|
315
326
|
}
|
316
|
-
const textResults = getPreparedResult();
|
327
|
+
const textResults = getPreparedResult(data);
|
317
328
|
const disabled = !textResults.length || resultType !== RESULT_TYPES.EXECUTE;
|
318
329
|
|
319
330
|
return data || error ? (
|
320
|
-
<
|
331
|
+
<ExecuteResult
|
321
332
|
result={content}
|
322
333
|
stats={stats}
|
323
334
|
error={error}
|
@@ -337,7 +348,7 @@ function QueryEditor(props) {
|
|
337
348
|
} = props;
|
338
349
|
|
339
350
|
return (
|
340
|
-
<
|
351
|
+
<ExplainResult
|
341
352
|
error={error}
|
342
353
|
explain={data}
|
343
354
|
astQuery={handleAstQuery}
|
@@ -425,46 +436,6 @@ function QueryEditor(props) {
|
|
425
436
|
return queries.length - 1 === currentIndex;
|
426
437
|
};
|
427
438
|
|
428
|
-
const renderHistoryNavigation = () => {
|
429
|
-
const {changeUserInput} = props;
|
430
|
-
return (
|
431
|
-
<div className={b('history-controls')}>
|
432
|
-
<QueriesHistory changeUserInput={changeUserInput} />
|
433
|
-
</div>
|
434
|
-
);
|
435
|
-
};
|
436
|
-
|
437
|
-
const getPreparedResult = () => {
|
438
|
-
const {
|
439
|
-
executeQuery: {data},
|
440
|
-
} = props;
|
441
|
-
const columnDivider = '\t';
|
442
|
-
const rowDivider = '\n';
|
443
|
-
|
444
|
-
if (!data?.result?.length) {
|
445
|
-
return '';
|
446
|
-
}
|
447
|
-
|
448
|
-
const columnHeaders = Object.keys(data.result[0]);
|
449
|
-
const rows = [columnHeaders].concat(data.result);
|
450
|
-
|
451
|
-
return rows
|
452
|
-
.map((item) => {
|
453
|
-
const row = [];
|
454
|
-
|
455
|
-
for (const field in item) {
|
456
|
-
if (typeof item[field] === 'object' || Array.isArray(item[field])) {
|
457
|
-
row.push(JSON.stringify(item[field]));
|
458
|
-
} else {
|
459
|
-
row.push(item[field]);
|
460
|
-
}
|
461
|
-
}
|
462
|
-
|
463
|
-
return row.join(columnDivider);
|
464
|
-
})
|
465
|
-
.join(rowDivider);
|
466
|
-
};
|
467
|
-
|
468
439
|
const onChangeWindow = _.throttle(() => {
|
469
440
|
updateEditor();
|
470
441
|
}, 100);
|
@@ -502,23 +473,10 @@ function QueryEditor(props) {
|
|
502
473
|
setSettingValue(SAVED_QUERIES_KEY, JSON.stringify(newSavedQueries));
|
503
474
|
};
|
504
475
|
|
505
|
-
const onDeleteQueryHandler = (queryName) => {
|
506
|
-
const {savedQueries = [], setSettingValue} = props;
|
507
|
-
const newSavedQueries = savedQueries.filter(
|
508
|
-
(el) => el.name.toLowerCase() !== queryName.toLowerCase(),
|
509
|
-
);
|
510
|
-
setSettingValue(SAVED_QUERIES_KEY, JSON.stringify(newSavedQueries));
|
511
|
-
};
|
512
|
-
|
513
|
-
const onUpdateQueryMode = (mode) => {
|
514
|
-
setQueryMode(mode);
|
515
|
-
props.setSettingValue(QUERY_INITIAL_MODE_KEY, mode);
|
516
|
-
};
|
517
|
-
|
518
476
|
const renderControls = () => {
|
519
|
-
const {executeQuery, explainQuery, savedQueries
|
477
|
+
const {executeQuery, explainQuery, savedQueries} = props;
|
520
478
|
|
521
|
-
if (
|
479
|
+
if (enableAdditionalQueryModes) {
|
522
480
|
return (
|
523
481
|
<QueryEditorControls
|
524
482
|
onRunButtonClick={handleSendExecuteClick}
|
@@ -528,7 +486,7 @@ function QueryEditor(props) {
|
|
528
486
|
onSaveQueryClick={onSaveQueryHandler}
|
529
487
|
savedQueries={savedQueries}
|
530
488
|
disabled={!executeQuery.input}
|
531
|
-
onUpdateQueryMode={
|
489
|
+
onUpdateQueryMode={setQueryMode}
|
532
490
|
queryMode={queryMode}
|
533
491
|
/>
|
534
492
|
);
|
@@ -543,27 +501,12 @@ function QueryEditor(props) {
|
|
543
501
|
onSaveQueryClick={onSaveQueryHandler}
|
544
502
|
savedQueries={savedQueries}
|
545
503
|
disabled={!executeQuery.input}
|
546
|
-
onUpdateQueryMode={
|
504
|
+
onUpdateQueryMode={setQueryMode}
|
547
505
|
queryMode={queryMode}
|
548
506
|
/>
|
549
507
|
);
|
550
508
|
};
|
551
509
|
|
552
|
-
const renderUpperControls = () => {
|
553
|
-
const {savedQueries, changeUserInput} = props;
|
554
|
-
|
555
|
-
return (
|
556
|
-
<div className={b('upper-controls')}>
|
557
|
-
{renderHistoryNavigation()}
|
558
|
-
<SavedQueries
|
559
|
-
savedQueries={savedQueries}
|
560
|
-
changeUserInput={changeUserInput}
|
561
|
-
onDeleteQuery={onDeleteQueryHandler}
|
562
|
-
/>
|
563
|
-
</div>
|
564
|
-
);
|
565
|
-
};
|
566
|
-
|
567
510
|
const {executeQuery, theme} = props;
|
568
511
|
const result = renderResult();
|
569
512
|
|
@@ -578,7 +521,11 @@ function QueryEditor(props) {
|
|
578
521
|
collapsedSizes={[100, 0]}
|
579
522
|
onSplitStartDragAdditional={onSplitStartDragAdditional}
|
580
523
|
>
|
581
|
-
<div
|
524
|
+
<div
|
525
|
+
className={b('pane-wrapper', {
|
526
|
+
top: true,
|
527
|
+
})}
|
528
|
+
>
|
582
529
|
<div className={b('monaco-wrapper')}>
|
583
530
|
<div className={b('monaco')}>
|
584
531
|
<MonacoEditor
|
@@ -592,7 +539,6 @@ function QueryEditor(props) {
|
|
592
539
|
</div>
|
593
540
|
</div>
|
594
541
|
{renderControls()}
|
595
|
-
{renderUpperControls()}
|
596
542
|
</div>
|
597
543
|
<div className={b('pane-wrapper')}>
|
598
544
|
{props.showPreview ? renderPreview() : result}
|
@@ -607,8 +553,6 @@ const mapStateToProps = (state) => {
|
|
607
553
|
executeQuery: state.executeQuery,
|
608
554
|
explainQuery: state.explainQuery,
|
609
555
|
savedQueries: getParsedSettingValue(state, SAVED_QUERIES_KEY),
|
610
|
-
initialQueryMode: getParsedSettingValue(state, QUERY_INITIAL_MODE_KEY),
|
611
|
-
enableQueryModesForExplain: getParsedSettingValue(state, ENABLE_QUERY_MODES_FOR_EXPLAIN),
|
612
556
|
showPreview: state.schema.showPreview,
|
613
557
|
currentSchema: state.schema.currentSchema,
|
614
558
|
monacoHotKey: state.executeQuery?.monacoHotKey,
|
@@ -617,7 +561,6 @@ const mapStateToProps = (state) => {
|
|
617
561
|
|
618
562
|
const mapDispatchToProps = {
|
619
563
|
sendExecuteQuery,
|
620
|
-
changeUserInput,
|
621
564
|
saveQueryToHistory,
|
622
565
|
goToPreviousQuery,
|
623
566
|
goToNextQuery,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
@import '
|
1
|
+
@import '../../../../styles/mixins.scss';
|
2
2
|
|
3
3
|
.query-editor {
|
4
4
|
position: relative;
|
@@ -24,7 +24,8 @@
|
|
24
24
|
|
25
25
|
width: 100%;
|
26
26
|
height: 100%;
|
27
|
-
|
27
|
+
|
28
|
+
border: 1px solid var(--yc-color-line-generic);
|
28
29
|
}
|
29
30
|
|
30
31
|
&__monaco-wrapper {
|
@@ -40,28 +41,11 @@
|
|
40
41
|
flex-direction: column;
|
41
42
|
|
42
43
|
background-color: var(--yc-color-base-background);
|
43
|
-
}
|
44
|
-
|
45
|
-
&__upper-controls {
|
46
|
-
position: absolute;
|
47
|
-
top: -38px;
|
48
|
-
right: 20px;
|
49
|
-
|
50
|
-
display: flex;
|
51
|
-
gap: 12px;
|
52
|
-
|
53
|
-
justify-content: flex-end;
|
54
|
-
align-items: center;
|
55
|
-
}
|
56
|
-
|
57
|
-
&__history-controls {
|
58
|
-
display: flex;
|
59
|
-
align-items: center;
|
60
|
-
}
|
61
44
|
|
62
|
-
|
63
|
-
|
45
|
+
&_top {
|
46
|
+
padding: 0 16px;
|
64
47
|
|
65
|
-
|
48
|
+
border-bottom: 1px solid var(--yc-color-line-generic);
|
49
|
+
}
|
66
50
|
}
|
67
51
|
}
|
package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/OldQueryEditorControls.tsx
RENAMED
@@ -6,10 +6,17 @@ import {Icon} from '../../../../components/Icon';
|
|
6
6
|
|
7
7
|
import SaveQuery from '../SaveQuery/SaveQuery';
|
8
8
|
|
9
|
-
import {
|
9
|
+
import {QueryEditorControlsProps, b} from './shared';
|
10
10
|
|
11
11
|
import './QueryEditorControls.scss';
|
12
12
|
|
13
|
+
type OldQueryModes = QueryModes.script | QueryModes.scan;
|
14
|
+
|
15
|
+
export const QueryModeSelectorTitles = {
|
16
|
+
[QueryModes.script]: 'Script',
|
17
|
+
[QueryModes.scan]: 'Scan',
|
18
|
+
} as const;
|
19
|
+
|
13
20
|
export const OldQueryEditorControls = ({
|
14
21
|
onRunButtonClick,
|
15
22
|
runIsLoading,
|
@@ -26,7 +33,7 @@ export const OldQueryEditorControls = ({
|
|
26
33
|
return {
|
27
34
|
text: `Run ${title}`,
|
28
35
|
action: () => {
|
29
|
-
onUpdateQueryMode(mode as
|
36
|
+
onUpdateQueryMode(mode as OldQueryModes);
|
30
37
|
},
|
31
38
|
};
|
32
39
|
});
|
@@ -44,7 +51,7 @@ export const OldQueryEditorControls = ({
|
|
44
51
|
loading={runIsLoading}
|
45
52
|
>
|
46
53
|
<Icon name="startPlay" viewBox="0 0 16 16" width={16} height={16} />
|
47
|
-
{`Run ${QueryModeSelectorTitles[queryMode]}`}
|
54
|
+
{`Run ${QueryModeSelectorTitles[queryMode as OldQueryModes]}`}
|
48
55
|
</Button>
|
49
56
|
<DropdownMenu
|
50
57
|
items={runModeSelectorMenuItems}
|
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 {
|
package/dist/containers/Tenant/{QueryEditor → Query}/QueryEditorControls/QueryEditorControls.tsx
RENAMED
@@ -8,10 +8,17 @@ import SaveQuery from '../SaveQuery/SaveQuery';
|
|
8
8
|
|
9
9
|
import i18n from '../i18n';
|
10
10
|
|
11
|
-
import {
|
11
|
+
import {QueryEditorControlsProps, b} from './shared';
|
12
12
|
|
13
13
|
import './QueryEditorControls.scss';
|
14
14
|
|
15
|
+
export const QueryModeSelectorTitles = {
|
16
|
+
[QueryModes.script]: 'Script',
|
17
|
+
[QueryModes.scan]: 'Scan',
|
18
|
+
[QueryModes.data]: 'Data',
|
19
|
+
[QueryModes.query]: 'Query',
|
20
|
+
} as const;
|
21
|
+
|
15
22
|
export const QueryEditorControls = ({
|
16
23
|
onRunButtonClick,
|
17
24
|
runIsLoading,
|
@@ -1,14 +1,9 @@
|
|
1
1
|
import block from 'bem-cn-lite';
|
2
2
|
|
3
|
-
import {QueryModes} from '../../../../types/store/query';
|
3
|
+
import type {QueryModes} from '../../../../types/store/query';
|
4
4
|
|
5
5
|
export const b = block('ydb-query-editor-controls');
|
6
6
|
|
7
|
-
export const QueryModeSelectorTitles = {
|
8
|
-
[QueryModes.script]: 'Script',
|
9
|
-
[QueryModes.scan]: 'Scan',
|
10
|
-
} as const;
|
11
|
-
|
12
7
|
export interface QueryEditorControlsProps {
|
13
8
|
onRunButtonClick: (mode?: QueryModes) => void;
|
14
9
|
runIsLoading: boolean;
|
@@ -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
|
+
};
|