ydb-embedded-ui 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +2 -2
  4. package/dist/assets/icons/cluster.svg +1 -0
  5. package/dist/assets/icons/hide.svg +1 -0
  6. package/dist/assets/icons/show.svg +1 -0
  7. package/dist/assets/icons/user-check.svg +1 -1
  8. package/dist/assets/icons/user-secret.svg +1 -1
  9. package/dist/components/AsideNavigation/AsideHeader.scss +1 -2
  10. package/dist/components/AsideNavigation/AsideHeaderFooterItem/AsideHeaderFooterItem.scss +7 -7
  11. package/dist/components/AsideNavigation/AsideHeaderTooltip/AsideHeaderTooltip.scss +2 -2
  12. package/dist/components/AsideNavigation/CompositeBar/CompositeBar.scss +6 -6
  13. package/dist/components/AsideNavigation/Drawer/Drawer.scss +5 -5
  14. package/dist/components/AsideNavigation/Logo/Logo.scss +3 -4
  15. package/dist/components/AsideNavigation/Settings/Settings.scss +27 -12
  16. package/dist/components/AsideNavigation/Settings/SettingsMenu/SettingsMenu.scss +14 -6
  17. package/dist/components/Breadcrumbs/Breadcrumbs.scss +2 -1
  18. package/dist/components/ClusterInfo/ClusterInfo.scss +19 -12
  19. package/dist/components/ClusterInfo/ClusterInfo.tsx +110 -10
  20. package/dist/components/CopyToClipboard/CopyToClipboard.tsx +39 -0
  21. package/dist/components/CriticalActionDialog/CriticalActionDialog.scss +5 -4
  22. package/dist/components/Divider/Divider.scss +7 -0
  23. package/dist/components/Divider/Divider.tsx +11 -0
  24. package/dist/components/EmptyState/EmptyState.scss +14 -10
  25. package/dist/components/EnableFullscreenButton/EnableFullscreenButton.tsx +22 -0
  26. package/dist/components/EntityStatus/EntityStatus.js +5 -3
  27. package/dist/components/EntityStatus/EntityStatus.scss +35 -13
  28. package/dist/components/FullGroupViewer/FullGroupViewer.js +2 -4
  29. package/dist/components/FullGroupViewer/FullGroupViewer.scss +6 -3
  30. package/dist/components/FullNodeViewer/FullNodeViewer.scss +19 -11
  31. package/dist/components/Fullscreen/Fullscreen.scss +28 -0
  32. package/dist/components/Fullscreen/Fullscreen.tsx +81 -0
  33. package/dist/components/GroupTreeViewer/GroupTreeViewer.scss +1 -0
  34. package/dist/components/GroupViewer/GroupViewer.scss +8 -4
  35. package/dist/components/Icon/Icon.js +2 -0
  36. package/dist/components/InfoViewer/InfoViewer.scss +22 -16
  37. package/dist/components/NodesViewer/NodesViewer.js +25 -35
  38. package/dist/components/NodesViewer/NodesViewer.scss +15 -11
  39. package/dist/components/PDiskViewer/PDiskViewer.scss +10 -4
  40. package/dist/components/Pagination/Pagination.scss +6 -3
  41. package/dist/components/PoolBar/PoolBar.scss +14 -10
  42. package/dist/components/PoolUsage/PoolUsage.scss +17 -9
  43. package/dist/components/ProgressViewer/ProgressViewer.js +1 -1
  44. package/dist/components/ProgressViewer/ProgressViewer.scss +28 -18
  45. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.scss +14 -0
  46. package/dist/components/QueryExecutionStatus/QueryExecutionStatus.tsx +29 -0
  47. package/dist/components/SplitPane/SplitPane.scss +33 -40
  48. package/dist/components/SplitPane/SplitPane.tsx +94 -0
  49. package/dist/components/Tablet/Tablet.scss +9 -6
  50. package/dist/components/TabletsOverall/TabletsOverall.scss +19 -0
  51. package/dist/components/TabletsOverall/TabletsOverall.tsx +105 -0
  52. package/dist/components/TabletsStatistic/TabletsStatistic.scss +24 -18
  53. package/dist/components/TabletsViewer/TabletsViewer.scss +12 -9
  54. package/dist/components/Tag/Tag.scss +6 -4
  55. package/dist/components/Tags/Tags.scss +1 -1
  56. package/dist/components/TreeView/TreeView.js +1 -1
  57. package/dist/components/TreeView/TreeView.scss +9 -0
  58. package/dist/components/TruncatedQuery/TruncatedQuery.scss +4 -3
  59. package/dist/containers/App/App.js +1 -0
  60. package/dist/containers/App/App.scss +50 -31
  61. package/dist/containers/App/Content.js +2 -2
  62. package/dist/containers/App/NodesTable.scss +25 -0
  63. package/dist/containers/App/TipPopup/TipPopup.scss +10 -6
  64. package/dist/containers/AppIcons/AppIcons.js +46 -22
  65. package/dist/containers/AsideNavigation/AsideNavigation.scss +1 -1
  66. package/dist/containers/AsideNavigation/AsideNavigation.tsx +12 -5
  67. package/dist/containers/Authentication/Authentication.scss +63 -14
  68. package/dist/containers/Authentication/Authentication.tsx +42 -9
  69. package/dist/containers/Cluster/Cluster.scss +5 -3
  70. package/dist/containers/Cluster/Cluster.tsx +49 -0
  71. package/dist/containers/Group/Group.scss +1 -1
  72. package/dist/containers/Header/Header.scss +15 -59
  73. package/dist/containers/Header/Header.tsx +75 -0
  74. package/dist/containers/Header/Host/Host.scss +10 -3
  75. package/dist/containers/Heatmap/Heatmap.js +1 -1
  76. package/dist/containers/Heatmap/Heatmap.scss +16 -7
  77. package/dist/containers/Heatmap/HeatmapCanvas/HeatmapCanvas.js +3 -3
  78. package/dist/containers/Heatmap/Histogram/Histogram.scss +21 -9
  79. package/dist/containers/Node/Node.js +1 -1
  80. package/dist/containers/Node/Node.scss +6 -4
  81. package/dist/containers/Nodes/Nodes.js +28 -27
  82. package/dist/containers/Nodes/Nodes.scss +5 -17
  83. package/dist/containers/Pdisk/Pdisk.scss +6 -4
  84. package/dist/containers/Pool/Pool.scss +7 -4
  85. package/dist/containers/ReduxTooltip/ReduxTooltip.scss +5 -1
  86. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +77 -0
  87. package/dist/containers/{StorageV2 → Storage}/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -1
  88. package/dist/containers/{StorageV2 → Storage}/Pdisk/Pdisk.scss +6 -4
  89. package/dist/containers/{StorageV2 → Storage}/Pdisk/Pdisk.tsx +1 -2
  90. package/dist/containers/{StorageV2 → Storage}/Storage.js +72 -34
  91. package/dist/containers/{StorageV2 → Storage}/Storage.scss +12 -14
  92. package/dist/containers/{StorageV2 → Storage}/StorageFilter/StorageFilter.js +1 -9
  93. package/dist/containers/{StorageV2 → Storage}/StorageGroups/StorageGroups.scss +2 -0
  94. package/dist/containers/{StorageV2 → Storage}/StorageGroups/StorageGroups.tsx +1 -1
  95. package/dist/containers/{StorageV2 → Storage}/StorageNodes/StorageNodes.scss +2 -0
  96. package/dist/containers/{StorageV2 → Storage}/StorageNodes/StorageNodes.tsx +1 -1
  97. package/dist/containers/{StorageV2 → Storage}/Vdisk/Vdisk.js +0 -0
  98. package/dist/containers/{StorageV2 → Storage}/Vdisk/Vdisk.scss +6 -4
  99. package/dist/containers/Tablet/Tablet.scss +13 -9
  100. package/dist/containers/Tablets/Tablets.js +21 -90
  101. package/dist/containers/Tablets/Tablets.scss +9 -35
  102. package/dist/containers/TabletsFilters/TabletsFilters.js +2 -75
  103. package/dist/containers/TabletsFilters/TabletsFilters.scss +15 -35
  104. package/dist/containers/Tenant/Acl/Acl.js +54 -47
  105. package/dist/containers/Tenant/Acl/Acl.scss +15 -4
  106. package/dist/containers/Tenant/{Compute → Diagnostics/Compute}/Compute.js +35 -12
  107. package/dist/containers/Tenant/Diagnostics/Compute/Compute.scss +14 -0
  108. package/dist/containers/Tenant/{Describe → Diagnostics/Describe}/Describe.js +50 -1
  109. package/dist/containers/Tenant/{Describe → Diagnostics/Describe}/Describe.scss +5 -3
  110. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.scss +27 -0
  111. package/dist/containers/Tenant/Diagnostics/DetailedOverview/DetailedOverview.tsx +88 -0
  112. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +50 -0
  113. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +208 -0
  114. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +75 -0
  115. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.js +191 -0
  116. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +79 -0
  117. package/dist/containers/Tenant/{Healthcheck → Diagnostics/Healthcheck}/IssuesViewer/IssueViewer.scss +25 -13
  118. package/dist/containers/Tenant/{Healthcheck → Diagnostics/Healthcheck}/IssuesViewer/IssuesViewer.js +2 -2
  119. package/dist/containers/Tenant/{Schema → Diagnostics}/HotKeys/HotKeys.js +14 -8
  120. package/dist/containers/Tenant/{Schema → Diagnostics}/HotKeys/HotKeys.scss +7 -5
  121. package/dist/containers/Tenant/{Network → Diagnostics/Network}/Network.js +39 -9
  122. package/dist/containers/Tenant/{Network → Diagnostics/Network}/Network.scss +35 -36
  123. package/dist/containers/Tenant/{Network → Diagnostics/Network}/NodeNetwork/NodeNetwork.js +0 -0
  124. package/dist/containers/Tenant/{Network → Diagnostics/Network}/NodeNetwork/NodeNetwork.scss +11 -9
  125. package/dist/containers/Tenant/Diagnostics/Overview/Overview.scss +13 -0
  126. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +123 -0
  127. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +200 -0
  128. package/dist/{components → containers/Tenant/Diagnostics}/TenantOverview/TenantOverview.scss +24 -17
  129. package/dist/containers/Tenant/{TopQueries → Diagnostics/TopQueries}/TopQueries.js +32 -30
  130. package/dist/containers/Tenant/{TopQueries → Diagnostics/TopQueries}/TopQueries.scss +10 -9
  131. package/dist/containers/Tenant/{TopShards → Diagnostics/TopShards}/TopShards.js +25 -29
  132. package/dist/containers/Tenant/{TopShards → Diagnostics/TopShards}/TopShards.scss +1 -13
  133. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.scss +38 -0
  134. package/dist/containers/Tenant/ObjectGeneral/ObjectGeneral.tsx +104 -0
  135. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +165 -0
  136. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +310 -0
  137. package/dist/containers/Tenant/Preview/Preview.js +50 -12
  138. package/dist/containers/Tenant/Preview/Preview.scss +45 -3
  139. package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.scss +85 -0
  140. package/dist/containers/Tenant/QueryEditor/QueriesHistory/QueriesHistory.tsx +94 -0
  141. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +291 -264
  142. package/dist/containers/Tenant/QueryEditor/QueryEditor.scss +47 -18
  143. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.js +132 -32
  144. package/dist/containers/Tenant/QueryEditor/QueryExplain/QueryExplain.scss +47 -11
  145. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.js +89 -20
  146. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +60 -6
  147. package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +10 -23
  148. package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.scss +15 -7
  149. package/dist/containers/Tenant/QueryEditor/SavedQueries/SavedQueries.js +7 -3
  150. package/dist/containers/Tenant/QueryEditor/SavedQueries/SavedQueries.scss +28 -17
  151. package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.js +7 -7
  152. package/dist/containers/Tenant/Schema/SchemaInfoViewer/SchemaInfoViewer.scss +1 -11
  153. package/dist/containers/Tenant/Schema/SchemaNode/SchemaNode.js +37 -17
  154. package/dist/containers/Tenant/Schema/SchemaNode/SchemaNode.scss +33 -12
  155. package/dist/containers/Tenant/Schema/SchemaNodeActions/SchemaNodeActions.scss +17 -0
  156. package/dist/containers/Tenant/Schema/SchemaNodeActions/SchemaNodeActions.tsx +125 -0
  157. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.js +5 -4
  158. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.scss +6 -2
  159. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.js +53 -34
  160. package/dist/containers/Tenant/Schema/SchemaViewer/SchemaViewer.scss +1 -22
  161. package/dist/containers/Tenant/Tenant.scss +3 -32
  162. package/dist/containers/Tenant/Tenant.tsx +161 -0
  163. package/dist/containers/Tenant/TenantPages.tsx +48 -0
  164. package/dist/containers/Tenant/utils/ToggleButton.scss +26 -0
  165. package/dist/containers/Tenant/utils/paneVisibilityToggleHelpers.tsx +126 -0
  166. package/dist/containers/Tenants/Tenants.js +41 -55
  167. package/dist/containers/Tenants/Tenants.scss +4 -17
  168. package/dist/containers/UserSettings/UserSettings.tsx +0 -2
  169. package/dist/containers/Vdisk/Vdisk.scss +6 -4
  170. package/dist/containers/VdiskPdiskNode/VdiskPdiskNode.js +1 -1
  171. package/dist/containers/VdiskPdiskNode/VdiskPdiskNode.scss +5 -5
  172. package/dist/{routes.js → routes.ts} +14 -4
  173. package/dist/store/reducers/clusterNodes.js +1 -1
  174. package/dist/store/reducers/fullscreen.ts +31 -0
  175. package/dist/store/reducers/header.ts +23 -0
  176. package/dist/store/reducers/hotKeys.js +1 -1
  177. package/dist/store/reducers/index.js +6 -0
  178. package/dist/store/reducers/saveQuery.ts +33 -0
  179. package/dist/store/reducers/schema.js +14 -0
  180. package/dist/store/reducers/shardsWorkload.js +1 -1
  181. package/dist/store/state-url-mapping.js +1 -1
  182. package/dist/store/utils.js +2 -6
  183. package/dist/styles/mixins.scss +49 -34
  184. package/dist/utils/autofetcher.ts +51 -0
  185. package/dist/utils/constants.js +25 -7
  186. package/dist/utils/createToast.tsx +23 -0
  187. package/dist/utils/getNodesColumns.js +25 -28
  188. package/dist/utils/index.js +6 -2
  189. package/package.json +8 -4
  190. package/dist/components/SplitPane/SplitPane.js +0 -368
  191. package/dist/components/TenantOverview/TenantOverview.js +0 -148
  192. package/dist/containers/Cluster/Cluster.js +0 -168
  193. package/dist/containers/Header/Header.js +0 -88
  194. package/dist/containers/StorageV2/DiskStateProgressBar/DiskStateProgressBar.scss +0 -81
  195. package/dist/containers/Tenant/Compute/Compute.scss +0 -6
  196. package/dist/containers/Tenant/Healthcheck/Healthcheck.js +0 -116
  197. package/dist/containers/Tenant/Healthcheck/Healthcheck.scss +0 -64
  198. package/dist/containers/Tenant/Schema/Info/Info.js +0 -84
  199. package/dist/containers/Tenant/Schema/Info/Info.scss +0 -3
  200. package/dist/containers/Tenant/Schema/SchemaMain/SchemaMain.js +0 -439
  201. package/dist/containers/Tenant/Schema/SchemaMain/SchemaMain.scss +0 -90
  202. package/dist/containers/Tenant/Schema/SchemaPages.js +0 -56
  203. package/dist/containers/Tenant/Tenant.js +0 -199
  204. package/dist/containers/Tenant/TenantPages.js +0 -35
@@ -1,16 +1,16 @@
1
- import React from 'react';
1
+ import {useEffect, useReducer, useRef, useState} from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import {connect} from 'react-redux';
3
+ import {connect, useDispatch} from 'react-redux';
4
4
  import cn from 'bem-cn-lite';
5
5
  import _ from 'lodash';
6
6
  import MonacoEditor from 'react-monaco-editor';
7
7
  import DataTable from '@yandex-cloud/react-data-table';
8
- import {Button, Toaster, CopyToClipboard} from '@yandex-cloud/uikit';
8
+ import {Button} from '@yandex-cloud/uikit';
9
9
  import {Select} from '@yandex-cloud/uikit/build/esm/components/unstable/Select';
10
10
  import SplitPane from '../../../components/SplitPane';
11
11
 
12
- import Pagination from '../../../components/Pagination/Pagination';
13
12
  import SaveQuery from './SaveQuery/SaveQuery';
13
+ import SavedQueries from './SavedQueries/SavedQueries';
14
14
  import Icon from '../../../components/Icon/Icon';
15
15
  import QueryResult from './QueryResult/QueryResult';
16
16
  import QueryExplain from './QueryExplain/QueryExplain';
@@ -27,14 +27,25 @@ import {
27
27
  import {getExplainQuery, getExplainQueryAst} from '../../../store/reducers/explainQuery';
28
28
  import {showTooltip} from '../../../store/reducers/tooltip';
29
29
  import {getSettingValue, setSettingValue} from '../../../store/reducers/settings';
30
- import {THEME_KEY, DEFAULT_SIZE_RESULT_PANE_KEY, SAVED_QUERIES_KEY} from '../../../utils/constants';
30
+ import {
31
+ DEFAULT_IS_QUERY_RESULT_COLLAPSED,
32
+ DEFAULT_SIZE_RESULT_PANE_KEY,
33
+ DEFAULT_TABLE_SETTINGS,
34
+ SAVED_QUERIES_KEY,
35
+ } from '../../../utils/constants';
31
36
  import {prepareQueryResponse} from '../../../utils/index';
32
37
 
33
38
  import {parseJson} from '../../../utils/utils';
34
39
 
35
40
  import './QueryEditor.scss';
36
-
37
- const toaster = new Toaster();
41
+ import Divider from '../../../components/Divider/Divider';
42
+ import QueriesHistory from './QueriesHistory/QueriesHistory';
43
+ import {
44
+ PaneVisibilityActionTypes,
45
+ paneVisibilityToggleReducerCreator,
46
+ } from '../utils/paneVisibilityToggleHelpers';
47
+ import Preview from '../Preview/Preview';
48
+ import { setShowPreview } from '../../../store/reducers/schema';
38
49
 
39
50
  export const RUN_ACTIONS = [
40
51
  {value: RUN_ACTIONS_VALUES.script, content: 'Run Script'},
@@ -42,11 +53,13 @@ export const RUN_ACTIONS = [
42
53
  ];
43
54
 
44
55
  const TABLE_SETTINGS = {
45
- displayIndices: false,
46
- syncHeadOnResize: true,
47
- stickyHead: DataTable.MOVING,
56
+ ...DEFAULT_TABLE_SETTINGS,
48
57
  sortable: false,
58
+ dynamicItemSizeGetter: () => 40,
59
+ dynamicRenderType: 'variable',
60
+ stripedRows: true,
49
61
  };
62
+
50
63
  const EDITOR_OPTIONS = {
51
64
  automaticLayout: true,
52
65
  selectOnLineNumbers: true,
@@ -63,66 +76,97 @@ const RESULT_TYPES = {
63
76
 
64
77
  const b = cn('query-editor');
65
78
 
66
- class QueryEditor extends React.Component {
67
- static propTypes = {
68
- sendQuery: PropTypes.func,
69
- path: PropTypes.string,
70
- response: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]),
71
- executeQuery: PropTypes.object,
72
- explainQuery: PropTypes.object,
73
- showTooltip: PropTypes.func,
74
- theme: PropTypes.string,
75
- };
79
+ const propTypes = {
80
+ sendQuery: PropTypes.func,
81
+ path: PropTypes.string,
82
+ response: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]),
83
+ executeQuery: PropTypes.object,
84
+ explainQuery: PropTypes.object,
85
+ showTooltip: PropTypes.func,
86
+ theme: PropTypes.string,
87
+ type: PropTypes.string,
88
+ };
76
89
 
77
- state = {
78
- resultType: RESULT_TYPES.EXECUTE,
79
- runAction: RUN_ACTIONS[0].value,
80
- };
90
+ const initialTenantCommonInfoState = {
91
+ triggerExpand: false,
92
+ triggerCollapse: false,
93
+ collapsed: true,
94
+ };
95
+ function QueryEditor(props) {
96
+ const [resultType, setResultType] = useState(RESULT_TYPES.EXECUTE);
81
97
 
82
- editorRef = null;
98
+ const dispatch = useDispatch()
83
99
 
84
- componentDidMount() {
85
- this.updateEditor();
100
+ const [resultVisibilityState, dispatchResultVisibilityState] = useReducer(
101
+ paneVisibilityToggleReducerCreator(DEFAULT_IS_QUERY_RESULT_COLLAPSED),
102
+ initialTenantCommonInfoState,
103
+ );
86
104
 
87
- window.addEventListener('resize', this.onChangeWindow);
88
- window.addEventListener('storage', this.storageEventHandler);
89
- }
105
+ const editorRef = useRef(null);
90
106
 
91
- checkIfHasUnsavedInput(e) {
92
- e.preventDefault();
93
- // Chrome requires returnValue to be set
94
- e.returnValue = '';
95
- }
107
+ useEffect(() => {
108
+ updateEditor();
96
109
 
97
- componentWillUnmount() {
98
- window.removeEventListener('resize', this.onChangeWindow);
99
- window.removeEventListener('storage', this.storageEventHandler);
100
- window.onbeforeunload = undefined;
101
- }
110
+ window.addEventListener('resize', onChangeWindow);
111
+ window.addEventListener('storage', storageEventHandler);
102
112
 
103
- componentDidUpdate() {
113
+ return () => {
114
+ window.removeEventListener('resize', onChangeWindow);
115
+ window.removeEventListener('storage', storageEventHandler);
116
+ window.onbeforeunload = undefined;
117
+ };
118
+ }, []);
119
+
120
+ useEffect(() => {
121
+ dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerCollapse);
122
+ }, []);
123
+
124
+ useEffect(() => {
125
+ const {showPreview} = props;
126
+ if (showPreview && resultVisibilityState.collapsed) {
127
+ dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
128
+ }
129
+ }, [props.showPreview, resultVisibilityState.collapsed]);
130
+
131
+ useEffect(() => {
104
132
  const {
105
133
  explainQuery: {data},
106
134
  executeQuery: {input, history},
107
- } = this.props;
135
+ } = props;
108
136
 
109
137
  const hasUnsavedInput = input
110
138
  ? input !== history.queries[history.queries?.length - 1]
111
139
  : false;
112
140
 
113
141
  if (hasUnsavedInput) {
114
- window.onbeforeunload = this.checkIfHasUnsavedInput;
142
+ window.onbeforeunload = checkIfHasUnsavedInput;
115
143
  } else {
116
144
  window.onbeforeunload = undefined;
117
145
  }
118
146
 
119
- if (!data || this.state.resultType !== RESULT_TYPES.EXPLAIN) {
147
+ if (!data || resultType !== RESULT_TYPES.EXPLAIN) {
120
148
  return;
121
149
  }
122
- }
150
+ }, [props.executeQuery, props.executeQuery]);
151
+
152
+ useEffect(() => {
153
+ const {
154
+ path,
155
+ executeQuery: {input},
156
+ } = props;
157
+ if (resultType === RESULT_TYPES.EXPLAIN) {
158
+ props.getExplainQuery({query: input, database: path});
159
+ }
160
+ }, [resultType]);
123
161
 
124
- editorDidMount = (editor, monaco) => {
125
- this.editorRef = editor;
162
+ const checkIfHasUnsavedInput = (e) => {
163
+ e.preventDefault();
164
+ // Chrome requires returnValue to be set
165
+ e.returnValue = '';
166
+ };
167
+
168
+ const editorDidMount = (editor, monaco) => {
169
+ editorRef.current = editor;
126
170
  editor.focus();
127
171
  editor.addAction({
128
172
  id: 'run',
@@ -140,7 +184,7 @@ class QueryEditor extends React.Component {
140
184
  // Method that will be executed when the action is triggered.
141
185
  // @param editor The editor instance is passed in as a convinience
142
186
  run: () => {
143
- this.handleSendClick();
187
+ handleSendClick();
144
188
  },
145
189
  });
146
190
 
@@ -154,7 +198,7 @@ class QueryEditor extends React.Component {
154
198
  contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
155
199
  contextMenuOrder: 2,
156
200
  run: () => {
157
- this.handlePreviousHistoryClick();
201
+ handlePreviousHistoryClick();
158
202
  },
159
203
  });
160
204
  editor.addAction({
@@ -167,7 +211,7 @@ class QueryEditor extends React.Component {
167
211
  contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
168
212
  contextMenuOrder: 3,
169
213
  run: () => {
170
- this.handleNextHistoryClick();
214
+ handleNextHistoryClick();
171
215
  },
172
216
  });
173
217
 
@@ -185,62 +229,65 @@ class QueryEditor extends React.Component {
185
229
  contextMenuGroupId: CONTEXT_MENU_GROUP_ID,
186
230
  contextMenuOrder: 4,
187
231
  run: () => {
188
- this.handleGetExplainQueryClick();
232
+ handleGetExplainQueryClick();
189
233
  },
190
234
  });
191
235
  };
192
- onChange = (newValue) => {
193
- this.props.changeUserInput({input: newValue});
236
+ const onChange = (newValue) => {
237
+ props.changeUserInput({input: newValue});
194
238
  };
195
239
 
196
- handleSendClick = () => {
240
+ const handleSendClick = () => {
197
241
  const {
198
242
  path,
199
243
  executeQuery: {input, history, runAction},
200
244
  sendQuery,
201
245
  saveQueryToHistory,
202
- } = this.props;
246
+ } = props;
203
247
 
204
- this.setState({resultType: RESULT_TYPES.EXECUTE});
248
+ setResultType(RESULT_TYPES.EXECUTE);
205
249
  sendQuery({query: input, database: path, action: runAction});
250
+ dispatch(setShowPreview(false))
206
251
 
207
252
  const {queries, currentIndex} = history;
208
253
  if (input !== queries[currentIndex]) {
209
254
  saveQueryToHistory(input);
210
255
  }
256
+ dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
211
257
  };
212
258
 
213
- handleCancelClick = () => {
214
- this.props.cancelQuery();
259
+ const handleGetExplainQueryClick = () => {
260
+ setResultType(RESULT_TYPES.EXPLAIN);
261
+ dispatch(setShowPreview(false))
262
+ dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
215
263
  };
216
264
 
217
- handleGetExplainQueryClick = () => {
265
+ const handleAstQuery = () => {
218
266
  const {
219
267
  path,
220
268
  executeQuery: {input},
221
- getExplainQuery,
222
- } = this.props;
269
+ getExplainQueryAst,
270
+ } = props;
271
+ getExplainQueryAst({query: input, database: path});
272
+ };
223
273
 
224
- this.setState({resultType: RESULT_TYPES.EXPLAIN}, () => {
225
- getExplainQuery({query: input, database: path});
226
- });
274
+ const onCollapseResultHandler = () => {
275
+ dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerCollapse);
276
+ };
277
+ const onExpandResultHandler = () => {
278
+ dispatchResultVisibilityState(PaneVisibilityActionTypes.triggerExpand);
227
279
  };
228
280
 
229
- handleAstQuery = () => {
230
- const {
231
- path,
232
- executeQuery: {input},
233
- getExplainQueryAst,
234
- } = this.props;
235
- getExplainQueryAst({query: input, database: path});
281
+ const onSplitStartDrugAdditional = () => {
282
+ dispatchResultVisibilityState(PaneVisibilityActionTypes.clear);
236
283
  };
237
284
 
238
- renderExecuteQuery = () => {
285
+ const renderExecuteQuery = () => {
239
286
  const {
240
287
  executeQuery: {data, error, stats},
241
288
  showTooltip,
242
- } = this.props;
243
- const result = this.getExecuteResult();
289
+ } = props;
290
+ const result = getExecuteResult();
244
291
  const shouldRenderAnswer = result.length || error;
245
292
 
246
293
  if (!shouldRenderAnswer) {
@@ -265,56 +312,62 @@ class QueryEditor extends React.Component {
265
312
  }
266
313
 
267
314
  const preparedData = prepareQueryResponse(data);
315
+
268
316
  const content = columns.length ? (
269
317
  <DataTable
270
318
  columns={columns}
271
319
  data={preparedData}
272
320
  settings={TABLE_SETTINGS}
273
- theme="common"
321
+ theme="yandex-cloud"
274
322
  />
275
323
  ) : (
276
324
  <div>{result}</div>
277
325
  );
278
- return <QueryResult result={content} stats={stats} />;
326
+ const results = getPreparedResult();
327
+ const disabled = !results.length || resultType !== RESULT_TYPES.EXECUTE;
328
+ return (
329
+ <QueryResult
330
+ result={content}
331
+ stats={stats}
332
+ error={Boolean(error)}
333
+ textResults={results}
334
+ copyDisabled={disabled}
335
+ isResultsCollapsed={resultVisibilityState.collapsed}
336
+ onExpandResults={onExpandResultHandler}
337
+ onCollapseResults={onCollapseResultHandler}
338
+ />
339
+ );
279
340
  };
280
-
281
- renderExplainQuery = () => {
341
+ const renderExplainQuery = () => {
282
342
  const {
283
343
  explainQuery: {data, dataAst, error, loading, loadingAst},
284
344
  theme,
285
- } = this.props;
286
-
287
- if (error) {
288
- return error.data ? error.data : error;
289
- } else if (!data && !loading) {
290
- return 'Explain of query is empty';
291
- } else if (!data) {
292
- return null;
293
- } else if (!data.nodes.length) {
294
- return 'There is no explanation for the request';
295
- }
345
+ } = props;
296
346
 
297
347
  return (
298
348
  <QueryExplain
349
+ error={error}
299
350
  explain={data}
300
- astQuery={this.handleAstQuery}
351
+ astQuery={handleAstQuery}
301
352
  ast={dataAst?.ast}
353
+ loading={loading}
302
354
  loadingAst={loadingAst}
303
355
  theme={theme}
356
+ isResultsCollapsed={resultVisibilityState.collapsed}
357
+ onExpandResults={onExpandResultHandler}
358
+ onCollapseResults={onCollapseResultHandler}
304
359
  />
305
360
  );
306
361
  };
307
362
 
308
- renderResult = () => {
309
- const {resultType} = this.state;
310
-
363
+ const renderResult = () => {
311
364
  let result;
312
365
  switch (resultType) {
313
366
  case RESULT_TYPES.EXECUTE:
314
- result = this.renderExecuteQuery();
367
+ result = renderExecuteQuery();
315
368
  break;
316
369
  case RESULT_TYPES.EXPLAIN:
317
- result = this.renderExplainQuery();
370
+ result = renderExplainQuery();
318
371
  break;
319
372
  default:
320
373
  result = null;
@@ -323,15 +376,24 @@ class QueryEditor extends React.Component {
323
376
  return result;
324
377
  };
325
378
 
326
- handlePreviousHistoryClick = () => {
379
+ const renderPreview = () => {
380
+ const {path, type, currentSchema = {}} = props;
381
+ const partCount = currentSchema?.PathDescription?.TableStats?.PartCount;
382
+ // onExpandResultHandler();
383
+ return (
384
+ <Preview database={path} table={currentSchema.Path} type={type} partCount={partCount} />
385
+ );
386
+ };
387
+
388
+ const handlePreviousHistoryClick = () => {
327
389
  const {
328
390
  changeUserInput,
329
391
  executeQuery: {history},
330
392
  goToPreviousQuery,
331
- } = this.props;
393
+ } = props;
332
394
  const {queries, currentIndex} = history;
333
395
 
334
- if (this.previousButtonIsDisabled()) {
396
+ if (previousButtonIsDisabled()) {
335
397
  return;
336
398
  }
337
399
 
@@ -339,15 +401,15 @@ class QueryEditor extends React.Component {
339
401
  changeUserInput({input: queries[currentIndex - 1]});
340
402
  };
341
403
 
342
- handleNextHistoryClick = () => {
404
+ const handleNextHistoryClick = () => {
343
405
  const {
344
406
  changeUserInput,
345
407
  executeQuery: {history},
346
408
  goToNextQuery,
347
- } = this.props;
409
+ } = props;
348
410
  const {queries, currentIndex} = history;
349
411
 
350
- if (this.nextButtonIsDisabled()) {
412
+ if (nextButtonIsDisabled()) {
351
413
  return;
352
414
  }
353
415
 
@@ -355,55 +417,38 @@ class QueryEditor extends React.Component {
355
417
  changeUserInput({input: queries[currentIndex + 1]});
356
418
  };
357
419
 
358
- previousButtonIsDisabled = () => {
420
+ const previousButtonIsDisabled = () => {
359
421
  const {
360
422
  history: {currentIndex},
361
- } = this.props.executeQuery;
423
+ } = props.executeQuery;
362
424
 
363
425
  return currentIndex <= 0;
364
426
  };
365
427
 
366
- nextButtonIsDisabled = () => {
428
+ const nextButtonIsDisabled = () => {
367
429
  const {
368
430
  history: {queries, currentIndex},
369
- } = this.props.executeQuery;
431
+ } = props.executeQuery;
370
432
 
371
433
  return queries.length - 1 === currentIndex;
372
434
  };
373
435
 
374
- renderHistoryNavigation = () => {
436
+ const renderHistoryNavigation = () => {
437
+ const {changeUserInput} = props;
375
438
  return (
376
439
  <div className={b('history-controls')}>
377
- <span className={b('history-label')}>History:</span>
378
- <Pagination
379
- previous={{
380
- handler: this.handlePreviousHistoryClick,
381
- hotkeyHandler: this.handlePreviousHistoryClick,
382
- hotkeyScope: 'all',
383
- hotkey: 'ctrl+up, command+up',
384
- tooltip: 'Previous query [ctrl+↑]',
385
- disabled: this.previousButtonIsDisabled(),
386
- }}
387
- next={{
388
- handler: this.handleNextHistoryClick,
389
- hotkeyHandler: this.handleNextHistoryClick,
390
- hotkeyScope: 'all',
391
- hotkey: 'ctrl+down, command+down',
392
- tooltip: 'Next query [ctrl+↓]',
393
- disabled: this.nextButtonIsDisabled(),
394
- }}
395
- />
440
+ <QueriesHistory changeUserInput={changeUserInput} />
396
441
  </div>
397
442
  );
398
443
  };
399
444
 
400
- getExecuteResult = () => {
445
+ const getExecuteResult = () => {
401
446
  const {
402
447
  data = [],
403
448
  error,
404
449
  loading,
405
450
  history: {queries},
406
- } = this.props.executeQuery;
451
+ } = props.executeQuery;
407
452
 
408
453
  if (error) {
409
454
  return error.data || error;
@@ -416,10 +461,10 @@ class QueryEditor extends React.Component {
416
461
  }
417
462
  };
418
463
 
419
- getPreparedResult = () => {
464
+ const getPreparedResult = () => {
420
465
  const {
421
466
  executeQuery: {data},
422
- } = this.props;
467
+ } = props;
423
468
  const columnDivider = '\t';
424
469
  const rowDivider = '\n';
425
470
 
@@ -447,68 +492,28 @@ class QueryEditor extends React.Component {
447
492
  .join(rowDivider);
448
493
  };
449
494
 
450
- renderClipboardButton = () => {
451
- const results = this.getPreparedResult();
452
- const {resultType} = this.state;
453
- const disabled = !results.length || resultType !== RESULT_TYPES.EXECUTE;
454
-
455
- return (
456
- <CopyToClipboard text={results} timeout={1000}>
457
- {(state) => {
458
- if (state === 'success') {
459
- toaster.createToast({
460
- name: 'Copied',
461
- title: 'Results were copied to clipboard successfully',
462
- type: state,
463
- });
464
- }
465
-
466
- return (
467
- <Button onClick={() => {}} disabled={disabled}>
468
- Copy results
469
- </Button>
470
- );
471
- }}
472
- </CopyToClipboard>
473
- );
474
- };
475
-
476
- onChangeWindow = _.throttle(() => {
477
- this.updateEditor();
495
+ const onChangeWindow = _.throttle(() => {
496
+ updateEditor();
478
497
  }, 100);
479
498
 
480
- storageEventHandler = (event) => {
499
+ const storageEventHandler = (event) => {
481
500
  if (event.key === SAVED_QUERIES_KEY) {
482
- this.props.setSettingValue(SAVED_QUERIES_KEY, event.newValue);
501
+ props.setSettingValue(SAVED_QUERIES_KEY, event.newValue);
483
502
  }
484
503
  };
485
504
 
486
- updateEditor = () => {
487
- if (this.editorRef) {
488
- this.editorRef.layout();
505
+ const updateEditor = () => {
506
+ if (editorRef.current) {
507
+ editorRef.current.layout();
489
508
  }
490
509
  };
491
510
 
492
- onChangeSplit = (size) => {
493
- this.setDefaultSizeResultPane(size);
494
- this.updateEditor();
495
- };
496
- setDefaultSizeResultPane = (size) => {
497
- localStorage.setItem(DEFAULT_SIZE_RESULT_PANE_KEY, size);
498
- };
499
- getDefaultSizeResultPane = () => {
500
- let size = parseInt(localStorage.getItem(DEFAULT_SIZE_RESULT_PANE_KEY), 10) || 250;
501
- size = `${size}px`;
502
-
503
- return size;
504
- };
505
-
506
- onSaveQueryHandler = (queryName) => {
511
+ const onSaveQueryHandler = (queryName) => {
507
512
  const {
508
513
  executeQuery: {input},
509
514
  savedQueries = [],
510
515
  setSettingValue,
511
- } = this.props;
516
+ } = props;
512
517
 
513
518
  const queryIndex = savedQueries.findIndex(
514
519
  (el) => el.name.toLowerCase() === queryName.toLowerCase(),
@@ -524,112 +529,132 @@ class QueryEditor extends React.Component {
524
529
  setSettingValue(SAVED_QUERIES_KEY, JSON.stringify(newSavedQueries));
525
530
  };
526
531
 
527
- onDeleteQueryHandler = (queryName) => {
528
- const {savedQueries = [], setSettingValue} = this.props;
532
+ const onDeleteQueryHandler = (queryName) => {
533
+ const {savedQueries = [], setSettingValue} = props;
529
534
  const newSavedQueries = savedQueries.filter(
530
535
  (el) => el.name.toLowerCase() !== queryName.toLowerCase(),
531
536
  );
532
537
  setSettingValue(SAVED_QUERIES_KEY, JSON.stringify(newSavedQueries));
533
538
  };
534
539
 
535
- render() {
536
- const {executeQuery, explainQuery, theme, savedQueries, changeUserInput} = this.props;
540
+ const renderControls = () => {
541
+ const {executeQuery, explainQuery, savedQueries} = props;
537
542
  const {runAction} = executeQuery;
538
543
  const runIsDisabled = !executeQuery.input || executeQuery.loading;
539
- const runText = _.find(RUN_ACTIONS, {value: runAction}).title;
540
- const loadingResult = executeQuery.loading || explainQuery.loading;
541
- const result = this.renderResult();
542
- const showSecondPane = Boolean(result) || loadingResult;
543
- const defaultSizeResultPane = this.getDefaultSizeResultPane();
544
-
544
+ const runText = _.find(RUN_ACTIONS, {value: runAction}).content;
545
545
  return (
546
- <div className={b()}>
547
- <SplitPane
548
- split="horizontal"
549
- primary="second"
550
- minSize={100}
551
- maxSize={-57}
552
- defaultSize={defaultSizeResultPane}
553
- hidePane={!showSecondPane}
554
- pane1Style={{minHeight: '50px'}}
555
- onChange={this.onChangeSplit}
546
+ <div className={b('controls')}>
547
+ <div className={b('control-run')}>
548
+ <Button
549
+ onClick={handleSendClick}
550
+ view="action"
551
+ pin="round-brick"
552
+ disabled={runIsDisabled}
553
+ loading={executeQuery.loading}
554
+ >
555
+ <Icon name="startPlay" viewBox="0 0 16 16" width={16} height={16} />
556
+ {runText}
557
+ </Button>
558
+ <Select
559
+ view="action"
560
+ options={RUN_ACTIONS}
561
+ value={undefined}
562
+ disabled={runIsDisabled}
563
+ pin="brick-round"
564
+ // renderSwitcher={() => (
565
+ // <div className={b('run-switcher')}>
566
+ // <Button
567
+ // view="action"
568
+ // pin="brick-round"
569
+ // disabled={runIsDisabled}
570
+ // loading={executeQuery.loading}
571
+ // >
572
+ // <Icon name="chevron-down" width={16} height={16} />
573
+ // </Button>
574
+ // </div>
575
+ // )}
576
+ onUpdate={(value) => {
577
+ props.selectRunAction(value[0]);
578
+ }}
579
+ />
580
+ </div>
581
+ <Button
582
+ onClick={handleGetExplainQueryClick}
583
+ disabled={!executeQuery.input}
584
+ loading={explainQuery.loading}
556
585
  >
557
- <div className={b('pane-wrapper')}>
558
- <div className={b('monaco-wrapper')}>
559
- <div className={b('monaco')}>
560
- <MonacoEditor
561
- language="sql"
562
- value={executeQuery.input}
563
- options={EDITOR_OPTIONS}
564
- onChange={this.onChange}
565
- editorDidMount={this.editorDidMount}
566
- theme={`vs-${theme}`}
567
- />
568
- </div>
569
- </div>
570
- <div className={b('controls')}>
571
- <div className={b('control-run')}>
572
- <Button
573
- onClick={this.handleSendClick}
574
- view="action"
575
- pin="round-brick"
576
- disabled={runIsDisabled}
577
- loading={executeQuery.loading}
578
- >
579
- {runText}
580
- </Button>
581
- <Select
582
- options={RUN_ACTIONS}
583
- value={runAction}
584
- disabled={runIsDisabled}
585
- renderSwitcher={() => (
586
- <div className={b('run-switcher')}>
587
- <Button
588
- view="action"
589
- pin="brick-round"
590
- disabled={runIsDisabled}
591
- loading={executeQuery.loading}
592
- >
593
- <Icon name="chevron-down" width={16} height={16} />
594
- </Button>
595
- </div>
596
- )}
597
- onUpdate={(value) => {
598
- this.props.selectRunAction(value);
599
- }}
600
- />
601
- </div>
602
- <Button
603
- onClick={this.handleGetExplainQueryClick}
604
- disabled={!executeQuery.input}
605
- loading={explainQuery.loading}
606
- >
607
- Explain
608
- </Button>
609
- {this.renderHistoryNavigation()}
610
- {this.renderClipboardButton()}
611
- <SaveQuery
612
- savedQueries={savedQueries}
613
- onSaveQuery={this.onSaveQueryHandler}
614
- saveButtonDisabled={runIsDisabled}
615
- changeUserInput={changeUserInput}
616
- onDeleteQuery={this.onDeleteQueryHandler}
586
+ Explain
587
+ </Button>
588
+ <Divider />
589
+ <SaveQuery
590
+ savedQueries={savedQueries}
591
+ onSaveQuery={onSaveQueryHandler}
592
+ saveButtonDisabled={runIsDisabled}
593
+ />
594
+ </div>
595
+ );
596
+ };
597
+
598
+ const renderUpperControls = () => {
599
+ const {savedQueries, changeUserInput} = props;
600
+
601
+ return (
602
+ <div className={b('upper-controls')}>
603
+ {renderHistoryNavigation()}
604
+ <SavedQueries
605
+ savedQueries={savedQueries}
606
+ changeUserInput={changeUserInput}
607
+ onDeleteQuery={onDeleteQueryHandler}
608
+ />
609
+ </div>
610
+ );
611
+ };
612
+
613
+ const {executeQuery, theme} = props;
614
+ const result = renderResult();
615
+
616
+ return (
617
+ <div className={b()}>
618
+ <SplitPane
619
+ direction="vertical"
620
+ defaultSizePaneKey={DEFAULT_SIZE_RESULT_PANE_KEY}
621
+ triggerCollapse={resultVisibilityState.triggerCollapse}
622
+ triggerExpand={resultVisibilityState.triggerExpand}
623
+ minSize={[0, 52]}
624
+ collapsedSizes={[100, 0]}
625
+ onSplitStartDrugAdditional={onSplitStartDrugAdditional}
626
+ >
627
+ <div className={b('pane-wrapper')}>
628
+ <div className={b('monaco-wrapper')}>
629
+ <div className={b('monaco')}>
630
+ <MonacoEditor
631
+ language="sql"
632
+ value={executeQuery.input}
633
+ options={EDITOR_OPTIONS}
634
+ onChange={onChange}
635
+ editorDidMount={editorDidMount}
636
+ theme={`vs-${theme}`}
617
637
  />
618
638
  </div>
619
639
  </div>
620
- {showSecondPane && <div className={b('pane-wrapper')}>{result}</div>}
621
- </SplitPane>
622
- </div>
623
- );
624
- }
640
+ {renderControls()}
641
+ {renderUpperControls()}
642
+ </div>
643
+ <div className={b('pane-wrapper')}>
644
+ {props.showPreview ? renderPreview() : result}
645
+ </div>
646
+ </SplitPane>
647
+ </div>
648
+ );
625
649
  }
626
650
 
627
651
  const mapStateToProps = (state) => {
628
652
  return {
629
653
  executeQuery: state.executeQuery,
630
654
  explainQuery: state.explainQuery,
631
- theme: getSettingValue(state, THEME_KEY),
632
655
  savedQueries: parseJson(getSettingValue(state, SAVED_QUERIES_KEY)),
656
+ showPreview: state.schema.showPreview,
657
+ currentSchema: state.schema.currentSchema,
633
658
  };
634
659
  };
635
660
 
@@ -646,4 +671,6 @@ const mapDispatchToProps = {
646
671
  selectRunAction,
647
672
  };
648
673
 
674
+ QueryEditor.propTypes = propTypes;
675
+
649
676
  export default connect(mapStateToProps, mapDispatchToProps)(QueryEditor);