ydb-embedded-ui 4.31.0 → 4.31.2

Sign up to get free protection for your applications and to get access to all the features.
package/README.md CHANGED
@@ -15,6 +15,8 @@ docker pull cr.yandex/yc/yandex-docker-local-ydb
15
15
  docker run -dp 8765:8765 cr.yandex/yc/yandex-docker-local-ydb
16
16
  ```
17
17
 
18
+ Open http://localhost:8765 to view it in the browser.
19
+
18
20
  ## Development
19
21
 
20
22
  1. Run on a machine with Docker installed:
@@ -8,12 +8,13 @@ export const convertResponse = (
8
8
  const preparedMetrics = data
9
9
  .map(({datapoints, target}) => {
10
10
  const metricDescription = metrics.find((metric) => metric.target === target);
11
- const chartData = datapoints.map((datapoint) => datapoint[0] || 0);
12
11
 
13
12
  if (!metricDescription) {
14
13
  return undefined;
15
14
  }
16
15
 
16
+ const chartData = datapoints.map((datapoint) => datapoint[0]);
17
+
17
18
  return {
18
19
  ...metricDescription,
19
20
  data: chartData,
@@ -1,4 +1,5 @@
1
1
  import {formatBytes} from '../../utils/bytesParsers';
2
+ import {EMPTY_DATA_PLACEHOLDER} from '../../utils/constants';
2
3
  import {roundToPrecision} from '../../utils/dataFormatters/dataFormatters';
3
4
  import {formatToMs} from '../../utils/timeParsers';
4
5
  import {isNumeric} from '../../utils/utils';
@@ -18,11 +19,19 @@ export const getDefaultDataFormatter = (dataType?: ChartDataType) => {
18
19
  }
19
20
  };
20
21
 
22
+ // Values in y axis won't be null and will always be present and properly formatted
23
+ // EMPTY_DATA_PLACEHOLDER is actually empty data format for values in a tooltip
21
24
  function formatChartValueToMs(value: ChartValue) {
25
+ if (value === null) {
26
+ return EMPTY_DATA_PLACEHOLDER;
27
+ }
22
28
  return formatToMs(roundToPrecision(convertToNumber(value), 2));
23
29
  }
24
30
 
25
31
  function formatChartValueToSize(value: ChartValue) {
32
+ if (value === null) {
33
+ return EMPTY_DATA_PLACEHOLDER;
34
+ }
26
35
  return formatBytes({value: convertToNumber(value), precision: 3});
27
36
  }
28
37
 
@@ -15,7 +15,7 @@ export interface MetricDescription {
15
15
  }
16
16
 
17
17
  export interface PreparedMetric extends MetricDescription {
18
- data: number[];
18
+ data: (number | null)[];
19
19
  }
20
20
 
21
21
  export interface PreparedMetricsData {
@@ -76,7 +76,7 @@ export const VirtualTable = <T,>({
76
76
 
77
77
  const [error, setError] = useState<IResponseError>();
78
78
 
79
- const [pendingRequests, setPendingRequests] = useState<Record<string, NodeJS.Timeout>>({});
79
+ const pendingRequests = useRef<Record<string, ReturnType<typeof setTimeout>>>({});
80
80
 
81
81
  const fetchChunkData = useCallback(
82
82
  async (id: string) => {
@@ -105,10 +105,13 @@ export const VirtualTable = <T,>({
105
105
  }
106
106
  }, DEFAULT_REQUEST_TIMEOUT);
107
107
 
108
- setPendingRequests((reqs) => {
109
- reqs[id] = timer;
110
- return reqs;
111
- });
108
+ // Chunk data load could be triggered by different events
109
+ // Cancel previous chunk request, while it is pending (instead of concurrentId)
110
+ if (pendingRequests.current[id]) {
111
+ const oldTimer = pendingRequests.current[id];
112
+ window.clearTimeout(oldTimer);
113
+ }
114
+ pendingRequests.current[id] = timer;
112
115
  },
113
116
  [fetchData, limit, sortParams],
114
117
  );
@@ -117,20 +120,27 @@ export const VirtualTable = <T,>({
117
120
  dispatch(initChunk(id));
118
121
  }, []);
119
122
 
120
- const onLeave = useCallback<OnLeave>(
121
- (id) => {
122
- dispatch(removeChunk(id));
123
+ const onLeave = useCallback<OnLeave>((id) => {
124
+ dispatch(removeChunk(id));
125
+
126
+ // If there is a pending request for the removed chunk, cancel it
127
+ // It made to prevent excessive requests on fast scroll
128
+ if (pendingRequests.current[id]) {
129
+ const timer = pendingRequests.current[id];
130
+ window.clearTimeout(timer);
131
+ delete pendingRequests.current[id];
132
+ }
133
+ }, []);
123
134
 
124
- // If there is a pending request for the removed chunk, cancel it
125
- // It made to prevent excessive requests on fast scroll
126
- if (pendingRequests[id]) {
127
- const timer = pendingRequests[id];
135
+ // Cancel all pending requests on component unmount
136
+ useEffect(() => {
137
+ return () => {
138
+ Object.values(pendingRequests.current).forEach((timer) => {
128
139
  window.clearTimeout(timer);
129
- delete pendingRequests[id];
130
- }
131
- },
132
- [pendingRequests],
133
- );
140
+ });
141
+ pendingRequests.current = {};
142
+ };
143
+ }, []);
134
144
 
135
145
  // Load chunks if they become active
136
146
  // This mecanism helps to set chunk active state from different sources, but load data only once
@@ -71,6 +71,8 @@ export const COLORS_PRIORITY = {
71
71
 
72
72
  export const TENANT_OVERVIEW_TABLES_LIMIT = 5;
73
73
 
74
+ export const EMPTY_DATA_PLACEHOLDER = '—';
75
+
74
76
  // ==== Titles ====
75
77
  export const DEVELOPER_UI_TITLE = 'Developer UI';
76
78
  export const CLUSTER_DEFAULT_TITLE = 'Cluster';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ydb-embedded-ui",
3
- "version": "4.31.0",
3
+ "version": "4.31.2",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -53,9 +53,9 @@
53
53
  "scripts": {
54
54
  "start": "react-app-rewired start",
55
55
  "dev": "DISABLE_ESLINT_PLUGIN=true TSC_COMPILE_ON_ERROR=true REACT_APP_BACKEND=http://localhost:8765 npm start",
56
- "build": "DISABLE_ESLINT_PLUGIN=true react-app-rewired build",
56
+ "build": "rm -rf build && DISABLE_ESLINT_PLUGIN=true react-app-rewired build",
57
57
  "//build:embedded": "echo 'PUBLIC_URL is a setting for create-react-app. Embedded version is built and hosted as is on ydb servers, with no way of knowing the final URL pattern. PUBLIC_URL=. keeps paths to all static relative, allowing servers to handle them as needed'",
58
- "build:embedded": "rm -rf build && PUBLIC_URL=. REACT_APP_BACKEND=http://localhost:8765 npm run build",
58
+ "build:embedded": "GENERATE_SOURCEMAP=false PUBLIC_URL=. REACT_APP_BACKEND=http://localhost:8765 npm run build",
59
59
  "lint:styles": "stylelint 'src/**/*.scss'",
60
60
  "unimported": "npx unimported --no-cache",
61
61
  "package": "rm -rf dist && copyfiles -u 1 'src/**/*' dist",