ydb-embedded-ui 4.30.0 → 4.31.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 (38) hide show
  1. package/dist/components/MetricChart/MetricChart.scss +34 -0
  2. package/dist/components/MetricChart/MetricChart.tsx +198 -0
  3. package/dist/components/MetricChart/convertReponse.ts +32 -0
  4. package/dist/components/MetricChart/getChartData.ts +20 -0
  5. package/dist/components/MetricChart/getDefaultDataFormatter.ts +36 -0
  6. package/dist/components/MetricChart/index.ts +2 -0
  7. package/dist/components/MetricChart/reducer.ts +86 -0
  8. package/dist/components/MetricChart/types.ts +32 -0
  9. package/dist/components/TimeFrameSelector/TimeFrameSelector.scss +5 -0
  10. package/dist/components/TimeFrameSelector/TimeFrameSelector.tsx +33 -0
  11. package/dist/containers/App/Content.js +16 -12
  12. package/dist/containers/Tenant/Diagnostics/TenantOverview/DefaultDashboard.tsx +50 -0
  13. package/dist/containers/Tenant/Diagnostics/TenantOverview/MetricsCards/MetricsCards.tsx +13 -4
  14. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/CpuDashboard.tsx +18 -0
  15. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TenantCpu.tsx +2 -0
  16. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantDashboard/TenantDashboard.scss +14 -0
  17. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantDashboard/TenantDashboard.tsx +71 -0
  18. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/MemoryDashboard.tsx +21 -0
  19. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TenantMemory.tsx +7 -1
  20. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +2 -1
  21. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/StorageDashboard.tsx +21 -0
  22. package/dist/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TenantStorage.tsx +2 -0
  23. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/en.json +7 -1
  24. package/dist/containers/Tenant/Diagnostics/TenantOverview/i18n/ru.json +7 -1
  25. package/dist/containers/UserSettings/i18n/en.json +4 -1
  26. package/dist/containers/UserSettings/i18n/ru.json +4 -1
  27. package/dist/containers/UserSettings/settings.ts +12 -1
  28. package/dist/services/api.ts +18 -0
  29. package/dist/services/settings.ts +2 -0
  30. package/dist/store/reducers/tenant/tenant.ts +6 -1
  31. package/dist/types/api/render.ts +34 -0
  32. package/dist/utils/cn.ts +3 -0
  33. package/dist/utils/constants.ts +2 -0
  34. package/dist/utils/timeParsers/formatDuration.ts +10 -0
  35. package/dist/utils/timeframes.ts +10 -0
  36. package/dist/utils/versions/getVersionsColors.ts +1 -0
  37. package/package.json +3 -1
  38. package/CHANGELOG.md +0 -1559
@@ -0,0 +1,71 @@
1
+ import {StringParam, useQueryParam} from 'use-query-params';
2
+
3
+ import {cn} from '../../../../../utils/cn';
4
+ import type {TimeFrame} from '../../../../../utils/timeframes';
5
+ import {useSetting, useTypedSelector} from '../../../../../utils/hooks';
6
+ import {DISPLAY_CHARTS_IN_DB_DIAGNOSTICS_KEY} from '../../../../../utils/constants';
7
+ import {TimeFrameSelector} from '../../../../../components/TimeFrameSelector/TimeFrameSelector';
8
+ import {
9
+ type ChartOptions,
10
+ MetricChart,
11
+ type MetricDescription,
12
+ } from '../../../../../components/MetricChart';
13
+
14
+ import './TenantDashboard.scss';
15
+
16
+ const CHART_WIDTH = 428;
17
+ const CHART_WIDTH_FULL = 872;
18
+
19
+ const b = cn('ydb-tenant-dashboard');
20
+
21
+ export interface ChartConfig {
22
+ metrics: MetricDescription[];
23
+ title: string;
24
+ options?: ChartOptions;
25
+ }
26
+
27
+ interface TenantDashboardProps {
28
+ charts: ChartConfig[];
29
+ }
30
+
31
+ export const TenantDashboard = ({charts}: TenantDashboardProps) => {
32
+ const [timeFrame = '1h', setTimeframe] = useQueryParam('timeframe', StringParam);
33
+
34
+ const {autorefresh} = useTypedSelector((state) => state.schema);
35
+
36
+ const [chartsEnabled] = useSetting(DISPLAY_CHARTS_IN_DB_DIAGNOSTICS_KEY);
37
+
38
+ if (!chartsEnabled) {
39
+ return null;
40
+ }
41
+
42
+ // If there is only one chart, display it with full width
43
+ const chartWidth = charts.length === 1 ? CHART_WIDTH_FULL : CHART_WIDTH;
44
+ const chartHeight = CHART_WIDTH / 1.5;
45
+
46
+ const renderContent = () => {
47
+ return charts.map((chartConfig) => {
48
+ return (
49
+ <MetricChart
50
+ key={chartConfig.metrics.map(({target}) => target).join('&')}
51
+ title={chartConfig.title}
52
+ metrics={chartConfig.metrics}
53
+ timeFrame={timeFrame as TimeFrame}
54
+ chartOptions={chartConfig.options}
55
+ autorefresh={autorefresh}
56
+ width={chartWidth}
57
+ height={chartHeight}
58
+ />
59
+ );
60
+ });
61
+ };
62
+
63
+ return (
64
+ <div className={b(null)}>
65
+ <div className={b('controls')}>
66
+ <TimeFrameSelector value={timeFrame as TimeFrame} onChange={setTimeframe} />
67
+ </div>
68
+ <div className={b('charts')}>{renderContent()}</div>
69
+ </div>
70
+ );
71
+ };
@@ -0,0 +1,21 @@
1
+ import {type ChartConfig, TenantDashboard} from '../TenantDashboard/TenantDashboard';
2
+ import i18n from '../i18n';
3
+
4
+ const memoryDashboardConfig: ChartConfig[] = [
5
+ {
6
+ title: i18n('charts.memory-usage'),
7
+ metrics: [
8
+ {
9
+ target: 'resources.memory.used_bytes',
10
+ title: i18n('charts.memory-usage'),
11
+ },
12
+ ],
13
+ options: {
14
+ dataType: 'size',
15
+ },
16
+ },
17
+ ];
18
+
19
+ export const MemoryDashboard = () => {
20
+ return <TenantDashboard charts={memoryDashboardConfig} />;
21
+ };
@@ -1,3 +1,4 @@
1
+ import {MemoryDashboard} from './MemoryDashboard';
1
2
  import {TopNodesByMemory} from './TopNodesByMemory';
2
3
 
3
4
  interface TenantMemoryProps {
@@ -5,5 +6,10 @@ interface TenantMemoryProps {
5
6
  }
6
7
 
7
8
  export function TenantMemory({path}: TenantMemoryProps) {
8
- return <TopNodesByMemory path={path} />;
9
+ return (
10
+ <>
11
+ <MemoryDashboard />
12
+ <TopNodesByMemory path={path} />
13
+ </>
14
+ );
9
15
  }
@@ -17,6 +17,7 @@ import {HealthcheckDetails} from './Healthcheck/HealthcheckDetails';
17
17
  import {MetricsCards, type TenantMetrics} from './MetricsCards/MetricsCards';
18
18
  import {TenantStorage} from './TenantStorage/TenantStorage';
19
19
  import {TenantMemory} from './TenantMemory/TenantMemory';
20
+ import {DefaultDashboard} from './DefaultDashboard';
20
21
  import {useHealthcheck} from './useHealthcheck';
21
22
 
22
23
  import './TenantOverview.scss';
@@ -140,7 +141,7 @@ export function TenantOverview({
140
141
  );
141
142
  }
142
143
  default: {
143
- return undefined;
144
+ return <DefaultDashboard />;
144
145
  }
145
146
  }
146
147
  };
@@ -0,0 +1,21 @@
1
+ import {type ChartConfig, TenantDashboard} from '../TenantDashboard/TenantDashboard';
2
+ import i18n from '../i18n';
3
+
4
+ const storageDashboardConfig: ChartConfig[] = [
5
+ {
6
+ title: i18n('charts.storage-usage'),
7
+ metrics: [
8
+ {
9
+ target: 'resources.storage.used_bytes',
10
+ title: i18n('charts.storage-usage'),
11
+ },
12
+ ],
13
+ options: {
14
+ dataType: 'size',
15
+ },
16
+ },
17
+ ];
18
+
19
+ export const StorageDashboard = () => {
20
+ return <TenantDashboard charts={storageDashboardConfig} />;
21
+ };
@@ -7,6 +7,7 @@ import {getSizeWithSignificantDigits} from '../../../../../utils/bytesParsers';
7
7
 
8
8
  import '../TenantOverview.scss';
9
9
 
10
+ import {StorageDashboard} from './StorageDashboard';
10
11
  import {TopTables} from './TopTables';
11
12
  import {TopGroups} from './TopGroups';
12
13
 
@@ -62,6 +63,7 @@ export function TenantStorage({tenantName, metrics}: TenantStorageProps) {
62
63
  ];
63
64
  return (
64
65
  <>
66
+ <StorageDashboard />
65
67
  <InfoViewer className={b('storage-info')} title="Storage details" info={info} />
66
68
  <TopTables path={tenantName} />
67
69
  <TopGroups tenant={tenantName} />
@@ -23,5 +23,11 @@
23
23
  "by-load": "by load",
24
24
  "by-memory": "by memory",
25
25
  "by-usage": "by usage",
26
- "by-size": "by size"
26
+ "by-size": "by size",
27
+
28
+ "charts.queries-per-second": "Queries per second",
29
+ "charts.transaction-latency": "Transactions latencies {{percentile}}",
30
+ "charts.cpu-usage": "CPU usage",
31
+ "charts.storage-usage": "Storage usage",
32
+ "charts.memory-usage": "Memory usage"
27
33
  }
@@ -23,5 +23,11 @@
23
23
  "by-load": "по нагрузке",
24
24
  "by-memory": "по памяти",
25
25
  "by-usage": "по потреблению",
26
- "by-size": "по размеру"
26
+ "by-size": "по размеру",
27
+
28
+ "charts.queries-per-second": "Количество запросов в секунду",
29
+ "charts.transaction-latency": "Задержка транзакций {{percentile}}",
30
+ "charts.cpu-usage": "Использование CPU",
31
+ "charts.storage-usage": "Использование хранилища",
32
+ "charts.memory-usage": "Использование памяти"
27
33
  }
@@ -23,5 +23,8 @@
23
23
  "settings.useVirtualTables.popover": "It will increase performance, but could work unstable",
24
24
 
25
25
  "settings.queryUseMultiSchema.title": "Allow queries with multiple result sets",
26
- "settings.queryUseMultiSchema.popover": "Use 'multi' schema for queries that enables queries with multiple result sets. Returns nothing on versions 23-3 and older"
26
+ "settings.queryUseMultiSchema.popover": "Use 'multi' schema for queries that enables queries with multiple result sets. Returns nothing on versions 23-3 and older",
27
+
28
+ "settings.displayChartsInDbDiagnostics.title": "Display charts in database diagnostics",
29
+ "settings.displayChartsInDbDiagnostics.popover": "Incorrect data may be displayed (shows data only for the database related to the current node), does not work well on static nodes"
27
30
  }
@@ -23,5 +23,8 @@
23
23
  "settings.useVirtualTables.popover": "Это улучшит производительность, но может работать нестабильно",
24
24
 
25
25
  "settings.queryUseMultiSchema.title": "Разрешить запросы с несколькими результатами",
26
- "settings.queryUseMultiSchema.popover": "Использовать для запросов схему 'multi', которая позволяет выполнять запросы с несколькими результатами. На версиях 23-3 и старше результат не возвращается вообще"
26
+ "settings.queryUseMultiSchema.popover": "Использовать для запросов схему 'multi', которая позволяет выполнять запросы с несколькими результатами. На версиях 23-3 и старше результат не возвращается вообще",
27
+
28
+ "settings.displayChartsInDbDiagnostics.title": "Показывать графики в диагностике базы данных",
29
+ "settings.displayChartsInDbDiagnostics.popover": "Могут отображаться неправильные данные (показывает данные только для базы, относящейся к текущей ноде), плохо работает на статических нодах"
27
30
  }
@@ -10,6 +10,7 @@ import {
10
10
  USE_BACKEND_PARAMS_FOR_TABLES_KEY,
11
11
  USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY,
12
12
  QUERY_USE_MULTI_SCHEMA_KEY,
13
+ DISPLAY_CHARTS_IN_DB_DIAGNOSTICS_KEY,
13
14
  } from '../../utils/constants';
14
15
  import {Lang, defaultLang} from '../../utils/i18n';
15
16
 
@@ -94,6 +95,11 @@ export const queryUseMultiSchemaSetting: SettingProps = {
94
95
  title: i18n('settings.queryUseMultiSchema.title'),
95
96
  helpPopoverContent: i18n('settings.queryUseMultiSchema.popover'),
96
97
  };
98
+ export const displayChartsInDbDiagnosticsSetting: SettingProps = {
99
+ settingKey: DISPLAY_CHARTS_IN_DB_DIAGNOSTICS_KEY,
100
+ title: i18n('settings.displayChartsInDbDiagnostics.title'),
101
+ helpPopoverContent: i18n('settings.displayChartsInDbDiagnostics.popover'),
102
+ };
97
103
 
98
104
  export const appearanceSection: SettingsSection = {
99
105
  id: 'appearanceSection',
@@ -103,7 +109,12 @@ export const appearanceSection: SettingsSection = {
103
109
  export const experimentsSection: SettingsSection = {
104
110
  id: 'experimentsSection',
105
111
  title: i18n('section.experiments'),
106
- settings: [useNodesEndpointSetting, useVirtualTables, queryUseMultiSchemaSetting],
112
+ settings: [
113
+ useNodesEndpointSetting,
114
+ useVirtualTables,
115
+ queryUseMultiSchemaSetting,
116
+ displayChartsInDbDiagnosticsSetting,
117
+ ],
107
118
  };
108
119
 
109
120
  export const generalPage: SettingsPage = {
@@ -28,6 +28,7 @@ import type {DescribeTopicResult} from '../types/api/topic';
28
28
  import type {TEvPDiskStateResponse} from '../types/api/pdisk';
29
29
  import type {TEvVDiskStateResponse} from '../types/api/vdisk';
30
30
  import type {TUserToken} from '../types/api/whoami';
31
+ import type {JsonRenderRequestParams, JsonRenderResponse} from '../types/api/render';
31
32
  import type {QuerySyntax} from '../types/store/query';
32
33
  import type {ComputeApiRequestParams, NodesApiRequestParams} from '../store/reducers/nodes/types';
33
34
  import type {StorageApiRequestParams} from '../store/reducers/storage/types';
@@ -377,7 +378,24 @@ export class YdbEmbeddedAPI extends AxiosWrapper {
377
378
  path_id: tenantId?.PathId,
378
379
  });
379
380
  }
381
+ getChartData(
382
+ {target, from, until, maxDataPoints}: JsonRenderRequestParams,
383
+ {concurrentId}: AxiosOptions = {},
384
+ ) {
385
+ const requestString = `${target}&from=${from}&until=${until}&maxDataPoints=${maxDataPoints}&format=json`;
380
386
 
387
+ return this.post<JsonRenderResponse>(
388
+ this.getPath('/viewer/json/render'),
389
+ requestString,
390
+ {},
391
+ {
392
+ concurrentId,
393
+ headers: {
394
+ 'Content-Type': 'application/x-www-form-urlencoded',
395
+ },
396
+ },
397
+ );
398
+ }
381
399
  /** @deprecated use localStorage instead */
382
400
  postSetting(settingsApi: string, name: string, value: string) {
383
401
  return this.request({
@@ -3,6 +3,7 @@ import {TENANT_PAGES_IDS} from '../store/reducers/tenant/constants';
3
3
  import {
4
4
  ASIDE_HEADER_COMPACT_KEY,
5
5
  CLUSTER_INFO_HIDDEN_KEY,
6
+ DISPLAY_CHARTS_IN_DB_DIAGNOSTICS_KEY,
6
7
  INVERTED_DISKS_KEY,
7
8
  LANGUAGE_KEY,
8
9
  LAST_USED_QUERY_ACTION_KEY,
@@ -37,6 +38,7 @@ export const DEFAULT_USER_SETTINGS: SettingsObject = {
37
38
  [PARTITIONS_HIDDEN_COLUMNS_KEY]: [],
38
39
  [CLUSTER_INFO_HIDDEN_KEY]: true,
39
40
  [USE_BACKEND_PARAMS_FOR_TABLES_KEY]: false,
41
+ [DISPLAY_CHARTS_IN_DB_DIAGNOSTICS_KEY]: false,
40
42
  };
41
43
 
42
44
  class SettingsManager {
@@ -24,7 +24,12 @@ const SET_METRICS_TAB = 'tenant/SET_METRICS_TAB';
24
24
  const CLEAR_TENANT = 'tenant/CLEAR_TENANT';
25
25
  const SET_DATA_WAS_NOT_LOADED = 'tenant/SET_DATA_WAS_NOT_LOADED';
26
26
 
27
- const initialState = {loading: false, wasLoaded: false};
27
+ // Tenant diagnostics tab content was requested twice,
28
+ // because requests were sent before state was set as loading and after tenant data is fully loaded
29
+ // So tenant data is considered loading from the start, there is no attempt to load tab content
30
+ // TODO: try fix with 'display: none' for tenant diagnostics tab content while tenant data loading,
31
+ // but with parallel (not sequent) data requests
32
+ const initialState = {loading: true, wasLoaded: false};
28
33
 
29
34
  const tenantReducer: Reducer<TenantState, TenantAction> = (state = initialState, action) => {
30
35
  switch (action.type) {
@@ -0,0 +1,34 @@
1
+ /**
2
+ * endpoint: /viewer/json/render
3
+ *
4
+ * source: https://github.com/ydb-platform/ydb/blob/main/ydb/core/viewer/json_render.h
5
+ */
6
+
7
+ export type JsonRenderResponse =
8
+ | {
9
+ error?: string;
10
+ status?: string;
11
+ }
12
+ | MetricData[];
13
+
14
+ export interface MetricData {
15
+ datapoints: MetricDatapoint[];
16
+ target: string;
17
+ title: string;
18
+ tags: MetricTags;
19
+ }
20
+
21
+ interface MetricTags {
22
+ name: string;
23
+ }
24
+
25
+ /** [metric value - null or double, timestamp - seconds] */
26
+ export type MetricDatapoint = [null | number, number];
27
+
28
+ export interface JsonRenderRequestParams {
29
+ /** metrics names in format "target=queries.latencies.p50&target=queries.latencies.p75&target=queries.latencies.p90" */
30
+ target: string;
31
+ from: number;
32
+ until: number;
33
+ maxDataPoints: number;
34
+ }
@@ -0,0 +1,3 @@
1
+ import cn from 'bem-cn-lite';
2
+
3
+ export {cn};
@@ -125,3 +125,5 @@ export const USE_BACKEND_PARAMS_FOR_TABLES_KEY = 'useBackendParamsForTables';
125
125
 
126
126
  // Enable schema that supports multiple resultsets
127
127
  export const QUERY_USE_MULTI_SCHEMA_KEY = 'queryUseMultiSchema';
128
+
129
+ export const DISPLAY_CHARTS_IN_DB_DIAGNOSTICS_KEY = 'displayChartsInDbDiagnostics';
@@ -1,4 +1,5 @@
1
1
  import {DAY_IN_SECONDS, HOUR_IN_SECONDS} from '../constants';
2
+ import {formatNumber} from '../dataFormatters/dataFormatters';
2
3
 
3
4
  import i18n from './i18n';
4
5
 
@@ -6,6 +7,8 @@ import i18n from './i18n';
6
7
  * Process time difference in ms and returns formated time.
7
8
  * By default only two major values are returned (days & hours, hours & minutes, minutes & seconds, etc.).
8
9
  * It can be altered with valuesCount arg
10
+ *
11
+ * value - duration in ms
9
12
  */
10
13
  export const formatDurationToShortTimeFormat = (value: number, valuesCount: 1 | 2 = 2) => {
11
14
  const ms = value % 1000;
@@ -62,3 +65,10 @@ export const formatDurationToShortTimeFormat = (value: number, valuesCount: 1 |
62
65
 
63
66
  return i18n('ms', duration);
64
67
  };
68
+
69
+ /**
70
+ * Parse ms duration to string
71
+ */
72
+ export const formatToMs = (value: number) => {
73
+ return i18n('ms', {ms: formatNumber(value)});
74
+ };
@@ -0,0 +1,10 @@
1
+ import {DAY_IN_SECONDS, HOUR_IN_SECONDS, MINUTE_IN_SECONDS} from './constants';
2
+
3
+ export const TIMEFRAMES = {
4
+ '30m': 30 * MINUTE_IN_SECONDS,
5
+ '1h': HOUR_IN_SECONDS,
6
+ '1d': DAY_IN_SECONDS,
7
+ '1w': 7 * DAY_IN_SECONDS,
8
+ } as const;
9
+
10
+ export type TimeFrame = keyof typeof TIMEFRAMES;
@@ -9,6 +9,7 @@ export const hashCode = (s: string) => {
9
9
  }, 0);
10
10
  };
11
11
 
12
+ // TODO: colors used in charts as well, need to move to constants
12
13
  // 11 distinct colors from https://mokole.com/palette.html
13
14
  export const COLORS = [
14
15
  '#008000', // green
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.30.0",
3
+ "version": "4.31.0",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -10,6 +10,7 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@gravity-ui/axios-wrapper": "^1.3.0",
13
+ "@gravity-ui/chartkit": "^4.15.0",
13
14
  "@gravity-ui/components": "^2.9.1",
14
15
  "@gravity-ui/date-utils": "^1.1.1",
15
16
  "@gravity-ui/i18n": "^1.0.0",
@@ -45,6 +46,7 @@
45
46
  "reselect": "4.1.6",
46
47
  "sass": "1.32.8",
47
48
  "url": "^0.11.0",
49
+ "use-query-params": "^2.2.1",
48
50
  "web-vitals": "1.1.2",
49
51
  "ydb-ui-components": "^3.6.0"
50
52
  },