ydb-embedded-ui 2.2.1 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/assets/icons/shield.svg +3 -0
  3. package/dist/components/Errors/403/AccessDenied.tsx +19 -0
  4. package/dist/components/Errors/403/index.ts +1 -0
  5. package/dist/components/Errors/i18n/en.json +4 -0
  6. package/dist/components/Errors/i18n/index.ts +11 -0
  7. package/dist/components/Errors/i18n/ru.json +4 -0
  8. package/dist/components/NodesViewer/NodesViewer.js +1 -1
  9. package/dist/components/QueryResultTable/QueryResultTable.tsx +16 -21
  10. package/dist/{containers/Storage/StorageFilter/StorageFilter.tsx → components/Search/Search.tsx} +22 -22
  11. package/dist/components/Search/index.ts +1 -0
  12. package/dist/containers/App/App.scss +5 -1
  13. package/dist/containers/Nodes/Nodes.js +6 -1
  14. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.scss +7 -5
  15. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -11
  16. package/dist/containers/Storage/Pdisk/Pdisk.scss +15 -8
  17. package/dist/containers/Storage/Pdisk/Pdisk.tsx +22 -14
  18. package/dist/containers/Storage/Storage.js +39 -50
  19. package/dist/containers/Storage/StorageGroups/StorageGroups.scss +1 -4
  20. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +27 -2
  21. package/dist/containers/Storage/StorageGroups/i18n/en.json +2 -1
  22. package/dist/containers/Storage/StorageGroups/i18n/ru.json +2 -1
  23. package/dist/containers/Storage/StorageNodes/StorageNodes.scss +14 -12
  24. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +7 -5
  25. package/dist/containers/Storage/Vdisk/Vdisk.js +36 -23
  26. package/dist/containers/Storage/Vdisk/Vdisk.scss +6 -0
  27. package/dist/containers/TabletsFilters/TabletsFilters.js +5 -0
  28. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.scss +6 -0
  29. package/dist/containers/Tenant/Diagnostics/Consumers/Consumers.tsx +82 -0
  30. package/dist/containers/Tenant/Diagnostics/Consumers/i18n/en.json +6 -0
  31. package/dist/containers/Tenant/Diagnostics/Consumers/i18n/index.ts +11 -0
  32. package/dist/containers/Tenant/Diagnostics/Consumers/i18n/ru.json +6 -0
  33. package/dist/containers/Tenant/Diagnostics/Consumers/index.ts +1 -0
  34. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +7 -0
  35. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +29 -11
  36. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +15 -8
  37. package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/Details.tsx +55 -0
  38. package/dist/containers/Tenant/Diagnostics/Healthcheck/Details/index.ts +1 -0
  39. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.scss +5 -5
  40. package/dist/containers/Tenant/Diagnostics/Healthcheck/Healthcheck.tsx +16 -6
  41. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/{IssueViewer.scss → IssueTree.scss} +3 -54
  42. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTree.tsx +87 -0
  43. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.scss +50 -0
  44. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/IssueTreeItem.tsx +25 -0
  45. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssueTreeItem/index.ts +1 -0
  46. package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/Preview.tsx +13 -16
  47. package/dist/containers/Tenant/Diagnostics/Healthcheck/{IssuePreview/IssuePreview.tsx → Preview/PreviewItem/PreviewItem.tsx} +6 -8
  48. package/dist/containers/Tenant/Diagnostics/Healthcheck/Preview/PreviewItem/index.ts +1 -0
  49. package/dist/containers/Tenant/Diagnostics/Overview/Overview.tsx +34 -19
  50. package/dist/containers/Tenant/Preview/Preview.scss +6 -0
  51. package/dist/containers/Tenant/QueryEditor/QueryEditor.js +1 -9
  52. package/dist/containers/Tenant/QueryEditor/QueryResult/QueryResult.scss +2 -2
  53. package/dist/containers/Tenant/QueryEditor/SaveQuery/SaveQuery.js +1 -1
  54. package/dist/containers/Tenant/Schema/SchemaTree/SchemaTree.tsx +27 -20
  55. package/dist/containers/Tenant/Tenant.tsx +14 -16
  56. package/dist/containers/Tenants/Tenants.js +1 -1
  57. package/dist/store/reducers/describe.ts +71 -0
  58. package/dist/store/reducers/healthcheckInfo.ts +123 -0
  59. package/dist/store/reducers/olapStats.js +13 -0
  60. package/dist/store/reducers/schema.js +43 -1
  61. package/dist/store/reducers/storage.js +27 -17
  62. package/dist/store/reducers/tenant.js +3 -1
  63. package/dist/store/utils.ts +21 -13
  64. package/dist/styles/mixins.scss +1 -1
  65. package/dist/types/api/consumers.ts +3 -0
  66. package/dist/types/api/healthcheck.ts +1 -1
  67. package/dist/types/api/storage.ts +35 -10
  68. package/dist/types/store/healthcheck.ts +5 -1
  69. package/dist/types/store/storage.ts +1 -0
  70. package/dist/utils/hooks/useAutofetcher.ts +9 -3
  71. package/package.json +1 -1
  72. package/dist/containers/Storage/StorageFilter/index.ts +0 -1
  73. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuePreview/index.ts +0 -1
  74. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/IssuesList.tsx +0 -62
  75. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesList/index.ts +0 -1
  76. package/dist/containers/Tenant/Diagnostics/Healthcheck/IssuesViewer/IssuesViewer.js +0 -151
  77. package/dist/store/reducers/describe.js +0 -45
  78. package/dist/store/reducers/healthcheckInfo.js +0 -45
@@ -4,10 +4,15 @@ import cn from 'bem-cn-lite';
4
4
 
5
5
  import {Loader} from '@gravity-ui/uikit';
6
6
 
7
- import {getHealthcheckInfo} from '../../../../store/reducers/healthcheckInfo';
7
+ import {SelfCheckResult} from '../../../../types/api/healthcheck';
8
+ import {
9
+ getHealthcheckInfo,
10
+ selectIssuesTreeById,
11
+ selectIssuesTreesRoots,
12
+ } from '../../../../store/reducers/healthcheckInfo';
8
13
  import {useAutofetcher} from '../../../../utils/hooks';
9
14
 
10
- import {IssuesList} from './IssuesList';
15
+ import {Details} from './Details';
11
16
  import {Preview} from './Preview';
12
17
 
13
18
  import i18n from './i18n';
@@ -29,6 +34,11 @@ export const Healthcheck = (props: HealthcheckProps) => {
29
34
  const dispatch = useDispatch();
30
35
 
31
36
  const {data, loading, wasLoaded, error} = useSelector((state: any) => state.healthcheckInfo);
37
+ const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
38
+
39
+ const issuesTreesRoots = useSelector(selectIssuesTreesRoots);
40
+ const expandedIssueTree = useSelector((state) => selectIssuesTreeById(state, expandedIssueId));
41
+
32
42
  const {autorefresh} = useSelector((state: any) => state.schema);
33
43
 
34
44
  const fetchHealthcheck = useCallback(() => {
@@ -61,15 +71,15 @@ export const Healthcheck = (props: HealthcheckProps) => {
61
71
  if (data && data['self_check_result']) {
62
72
  return preview ? (
63
73
  <Preview
64
- data={data}
74
+ issuesTrees={issuesTreesRoots}
75
+ selfCheckResult={selfCheckResult}
65
76
  loading={loading}
66
77
  onShowMore={showMoreHandler}
67
78
  onUpdate={fetchHealthcheck}
68
79
  />
69
80
  ) : (
70
- <IssuesList
71
- data={data}
72
- expandedIssueId={expandedIssueId}
81
+ <Details
82
+ issueTree={expandedIssueTree}
73
83
  loading={loading}
74
84
  onUpdate={fetchHealthcheck}
75
85
  />
@@ -1,56 +1,5 @@
1
1
  @import '../../../../../styles/mixins.scss';
2
2
 
3
- .issue {
4
- display: flex;
5
- justify-content: space-between;
6
- align-items: center;
7
-
8
- height: 40px;
9
-
10
- cursor: pointer;
11
-
12
- &__field {
13
- display: flex;
14
- overflow: hidden;
15
-
16
- &_status {
17
- display: flex;
18
-
19
- white-space: nowrap;
20
- }
21
- &_additional {
22
- width: max-content;
23
-
24
- cursor: pointer;
25
-
26
- color: var(--yc-color-text-link);
27
-
28
- &:hover {
29
- color: var(--yc-color-text-link-hover);
30
- }
31
- }
32
- &_message {
33
- overflow: hidden;
34
- flex-shrink: 0;
35
-
36
- width: 300px;
37
-
38
- white-space: normal;
39
- }
40
- }
41
-
42
- &__field-tooltip {
43
- &#{&} {
44
- min-width: 500px;
45
- max-width: 500px;
46
- }
47
- }
48
-
49
- &__field-label {
50
- color: var(--yc-color-text-secondary);
51
- }
52
- }
53
-
54
3
  .indicator {
55
4
  width: 12px;
56
5
  height: 12px;
@@ -86,12 +35,12 @@
86
35
  }
87
36
  }
88
37
 
89
- .issue-viewer {
38
+ .issue-tree {
90
39
  display: flex;
91
40
 
92
41
  width: 820px;
93
42
 
94
- &__tree {
43
+ &__block {
95
44
  width: 100%;
96
45
  }
97
46
 
@@ -163,7 +112,7 @@
163
112
  padding-left: 0 !important;
164
113
  }
165
114
 
166
- .issue-viewer__info-panel {
115
+ .issue-tree__info-panel {
167
116
  margin-left: $calculated-margin;
168
117
  }
169
118
  }
@@ -0,0 +1,87 @@
1
+ import {useCallback, useState} from 'react';
2
+ import cn from 'bem-cn-lite';
3
+ import _omit from 'lodash/omit';
4
+
5
+ // @ts-ignore
6
+ import JSONTree from 'react-json-inspector';
7
+
8
+ import {TreeView} from 'ydb-ui-components';
9
+
10
+ import {IIssuesTree} from '../../../../../types/store/healthcheck';
11
+
12
+ import {IssueTreeItem} from './IssueTreeItem';
13
+
14
+ import './IssueTree.scss';
15
+
16
+ const b = cn('issue-tree');
17
+
18
+ interface IssuesViewerProps {
19
+ issueTree: IIssuesTree;
20
+ }
21
+
22
+ const IssueTree = ({issueTree}: IssuesViewerProps) => {
23
+ const [collapsedIssues, setCollapsedIssues] = useState<Record<string, boolean>>({});
24
+
25
+ const renderTree = useCallback(
26
+ (data: IIssuesTree[]) => {
27
+ return data.map((item) => {
28
+ const {id} = item;
29
+ const {status, message, type, reasonsItems, level, ...rest} = item;
30
+
31
+ const isCollapsed =
32
+ typeof collapsedIssues[id] === 'undefined' || collapsedIssues[id];
33
+
34
+ const toggleCollapsed = () => {
35
+ setCollapsedIssues((collapsedIssues) => ({
36
+ ...collapsedIssues,
37
+ [id]: !isCollapsed,
38
+ }));
39
+ };
40
+
41
+ return (
42
+ <TreeView
43
+ key={id}
44
+ name={<IssueTreeItem status={status} message={message} type={type} />}
45
+ collapsed={isCollapsed}
46
+ hasArrow={true}
47
+ onClick={toggleCollapsed}
48
+ onArrowClick={toggleCollapsed}
49
+ level={level - 1}
50
+ >
51
+ {renderInfoPanel(_omit(rest, ['reason']))}
52
+ {renderTree(reasonsItems || [])}
53
+ </TreeView>
54
+ );
55
+ });
56
+ },
57
+ [issueTree, collapsedIssues],
58
+ );
59
+
60
+ const renderInfoPanel = useCallback(
61
+ (info) => {
62
+ if (!info) {
63
+ return null;
64
+ }
65
+
66
+ return (
67
+ <div className={b('info-panel')}>
68
+ <JSONTree
69
+ data={info}
70
+ search={false}
71
+ isExpanded={() => true}
72
+ className={b('inspector')}
73
+ />
74
+ </div>
75
+ );
76
+ },
77
+ [issueTree],
78
+ );
79
+
80
+ return (
81
+ <div className={b()}>
82
+ <div className={b('block')}>{renderTree([issueTree])}</div>
83
+ </div>
84
+ );
85
+ };
86
+
87
+ export default IssueTree;
@@ -0,0 +1,50 @@
1
+ .issue-tree-item {
2
+ display: flex;
3
+ justify-content: space-between;
4
+ align-items: center;
5
+
6
+ height: 40px;
7
+
8
+ cursor: pointer;
9
+
10
+ &__field {
11
+ display: flex;
12
+ overflow: hidden;
13
+
14
+ &_status {
15
+ display: flex;
16
+
17
+ white-space: nowrap;
18
+ }
19
+ &_additional {
20
+ width: max-content;
21
+
22
+ cursor: pointer;
23
+
24
+ color: var(--yc-color-text-link);
25
+
26
+ &:hover {
27
+ color: var(--yc-color-text-link-hover);
28
+ }
29
+ }
30
+ &_message {
31
+ overflow: hidden;
32
+ flex-shrink: 0;
33
+
34
+ width: 300px;
35
+
36
+ white-space: normal;
37
+ }
38
+ }
39
+
40
+ &__field-tooltip {
41
+ &#{&} {
42
+ min-width: 500px;
43
+ max-width: 500px;
44
+ }
45
+ }
46
+
47
+ &__field-label {
48
+ color: var(--yc-color-text-secondary);
49
+ }
50
+ }
@@ -0,0 +1,25 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ import EntityStatus from '../../../../../../components/EntityStatus/EntityStatus';
4
+
5
+ import './IssueTreeItem.scss';
6
+
7
+ const b = cn('issue-tree-item');
8
+
9
+ interface IssueRowProps {
10
+ status: string;
11
+ message: string;
12
+ type: string;
13
+ onClick?: VoidFunction;
14
+ }
15
+
16
+ export const IssueTreeItem = ({status, message, type, onClick}: IssueRowProps) => {
17
+ return (
18
+ <div className={b()} onClick={onClick}>
19
+ <div className={b('field', {status: true})}>
20
+ <EntityStatus mode="icons" status={status} name={type} />
21
+ </div>
22
+ <div className={b('field', {message: true})}>{message}</div>
23
+ </div>
24
+ );
25
+ };
@@ -0,0 +1 @@
1
+ export * from './IssueTreeItem';
@@ -1,4 +1,3 @@
1
- import {useMemo} from 'react';
2
1
  import cn from 'bem-cn-lite';
3
2
 
4
3
  import {Button, Icon} from '@gravity-ui/uikit';
@@ -6,34 +5,28 @@ import {Button, Icon} from '@gravity-ui/uikit';
6
5
  import updateArrow from '../../../../../assets/icons/update-arrow.svg';
7
6
 
8
7
  import {SelfCheckResult} from '../../../../../types/api/healthcheck';
9
- import type {IHealthCheck} from '../../../../../types/store/healthcheck';
8
+ import type {IIssuesTree} from '../../../../../types/store/healthcheck';
10
9
 
11
- import {IssuePreview} from '../IssuePreview';
10
+ import {PreviewItem} from './PreviewItem';
12
11
 
13
12
  import i18n from '../i18n';
14
13
 
15
14
  const b = cn('healthcheck');
16
15
 
17
16
  interface PreviewProps {
18
- data?: IHealthCheck;
17
+ selfCheckResult: SelfCheckResult;
18
+ issuesTrees?: IIssuesTree[];
19
19
  loading?: boolean;
20
- onUpdate: VoidFunction;
21
20
  onShowMore?: (id: string) => void;
21
+ onUpdate: VoidFunction;
22
22
  }
23
23
 
24
24
  export const Preview = (props: PreviewProps) => {
25
- const {data, loading, onShowMore, onUpdate} = props;
25
+ const {selfCheckResult, issuesTrees, loading, onShowMore, onUpdate} = props;
26
26
 
27
- const selfCheckResult = data?.self_check_result || SelfCheckResult.UNSPECIFIED;
28
27
  const isStatusOK = selfCheckResult === SelfCheckResult.GOOD;
29
28
 
30
- const issuesLog = data?.issue_log;
31
- const firstLevelIssues = useMemo(
32
- () => issuesLog?.filter(({level}) => level === 1),
33
- [issuesLog],
34
- );
35
-
36
- if (!data) {
29
+ if (!issuesTrees) {
37
30
  return null;
38
31
  }
39
32
 
@@ -58,8 +51,12 @@ export const Preview = (props: PreviewProps) => {
58
51
  <div className={b('preview-content')}>
59
52
  {isStatusOK
60
53
  ? i18n('status_message.ok')
61
- : firstLevelIssues?.map((issue) => (
62
- <IssuePreview key={issue.id} data={issue} onShowMore={onShowMore} />
54
+ : issuesTrees?.map((issueTree) => (
55
+ <PreviewItem
56
+ key={issueTree.id}
57
+ data={issueTree}
58
+ onShowMore={onShowMore}
59
+ />
63
60
  ))}
64
61
  </div>
65
62
  );
@@ -2,19 +2,19 @@ import cn from 'bem-cn-lite';
2
2
 
3
3
  import {Link, Text} from '@gravity-ui/uikit';
4
4
 
5
- import EntityStatus from '../../../../../components/EntityStatus/EntityStatus';
6
- import {IssueLog} from '../../../../../types/api/healthcheck';
5
+ import EntityStatus from '../../../../../../components/EntityStatus/EntityStatus';
6
+ import {IssueLog} from '../../../../../../types/api/healthcheck';
7
7
 
8
- import i18n from '../i18n';
8
+ import i18n from '../../i18n';
9
9
 
10
10
  const b = cn('healthcheck');
11
11
 
12
- interface IssuePreviewProps {
12
+ interface PreviewItemProps {
13
13
  data?: IssueLog;
14
14
  onShowMore?: (id: string) => void;
15
15
  }
16
16
 
17
- export const IssuePreview = (props: IssuePreviewProps) => {
17
+ export const PreviewItem = (props: PreviewItemProps) => {
18
18
  const {data, onShowMore} = props;
19
19
 
20
20
  if (!data) {
@@ -27,9 +27,7 @@ export const IssuePreview = (props: IssuePreviewProps) => {
27
27
  <Text as="div" color="secondary" variant="body-2">
28
28
  {data.message}
29
29
  </Text>
30
- <Link onClick={() => onShowMore && onShowMore(data.id)}>
31
- {i18n('label.show-details')}
32
- </Link>
30
+ <Link onClick={() => onShowMore?.(data.id)}>{i18n('label.show-details')}</Link>
33
31
  </div>
34
32
  );
35
33
  };
@@ -0,0 +1 @@
1
+ export * from './PreviewItem';
@@ -15,9 +15,12 @@ import {
15
15
  import {EPathType} from '../../../../types/api/schema';
16
16
  import {isColumnEntityType, isTableType} from '../../utils/schema';
17
17
  //@ts-ignore
18
- import {getSchema} from '../../../../store/reducers/schema';
18
+ import {getSchema, resetLoadingState} from '../../../../store/reducers/schema';
19
19
  //@ts-ignore
20
- import {getOlapStats} from '../../../../store/reducers/olapStats';
20
+ import {
21
+ getOlapStats,
22
+ resetLoadingState as resetOlapLoadingState,
23
+ } from '../../../../store/reducers/olapStats';
21
24
  import {useAutofetcher} from '../../../../utils/hooks';
22
25
 
23
26
  import './Overview.scss';
@@ -64,24 +67,36 @@ function Overview(props: OverviewProps) {
64
67
 
65
68
  const {
66
69
  currentSchema: currentItem = {},
67
- loading,
70
+ loading: schemaLoading,
68
71
  wasLoaded,
69
72
  autorefresh,
70
73
  currentSchemaPath,
71
74
  } = useSelector((state: any) => state.schema);
72
75
 
73
- const {
74
- data: { result: olapStats } = { result: undefined },
75
- } = useSelector((state: any) => state.olapStats);
76
+ const {data: {result: olapStats} = {result: undefined}, loading: olapStatsLoading} =
77
+ useSelector((state: any) => state.olapStats);
78
+
79
+ const loading = schemaLoading || olapStatsLoading;
76
80
 
77
- useAutofetcher(() => {
78
- const schemaPath = currentSchemaPath || tenantName;
79
- dispatch(getSchema({path: schemaPath}));
81
+ useAutofetcher(
82
+ (isBackground) => {
83
+ if (!isBackground) {
84
+ dispatch(resetLoadingState());
85
+ }
80
86
 
81
- if (isTableType(type) && isColumnEntityType(type)) {
82
- dispatch(getOlapStats({path: schemaPath}));
83
- }
84
- }, [currentSchemaPath, dispatch, tenantName, type], autorefresh);
87
+ const schemaPath = currentSchemaPath || tenantName;
88
+ dispatch(getSchema({path: schemaPath}));
89
+
90
+ if (isTableType(type) && isColumnEntityType(type)) {
91
+ if (!isBackground) {
92
+ dispatch(resetOlapLoadingState());
93
+ }
94
+ dispatch(getOlapStats({path: schemaPath}));
95
+ }
96
+ },
97
+ [currentSchemaPath, dispatch, tenantName, type],
98
+ autorefresh,
99
+ );
85
100
 
86
101
  const tableSchema =
87
102
  currentItem?.PathDescription?.Table || currentItem?.PathDescription?.ColumnTableDescription;
@@ -116,17 +131,17 @@ function Overview(props: OverviewProps) {
116
131
  [EPathType.EPathTypePersQueueGroup]: () => <PersQueueGroupInfo data={schemaData} />,
117
132
  };
118
133
 
119
- return (type && pathTypeToComponent[type]?.()) || (
120
- <SchemaInfoViewer fullPath={currentItem.Path} data={schemaData} />
134
+ return (
135
+ (type && pathTypeToComponent[type]?.()) || (
136
+ <SchemaInfoViewer fullPath={currentItem.Path} data={schemaData} />
137
+ )
121
138
  );
122
- }
139
+ };
123
140
 
124
141
  return loading && !wasLoaded ? (
125
142
  renderLoader()
126
143
  ) : (
127
- <div className={props.className}>
128
- {renderContent()}
129
- </div>
144
+ <div className={props.className}>{renderContent()}</div>
130
145
  );
131
146
  }
132
147
 
@@ -52,7 +52,13 @@
52
52
  &__result {
53
53
  overflow: auto;
54
54
 
55
+ // This fixes last row display for ordinary preview (not fullscreen)
55
56
  height: calc(100% - 40px);
56
57
  padding: 0 10px;
58
+
59
+ // Fix white space footer block for fullscreen preview
60
+ .kv-fullscreen & {
61
+ height: 100%;
62
+ }
57
63
  }
58
64
  }
@@ -54,8 +54,6 @@ export const RUN_ACTIONS = [
54
54
 
55
55
  const TABLE_SETTINGS = {
56
56
  sortable: false,
57
- dynamicItemSizeGetter: () => 40,
58
- dynamicRenderType: 'variable',
59
57
  };
60
58
 
61
59
  const EDITOR_OPTIONS = {
@@ -511,13 +509,7 @@ function QueryEditor(props) {
511
509
  };
512
510
 
513
511
  const renderControls = () => {
514
- const {
515
- executeQuery,
516
- explainQuery,
517
- savedQueries,
518
- selectRunAction,
519
- setSettingValue,
520
- } = props;
512
+ const {executeQuery, explainQuery, savedQueries, selectRunAction, setSettingValue} = props;
521
513
  const {runAction} = executeQuery;
522
514
  const runIsDisabled = !executeQuery.input || executeQuery.loading;
523
515
  const runText = _.find(RUN_ACTIONS, {value: runAction}).content;
@@ -15,8 +15,8 @@
15
15
  }
16
16
  &_fullscreen {
17
17
  width: 100%;
18
- margin-top: 0;
19
- padding: 10px;
18
+ margin-top: 10px;
19
+ padding: 0 10px 10px;
20
20
  }
21
21
  }
22
22
 
@@ -83,7 +83,7 @@ function SaveQuery({savedQueries, onSaveQuery, saveButtonDisabled}) {
83
83
  <TextInput
84
84
  id="queryName"
85
85
  placeholder="Enter query name"
86
- text={queryName}
86
+ value={queryName}
87
87
  onUpdate={onQueryNameChange}
88
88
  hasClear
89
89
  autoFocus
@@ -3,7 +3,7 @@ import {useDispatch} from 'react-redux';
3
3
 
4
4
  import {NavigationTree} from 'ydb-ui-components';
5
5
 
6
- import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema';
6
+ import {setCurrentSchemaPath, getSchema, preloadSchema} from '../../../../store/reducers/schema';
7
7
  import {getDescribe} from '../../../../store/reducers/describe';
8
8
  import {getSchemaAcl} from '../../../../store/reducers/schemaAcl';
9
9
  import type {EPathType} from '../../../../types/api/schema';
@@ -19,28 +19,35 @@ interface SchemaTreeProps {
19
19
  }
20
20
 
21
21
  export function SchemaTree(props: SchemaTreeProps) {
22
- const {
23
- rootPath,
24
- rootName,
25
- rootType,
26
- currentPath,
27
- } = props;
22
+ const {rootPath, rootName, rootType, currentPath} = props;
28
23
 
29
24
  const dispatch = useDispatch();
30
25
 
31
- const fetchPath = (path: string) => window.api.getSchema(
32
- {path},
33
- {concurrentId: `NavigationTree.getSchema|${path}`},
34
- )
35
- .then(({PathDescription: {Children = []} = {}}) => {
36
- return Children.map(({Name = '', PathType, PathSubType}) => ({
37
- name: Name,
38
- type: mapPathTypeToNavigationTreeType(PathType, PathSubType),
39
- // FIXME: should only be explicitly set to true for tables with indexes
40
- // at the moment of writing there is no property to determine this, fix later
41
- expandable: true,
42
- }));
43
- });
26
+ const fetchPath = (path: string) =>
27
+ window.api
28
+ .getSchema({path}, {concurrentId: `NavigationTree.getSchema|${path}`})
29
+ .then((data) => {
30
+ const {PathDescription: {Children = []} = {}} = data;
31
+
32
+ dispatch(preloadSchema(path, data));
33
+
34
+ return Children.map((childData) => {
35
+ const {Name = '', PathType, PathSubType} = childData;
36
+
37
+ // not full data, but it contains PathType, which ensures seamless switch between nodes
38
+ dispatch(
39
+ preloadSchema(`${path}/${Name}`, {PathDescription: {Self: childData}}),
40
+ );
41
+
42
+ return {
43
+ name: Name,
44
+ type: mapPathTypeToNavigationTreeType(PathType, PathSubType),
45
+ // FIXME: should only be explicitly set to true for tables with indexes
46
+ // at the moment of writing there is no property to determine this, fix later
47
+ expandable: true,
48
+ };
49
+ });
50
+ });
44
51
 
45
52
  const handleActivePathUpdate = (activePath: string) => {
46
53
  dispatch(setCurrentSchemaPath(activePath));