ydb-embedded-ui 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +2 -0
  3. package/dist/components/DateRange/DateRange.scss +11 -0
  4. package/dist/{containers/Tenant/Diagnostics/TopShards → components}/DateRange/DateRange.tsx +7 -7
  5. package/dist/{containers/Tenant/Diagnostics/TopShards → components}/DateRange/index.ts +0 -0
  6. package/dist/components/Illustration/Illustration.tsx +4 -11
  7. package/dist/components/InfoViewer/InfoViewer.scss +2 -0
  8. package/dist/containers/Storage/DiskStateProgressBar/DiskStateProgressBar.tsx +1 -1
  9. package/dist/containers/Storage/StorageNodes/StorageNodes.tsx +16 -0
  10. package/dist/containers/Tenant/Diagnostics/Diagnostics.tsx +4 -5
  11. package/dist/containers/Tenant/Diagnostics/DiagnosticsPages.ts +7 -7
  12. package/dist/containers/Tenant/Diagnostics/{TopShards/TopShards.scss → OverloadedShards/OverloadedShards.scss} +1 -1
  13. package/dist/containers/Tenant/Diagnostics/{TopShards/TopShards.tsx → OverloadedShards/OverloadedShards.tsx} +10 -11
  14. package/dist/containers/Tenant/Diagnostics/{TopShards → OverloadedShards}/i18n/en.json +0 -0
  15. package/dist/containers/Tenant/Diagnostics/OverloadedShards/i18n/index.ts +11 -0
  16. package/dist/containers/Tenant/Diagnostics/{TopShards → OverloadedShards}/i18n/ru.json +0 -0
  17. package/dist/containers/Tenant/Diagnostics/OverloadedShards/index.ts +1 -0
  18. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.scss +16 -19
  19. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.tsx +202 -0
  20. package/dist/containers/Tenant/Diagnostics/TopQueries/i18n/en.json +4 -0
  21. package/dist/containers/Tenant/Diagnostics/{TopShards → TopQueries}/i18n/index.ts +1 -1
  22. package/dist/containers/Tenant/Diagnostics/TopQueries/i18n/ru.json +4 -0
  23. package/dist/containers/Tenant/Diagnostics/TopQueries/index.ts +1 -0
  24. package/dist/containers/UserSettings/UserSettings.tsx +1 -1
  25. package/dist/services/api.d.ts +7 -0
  26. package/dist/store/reducers/describe.ts +4 -1
  27. package/dist/store/reducers/executeTopQueries.ts +170 -0
  28. package/dist/store/reducers/settings.js +1 -1
  29. package/dist/store/reducers/shardsWorkload.ts +9 -9
  30. package/dist/store/reducers/storage.js +2 -0
  31. package/dist/store/reducers/{tablets.js → tablets.ts} +30 -17
  32. package/dist/store/state-url-mapping.js +10 -2
  33. package/dist/types/api/compute.ts +52 -0
  34. package/dist/types/api/consumer.ts +257 -0
  35. package/dist/types/api/enums.ts +2 -2
  36. package/dist/types/api/nodes.ts +5 -2
  37. package/dist/types/api/pdisk.ts +3 -0
  38. package/dist/types/api/schema.ts +1 -0
  39. package/dist/types/api/storage.ts +31 -28
  40. package/dist/types/api/tablet.ts +18 -2
  41. package/dist/types/api/tenant.ts +4 -1
  42. package/dist/types/api/topic.ts +157 -0
  43. package/dist/types/api/vdisk.ts +3 -0
  44. package/dist/types/store/executeTopQueries.ts +29 -0
  45. package/dist/types/store/schema.ts +3 -3
  46. package/dist/types/store/shardsWorkload.ts +3 -3
  47. package/dist/types/store/tablets.ts +42 -0
  48. package/dist/utils/getNodesColumns.js +8 -1
  49. package/package.json +3 -3
  50. package/dist/containers/Tenant/Diagnostics/TopQueries/TopQueries.js +0 -188
  51. package/dist/containers/Tenant/Diagnostics/TopShards/DateRange/DateRange.scss +0 -13
  52. package/dist/containers/Tenant/Diagnostics/TopShards/index.ts +0 -1
  53. package/dist/store/reducers/executeTopQueries.js +0 -66
  54. package/dist/types/api/consumers.ts +0 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.2.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.1.0...v3.2.0) (2023-01-09)
4
+
5
+
6
+ ### Features
7
+
8
+ * **Nodes:** display rack in table ([3b8cdd5](https://github.com/ydb-platform/ydb-embedded-ui/commit/3b8cdd5b472f98132b2faaa9b71b8911750545a6))
9
+ * **StorageNodes:** display datacenter in table ([4507bfd](https://github.com/ydb-platform/ydb-embedded-ui/commit/4507bfde839b0aafa3722828b7528885c6ac8f84))
10
+ * **TopQueries:** date range filter ([b9a8e95](https://github.com/ydb-platform/ydb-embedded-ui/commit/b9a8e9504fa68556a724b214ee91b73ec900d37e))
11
+ * **TopQueries:** filter by query text ([2c8ea97](https://github.com/ydb-platform/ydb-embedded-ui/commit/2c8ea97dd215ea59165cf05315bc5809cf7fafd7))
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * **InfoViewer:** min width for values ([64a4fd4](https://github.com/ydb-platform/ydb-embedded-ui/commit/64a4fd4de16738a9e2fac9cb4fba94eafc938762))
17
+ * **Nodes:** open external link in new tab ([b7c3ddd](https://github.com/ydb-platform/ydb-embedded-ui/commit/b7c3ddd1e611f2b61466e3eda51f3341f8407588))
18
+ * **TopQueries:** proper table dynamic render type ([9add6ca](https://github.com/ydb-platform/ydb-embedded-ui/commit/9add6ca9fbfe0475caf1586070a800210320cee6))
19
+ * **TopShards:** rename to overloaded shards ([d9978bd](https://github.com/ydb-platform/ydb-embedded-ui/commit/d9978bdd84b9a883e4eefcac7f85f856da55d770))
20
+ * **UserSettings:** treat invertedDisks settings as string ([ad7742a](https://github.com/ydb-platform/ydb-embedded-ui/commit/ad7742a6bf0be59c2b9cbbf947aaa66f79d748be))
21
+
3
22
  ## [3.1.0](https://github.com/ydb-platform/ydb-embedded-ui/compare/v3.0.1...v3.1.0) (2022-12-13)
4
23
 
5
24
 
package/README.md CHANGED
@@ -15,6 +15,8 @@ Local viewer for YDB clusters
15
15
  3) Open [http://localhost:3000](http://localhost:3000) to view it in the browser. The page will reload if you make edits.\
16
16
  You will also see any lint errors in the console.
17
17
 
18
+ For API reference, open Swagger UI on http://localhost:8765/viewer/api/.
19
+
18
20
  ### Making a production bundle.
19
21
 
20
22
  Base command `npm run build` builds the app for production to the `build` folder.\
@@ -0,0 +1,11 @@
1
+ .date-range {
2
+ &__input {
3
+ min-width: 190px;
4
+ padding: 5px 8px;
5
+
6
+ color: var(--yc-color-text-primary);
7
+ border: 1px solid var(--yc-color-line-generic);
8
+ border-radius: var(--yc-border-radius-m);
9
+ background: transparent;
10
+ }
11
+ }
@@ -1,9 +1,9 @@
1
- import cn from 'bem-cn-lite';
2
1
  import {ChangeEventHandler} from 'react';
2
+ import cn from 'bem-cn-lite';
3
3
 
4
4
  import './DateRange.scss';
5
5
 
6
- const b = cn('top-shards');
6
+ const b = cn('date-range');
7
7
 
8
8
  export interface DateRangeValues {
9
9
  /** ms from epoch */
@@ -54,21 +54,21 @@ export const DateRange = ({from, to, className, onChange}: DateRangeProps) => {
54
54
  const endISO = toTimezonelessISOString(to);
55
55
 
56
56
  return (
57
- <div className={b('date-range', className)}>
57
+ <div className={b(null, className)}>
58
58
  <input
59
59
  type="datetime-local"
60
- value={startISO}
60
+ value={startISO || ''}
61
61
  max={endISO}
62
62
  onChange={handleFromChange}
63
- className={b('date-range-input')}
63
+ className={b('input')}
64
64
  />
65
65
 
66
66
  <input
67
67
  type="datetime-local"
68
68
  min={startISO}
69
- value={endISO}
69
+ value={endISO || ''}
70
70
  onChange={handleToChange}
71
- className={b('date-range-input')}
71
+ className={b('input')}
72
72
  />
73
73
  </div>
74
74
  );
@@ -1,8 +1,8 @@
1
- import {useEffect, useState} from 'react';
1
+ import {ImgHTMLAttributes, useEffect, useState} from 'react';
2
2
  import cn from 'bem-cn-lite';
3
3
  import {useThemeValue} from '@gravity-ui/uikit';
4
4
 
5
- export interface IllustrationProps {
5
+ export interface IllustrationProps extends ImgHTMLAttributes<HTMLImageElement> {
6
6
  name: string;
7
7
  className?: string;
8
8
  }
@@ -38,12 +38,5 @@ export const Illustration = ({name, className, ...props}: IllustrationProps) =>
38
38
  }
39
39
  }, [srcGetter]);
40
40
 
41
- return (
42
- <img
43
- alt={name}
44
- src={src}
45
- className={b(null, className)}
46
- {...props}
47
- />
48
- );
49
- }
41
+ return <img alt={name} src={src} className={b(null, className)} {...props} />;
42
+ };
@@ -54,6 +54,8 @@
54
54
  &__value {
55
55
  display: flex;
56
56
 
57
+ min-width: 120px;
58
+
57
59
  word-break: break-all;
58
60
  }
59
61
 
@@ -27,7 +27,7 @@ function DiskStateProgressBar({
27
27
  diskAllocatedPercent = -1,
28
28
  severity,
29
29
  }: DiskStateProgressBarProps) {
30
- const inverted = useSelector((state) => getSettingValue(state, INVERTED_DISKS_KEY));
30
+ const inverted = useSelector((state) => JSON.parse(getSettingValue(state, INVERTED_DISKS_KEY)));
31
31
 
32
32
  const renderAllocatedPercent = () => {
33
33
  return (
@@ -16,6 +16,8 @@ import './StorageNodes.scss';
16
16
  enum TableColumnsIds {
17
17
  NodeId = 'NodeId',
18
18
  FQDN = 'FQDN',
19
+ DataCenter = 'DataCenter',
20
+ Rack = 'Rack',
19
21
  uptime = 'uptime',
20
22
  PDisks = 'PDisks',
21
23
  Missing = 'Missing',
@@ -36,6 +38,8 @@ interface StorageNodesProps {
36
38
  const tableColumnsNames: Record<TableColumnsIdsValues, string> = {
37
39
  NodeId: 'Node ID',
38
40
  FQDN: 'FQDN',
41
+ DataCenter: 'DC',
42
+ Rack: 'Rack',
39
43
  uptime: 'Uptime',
40
44
  PDisks: 'PDisks',
41
45
  Missing: 'Missing',
@@ -96,6 +100,18 @@ function StorageNodes({
96
100
  },
97
101
  align: DataTable.LEFT,
98
102
  },
103
+ {
104
+ name: TableColumnsIds.DataCenter,
105
+ header: tableColumnsNames[TableColumnsIds.DataCenter],
106
+ render: ({row}) => row.DataCenter || '—',
107
+ align: DataTable.LEFT,
108
+ },
109
+ {
110
+ name: TableColumnsIds.Rack,
111
+ header: tableColumnsNames[TableColumnsIds.Rack],
112
+ render: ({row}) => row.Rack || '—',
113
+ align: DataTable.LEFT,
114
+ },
99
115
  {
100
116
  name: TableColumnsIds.uptime,
101
117
  header: tableColumnsNames[TableColumnsIds.uptime],
@@ -9,11 +9,10 @@ import {Switch, Tabs} from '@gravity-ui/uikit';
9
9
 
10
10
  import {Loader} from '../../../components/Loader';
11
11
 
12
- //@ts-ignore
13
- import TopQueries from './TopQueries/TopQueries';
12
+ import {TopQueries} from './TopQueries';
14
13
  //@ts-ignore
15
14
  import DetailedOverview from './DetailedOverview/DetailedOverview';
16
- import {TopShards} from './TopShards';
15
+ import {OverloadedShards} from './OverloadedShards';
17
16
  //@ts-ignore
18
17
  import Storage from '../../Storage/Storage';
19
18
  //@ts-ignore
@@ -130,8 +129,8 @@ function Diagnostics(props: DiagnosticsProps) {
130
129
  />
131
130
  );
132
131
  }
133
- case GeneralPagesIds.topShards: {
134
- return <TopShards tenantPath={tenantNameString} type={type} />;
132
+ case GeneralPagesIds.overloadedShards: {
133
+ return <OverloadedShards tenantPath={tenantNameString} type={type} />;
135
134
  }
136
135
  case GeneralPagesIds.nodes: {
137
136
  return (
@@ -3,7 +3,7 @@ import {EPathType} from '../../../types/api/schema';
3
3
  export enum GeneralPagesIds {
4
4
  'overview' = 'Overview',
5
5
  'topQueries' = 'topQueries',
6
- 'topShards' = 'topShards',
6
+ 'overloadedShards' = 'overloadedShards',
7
7
  'nodes' = 'Nodes',
8
8
  'tablets' = 'Tablets',
9
9
  'storage' = 'Storage',
@@ -29,9 +29,9 @@ const topQueries = {
29
29
  title: 'Top queries',
30
30
  };
31
31
 
32
- const topShards = {
33
- id: GeneralPagesIds.topShards,
34
- title: 'Top shards',
32
+ const overloadedShards = {
33
+ id: GeneralPagesIds.overloadedShards,
34
+ title: 'Overloaded shards',
35
35
  };
36
36
 
37
37
  const nodes = {
@@ -75,7 +75,7 @@ const consumers = {
75
75
  export const DATABASE_PAGES = [
76
76
  overview,
77
77
  topQueries,
78
- topShards,
78
+ overloadedShards,
79
79
  nodes,
80
80
  tablets,
81
81
  storage,
@@ -83,9 +83,9 @@ export const DATABASE_PAGES = [
83
83
  describe,
84
84
  ];
85
85
 
86
- export const TABLE_PAGES = [overview, topShards, graph, tablets, hotKeys, describe];
86
+ export const TABLE_PAGES = [overview, overloadedShards, graph, tablets, hotKeys, describe];
87
87
 
88
- export const DIR_PAGES = [overview, topShards, describe];
88
+ export const DIR_PAGES = [overview, overloadedShards, describe];
89
89
 
90
90
  export const CDC_STREAM_PAGES = [overview, consumers, describe];
91
91
  export const TOPIC_PAGES = [overview, consumers, describe];
@@ -1,4 +1,4 @@
1
- .top-shards {
1
+ .overloaded-shards {
2
2
  display: flex;
3
3
  flex-direction: column;
4
4
 
@@ -5,6 +5,7 @@ import cn from 'bem-cn-lite';
5
5
  import DataTable, {Column, Settings, SortOrder} from '@yandex-cloud/react-data-table';
6
6
  import {Loader} from '@gravity-ui/uikit';
7
7
 
8
+ import {DateRange, DateRangeValues} from '../../../../components/DateRange';
8
9
  import InternalLink from '../../../../components/InternalLink/InternalLink';
9
10
 
10
11
  import HistoryContext from '../../../../contexts/HistoryContext';
@@ -13,8 +14,8 @@ import routes, {createHref} from '../../../../routes';
13
14
 
14
15
  import {
15
16
  sendShardQuery,
16
- setShardQueryOptions,
17
- setTopShardFilters,
17
+ setShardsState,
18
+ setShardsQueryFilters,
18
19
  } from '../../../../store/reducers/shardsWorkload';
19
20
  import {setCurrentSchemaPath, getSchema} from '../../../../store/reducers/schema';
20
21
  import type {IShardsWorkloadFilters} from '../../../../types/store/shardsWorkload';
@@ -30,12 +31,10 @@ import {getDefaultNodePath} from '../../../Node/NodePages';
30
31
 
31
32
  import {isColumnEntityType} from '../../utils/schema';
32
33
 
33
- import {DateRange, DateRangeValues} from './DateRange';
34
-
35
34
  import i18n from './i18n';
36
- import './TopShards.scss';
35
+ import './OverloadedShards.scss';
37
36
 
38
- const b = cn('top-shards');
37
+ const b = cn('overloaded-shards');
39
38
  const bLink = cn('yc-link');
40
39
 
41
40
  const TABLE_SETTINGS: Settings = {
@@ -83,12 +82,12 @@ function dataTableToStringSortOrder(value: SortOrder | SortOrder[] = []) {
83
82
  return sortOrders.map(({columnId}) => columnId).join(',');
84
83
  }
85
84
 
86
- interface TopShardsProps {
85
+ interface OverloadedShardsProps {
87
86
  tenantPath: string;
88
87
  type?: EPathType;
89
88
  }
90
89
 
91
- export const TopShards = ({tenantPath, type}: TopShardsProps) => {
90
+ export const OverloadedShards = ({tenantPath, type}: OverloadedShardsProps) => {
92
91
  const dispatch = useDispatch();
93
92
 
94
93
  const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema);
@@ -134,7 +133,7 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
134
133
  // don't show loader for requests triggered by table sort, only for path change
135
134
  useEffect(() => {
136
135
  dispatch(
137
- setShardQueryOptions({
136
+ setShardsState({
138
137
  wasLoaded: false,
139
138
  data: undefined,
140
139
  }),
@@ -144,14 +143,14 @@ export const TopShards = ({tenantPath, type}: TopShardsProps) => {
144
143
  const history = useContext(HistoryContext);
145
144
 
146
145
  const onSort = (newSortOrder?: SortOrder | SortOrder[]) => {
147
- // omit information about sort order to disable ASC order, only DESC makes sense for top shards
146
+ // omit information about sort order to disable ASC order, only DESC makes sense for overloaded shards
148
147
  // use a string (and not the DataTable default format) to prevent reference change,
149
148
  // which would cause an excess state change, to avoid repeating requests
150
149
  setSortOrder(dataTableToStringSortOrder(newSortOrder));
151
150
  };
152
151
 
153
152
  const handleDateRangeChange = (value: DateRangeValues) => {
154
- dispatch(setTopShardFilters(value));
153
+ dispatch(setShardsQueryFilters(value));
155
154
  setFilters(value);
156
155
  };
157
156
 
@@ -0,0 +1,11 @@
1
+ import {i18n, Lang} from '../../../../../utils/i18n';
2
+
3
+ import en from './en.json';
4
+ import ru from './ru.json';
5
+
6
+ const COMPONENT = 'ydb-diagnostics-overloaded-shards';
7
+
8
+ i18n.registerKeyset(Lang.En, COMPONENT, en);
9
+ i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
10
+
11
+ export default i18n.keyset(COMPONENT);
@@ -0,0 +1 @@
1
+ export * from './OverloadedShards';
@@ -1,43 +1,40 @@
1
1
  @import '../../../../styles/mixins.scss';
2
2
 
3
3
  .kv-top-queries {
4
+ display: flex;
5
+ flex-direction: column;
6
+
4
7
  height: 100%;
5
8
 
6
9
  @include query-data-table;
7
- &__message-container {
8
- padding: 15px 0;
9
- }
10
10
 
11
11
  &__loader {
12
12
  display: flex;
13
13
  justify-content: center;
14
14
  }
15
15
 
16
- &__owner-container {
17
- margin: 10px;
16
+ &__controls {
17
+ display: flex;
18
+ flex-wrap: wrap;
19
+ gap: 16px;
18
20
 
19
- .yc-staff-card {
20
- display: inline-block;
21
- }
21
+ margin-bottom: 10px;
22
22
  }
23
23
 
24
- &__text {
25
- font-size: var(--yc-text-body-1-font-size);
26
- line-height: var(--yc-text-body-1-line-height);
27
-
28
- color: var(--yc-color-text-primary);
29
-
30
- &::first-letter {
31
- color: var(--yc-color-text-danger);
32
- }
24
+ &__search {
25
+ @include search();
33
26
  }
34
27
 
35
- &__result &__table-content {
36
- & .data-table {
28
+ &__result {
29
+ overflow: auto;
30
+ flex-grow: 1;
31
+
32
+ .data-table {
37
33
  &,
38
34
  &__table {
39
35
  width: 100%;
40
36
  }
37
+
41
38
  &__td {
42
39
  vertical-align: top;
43
40
  white-space: pre;
@@ -0,0 +1,202 @@
1
+ import {useCallback, useEffect, useRef, useState} from 'react';
2
+ import {useDispatch} from 'react-redux';
3
+ import cn from 'bem-cn-lite';
4
+
5
+ import DataTable, {Column, Settings} from '@yandex-cloud/react-data-table';
6
+ import {Loader} from '@gravity-ui/uikit';
7
+
8
+ import {DateRange, DateRangeValues} from '../../../../components/DateRange';
9
+ import {Search} from '../../../../components/Search';
10
+ import TruncatedQuery from '../../../../components/TruncatedQuery/TruncatedQuery';
11
+
12
+ import {changeUserInput} from '../../../../store/reducers/executeQuery';
13
+ import {
14
+ fetchTopQueries,
15
+ setTopQueriesFilters,
16
+ setTopQueriesState,
17
+ } from '../../../../store/reducers/executeTopQueries';
18
+
19
+ import type {KeyValueRow} from '../../../../types/api/query';
20
+ import type {EPathType} from '../../../../types/api/schema';
21
+ import type {ITopQueriesFilters} from '../../../../types/store/executeTopQueries';
22
+ import type {IQueryResult} from '../../../../types/store/query';
23
+
24
+ import {DEFAULT_TABLE_SETTINGS, HOUR_IN_SECONDS} from '../../../../utils/constants';
25
+ import {useAutofetcher, useTypedSelector} from '../../../../utils/hooks';
26
+ import {prepareQueryError} from '../../../../utils/query';
27
+
28
+ import {isColumnEntityType} from '../../utils/schema';
29
+ import {TenantGeneralTabsIds} from '../../TenantPages';
30
+
31
+ import i18n from './i18n';
32
+ import './TopQueries.scss';
33
+
34
+ const b = cn('kv-top-queries');
35
+
36
+ const TABLE_SETTINGS: Settings = {
37
+ ...DEFAULT_TABLE_SETTINGS,
38
+ dynamicRenderType: 'variable',
39
+ };
40
+
41
+ const MAX_QUERY_HEIGHT = 10;
42
+ const COLUMNS: Column<KeyValueRow>[] = [
43
+ {
44
+ name: 'CPUTimeUs',
45
+ width: 140,
46
+ sortAccessor: (row) => Number(row['CPUTimeUs']),
47
+ },
48
+ {
49
+ name: 'QueryText',
50
+ width: 500,
51
+ sortable: false,
52
+ render: ({value}) => <TruncatedQuery value={value} maxQueryHeight={MAX_QUERY_HEIGHT} />,
53
+ },
54
+ ];
55
+
56
+ interface TopQueriesProps {
57
+ path: string;
58
+ changeSchemaTab: (tab: TenantGeneralTabsIds) => void;
59
+ type?: EPathType;
60
+ }
61
+
62
+ export const TopQueries = ({path, type, changeSchemaTab}: TopQueriesProps) => {
63
+ const dispatch = useDispatch();
64
+
65
+ const {autorefresh} = useTypedSelector((state) => state.schema);
66
+
67
+ const {
68
+ loading,
69
+ wasLoaded,
70
+ error,
71
+ data: {result: data = undefined} = {},
72
+ filters: storeFilters,
73
+ } = useTypedSelector((state) => state.executeTopQueries);
74
+
75
+ const preventFetch = useRef(false);
76
+
77
+ // some filters sync between redux state and URL
78
+ // component state is for default values,
79
+ // default values are determined from the query response, and should not propagate to URL
80
+ const [filters, setFilters] = useState<ITopQueriesFilters>(storeFilters);
81
+
82
+ useEffect(() => {
83
+ dispatch(setTopQueriesFilters(filters));
84
+ }, [dispatch, filters]);
85
+
86
+ const setDefaultFiltersFromResponse = (responseData?: IQueryResult) => {
87
+ const intervalEnd = responseData?.result?.[0]?.IntervalEnd;
88
+
89
+ if (intervalEnd) {
90
+ const to = new Date(intervalEnd).getTime();
91
+ const from = new Date(to - HOUR_IN_SECONDS * 1000).getTime();
92
+
93
+ setFilters((currentFilters) => {
94
+ // request without filters returns the latest interval with data
95
+ // only in this case should update filters in ui
96
+ // also don't update if user already interacted with controls
97
+ const shouldUpdateFilters = !currentFilters.from && !currentFilters.to;
98
+
99
+ if (!shouldUpdateFilters) {
100
+ return currentFilters;
101
+ }
102
+
103
+ preventFetch.current = true;
104
+
105
+ return {...currentFilters, from, to};
106
+ });
107
+ }
108
+ };
109
+
110
+ useAutofetcher(
111
+ (isBackground) => {
112
+ if (preventFetch.current) {
113
+ preventFetch.current = false;
114
+ return;
115
+ }
116
+
117
+ if (!isBackground) {
118
+ dispatch(
119
+ setTopQueriesState({
120
+ wasLoaded: false,
121
+ data: undefined,
122
+ }),
123
+ );
124
+ }
125
+
126
+ // @ts-expect-error
127
+ // typed dispatch required, remove error expectation after adding it
128
+ dispatch(fetchTopQueries({database: path, filters})).then(
129
+ setDefaultFiltersFromResponse,
130
+ );
131
+ },
132
+ [dispatch, filters, path],
133
+ autorefresh,
134
+ );
135
+
136
+ const handleRowClick = useCallback(
137
+ (row) => {
138
+ const {QueryText: input} = row;
139
+
140
+ dispatch(changeUserInput({input}));
141
+ changeSchemaTab(TenantGeneralTabsIds.query);
142
+ },
143
+ [changeSchemaTab, dispatch],
144
+ );
145
+
146
+ const handleTextSearchUpdate = (text: string) => {
147
+ setFilters((currentFilters) => ({...currentFilters, text}));
148
+ };
149
+
150
+ const handleDateRangeChange = (value: DateRangeValues) => {
151
+ setFilters((currentFilters) => ({...currentFilters, ...value}));
152
+ };
153
+
154
+ const renderLoader = () => {
155
+ return (
156
+ <div className={b('loader')}>
157
+ <Loader size="m" />
158
+ </div>
159
+ );
160
+ };
161
+
162
+ const renderContent = () => {
163
+ if (loading && !wasLoaded) {
164
+ return renderLoader();
165
+ }
166
+
167
+ if (error && !error.isCancelled) {
168
+ return <div className="error">{prepareQueryError(error)}</div>;
169
+ }
170
+
171
+ if (!data || isColumnEntityType(type)) {
172
+ return i18n('no-data');
173
+ }
174
+
175
+ return (
176
+ <div className={b('result')}>
177
+ <DataTable
178
+ columns={COLUMNS}
179
+ data={data}
180
+ settings={TABLE_SETTINGS}
181
+ onRowClick={handleRowClick}
182
+ theme="yandex-cloud"
183
+ />
184
+ </div>
185
+ );
186
+ };
187
+
188
+ return (
189
+ <div className={b()}>
190
+ <div className={b('controls')}>
191
+ <Search
192
+ value={filters.text}
193
+ onChange={handleTextSearchUpdate}
194
+ placeholder={i18n('filter.text.placeholder')}
195
+ className={b('search')}
196
+ />
197
+ <DateRange from={filters.from} to={filters.to} onChange={handleDateRangeChange} />
198
+ </div>
199
+ {renderContent()}
200
+ </div>
201
+ );
202
+ };
@@ -0,0 +1,4 @@
1
+ {
2
+ "no-data": "No data",
3
+ "filter.text.placeholder": "Search by query text..."
4
+ }
@@ -3,7 +3,7 @@ import {i18n, Lang} from '../../../../../utils/i18n';
3
3
  import en from './en.json';
4
4
  import ru from './ru.json';
5
5
 
6
- const COMPONENT = 'ydb-diagnostics-top-shards';
6
+ const COMPONENT = 'ydb-diagnostics-top-queries';
7
7
 
8
8
  i18n.registerKeyset(Lang.En, COMPONENT, en);
9
9
  i18n.registerKeyset(Lang.Ru, COMPONENT, ru);
@@ -0,0 +1,4 @@
1
+ {
2
+ "no-data": "Нет данных",
3
+ "filter.text.placeholder": "Искать по тексту запроса..."
4
+ }
@@ -0,0 +1 @@
1
+ export * from './TopQueries';
@@ -67,7 +67,7 @@ const mapStateToProps = (state: any) => {
67
67
 
68
68
  return {
69
69
  theme,
70
- invertedDisks,
70
+ invertedDisks: JSON.parse(invertedDisks),
71
71
  };
72
72
  };
73
73
 
@@ -48,6 +48,13 @@ interface Window {
48
48
  getTenantInfo: (params: {
49
49
  path: string;
50
50
  }) => Promise<import('../types/api/tenant').TTenantInfo>;
51
+ getTabletsInfo: (params: {
52
+ nodes?: string[];
53
+ path?: string;
54
+ }) => Promise<import('../types/api/tablet').TEvTabletStateResponse>;
55
+ getHeatmapData: (params: {
56
+ path: string;
57
+ }) => Promise<import('../types/api/schema').TEvDescribeSchemeResult>;
51
58
  [method: string]: Function;
52
59
  };
53
60
  }