@parca/profile 0.19.143 → 0.19.145

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 (30) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/MatchersInput/SuggestionsList.d.ts.map +1 -1
  3. package/dist/MatchersInput/SuggestionsList.js +73 -63
  4. package/dist/MatchersInput/index.d.ts.map +1 -1
  5. package/dist/MatchersInput/index.js +4 -5
  6. package/dist/ProfileTypeSelector/index.d.ts.map +1 -1
  7. package/dist/ProfileTypeSelector/index.js +33 -52
  8. package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -1
  9. package/dist/ProfileView/components/ColorStackLegend.js +70 -118
  10. package/dist/ProfileView/components/ProfileFilters/index.d.ts.map +1 -1
  11. package/dist/ProfileView/components/ProfileFilters/index.js +0 -1
  12. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -1
  13. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.js +319 -123
  14. package/dist/SelectWithRefresh/index.js +38 -33
  15. package/dist/SimpleMatchers/Select.d.ts.map +1 -1
  16. package/dist/SimpleMatchers/Select.js +63 -68
  17. package/dist/SourceView/Highlighter.d.ts.map +1 -1
  18. package/dist/SourceView/Highlighter.js +1 -1
  19. package/dist/useQuery.js +2 -1
  20. package/package.json +3 -3
  21. package/src/MatchersInput/SuggestionsList.tsx +71 -86
  22. package/src/MatchersInput/index.tsx +61 -74
  23. package/src/ProfileTypeSelector/index.tsx +4 -7
  24. package/src/ProfileView/components/ColorStackLegend.tsx +15 -23
  25. package/src/ProfileView/components/ProfileFilters/index.tsx +8 -13
  26. package/src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx +113 -115
  27. package/src/SelectWithRefresh/index.tsx +28 -28
  28. package/src/SimpleMatchers/Select.tsx +29 -37
  29. package/src/SourceView/Highlighter.tsx +2 -2
  30. package/src/useQuery.tsx +1 -1
@@ -32,7 +32,7 @@ import { c as _c } from "react-compiler-runtime";
32
32
  // See the License for the specific language governing permissions and
33
33
  // limitations under the License.
34
34
 
35
- import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
35
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
36
36
  import { Icon } from '@iconify/react';
37
37
  import { useVirtualizer } from '@tanstack/react-virtual';
38
38
  import cx from 'classnames';
@@ -41,6 +41,7 @@ import { Button, DividerWithLabel, RefreshButton, useParcaContext } from '@parca
41
41
  import { TEST_IDS, testId } from '@parca/test-utils/dist/test-ids';
42
42
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
43
43
  var CustomSelect = function CustomSelect(_ref) {
44
+ var _filteredItems$reduce, _filteredItems$reduce2;
44
45
  var itemsProp = _ref.items,
45
46
  selectedKey = _ref.selectedKey,
46
47
  onSelection = _ref.onSelection,
@@ -92,29 +93,34 @@ var CustomSelect = function CustomSelect(_ref) {
92
93
  var containerRef = useRef(null);
93
94
  var optionsRef = useRef(null);
94
95
  var searchInputRef = useRef(null);
95
- var handleRefetch = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
96
- return _regenerator().w(function (_context) {
97
- while (1) switch (_context.p = _context.n) {
98
- case 0:
99
- if (!(refetchValues == null || isRefetching)) {
100
- _context.n = 1;
101
- break;
102
- }
103
- return _context.a(2);
104
- case 1:
105
- setIsRefetching(true);
106
- _context.p = 2;
107
- _context.n = 3;
108
- return refetchValues();
109
- case 3:
110
- _context.p = 3;
111
- setIsRefetching(false);
112
- return _context.f(3);
113
- case 4:
114
- return _context.a(2);
115
- }
116
- }, _callee, null, [[2,, 3, 4]]);
117
- })), [refetchValues, isRefetching]);
96
+ var handleRefetch = /*#__PURE__*/function () {
97
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee() {
98
+ return _regenerator().w(function (_context) {
99
+ while (1) switch (_context.p = _context.n) {
100
+ case 0:
101
+ if (!(refetchValues == null || isRefetching)) {
102
+ _context.n = 1;
103
+ break;
104
+ }
105
+ return _context.a(2);
106
+ case 1:
107
+ setIsRefetching(true);
108
+ _context.p = 2;
109
+ _context.n = 3;
110
+ return refetchValues();
111
+ case 3:
112
+ _context.p = 3;
113
+ setIsRefetching(false);
114
+ return _context.f(3);
115
+ case 4:
116
+ return _context.a(2);
117
+ }
118
+ }, _callee, null, [[2,, 3, 4]]);
119
+ }));
120
+ return function handleRefetch() {
121
+ return _ref2.apply(this, arguments);
122
+ };
123
+ }();
118
124
  useEffect(function () {
119
125
  var timer = setTimeout(function () {
120
126
  return setDebouncedSearchTerm(searchTerm);
@@ -123,23 +129,18 @@ var CustomSelect = function CustomSelect(_ref) {
123
129
  return clearTimeout(timer);
124
130
  };
125
131
  }, [searchTerm]);
126
- var items = useMemo(function () {
127
- if (itemsProp[0] != null && 'type' in itemsProp[0]) {
128
- return itemsProp.flatMap(function (item) {
129
- return item.values.map(function (v) {
130
- return _objectSpread(_objectSpread({}, v), {}, {
131
- type: item.type
132
- });
133
- });
134
- });
135
- }
136
- return itemsProp.map(function (item_0) {
137
- return _objectSpread(_objectSpread({}, item_0), {}, {
138
- type: ''
132
+ var items = itemsProp[0] != null && 'type' in itemsProp[0] ? itemsProp.flatMap(function (item) {
133
+ return item.values.map(function (v) {
134
+ return _objectSpread(_objectSpread({}, v), {}, {
135
+ type: item.type
139
136
  });
140
137
  });
141
- }, [itemsProp]);
142
- var filteredItems = useMemo(function () {
138
+ }) : itemsProp.map(function (item_0) {
139
+ return _objectSpread(_objectSpread({}, item_0), {}, {
140
+ type: ''
141
+ });
142
+ });
143
+ var computeFilteredItems = function computeFilteredItems() {
143
144
  if (!searchable) return items;
144
145
  var lowerSearch = debouncedSearchTerm.toLowerCase();
145
146
  var filtered = items.filter(function (item_1) {
@@ -153,7 +154,8 @@ var CustomSelect = function CustomSelect(_ref) {
153
154
  return filtered.sort(function (a_0, b_0) {
154
155
  return levenshtein.get(a_0.key, debouncedSearchTerm) - levenshtein.get(b_0.key, debouncedSearchTerm);
155
156
  });
156
- }, [items, debouncedSearchTerm, searchable]);
157
+ };
158
+ var filteredItems = computeFilteredItems();
157
159
  var selection = editable ? selectedKey : items.find(function (v_0) {
158
160
  return v_0.key === selectedKey;
159
161
  });
@@ -252,29 +254,25 @@ var CustomSelect = function CustomSelect(_ref) {
252
254
  e_0.target.value = '';
253
255
  e_0.target.value = value_0;
254
256
  };
255
- var groupedFilteredItems = useMemo(function () {
256
- return filteredItems.reduce(function (acc, item_2) {
257
- var group = acc.find(function (g) {
258
- return g.type === item_2.type;
259
- });
260
- if (group != null) {
261
- group.values.push(item_2);
262
- } else {
263
- acc.push({
264
- type: item_2.type,
265
- values: [item_2]
266
- });
267
- }
268
- return acc;
269
- }, []).sort(function (a_1, b_1) {
270
- return a_1.values.length - b_1.values.length;
271
- });
272
- }, [filteredItems]);
273
- var showHeaders = useMemo(function () {
274
- return groupedFilteredItems.length > 1 && groupedFilteredItems.every(function (g_0) {
275
- return g_0.type !== '';
257
+ var groupedFilteredItems = filteredItems.reduce(function (acc, item_2) {
258
+ var group = acc.find(function (g) {
259
+ return g.type === item_2.type;
276
260
  });
277
- }, [groupedFilteredItems]);
261
+ if (group != null) {
262
+ group.values.push(item_2);
263
+ } else {
264
+ acc.push({
265
+ type: item_2.type,
266
+ values: [item_2]
267
+ });
268
+ }
269
+ return acc;
270
+ }, []).sort(function (a_1, b_1) {
271
+ return a_1.values.length - b_1.values.length;
272
+ });
273
+ var showHeaders = groupedFilteredItems.length > 1 && groupedFilteredItems.every(function (g_0) {
274
+ return g_0.type !== '';
275
+ });
278
276
  var flatList = useMemo(function () {
279
277
  var list = [];
280
278
  var optionIndex = 0;
@@ -314,12 +312,9 @@ var CustomSelect = function CustomSelect(_ref) {
314
312
  }
315
313
  return list;
316
314
  }, [groupedFilteredItems, showHeaders]);
317
- var longestKey = useMemo(function () {
318
- var _filteredItems$reduce, _filteredItems$reduce2;
319
- return (_filteredItems$reduce = (_filteredItems$reduce2 = filteredItems.reduce(function (a_2, b_2) {
320
- return a_2.key.length > b_2.key.length ? a_2 : b_2;
321
- }, filteredItems[0])) === null || _filteredItems$reduce2 === void 0 ? void 0 : _filteredItems$reduce2.key) !== null && _filteredItems$reduce !== void 0 ? _filteredItems$reduce : '';
322
- }, [filteredItems]);
315
+ var longestKey = (_filteredItems$reduce = (_filteredItems$reduce2 = filteredItems.reduce(function (a_2, b_2) {
316
+ return a_2.key.length > b_2.key.length ? a_2 : b_2;
317
+ }, filteredItems[0])) === null || _filteredItems$reduce2 === void 0 ? void 0 : _filteredItems$reduce2.key) !== null && _filteredItems$reduce !== void 0 ? _filteredItems$reduce : '';
323
318
  var rowVirtualizer = useVirtualizer({
324
319
  count: flatList.length,
325
320
  getScrollElement: function getScrollElement() {
@@ -1 +1 @@
1
- {"version":3,"file":"Highlighter.d.ts","sourceRoot":"","sources":["../../src/SourceView/Highlighter.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,iBAAiB,EAAiB,MAAM,OAAO,CAAC;AAIxD,OAAO,EAAC,KAAK,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAcjE,UAAU,aAAa;IAErB,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,UAAU,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAC7C,eAAe,EAAE,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;CACxD;AAED,KAAK,QAAQ,GAAG,CAAC,EAAC,IAAI,EAAE,UAAU,EAAE,eAAe,EAAC,EAAE,aAAa,KAAK,GAAG,CAAC,OAAO,CAAC;AAEpF,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAuED,MAAM,MAAM,cAAc,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GAAG,SAAS,CAAC;AAEpG,eAAO,MAAM,oBAAoB,GAC/B,aAAa,cAAc,EAC3B,OAAO,MAAM,EACb,UAAU,MAAM,EAChB,eAAe,iBAAiB,CAAC,cAAc,CAAC,KAC/C,QAqEF,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,6BAA2B,gBAAgB,KAAG,GAAG,CAAC,OAyC7E,CAAC"}
1
+ {"version":3,"file":"Highlighter.d.ts","sourceRoot":"","sources":["../../src/SourceView/Highlighter.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,iBAAiB,EAAQ,MAAM,OAAO,CAAC;AAI/C,OAAO,EAAC,KAAK,kBAAkB,EAAC,MAAM,0BAA0B,CAAC;AAcjE,UAAU,aAAa;IAErB,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,UAAU,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAC7C,eAAe,EAAE,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;CACxD;AAED,KAAK,QAAQ,GAAG,CAAC,EAAC,IAAI,EAAE,UAAU,EAAE,eAAe,EAAC,EAAE,aAAa,KAAK,GAAG,CAAC,OAAO,CAAC;AAEpF,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAuED,MAAM,MAAM,cAAc,GAAG,CAAC,UAAU,EAAE,MAAM,KAAK;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GAAG,SAAS,CAAC;AAEpG,eAAO,MAAM,oBAAoB,GAC/B,aAAa,cAAc,EAC3B,OAAO,MAAM,EACb,UAAU,MAAM,EAChB,eAAe,iBAAiB,CAAC,cAAc,CAAC,KAC/C,QAqEF,CAAC;AAEF,eAAO,MAAM,WAAW,GAAI,6BAA2B,gBAAgB,KAAG,GAAG,CAAC,OAyC7E,CAAC"}
@@ -12,7 +12,7 @@ import { c as _c } from "react-compiler-runtime";
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
 
15
- import { useId, useMemo } from 'react';
15
+ import { useId } from 'react';
16
16
  import cx from 'classnames';
17
17
  import { scaleLinear } from 'd3-scale';
18
18
  import createElement from 'react-syntax-highlighter/dist/cjs/create-element';
package/dist/useQuery.js CHANGED
@@ -47,7 +47,8 @@ export var useQuery = function useQuery(client, profileSource, reportType, optio
47
47
  var protoFiltersKey = t2;
48
48
  var t3;
49
49
  if ($[4] !== profileSource) {
50
- t3 = profileSource.toKey();
50
+ var _profileSource$toKey;
51
+ t3 = (_profileSource$toKey = profileSource === null || profileSource === void 0 ? void 0 : profileSource.toKey()) !== null && _profileSource$toKey !== void 0 ? _profileSource$toKey : "";
51
52
  $[4] = profileSource;
52
53
  $[5] = t3;
53
54
  } else {
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.19.143",
3
+ "version": "0.19.145",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@floating-ui/react": "^0.27.12",
7
7
  "@headlessui/react": "^1.7.19",
8
8
  "@iconify/react": "^4.0.0",
9
9
  "@parca/client": "0.17.23",
10
- "@parca/components": "0.16.415",
10
+ "@parca/components": "0.16.416",
11
11
  "@parca/dynamicsize": "0.16.74",
12
12
  "@parca/hooks": "0.0.125",
13
13
  "@parca/icons": "0.16.82",
@@ -89,5 +89,5 @@
89
89
  "access": "public",
90
90
  "registry": "https://registry.npmjs.org/"
91
91
  },
92
- "gitHead": "04513bb1ef009ded310263c5381cbebb004826e0"
92
+ "gitHead": "125dbac3accf1ebbac6df49dcd72a38c1e6b4d39"
93
93
  }
@@ -11,7 +11,7 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import React, {Fragment, useCallback, useEffect, useState} from 'react';
14
+ import React, {Fragment, useEffect, useState} from 'react';
15
15
 
16
16
  import {Transition} from '@headlessui/react';
17
17
  import {usePopper} from 'react-popper';
@@ -90,7 +90,7 @@ const SuggestionsList = ({
90
90
  const [isRefetchingValues, setIsRefetchingValues] = useState(false);
91
91
  const [isRefetchingNames, setIsRefetchingNames] = useState(false);
92
92
 
93
- const handleRefetchValues = useCallback(async () => {
93
+ const handleRefetchValues = async (): Promise<void> => {
94
94
  if (isRefetchingValues) return;
95
95
 
96
96
  setIsRefetchingValues(true);
@@ -99,9 +99,9 @@ const SuggestionsList = ({
99
99
  } finally {
100
100
  setIsRefetchingValues(false);
101
101
  }
102
- }, [refetchLabelValues, isRefetchingValues]);
102
+ };
103
103
 
104
- const handleRefetchNames = useCallback(async () => {
104
+ const handleRefetchNames = async (): Promise<void> => {
105
105
  if (isRefetchingNames) return;
106
106
 
107
107
  setIsRefetchingNames(true);
@@ -110,54 +110,45 @@ const SuggestionsList = ({
110
110
  } finally {
111
111
  setIsRefetchingNames(false);
112
112
  }
113
- }, [refetchLabelNames, isRefetchingNames]);
113
+ };
114
114
 
115
115
  const suggestionsLength =
116
116
  suggestions.literals.length + suggestions.labelNames.length + suggestions.labelValues.length;
117
117
 
118
- const getSuggestion = useCallback(
119
- (index: number): Suggestion => {
120
- if (index < suggestions.labelNames.length) {
121
- return suggestions.labelNames[index];
122
- }
123
- if (index < suggestions.labelNames.length + suggestions.literals.length) {
124
- return suggestions.literals[index - suggestions.labelNames.length];
125
- }
126
- return suggestions.labelValues[
127
- index - suggestions.labelNames.length - suggestions.literals.length
128
- ];
129
- },
130
- [suggestions]
131
- );
118
+ const getSuggestion = (index: number): Suggestion => {
119
+ if (index < suggestions.labelNames.length) {
120
+ return suggestions.labelNames[index];
121
+ }
122
+ if (index < suggestions.labelNames.length + suggestions.literals.length) {
123
+ return suggestions.literals[index - suggestions.labelNames.length];
124
+ }
125
+ return suggestions.labelValues[
126
+ index - suggestions.labelNames.length - suggestions.literals.length
127
+ ];
128
+ };
132
129
 
133
- const resetHighlight = useCallback(
134
- (): void => setHighlightedSuggestionIndex(-1),
135
- [setHighlightedSuggestionIndex]
136
- );
130
+ const resetHighlight = (): void => setHighlightedSuggestionIndex(-1);
137
131
 
138
- const applyHighlightedSuggestion = useCallback((): void => {
132
+ const applyHighlightedSuggestion = (): void => {
139
133
  applySuggestion(getSuggestion(highlightedSuggestionIndex));
140
134
  resetHighlight();
141
- }, [resetHighlight, applySuggestion, highlightedSuggestionIndex, getSuggestion]);
135
+ };
142
136
 
143
- const applySuggestionWithIndex = useCallback(
144
- (index: number): void => {
145
- applySuggestion(getSuggestion(index));
146
- resetHighlight();
147
- },
148
- [resetHighlight, applySuggestion, getSuggestion]
149
- );
137
+ const applySuggestionWithIndex = (index: number): void => {
138
+ applySuggestion(getSuggestion(index));
139
+ resetHighlight();
140
+ };
150
141
 
151
- const highlightNext = useCallback((): void => {
142
+ const highlightNext = (): void => {
152
143
  const nextIndex = highlightedSuggestionIndex + 1;
153
144
  if (nextIndex === suggestionsLength) {
154
145
  resetHighlight();
155
146
  return;
156
147
  }
157
148
  setHighlightedSuggestionIndex(nextIndex);
158
- }, [highlightedSuggestionIndex, suggestionsLength, resetHighlight]);
149
+ };
159
150
 
160
- const highlightPrevious = useCallback((): void => {
151
+ const highlightPrevious = (): void => {
161
152
  if (highlightedSuggestionIndex === -1) {
162
153
  // Didn't select anything, so starting at the bottom.
163
154
  setHighlightedSuggestionIndex(suggestionsLength - 1);
@@ -165,66 +156,60 @@ const SuggestionsList = ({
165
156
  }
166
157
 
167
158
  setHighlightedSuggestionIndex(highlightedSuggestionIndex - 1);
168
- }, [highlightedSuggestionIndex, suggestionsLength]);
159
+ };
169
160
 
170
- const handleKeyPress = useCallback(
171
- (event: React.KeyboardEvent<HTMLTextAreaElement>): void => {
172
- if (event.key === 'Enter') {
173
- // Disable new line in the text area
174
- event.preventDefault();
175
- }
176
- // If there is a highlighted suggestion and enter is hit, we complete
177
- // with the highlighted suggestion.
178
- if (highlightedSuggestionIndex >= 0 && event.key === 'Enter') {
179
- applyHighlightedSuggestion();
180
- }
181
-
182
- // If no suggestions is highlighted and we hit enter, we run the query,
183
- // and hide suggestions until another actions enables them again.
184
- if (highlightedSuggestionIndex === -1 && event.key === 'Enter') {
185
- setShowSuggest(false);
186
- runQuery();
187
- return;
188
- }
161
+ const handleKeyPress = (event: React.KeyboardEvent<HTMLTextAreaElement>): void => {
162
+ if (event.key === 'Enter') {
163
+ // Disable new line in the text area
164
+ event.preventDefault();
165
+ }
166
+ // If there is a highlighted suggestion and enter is hit, we complete
167
+ // with the highlighted suggestion.
168
+ if (highlightedSuggestionIndex >= 0 && event.key === 'Enter') {
169
+ applyHighlightedSuggestion();
170
+ }
189
171
 
190
- setShowSuggest(true);
191
- },
192
- [highlightedSuggestionIndex, applyHighlightedSuggestion, runQuery]
193
- );
172
+ // If no suggestions is highlighted and we hit enter, we run the query,
173
+ // and hide suggestions until another actions enables them again.
174
+ if (highlightedSuggestionIndex === -1 && event.key === 'Enter') {
175
+ setShowSuggest(false);
176
+ runQuery();
177
+ return;
178
+ }
194
179
 
195
- const handleKeyDown = useCallback(
196
- (event: KeyboardEvent): void => {
197
- // Don't need to handle any key interactions if no suggestions there.
198
- if (suggestionsLength === 0 || !['Tab', 'ArrowUp', 'ArrowDown'].includes(event.key)) {
199
- return;
200
- }
180
+ setShowSuggest(true);
181
+ };
201
182
 
202
- event.preventDefault();
183
+ const handleKeyDown = (event: KeyboardEvent): void => {
184
+ // Don't need to handle any key interactions if no suggestions there.
185
+ if (suggestionsLength === 0 || !['Tab', 'ArrowUp', 'ArrowDown'].includes(event.key)) {
186
+ return;
187
+ }
203
188
 
204
- // Handle tabbing through suggestions.
205
- if (event.key === 'Tab' && suggestionsLength > 0) {
206
- event.preventDefault();
207
- if (event.shiftKey) {
208
- // Shift + tab goes up.
209
- highlightPrevious();
210
- return;
211
- }
212
- // Just tab goes down.
213
- highlightNext();
214
- }
189
+ event.preventDefault();
215
190
 
216
- // Up arrow highlights previous suggestions.
217
- if (event.key === 'ArrowUp') {
191
+ // Handle tabbing through suggestions.
192
+ if (event.key === 'Tab' && suggestionsLength > 0) {
193
+ event.preventDefault();
194
+ if (event.shiftKey) {
195
+ // Shift + tab goes up.
218
196
  highlightPrevious();
197
+ return;
219
198
  }
199
+ // Just tab goes down.
200
+ highlightNext();
201
+ }
220
202
 
221
- // Down arrow highlights next suggestions.
222
- if (event.key === 'ArrowDown') {
223
- highlightNext();
224
- }
225
- },
226
- [suggestionsLength, highlightNext, highlightPrevious]
227
- );
203
+ // Up arrow highlights previous suggestions.
204
+ if (event.key === 'ArrowUp') {
205
+ highlightPrevious();
206
+ }
207
+
208
+ // Down arrow highlights next suggestions.
209
+ if (event.key === 'ArrowDown') {
210
+ highlightNext();
211
+ }
212
+ };
228
213
 
229
214
  useEffect(() => {
230
215
  const el = inputRef.current;
@@ -11,7 +11,7 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import React, {useMemo, useRef, useState} from 'react';
14
+ import React, {useRef, useState} from 'react';
15
15
 
16
16
  import cx from 'classnames';
17
17
  import TextareaAutosize from 'react-textarea-autosize';
@@ -48,91 +48,78 @@ const MatchersInput = ({setDraftMatchers, draftParsedQuery, commitDraft}: Props)
48
48
 
49
49
  const value = draftParsedQuery != null ? draftParsedQuery.matchersString() : '';
50
50
 
51
- const suggestionSections = useMemo(() => {
52
- const suggestionSections = new Suggestions();
53
- Query.suggest(`${draftParsedQuery?.profileName() as string}{${value}`).forEach(function (s) {
54
- // Skip suggestions that we just completed. This really only works,
55
- // because we know the language is not repetitive. For a language that
56
- // has a repeating word, this would not work.
57
- if (lastCompleted !== null && lastCompleted.type === s.type) {
58
- return;
59
- }
51
+ const suggestionSections = new Suggestions();
52
+ Query.suggest(`${draftParsedQuery?.profileName() as string}{${value}`).forEach(function (s) {
53
+ // Skip suggestions that we just completed. This really only works,
54
+ // because we know the language is not repetitive. For a language that
55
+ // has a repeating word, this would not work.
56
+ if (lastCompleted !== null && lastCompleted.type === s.type) {
57
+ return;
58
+ }
60
59
 
61
- // Need to figure out if any literal suggestions make sense, but a
62
- // closing bracket doesn't in the guided query experience because all
63
- // we have the user do is type the matchers.
64
- if (s.type === 'literal' && s.value !== '}') {
65
- suggestionSections.literals.push({
60
+ // Need to figure out if any literal suggestions make sense, but a
61
+ // closing bracket doesn't in the guided query experience because all
62
+ // we have the user do is type the matchers.
63
+ if (s.type === 'literal' && s.value !== '}') {
64
+ suggestionSections.literals.push({
65
+ type: s.type,
66
+ typeahead: s.typeahead,
67
+ value: s.value,
68
+ });
69
+ }
70
+ if (s.type === 'labelName') {
71
+ const inputValue = s.typeahead.trim().toLowerCase();
72
+ const inputLength = inputValue.length;
73
+ const matches = labelNames.filter(function (label) {
74
+ return label.toLowerCase().slice(0, inputLength) === inputValue;
75
+ });
76
+
77
+ matches.forEach(m => {
78
+ const suggestion = {
66
79
  type: s.type,
67
80
  typeahead: s.typeahead,
68
- value: s.value,
69
- });
70
- }
71
- if (s.type === 'labelName') {
72
- const inputValue = s.typeahead.trim().toLowerCase();
73
- const inputLength = inputValue.length;
74
- const matches = labelNames.filter(function (label) {
75
- return label.toLowerCase().slice(0, inputLength) === inputValue;
76
- });
77
-
78
- matches.forEach(m => {
79
- const suggestion = {
80
- type: s.type,
81
- typeahead: s.typeahead,
82
- value: m,
83
- };
84
-
85
- if (shouldHandlePrefixes) {
86
- const mapping = labelNameMappings.find(l => l.displayName === m);
87
- if (mapping != null) {
88
- (suggestion as any).fullName = mapping.fullName;
89
- }
90
- }
91
-
92
- suggestionSections.labelNames.push(suggestion);
93
- });
94
- }
95
-
96
- if (s.type === 'labelValue') {
97
- let labelNameForQuery = s.labelName;
81
+ value: m,
82
+ };
98
83
 
99
84
  if (shouldHandlePrefixes) {
100
- const mapping = labelNameMappings.find(l => l.displayName === s.labelName);
85
+ const mapping = labelNameMappings.find(l => l.displayName === m);
101
86
  if (mapping != null) {
102
- labelNameForQuery = mapping.fullName;
87
+ (suggestion as any).fullName = mapping.fullName;
103
88
  }
104
89
  }
105
90
 
106
- if (currentLabelName === null || labelNameForQuery !== currentLabelName) {
107
- setCurrentLabelName(labelNameForQuery);
108
- return;
109
- }
91
+ suggestionSections.labelNames.push(suggestion);
92
+ });
93
+ }
94
+
95
+ if (s.type === 'labelValue') {
96
+ let labelNameForQuery = s.labelName;
110
97
 
111
- if (labelValues !== null) {
112
- labelValues
113
- .filter(v => v.slice(0, s.typeahead.length) === s.typeahead)
114
- .forEach(v =>
115
- suggestionSections.labelValues.push({
116
- type: s.type,
117
- typeahead: s.typeahead,
118
- value: v,
119
- })
120
- );
98
+ if (shouldHandlePrefixes) {
99
+ const mapping = labelNameMappings.find(l => l.displayName === s.labelName);
100
+ if (mapping != null) {
101
+ labelNameForQuery = mapping.fullName;
121
102
  }
122
103
  }
123
- });
124
- return suggestionSections;
125
- }, [
126
- draftParsedQuery,
127
- lastCompleted,
128
- labelNames,
129
- labelValues,
130
- currentLabelName,
131
- value,
132
- shouldHandlePrefixes,
133
- labelNameMappings,
134
- setCurrentLabelName,
135
- ]);
104
+
105
+ if (currentLabelName === null || labelNameForQuery !== currentLabelName) {
106
+ setCurrentLabelName(labelNameForQuery);
107
+ return;
108
+ }
109
+
110
+ if (labelValues !== null) {
111
+ labelValues
112
+ .filter(v => v.slice(0, s.typeahead.length) === s.typeahead)
113
+ .forEach(v =>
114
+ suggestionSections.labelValues.push({
115
+ type: s.type,
116
+ typeahead: s.typeahead,
117
+ value: v,
118
+ })
119
+ );
120
+ }
121
+ }
122
+ });
136
123
 
137
124
  const resetLastCompleted = (): void => setLastCompleted(new Suggestion('', '', ''));
138
125
 
@@ -11,8 +11,6 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import {useMemo} from 'react';
15
-
16
14
  import {RpcError} from '@protobuf-ts/runtime-rpc';
17
15
 
18
16
  import {ProfileType, ProfileTypesResponse} from '@parca/client';
@@ -180,13 +178,12 @@ const ProfileTypeSelector = ({
180
178
  flexibleKnownProfilesDetection = false,
181
179
  disabled,
182
180
  }: Props): JSX.Element => {
183
- const profileNames = useMemo(() => {
184
- return (error === undefined || error == null) &&
185
- profileTypesData !== undefined &&
186
- profileTypesData != null
181
+ const profileNames =
182
+ (error === undefined || error == null) &&
183
+ profileTypesData !== undefined &&
184
+ profileTypesData != null
187
185
  ? normalizeProfileTypesData(profileTypesData.types)
188
186
  : [];
189
- }, [profileTypesData, error]);
190
187
 
191
188
  const profileLabels = (
192
189
  profileNames.length > 0 ? profileNames : selectedKey != null ? [selectedKey] : []