ydb-embedded-ui 4.9.0 → 4.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/components/BasicNodeViewer/BasicNodeViewer.tsx +7 -4
  3. package/dist/components/EntityStatus/EntityStatus.js +3 -1
  4. package/dist/components/FormattedBytes/FormattedBytes.tsx +10 -0
  5. package/dist/components/FormattedBytes/utils.tsx +13 -0
  6. package/dist/components/FullNodeViewer/FullNodeViewer.tsx +73 -0
  7. package/dist/components/InfoViewer/formatters/schema.ts +3 -1
  8. package/dist/components/InfoViewer/formatters/table.ts +6 -5
  9. package/dist/components/ProblemFilter/ProblemFilter.tsx +2 -2
  10. package/dist/components/SpeedMultiMeter/SpeedMultiMeter.tsx +4 -4
  11. package/dist/components/TableWithControlsLayout/TableWithControlsLayout.scss +32 -0
  12. package/dist/components/TableWithControlsLayout/TableWithControlsLayout.tsx +43 -0
  13. package/dist/components/TruncatedQuery/{TruncatedQuery.js → TruncatedQuery.tsx} +10 -8
  14. package/dist/containers/AsideNavigation/AsideNavigation.tsx +8 -8
  15. package/dist/containers/Cluster/Cluster.scss +4 -5
  16. package/dist/containers/Cluster/Cluster.tsx +13 -28
  17. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.scss +4 -0
  18. package/dist/containers/Cluster/ClusterInfo/ClusterInfo.tsx +7 -0
  19. package/dist/containers/Cluster/ClusterInfoSkeleton/ClusterInfoSkeleton.tsx +1 -1
  20. package/dist/containers/Cluster/utils.tsx +0 -11
  21. package/dist/containers/Header/Header.scss +1 -5
  22. package/dist/containers/Node/Node.tsx +3 -3
  23. package/dist/containers/Nodes/Nodes.scss +1 -24
  24. package/dist/containers/Nodes/Nodes.tsx +30 -40
  25. package/dist/containers/Storage/PDisk/PDisk.tsx +2 -7
  26. package/dist/containers/Storage/Storage.scss +1 -14
  27. package/dist/containers/Storage/Storage.tsx +237 -0
  28. package/dist/containers/Storage/StorageGroups/StorageGroups.tsx +45 -40
  29. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +12 -16
  30. package/dist/containers/Storage/StorageTypeFilter/StorageTypeFilter.tsx +3 -1
  31. package/dist/containers/Storage/{StorageVisibleEntityFilter/StorageVisibleEntityFilter.tsx → StorageVisibleEntitiesFilter/StorageVisibleEntitiesFilter.tsx} +4 -2
  32. package/dist/containers/Storage/UsageFilter/UsageFilter.scss +1 -0
  33. package/dist/containers/Storage/UsageFilter/UsageFilter.tsx +17 -17
  34. package/dist/containers/Tenant/Diagnostics/Diagnostics.scss +6 -2
  35. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +3 -3
  36. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.js +7 -4
  37. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.scss +0 -15
  38. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +10 -3
  39. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.scss +3 -12
  40. package/dist/containers/Tenant/ObjectSummary/ObjectSummary.tsx +2 -7
  41. package/dist/containers/Tenant/{Preview → Query/Preview}/Preview.scss +1 -1
  42. package/dist/containers/Tenant/Query/Preview/Preview.tsx +121 -0
  43. package/dist/containers/Tenant/Query/QueriesHistory/QueriesHistory.tsx +1 -1
  44. package/dist/containers/Tenant/Query/QueryEditor/QueryEditor.js +6 -8
  45. package/dist/containers/Tenant/Query/SavedQueries/SavedQueries.tsx +1 -1
  46. package/dist/containers/Tenant/Query/i18n/en.json +9 -2
  47. package/dist/containers/Tenant/Query/i18n/ru.json +9 -2
  48. package/dist/containers/Tenants/Tenants.scss +1 -13
  49. package/dist/containers/Tenants/Tenants.tsx +262 -0
  50. package/dist/services/api.ts +8 -3
  51. package/dist/store/reducers/nodes/nodes.ts +4 -112
  52. package/dist/store/reducers/nodes/selectors.ts +74 -0
  53. package/dist/store/reducers/nodes/utils.ts +46 -0
  54. package/dist/store/reducers/partitions/types.ts +3 -3
  55. package/dist/store/reducers/settings/settings.ts +4 -2
  56. package/dist/store/reducers/settings/types.ts +3 -1
  57. package/dist/store/reducers/storage/selectors.ts +279 -0
  58. package/dist/store/reducers/storage/storage.ts +191 -0
  59. package/dist/store/reducers/storage/types.ts +80 -0
  60. package/dist/store/reducers/tenants/selectors.ts +46 -0
  61. package/dist/store/reducers/tenants/tenants.ts +21 -14
  62. package/dist/store/reducers/tenants/types.ts +20 -5
  63. package/dist/store/reducers/tenants/utils.ts +68 -0
  64. package/dist/types/additionalProps.ts +8 -0
  65. package/dist/types/api/compute.ts +27 -2
  66. package/dist/types/api/nodes.ts +12 -1
  67. package/dist/types/api/schema/cdcStream.ts +32 -0
  68. package/dist/types/api/schema/columnEntity.ts +138 -0
  69. package/dist/types/api/schema/externalDataSource.ts +24 -0
  70. package/dist/types/api/schema/externalTable.ts +14 -0
  71. package/dist/types/api/schema/index.ts +10 -0
  72. package/dist/types/api/schema/persQueueGroup.ts +191 -0
  73. package/dist/types/api/schema/schema.ts +299 -0
  74. package/dist/types/api/schema/shared.ts +42 -0
  75. package/dist/types/api/schema/table.ts +616 -0
  76. package/dist/types/api/schema/tableIndex.ts +33 -0
  77. package/dist/types/api/storage.ts +1 -1
  78. package/dist/types/store/topic.ts +3 -3
  79. package/dist/utils/bytesParsers/__test__/formatBytes.test.ts +38 -0
  80. package/dist/utils/bytesParsers/convertBytesObjectToSpeed.ts +2 -2
  81. package/dist/utils/bytesParsers/formatBytes.ts +132 -0
  82. package/dist/utils/bytesParsers/i18n/en.json +1 -0
  83. package/dist/utils/bytesParsers/i18n/ru.json +1 -0
  84. package/dist/utils/bytesParsers/index.ts +1 -1
  85. package/dist/utils/index.js +5 -10
  86. package/dist/utils/numeral.ts +8 -0
  87. package/package.json +1 -1
  88. package/dist/assets/icons/versions.svg +0 -3
  89. package/dist/components/FullNodeViewer/FullNodeViewer.js +0 -89
  90. package/dist/containers/Node/NodeOverview/NodeOverview.scss +0 -0
  91. package/dist/containers/Node/NodeOverview/NodeOverview.tsx +0 -21
  92. package/dist/containers/Storage/Storage.js +0 -350
  93. package/dist/containers/Tenant/Preview/Preview.js +0 -168
  94. package/dist/containers/Tenants/Tenants.js +0 -363
  95. package/dist/store/reducers/storage/storage.js +0 -404
  96. package/dist/types/api/schema.ts +0 -1326
  97. package/dist/utils/bytesParsers/formatBytesCustom.ts +0 -57
@@ -1,9 +1,8 @@
1
- import _ from 'lodash';
2
1
  import cn from 'bem-cn-lite';
3
2
 
4
3
  import DataTable, {Column, Settings, SortOrder} from '@gravity-ui/react-data-table';
5
4
 
6
- import type {VisibleEntities} from '../../../store/reducers/storage/types';
5
+ import type {PreparedStorageNode, VisibleEntities} from '../../../store/reducers/storage/types';
7
6
 
8
7
  import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants';
9
8
  import {
@@ -25,7 +24,7 @@ enum TableColumnsIds {
25
24
  FQDN = 'FQDN',
26
25
  DataCenter = 'DataCenter',
27
26
  Rack = 'Rack',
28
- uptime = 'uptime',
27
+ Uptime = 'Uptime',
29
28
  PDisks = 'PDisks',
30
29
  Missing = 'Missing',
31
30
  }
@@ -34,8 +33,7 @@ type TableColumnsIdsKeys = keyof typeof TableColumnsIds;
34
33
  type TableColumnsIdsValues = typeof TableColumnsIds[TableColumnsIdsKeys];
35
34
 
36
35
  interface StorageNodesProps {
37
- data: any;
38
- nodes: any;
36
+ data: PreparedStorageNode[];
39
37
  tableSettings: Settings;
40
38
  visibleEntities: VisibleEntities;
41
39
  nodesUptimeFilter: keyof typeof NodesUptimeFilterValues;
@@ -48,7 +46,7 @@ const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
48
46
  FQDN: 'FQDN',
49
47
  DataCenter: 'DC',
50
48
  Rack: 'Rack',
51
- uptime: 'Uptime',
49
+ Uptime: 'Uptime',
52
50
  PDisks: 'PDisks',
53
51
  Missing: 'Missing',
54
52
  };
@@ -75,7 +73,7 @@ function setSortOrder(visibleEntities: VisibleEntities): SortOrder | undefined {
75
73
  }
76
74
  }
77
75
 
78
- function StorageNodes({
76
+ export function StorageNodes({
79
77
  data,
80
78
  tableSettings,
81
79
  visibleEntities,
@@ -85,7 +83,7 @@ function StorageNodes({
85
83
  }: StorageNodesProps) {
86
84
  const getNodeRef = additionalNodesInfo?.getNodeRef;
87
85
 
88
- const allColumns: Column<any>[] = [
86
+ const allColumns: Column<PreparedStorageNode>[] = [
89
87
  {
90
88
  name: TableColumnsIds.NodeId,
91
89
  header: tableColumnsNames[TableColumnsIds.NodeId],
@@ -114,8 +112,8 @@ function StorageNodes({
114
112
  align: DataTable.LEFT,
115
113
  },
116
114
  {
117
- name: TableColumnsIds.uptime,
118
- header: tableColumnsNames[TableColumnsIds.uptime],
115
+ name: TableColumnsIds.Uptime,
116
+ header: tableColumnsNames[TableColumnsIds.Uptime],
119
117
  width: 130,
120
118
  sortAccessor: ({StartTime}) => (StartTime ? -StartTime : 0),
121
119
  align: DataTable.RIGHT,
@@ -131,11 +129,11 @@ function StorageNodes({
131
129
  name: TableColumnsIds.PDisks,
132
130
  className: b('pdisks-column'),
133
131
  header: tableColumnsNames[TableColumnsIds.PDisks],
134
- render: ({value, row}) => (
132
+ render: ({row}) => (
135
133
  <div className={b('pdisks-wrapper')}>
136
- {_.map(value as any, (el) => (
137
- <div className={b('pdisks-item')} key={el.PDiskId}>
138
- <PDisk data={el} nodeId={row.NodeId} />
134
+ {row.PDisks?.map((pDisk) => (
135
+ <div className={b('pdisks-item')} key={pDisk.PDiskId}>
136
+ <PDisk data={pDisk} nodeId={row.NodeId} />
139
137
  </div>
140
138
  ))}
141
139
  </div>
@@ -195,5 +193,3 @@ function StorageNodes({
195
193
  />
196
194
  ) : null;
197
195
  }
198
-
199
- export default StorageNodes;
@@ -13,9 +13,11 @@ interface StorageTypeFilterProps {
13
13
  onChange: (value: string) => void;
14
14
  }
15
15
 
16
+ const storageTypeFilterQa = 'storage-type-filter';
17
+
16
18
  export const StorageTypeFilter = ({value, onChange}: StorageTypeFilterProps) => {
17
19
  return (
18
- <RadioButton value={value} onUpdate={onChange}>
20
+ <RadioButton value={value} onUpdate={onChange} qa={storageTypeFilterQa}>
19
21
  <RadioButton.Option value={STORAGE_TYPES.groups}>
20
22
  {StorageTypesTitles[STORAGE_TYPES.groups]}
21
23
  </RadioButton.Option>
@@ -14,9 +14,11 @@ interface StorageProblemFilterProps {
14
14
  onChange: (value: string) => void;
15
15
  }
16
16
 
17
- export const StorageVisibleEntityFilter = ({value, onChange}: StorageProblemFilterProps) => {
17
+ const storageVisibleEntitiesFilterQa = 'storage-visible-entities-filter';
18
+
19
+ export const StorageVisibleEntitiesFilter = ({value, onChange}: StorageProblemFilterProps) => {
18
20
  return (
19
- <RadioButton value={value} onUpdate={onChange}>
21
+ <RadioButton value={value} onUpdate={onChange} qa={storageVisibleEntitiesFilterQa}>
20
22
  <RadioButton.Option value={VISIBLE_ENTITIES.missing}>
21
23
  {VisibleEntitiesTitles[VISIBLE_ENTITIES.missing]}
22
24
  </RadioButton.Option>
@@ -13,6 +13,7 @@
13
13
 
14
14
  &-meta {
15
15
  position: relative;
16
+ z-index: 0;
16
17
 
17
18
  padding: 0 5px;
18
19
 
@@ -3,7 +3,7 @@ import cn from 'bem-cn-lite';
3
3
 
4
4
  import {Select, SelectOption} from '@gravity-ui/uikit';
5
5
 
6
- import EntityStatus from "../../../components/EntityStatus/EntityStatus";
6
+ import EntityStatus from '../../../components/EntityStatus/EntityStatus';
7
7
 
8
8
  import {getUsageSeverityForEntityStatus} from '../utils';
9
9
 
@@ -27,14 +27,7 @@ interface UsageFilterProps {
27
27
  const b = cn('usage-filter');
28
28
 
29
29
  export const UsageFilter = (props: UsageFilterProps) => {
30
- const {
31
- className,
32
- value = [],
33
- groups = [],
34
- onChange,
35
- debounce = 200,
36
- disabled,
37
- } = props;
30
+ const {className, value = [], groups = [], onChange, debounce = 200, disabled} = props;
38
31
 
39
32
  const [filterValue, setFilterValue] = useState(value);
40
33
  const timer = useRef<number>();
@@ -50,11 +43,15 @@ export const UsageFilter = (props: UsageFilterProps) => {
50
43
  });
51
44
  }, [value]);
52
45
 
53
- const options = useMemo(() => groups.map(({threshold, count}) => ({
54
- value: String(threshold),
55
- text: `${threshold}%`,
56
- data: {count}
57
- })), [groups]);
46
+ const options = useMemo(
47
+ () =>
48
+ groups.map(({threshold, count}) => ({
49
+ value: String(threshold),
50
+ text: `${threshold}%`,
51
+ data: {count},
52
+ })),
53
+ [groups],
54
+ );
58
55
 
59
56
  const handleUpdate = (newValue: string[]) => {
60
57
  setFilterValue(newValue);
@@ -67,17 +64,20 @@ export const UsageFilter = (props: UsageFilterProps) => {
67
64
 
68
65
  const maxWidth = Math.max(...groups.map(({count}) => count));
69
66
 
70
- const renderOption = ({value, data, text}: SelectOption) => (
67
+ const renderOption = ({value: optionValue, data, text}: SelectOption) => (
71
68
  <div className={b('option')}>
72
69
  <EntityStatus
73
70
  className={b('option-title')}
74
- status={getUsageSeverityForEntityStatus(Number(value))}
71
+ status={getUsageSeverityForEntityStatus(Number(optionValue))}
75
72
  name={text}
76
73
  size="xs"
77
74
  />
78
75
  <div className={b('option-meta')}>
79
76
  {i18n('groups_count', {count: data.count})}
80
- <div className={b('option-bar')} style={{width: `${data.count / maxWidth * 100}%`}} />
77
+ <div
78
+ className={b('option-bar')}
79
+ style={{width: `${(data.count / maxWidth) * 100}%`}}
80
+ />
81
81
  </div>
82
82
  </div>
83
83
  );
@@ -39,11 +39,15 @@
39
39
  width: 100%;
40
40
  padding: 0 20px;
41
41
 
42
- & .global-storage,
43
- & .ydb-nodes {
42
+ .ydb-table-with-controls-layout {
44
43
  &__controls {
44
+ height: 46px;
45
45
  padding-top: 0;
46
46
  }
47
+
48
+ .data-table__sticky_moving {
49
+ top: 46px !important;
50
+ }
47
51
  }
48
52
  }
49
53
  }
@@ -13,14 +13,14 @@ import {useTypedSelector} from '../../../utils/hooks';
13
13
  import routes, {createHref} from '../../../routes';
14
14
  import type {TenantDiagnosticsTab} from '../../../store/reducers/tenant/types';
15
15
  import {enableAutorefresh, disableAutorefresh} from '../../../store/reducers/schema/schema';
16
- import { setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
16
+ import {setDiagnosticsTab} from '../../../store/reducers/tenant/tenant';
17
17
  import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../store/reducers/tenant/constants';
18
18
 
19
19
  import {Loader} from '../../../components/Loader';
20
20
 
21
21
  import {Heatmap} from '../../Heatmap';
22
22
  import {Nodes} from '../../Nodes';
23
- import Storage from '../../Storage/Storage';
23
+ import {Storage} from '../../Storage/Storage';
24
24
  import {Tablets} from '../../Tablets';
25
25
 
26
26
  import Describe from './Describe/Describe';
@@ -130,7 +130,7 @@ function Diagnostics(props: DiagnosticsProps) {
130
130
  return <Tablets path={currentSchemaPath} />;
131
131
  }
132
132
  case TENANT_DIAGNOSTICS_TABS_IDS.storage: {
133
- return <Storage tenant={tenantNameString} database={true} />;
133
+ return <Storage tenant={tenantNameString} />;
134
134
  }
135
135
  case TENANT_DIAGNOSTICS_TABS_IDS.network: {
136
136
  return <Network path={tenantNameString} />;
@@ -27,10 +27,13 @@ const renderName = (tenant) => {
27
27
  const {Name} = tenant;
28
28
  return (
29
29
  <div className={b('tenant-name-wrapper')}>
30
- <EntityStatus status={tenant.State} />
31
- <span className={b('tenant-name-trim')}>
32
- <span className={b('tenant-name')}>{Name}</span>
33
- </span>
30
+ <EntityStatus
31
+ status={tenant.State}
32
+ name={Name}
33
+ withLeftTrim
34
+ hasClipboardButton
35
+ clipboardButtonAlwaysVisible
36
+ />
34
37
  </div>
35
38
  );
36
39
  }
@@ -10,21 +10,6 @@
10
10
  display: flex;
11
11
  overflow: hidden;
12
12
  align-items: center;
13
-
14
- & .yc-link {
15
- display: flex;
16
- }
17
- }
18
- &__tenant-name-trim {
19
- overflow: hidden;
20
-
21
- white-space: nowrap;
22
- text-overflow: ellipsis;
23
- direction: rtl;
24
- }
25
-
26
- &__tenant-name {
27
- unicode-bidi: plaintext;
28
13
  }
29
14
 
30
15
  &__top {
@@ -9,7 +9,7 @@ import {Loader} from '@gravity-ui/uikit';
9
9
 
10
10
  import {DateRange, DateRangeValues} from '../../../../components/DateRange';
11
11
  import {Search} from '../../../../components/Search';
12
- import TruncatedQuery from '../../../../components/TruncatedQuery/TruncatedQuery';
12
+ import {TruncatedQuery} from '../../../../components/TruncatedQuery/TruncatedQuery';
13
13
 
14
14
  import {changeUserInput} from '../../../../store/reducers/executeQuery';
15
15
  import {
@@ -23,7 +23,11 @@ import type {EPathType} from '../../../../types/api/schema';
23
23
  import type {ITopQueriesFilters} from '../../../../types/store/executeTopQueries';
24
24
  import type {IQueryResult} from '../../../../types/store/query';
25
25
 
26
- import {TENANT_PAGE, TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
26
+ import {
27
+ TENANT_PAGE,
28
+ TENANT_PAGES_IDS,
29
+ TENANT_QUERY_TABS_ID,
30
+ } from '../../../../store/reducers/tenant/constants';
27
31
  import {formatDateTime, formatNumber} from '../../../../utils';
28
32
  import {HOUR_IN_SECONDS} from '../../../../utils/constants';
29
33
  import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
@@ -50,7 +54,10 @@ const COLUMNS: Column<KeyValueRow>[] = [
50
54
  sortable: false,
51
55
  render: ({row}) => (
52
56
  <div className={b('query')}>
53
- <TruncatedQuery value={row.QueryText} maxQueryHeight={MAX_QUERY_HEIGHT} />
57
+ <TruncatedQuery
58
+ value={row.QueryText?.toString()}
59
+ maxQueryHeight={MAX_QUERY_HEIGHT}
60
+ />
54
61
  </div>
55
62
  ),
56
63
  },
@@ -26,7 +26,7 @@
26
26
 
27
27
  &__action-button {
28
28
  position: absolute;
29
- top: 8px; // centered relative to the heading
29
+ top: 19px; // centered relative to the heading
30
30
  right: 5px; // centered relative to the collapsed panel
31
31
 
32
32
  background-color: var(--yc-color-base-background);
@@ -51,20 +51,11 @@
51
51
  flex: 1 1 auto;
52
52
 
53
53
  height: 100%;
54
- padding: 0 12px 12px;
54
+ padding: 0 12px 12px 16px;
55
55
  }
56
56
 
57
57
  &__tree-header {
58
- display: flex;
59
- flex: 0 0 auto;
60
- justify-content: space-between;
61
- align-items: center;
62
-
63
- padding: 12px 12px 8px;
64
- }
65
-
66
- &__tree-title {
67
- font-weight: 600;
58
+ padding: 23px 12px 17px 20px;
68
59
  }
69
60
 
70
61
  &__sticky-top {
@@ -48,10 +48,7 @@ import {
48
48
  } from '../utils/paneVisibilityToggleHelpers';
49
49
  import {setShowPreview} from '../../../store/reducers/schema/schema';
50
50
  import {setQueryTab, setTenantPage} from '../../../store/reducers/tenant/tenant';
51
- import {
52
- TENANT_PAGES_IDS,
53
- TENANT_QUERY_TABS_ID,
54
- } from '../../../store/reducers/tenant/constants';
51
+ import {TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID} from '../../../store/reducers/tenant/constants';
55
52
 
56
53
  import './ObjectSummary.scss';
57
54
 
@@ -246,9 +243,7 @@ function ObjectSummary(props: ObjectSummaryProps) {
246
243
  const renderTree = () => {
247
244
  return (
248
245
  <div className={b('tree-wrapper')}>
249
- <div className={b('tree-header')}>
250
- <div className={b('tree-title')}>Navigation</div>
251
- </div>
246
+ <div className={b('tree-header')}>Navigation</div>
252
247
  <div className={b('tree')}>
253
248
  {pathData && (
254
249
  <SchemaTree
@@ -1,4 +1,4 @@
1
- @import '../../../styles/mixins.scss';
1
+ @import '../../../../styles/mixins.scss';
2
2
 
3
3
  .kv-preview {
4
4
  height: 100%;
@@ -0,0 +1,121 @@
1
+ import {useCallback} from 'react';
2
+ import {useDispatch} from 'react-redux';
3
+ import cn from 'bem-cn-lite';
4
+
5
+ import {Loader, Button} from '@gravity-ui/uikit';
6
+
7
+ import type {EPathType} from '../../../../types/api/schema';
8
+ import {sendQuery, setQueryOptions} from '../../../../store/reducers/preview';
9
+ import {setShowPreview} from '../../../../store/reducers/schema/schema';
10
+ import {prepareQueryError} from '../../../../utils/query';
11
+ import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
12
+
13
+ import {Icon} from '../../../../components/Icon';
14
+ import Fullscreen from '../../../../components/Fullscreen/Fullscreen';
15
+ import {QueryResultTable} from '../../../../components/QueryResultTable';
16
+ import EnableFullscreenButton from '../../../../components/EnableFullscreenButton/EnableFullscreenButton';
17
+
18
+ import {isTableType} from '../../utils/schema';
19
+
20
+ import i18n from '../i18n';
21
+
22
+ import './Preview.scss';
23
+
24
+ const b = cn('kv-preview');
25
+
26
+ interface PreviewProps {
27
+ database: string;
28
+ type: EPathType | undefined;
29
+ }
30
+
31
+ export const Preview = ({database, type}: PreviewProps) => {
32
+ const dispatch = useDispatch();
33
+
34
+ const {data = {}, loading, error, wasLoaded} = useTypedSelector((state) => state.preview);
35
+ const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
36
+ const isFullscreen = useTypedSelector((state) => state.fullscreen);
37
+
38
+ const sendQueryForPreview = useCallback(
39
+ (isBackground) => {
40
+ if (!isTableType(type)) {
41
+ return;
42
+ }
43
+
44
+ if (!isBackground) {
45
+ dispatch(
46
+ setQueryOptions({
47
+ wasLoaded: false,
48
+ data: undefined,
49
+ }),
50
+ );
51
+ }
52
+
53
+ const query = `--!syntax_v1\nselect * from \`${currentSchemaPath}\` limit 32`;
54
+
55
+ dispatch(
56
+ sendQuery({
57
+ query,
58
+ database,
59
+ action: 'execute-scan',
60
+ }),
61
+ );
62
+ },
63
+ [dispatch, database, currentSchemaPath, type],
64
+ );
65
+
66
+ useAutofetcher(sendQueryForPreview, [sendQueryForPreview], autorefresh);
67
+
68
+ const handleClosePreview = () => {
69
+ dispatch(setShowPreview(false));
70
+ };
71
+
72
+ const renderHeader = () => {
73
+ return (
74
+ <div className={b('header')}>
75
+ <div className={b('title')}>
76
+ {i18n('preview.title')}{' '}
77
+ <div className={b('table-name')}>{currentSchemaPath}</div>
78
+ </div>
79
+ <div className={b('controls-left')}>
80
+ <EnableFullscreenButton disabled={Boolean(error)} />
81
+ <Button
82
+ view="flat-secondary"
83
+ onClick={handleClosePreview}
84
+ title={i18n('preview.close')}
85
+ >
86
+ <Icon name="close" viewBox={'0 0 16 16'} width={16} height={16} />
87
+ </Button>
88
+ </div>
89
+ </div>
90
+ );
91
+ };
92
+
93
+ if (loading && !wasLoaded) {
94
+ return (
95
+ <div className={b('loader-container')}>
96
+ <Loader size="m" />
97
+ </div>
98
+ );
99
+ }
100
+
101
+ let message;
102
+
103
+ if (!isTableType(type)) {
104
+ message = <div className={b('message-container')}>{i18n('preview.not-available')}</div>;
105
+ } else if (error) {
106
+ message = <div className={b('message-container')}>{prepareQueryError(error)}</div>;
107
+ }
108
+
109
+ const content = message ?? (
110
+ <div className={b('result')}>
111
+ <QueryResultTable data={data.result} columns={data.columns} />
112
+ </div>
113
+ );
114
+
115
+ return (
116
+ <div className={b()}>
117
+ {renderHeader()}
118
+ {isFullscreen ? <Fullscreen>{content}</Fullscreen> : content}
119
+ </div>
120
+ );
121
+ };
@@ -3,7 +3,7 @@ import block from 'bem-cn-lite';
3
3
 
4
4
  import DataTable, {Column} from '@gravity-ui/react-data-table';
5
5
 
6
- import TruncatedQuery from '../../../../components/TruncatedQuery/TruncatedQuery';
6
+ import {TruncatedQuery} from '../../../../components/TruncatedQuery/TruncatedQuery';
7
7
  import {setQueryTab} from '../../../../store/reducers/tenant/tenant';
8
8
  import {TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
9
9
  import {useTypedSelector} from '../../../../utils/hooks';
@@ -35,7 +35,7 @@ import {
35
35
  PaneVisibilityActionTypes,
36
36
  paneVisibilityToggleReducerCreator,
37
37
  } from '../../utils/paneVisibilityToggleHelpers';
38
- import Preview from '../../Preview/Preview';
38
+ import {Preview} from '../Preview/Preview';
39
39
 
40
40
  import {ExecuteResult} from '../ExecuteResult/ExecuteResult';
41
41
  import {ExplainResult} from '../ExplainResult/ExplainResult';
@@ -104,8 +104,10 @@ function QueryEditor(props) {
104
104
 
105
105
  useEffect(() => {
106
106
  if (savedPath !== path) {
107
+ if (savedPath) {
108
+ changeUserInput({input: ''});
109
+ }
107
110
  setTenantPath(path);
108
- changeUserInput({input: ''});
109
111
  }
110
112
  }, [changeUserInput, setTenantPath, path, savedPath]);
111
113
 
@@ -380,12 +382,8 @@ function QueryEditor(props) {
380
382
  };
381
383
 
382
384
  const renderPreview = () => {
383
- const {path, type, currentSchema = {}} = props;
384
- const partCount = currentSchema?.PathDescription?.TableStats?.PartCount;
385
- // onExpandResultHandler();
386
- return (
387
- <Preview database={path} table={currentSchema.Path} type={type} partCount={partCount} />
388
- );
385
+ const {path, type} = props;
386
+ return <Preview database={path} type={type} />;
389
387
  };
390
388
 
391
389
  const handlePreviousHistoryClick = () => {
@@ -10,7 +10,7 @@ import {setQueryNameToEdit} from '../../../../store/reducers/saveQuery';
10
10
  import {setQueryTab} from '../../../../store/reducers/tenant/tenant';
11
11
  import {TENANT_QUERY_TABS_ID} from '../../../../store/reducers/tenant/constants';
12
12
 
13
- import TruncatedQuery from '../../../../components/TruncatedQuery/TruncatedQuery';
13
+ import {TruncatedQuery} from '../../../../components/TruncatedQuery/TruncatedQuery';
14
14
  import {IconWrapper} from '../../../../components/Icon';
15
15
 
16
16
  import {MAX_QUERY_HEIGHT, QUERY_TABLE_SETTINGS} from '../../utils/constants';
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "controls.query-mode-selector_type": "Query type:",
3
- "tabs.newQuery": "New query",
3
+
4
+ "tabs.newQuery": "Query",
4
5
  "tabs.history": "History",
5
6
  "tabs.saved": "Saved",
7
+
6
8
  "history.empty": "History is empty",
7
9
  "saved.empty": "There are no saved queries",
10
+
8
11
  "delete-dialog.header": "Delete query",
9
12
  "delete-dialog.question": "Are you sure you want to delete query",
10
13
  "delete-dialog.delete": "Delete",
11
- "delete-dialog.cancel": "Cancel"
14
+ "delete-dialog.cancel": "Cancel",
15
+
16
+ "preview.title": "Preview",
17
+ "preview.not-available": "Preview is not available",
18
+ "preview.close": "Close preview"
12
19
  }
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "controls.query-mode-selector_type": "Тип запроса:",
3
- "tabs.newQuery": "Новый запрос",
3
+
4
+ "tabs.newQuery": "Запрос",
4
5
  "tabs.history": "История",
5
6
  "tabs.saved": "Сохраненные",
7
+
6
8
  "history.empty": "История пуста",
7
9
  "saved.empty": "Нет сохраненных запросов",
10
+
8
11
  "delete-dialog.header": "Удалить запрос",
9
12
  "delete-dialog.question": "Вы уверены что хотите удалить запрос",
10
13
  "delete-dialog.delete": "Удалить",
11
- "delete-dialog.cancel": "Отменить"
14
+ "delete-dialog.cancel": "Отменить",
15
+
16
+ "preview.title": "Предпросмотр",
17
+ "preview.not-available": "Предпросмотр недоступен",
18
+ "preview.close": "Закрыть предпросмотр"
12
19
  }
@@ -1,9 +1,6 @@
1
1
  @import '../../styles/mixins.scss';
2
2
 
3
3
  .tenants {
4
- height: 100%;
5
- @include flex-container();
6
-
7
4
  &__format-label {
8
5
  margin-right: 15px;
9
6
  }
@@ -28,16 +25,7 @@
28
25
  }
29
26
  }
30
27
 
31
- &__controls {
32
- @include controls();
33
- }
34
-
35
- &__table-wrapper {
36
- overflow: auto;
37
- flex-grow: 1;
38
-
39
- @include freeze-nth-column(1);
40
-
28
+ &__table {
41
29
  @include table-styles;
42
30
  }
43
31