@parca/profile 0.19.62 → 0.19.63

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,10 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.19.63](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.62...@parca/profile@0.19.63) (2025-10-10)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
6
10
  ## [0.19.62](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.61...@parca/profile@0.19.62) (2025-10-08)
7
11
 
8
12
  **Note:** Version bump only for package @parca/profile
@@ -20,7 +20,8 @@ interface Props {
20
20
  isLabelValuesLoading: boolean;
21
21
  shouldTrimPrefix: boolean;
22
22
  refetchLabelValues: () => void;
23
+ refetchLabelNames: () => void;
23
24
  }
24
- declare const SuggestionsList: ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, shouldTrimPrefix, refetchLabelValues, }: Props) => JSX.Element;
25
+ declare const SuggestionsList: ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, shouldTrimPrefix, refetchLabelValues, refetchLabelNames, }: Props) => JSX.Element;
25
26
  export default SuggestionsList;
26
27
  //# sourceMappingURL=SuggestionsList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SuggestionsList.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/SuggestionsList.tsx"],"names":[],"mappings":"AAwBA,qBAAa,UAAU;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;gBAEF,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAK3D;AAED,qBAAa,WAAW;IACtB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,WAAW,EAAE,UAAU,EAAE,CAAC;;CAO3B;AAED,UAAU,KAAK;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAClD,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,MAAM,IAAI,CAAC;CAChC;AAaD,QAAA,MAAM,eAAe,GAAI,sJAUtB,KAAK,KAAG,GAAG,CAAC,OAwSd,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"SuggestionsList.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/SuggestionsList.tsx"],"names":[],"mappings":"AAyBA,qBAAa,UAAU;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;gBAEF,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAK3D;AAED,qBAAa,WAAW;IACtB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,UAAU,EAAE,UAAU,EAAE,CAAC;IACzB,WAAW,EAAE,UAAU,EAAE,CAAC;;CAO3B;AAED,UAAU,KAAK;IACb,WAAW,EAAE,WAAW,CAAC;IACzB,eAAe,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IAClD,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,MAAM,IAAI,CAAC;CAC/B;AAkDD,QAAA,MAAM,eAAe,GAAI,yKAWtB,KAAK,KAAG,GAAG,CAAC,OAkUd,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  // Copyright 2022 The Parca Authors
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@ import { Icon } from '@iconify/react';
17
17
  import cx from 'classnames';
18
18
  import { usePopper } from 'react-popper';
19
19
  import { useParcaContext } from '@parca/components';
20
+ import { TEST_IDS, testId } from '@parca/test-utils';
20
21
  import SuggestionItem from './SuggestionItem';
21
22
  export class Suggestion {
22
23
  constructor(type, typeahead, value) {
@@ -36,29 +37,50 @@ const LoadingSpinner = () => {
36
37
  const { loader: Spinner } = useParcaContext();
37
38
  return _jsx("div", { className: "pt-2 pb-4", children: Spinner });
38
39
  };
40
+ const RefreshButton = ({ onClick, disabled, title, testId }) => {
41
+ return (_jsx("div", { className: "absolute w-full flex items-center justify-center bottom-0 px-3 py-2 bg-gray-50 dark:bg-gray-900", children: _jsxs("button", { onClick: e => {
42
+ e.preventDefault();
43
+ e.stopPropagation();
44
+ onClick();
45
+ }, disabled: disabled, className: cx('py-1 px-2 flex items-center gap-1 rounded-full transition-all duration-200 w-auto justify-center', disabled
46
+ ? 'cursor-wait opacity-50'
47
+ : 'hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer'), title: title, type: "button", "data-testid": testId, children: [_jsx(Icon, { icon: "system-uicons:reset", className: cx('w-3 h-3 text-gray-500 dark:text-gray-400', disabled && 'animate-spin') }), _jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Refresh results" })] }) }));
48
+ };
39
49
  const transformLabelsForSuggestions = (labelNames, shouldTrimPrefix = false) => {
40
50
  const trimmedLabel = shouldTrimPrefix ? labelNames.split('.').pop() ?? labelNames : labelNames;
41
51
  return trimmedLabel;
42
52
  };
43
- const SuggestionsList = ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, shouldTrimPrefix = false, refetchLabelValues, }) => {
53
+ const SuggestionsList = ({ suggestions, applySuggestion, inputRef, runQuery, focusedInput, isLabelNamesLoading, isLabelValuesLoading, shouldTrimPrefix = false, refetchLabelValues, refetchLabelNames, }) => {
44
54
  const [popperElement, setPopperElement] = useState(null);
45
55
  const { styles, attributes } = usePopper(inputRef, popperElement, {
46
56
  placement: 'bottom-start',
47
57
  });
48
58
  const [highlightedSuggestionIndex, setHighlightedSuggestionIndex] = useState(-1);
49
59
  const [showSuggest, setShowSuggest] = useState(true);
50
- const [isRefetching, setIsRefetching] = useState(false);
51
- const handleRefetch = useCallback(async () => {
52
- if (isRefetching)
60
+ const [isRefetchingValues, setIsRefetchingValues] = useState(false);
61
+ const [isRefetchingNames, setIsRefetchingNames] = useState(false);
62
+ const handleRefetchValues = useCallback(async () => {
63
+ if (isRefetchingValues)
53
64
  return;
54
- setIsRefetching(true);
65
+ setIsRefetchingValues(true);
55
66
  try {
56
67
  await refetchLabelValues();
57
68
  }
58
69
  finally {
59
- setIsRefetching(false);
70
+ setIsRefetchingValues(false);
71
+ }
72
+ }, [refetchLabelValues, isRefetchingValues]);
73
+ const handleRefetchNames = useCallback(async () => {
74
+ if (isRefetchingNames)
75
+ return;
76
+ setIsRefetchingNames(true);
77
+ try {
78
+ await refetchLabelNames();
79
+ }
80
+ finally {
81
+ setIsRefetchingNames(false);
60
82
  }
61
- }, [refetchLabelValues, isRefetching]);
83
+ }, [refetchLabelNames, isRefetchingNames]);
62
84
  const suggestionsLength = suggestions.literals.length + suggestions.labelNames.length + suggestions.labelValues.length;
63
85
  const getSuggestion = useCallback((index) => {
64
86
  if (index < suggestions.labelNames.length) {
@@ -150,14 +172,15 @@ const SuggestionsList = ({ suggestions, applySuggestion, inputRef, runQuery, foc
150
172
  inputRef.removeEventListener('keypress', handleKeyPress);
151
173
  };
152
174
  }, [inputRef, highlightedSuggestionIndex, suggestions, handleKeyPress, handleKeyDown]);
153
- return (_jsx(_Fragment, { children: suggestionsLength > 0 && (_jsx("div", { ref: setPopperElement, style: { ...styles.popper, marginLeft: 0 }, ...attributes.popper, className: "z-50", children: _jsx(Transition, { show: focusedInput && showSuggest, as: Fragment, leave: "transition ease-in duration-100", leaveFrom: "opacity-100", leaveTo: "opacity-0", children: _jsx("div", { style: { width: inputRef?.offsetWidth }, className: "absolute z-10 mt-1 max-h-[400px] overflow-auto rounded-md bg-gray-50 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-900 sm:text-sm", children: _jsxs("div", { className: "relative pb-12", children: [isLabelNamesLoading ? (_jsx(LoadingSpinner, {})) : (_jsx(_Fragment, { children: suggestions.labelNames.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex === i, onHighlight: () => setHighlightedSuggestionIndex(i), onApplySuggestion: () => applySuggestionWithIndex(i), onResetHighlight: () => resetHighlight(), value: transformLabelsForSuggestions(l.value, shouldTrimPrefix) }, transformLabelsForSuggestions(l.value, shouldTrimPrefix)))) })), suggestions.literals.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex === i + suggestions.labelNames.length, onHighlight: () => setHighlightedSuggestionIndex(i + suggestions.labelNames.length), onApplySuggestion: () => applySuggestionWithIndex(i + suggestions.labelNames.length), onResetHighlight: () => resetHighlight(), value: l.value }, l.value))), isLabelValuesLoading ? (_jsx(LoadingSpinner, {})) : suggestions.labelNames.length === 0 && suggestions.literals.length === 0 ? (_jsxs(_Fragment, { children: [suggestions.labelValues.length === 0 ? (_jsx("div", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center", "data-testid": "suggestions-no-results", children: "No label values found" })) : (suggestions.labelValues.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex ===
154
- i + suggestions.labelNames.length + suggestions.literals.length, onHighlight: () => setHighlightedSuggestionIndex(i + suggestions.labelNames.length + suggestions.literals.length), onApplySuggestion: () => applySuggestionWithIndex(i + suggestions.labelNames.length + suggestions.literals.length), onResetHighlight: () => resetHighlight(), value: l.value }, l.value)))), _jsx("div", { className: "absolute w-full flex items-center justify-center bottom-0 px-3 py-2 bg-gray-50 dark:bg-gray-800", children: _jsxs("button", { onClick: e => {
155
- e.preventDefault();
156
- e.stopPropagation();
157
- void handleRefetch();
158
- }, disabled: isRefetching, className: cx('p-1 flex items-center gap-1 rounded-full transition-all duration-200 w-auto justify-center', isRefetching
159
- ? 'cursor-wait opacity-50'
160
- : 'hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer'), title: "Refresh label values", type: "button", "data-testid": "suggestions-refresh-button", children: [_jsx(Icon, { icon: "system-uicons:reset", className: cx('w-3 h-3 text-gray-500 dark:text-gray-400', isRefetching && 'animate-spin') }), _jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Refresh results" })] }) })] })) : (suggestions.labelValues.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex ===
175
+ useEffect(() => {
176
+ if (suggestionsLength > 0 && focusedInput) {
177
+ setShowSuggest(true);
178
+ }
179
+ }, [suggestionsLength, focusedInput]);
180
+ return (_jsx(_Fragment, { children: suggestionsLength > 0 && (_jsx("div", { ref: setPopperElement, style: { ...styles.popper, marginLeft: 0 }, ...attributes.popper, className: "z-50", children: _jsx(Transition, { show: focusedInput && showSuggest, as: Fragment, leave: "transition ease-in duration-100", leaveFrom: "opacity-100", leaveTo: "opacity-0", children: _jsx("div", { style: { width: inputRef?.offsetWidth }, className: "absolute z-10 mt-1 max-h-[400px] overflow-auto rounded-md bg-gray-50 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-900 sm:text-sm", children: _jsxs("div", { className: cx('relative', {
181
+ 'pb-12': suggestions.labelNames.length === 0 && suggestions.literals.length === 0,
182
+ }), children: [isLabelNamesLoading ? (_jsx(LoadingSpinner, {})) : suggestions.literals.length === 0 && suggestions.labelValues.length === 0 ? (_jsxs(_Fragment, { children: [suggestions.labelNames.length === 0 ? (_jsx("div", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center", ...testId(TEST_IDS.SUGGESTIONS_NO_RESULTS), children: "No label names found" })) : (suggestions.labelNames.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex === i, onHighlight: () => setHighlightedSuggestionIndex(i), onApplySuggestion: () => applySuggestionWithIndex(i), onResetHighlight: () => resetHighlight(), value: transformLabelsForSuggestions(l.value, shouldTrimPrefix) }, transformLabelsForSuggestions(l.value, shouldTrimPrefix))))), _jsx(RefreshButton, { onClick: () => void handleRefetchNames(), disabled: isRefetchingNames, title: "Refresh label names", testId: "suggestions-refresh-names-button" })] })) : (_jsx(_Fragment, { children: suggestions.labelNames.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex === i, onHighlight: () => setHighlightedSuggestionIndex(i), onApplySuggestion: () => applySuggestionWithIndex(i), onResetHighlight: () => resetHighlight(), value: transformLabelsForSuggestions(l.value, shouldTrimPrefix) }, transformLabelsForSuggestions(l.value, shouldTrimPrefix)))) })), suggestions.literals.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex === i + suggestions.labelNames.length, onHighlight: () => setHighlightedSuggestionIndex(i + suggestions.labelNames.length), onApplySuggestion: () => applySuggestionWithIndex(i + suggestions.labelNames.length), onResetHighlight: () => resetHighlight(), value: l.value }, l.value))), isLabelValuesLoading ? (_jsx(LoadingSpinner, {})) : suggestions.labelNames.length === 0 && suggestions.literals.length === 0 ? (_jsxs(_Fragment, { children: [suggestions.labelValues.length === 0 ? (_jsx("div", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center", ...testId(TEST_IDS.SUGGESTIONS_NO_RESULTS), children: "No label values found" })) : (suggestions.labelValues.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex ===
183
+ i + suggestions.labelNames.length + suggestions.literals.length, onHighlight: () => setHighlightedSuggestionIndex(i + suggestions.labelNames.length + suggestions.literals.length), onApplySuggestion: () => applySuggestionWithIndex(i + suggestions.labelNames.length + suggestions.literals.length), onResetHighlight: () => resetHighlight(), value: l.value }, l.value)))), _jsx(RefreshButton, { onClick: () => void handleRefetchValues(), disabled: isRefetchingValues, title: "Refresh label values", testId: "suggestions-refresh-values-button" })] })) : (suggestions.labelValues.map((l, i) => (_jsx(SuggestionItem, { isHighlighted: highlightedSuggestionIndex ===
161
184
  i + suggestions.labelNames.length + suggestions.literals.length, onHighlight: () => setHighlightedSuggestionIndex(i + suggestions.labelNames.length + suggestions.literals.length), onApplySuggestion: () => applySuggestionWithIndex(i + suggestions.labelNames.length + suggestions.literals.length), onResetHighlight: () => resetHighlight(), value: l.value }, l.value))))] }) }) }) })) }));
162
185
  };
163
186
  export default SuggestionsList;
@@ -17,6 +17,7 @@ export interface ILabelNamesResult {
17
17
  interface UseLabelNames {
18
18
  result: ILabelNamesResult;
19
19
  loading: boolean;
20
+ refetch: () => void;
20
21
  }
21
22
  export declare const useLabelNames: (client: QueryServiceClient, profileType: string, start?: number, end?: number, match?: string[]) => UseLabelNames;
22
23
  interface UseLabelValues {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,EAAgB,MAAM,eAAe,CAAC;AAE/F,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAIpC,OAAO,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAKrD,UAAU,kBAAkB;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,aAAa,GACxB,QAAQ,kBAAkB,EAC1B,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,QAAQ,MAAM,EAAE,KACf,aAwBF,CAAC;AAEF,UAAU,cAAc;IACtB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,KAAK,CAAC,EAAE,KAAK,CAAC;KACf,CAAC;IACF,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,GACzB,QAAQ,kBAAkB,EAC1B,WAAW,MAAM,EACjB,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,cA+BF,CAAC;AAEF,eAAO,MAAM,8BAA8B,GACzC,WAAW,MAAM,EACjB,oBAAoB,iBAAiB,KACpC,MAAM,EAWR,CAAC;AAuMF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAWxF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,EAAgB,MAAM,eAAe,CAAC;AAE/F,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAIpC,OAAO,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAKrD,UAAU,kBAAkB;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,aAAa,GACxB,QAAQ,kBAAkB,EAC1B,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,QAAQ,MAAM,EAAE,KACf,aA8BF,CAAC;AAEF,UAAU,cAAc;IACtB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,KAAK,CAAC,EAAE,KAAK,CAAC;KACf,CAAC;IACF,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,eAAO,MAAM,cAAc,GACzB,QAAQ,kBAAkB,EAC1B,WAAW,MAAM,EACjB,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,cA+BF,CAAC;AAEF,eAAO,MAAM,8BAA8B,GACzC,WAAW,MAAM,EACjB,oBAAoB,iBAAiB,KACpC,MAAM,EAWR,CAAC;AA2MF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAWxF"}
@@ -24,7 +24,7 @@ import useGrpcQuery from '../useGrpcQuery';
24
24
  import SuggestionsList, { Suggestion, Suggestions } from './SuggestionsList';
25
25
  export const useLabelNames = (client, profileType, start, end, match) => {
26
26
  const metadata = useGrpcMetadata();
27
- const { data, isLoading, error } = useGrpcQuery({
27
+ const { data, isLoading, error, refetch } = useGrpcQuery({
28
28
  key: ['labelNames', profileType, match?.join(','), start, end],
29
29
  queryFn: async (signal) => {
30
30
  const request = { match: match !== undefined ? match : [] };
@@ -43,7 +43,13 @@ export const useLabelNames = (client, profileType, start, end, match) => {
43
43
  keepPreviousData: false,
44
44
  },
45
45
  });
46
- return { result: { response: data, error: error }, loading: isLoading };
46
+ return {
47
+ result: { response: data, error: error },
48
+ loading: isLoading,
49
+ refetch: () => {
50
+ void refetch();
51
+ },
52
+ };
47
53
  };
48
54
  export const useLabelValues = (client, labelName, profileType, start, end) => {
49
55
  const metadata = useGrpcMetadata();
@@ -89,7 +95,7 @@ const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
89
95
  const inputRef = useRef(null);
90
96
  const [focusedInput, setFocusedInput] = useState(false);
91
97
  const [lastCompleted, setLastCompleted] = useState(new Suggestion('', '', ''));
92
- const { labelNames, labelValues, labelNameMappings, isLabelNamesLoading, isLabelValuesLoading, currentLabelName, setCurrentLabelName, shouldHandlePrefixes, refetchLabelValues, } = useLabels();
98
+ const { labelNames, labelValues, labelNameMappings, isLabelNamesLoading, isLabelValuesLoading, currentLabelName, setCurrentLabelName, shouldHandlePrefixes, refetchLabelValues, refetchLabelNames, } = useLabels();
93
99
  const value = currentQuery.matchersString();
94
100
  const suggestionSections = useMemo(() => {
95
101
  const suggestionSections = new Suggestions();
@@ -204,7 +210,7 @@ const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
204
210
  ? 'Select a profile first to enter a filter...'
205
211
  : 'filter profiles... eg. node="test"', onChange: onChange, value: value, onBlur: unfocus, ...testId(TEST_IDS.MATCHERS_TEXTAREA), onFocus: focus, disabled: profileSelected, title: profileSelected
206
212
  ? 'Select a profile first to enter a filter...'
207
- : 'filter profiles... eg. node="test"', id: "matchers-input" }), _jsx(SuggestionsList, { isLabelNamesLoading: isLabelNamesLoading, suggestions: suggestionSections, applySuggestion: applySuggestion, inputRef: inputRef.current, runQuery: runQuery, focusedInput: focusedInput, isLabelValuesLoading: isLabelValuesLoading && lastCompleted.type === 'literal', shouldTrimPrefix: shouldHandlePrefixes, refetchLabelValues: refetchLabelValues })] }));
213
+ : 'filter profiles... eg. node="test"', id: "matchers-input" }), _jsx(SuggestionsList, { isLabelNamesLoading: isLabelNamesLoading, suggestions: suggestionSections, applySuggestion: applySuggestion, inputRef: inputRef.current, runQuery: runQuery, focusedInput: focusedInput, isLabelValuesLoading: isLabelValuesLoading && lastCompleted.type === 'literal' && lastCompleted.value !== ',', shouldTrimPrefix: shouldHandlePrefixes, refetchLabelValues: refetchLabelValues, refetchLabelNames: refetchLabelNames })] }));
208
214
  };
209
215
  export default function MatchersInputWithProvider(props) {
210
216
  return (_jsx(LabelsProvider, { queryClient: props.queryClient, profileType: props.profileType, start: props.start, end: props.end, children: _jsx(MatchersInput, { ...props }) }));
@@ -31,7 +31,7 @@ interface CustomSelectProps {
31
31
  searchable?: boolean;
32
32
  onButtonClick?: () => void;
33
33
  editable?: boolean;
34
- refetchLabelValues?: () => void;
34
+ refetchValues?: () => void;
35
35
  showLoadingInButton?: boolean;
36
36
  hasRefreshButton?: boolean;
37
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/Select.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAQtE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC;IACpB,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,UAAU,iBAAiB;IACzB,KAAK,EAAE,iBAAiB,EAAE,GAAG,UAAU,EAAE,CAAC;IAC1C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAsV7C,CAAC;AAkDF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/Select.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAStE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC;IACpB,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,UAAU,iBAAiB;IACzB,KAAK,EAAE,iBAAiB,EAAE,GAAG,UAAU,EAAE,CAAC;IAC1C,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAyV7C,CAAC;AAkDF,eAAe,YAAY,CAAC"}
@@ -16,7 +16,8 @@ import { Icon } from '@iconify/react';
16
16
  import cx from 'classnames';
17
17
  import levenshtein from 'fast-levenshtein';
18
18
  import { Button, DividerWithLabel, useParcaContext } from '@parca/components';
19
- const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder = 'Select an item', width, className = '', loading, primary = false, disabled = false, icon, id, optionsClassname = '', searchable = false, onButtonClick, editable = false, refetchLabelValues, showLoadingInButton = false, hasRefreshButton = false, }) => {
19
+ import { TEST_IDS, testId } from '@parca/test-utils/dist/test-ids';
20
+ const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder = 'Select an item', width, className = '', loading, primary = false, disabled = false, icon, id, optionsClassname = '', searchable = false, onButtonClick, editable = false, refetchValues, showLoadingInButton = false, hasRefreshButton = false, }) => {
20
21
  const { loader } = useParcaContext();
21
22
  const [isOpen, setIsOpen] = useState(false);
22
23
  const [focusedIndex, setFocusedIndex] = useState(-1);
@@ -27,16 +28,16 @@ const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder
27
28
  const searchInputRef = useRef(null);
28
29
  const optionRefs = useRef([]);
29
30
  const handleRefetch = useCallback(async () => {
30
- if (refetchLabelValues == null || isRefetching)
31
+ if (refetchValues == null || isRefetching)
31
32
  return;
32
33
  setIsRefetching(true);
33
34
  try {
34
- await refetchLabelValues();
35
+ await refetchValues();
35
36
  }
36
37
  finally {
37
38
  setIsRefetching(false);
38
39
  }
39
- }, [refetchLabelValues, isRefetching]);
40
+ }, [refetchValues, isRefetching]);
40
41
  let items = [];
41
42
  if (itemsProp[0] != null && 'type' in itemsProp[0]) {
42
43
  items = itemsProp.flatMap(item => item.values.map(v => ({ ...v, type: item.type })));
@@ -137,7 +138,7 @@ const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder
137
138
  const primaryStyles = 'text-gray-100 dark:gray-900 bg-indigo-600 border-indigo-500 font-medium py-2 px-4';
138
139
  const renderSelection = (selection) => {
139
140
  if (showLoadingInButton && loading === true && selectedKey === '') {
140
- return (_jsxs("span", { className: "flex items-center gap-2", "data-testid": "label-value-loading-indicator", children: [_jsx(Icon, { icon: "svg-spinners:ring-resize", className: "w-4 h-4" }), _jsx("span", { children: "Loading..." })] }));
141
+ return (_jsxs("span", { className: "flex items-center gap-2", ...testId(TEST_IDS.LABEL_VALUE_LOADING_INDICATOR), children: [_jsx(Icon, { icon: "svg-spinners:ring-resize", className: "w-4 h-4" }), _jsx("span", { children: "Loading..." })] }));
141
142
  }
142
143
  if (editable) {
143
144
  return typeof selection === 'string' && selection.length > 0 ? selection : placeholder;
@@ -176,13 +177,13 @@ const CustomSelect = ({ items: itemsProp, selectedKey, onSelection, placeholder
176
177
  return (_jsxs("div", { ref: containerRef, className: "relative", onKeyDown: handleKeyDown, onClick: onButtonClick, children: [_jsxs("div", { id: id, onClick: () => !disabled && setIsOpen(!isOpen), className: cx(styles, width !== undefined ? `w-${width}` : 'w-full', disabled ? 'cursor-not-allowed opacity-50 pointer-events-none' : '', primary ? primaryStyles : defaultStyles, { [className]: className.length > 0 }), tabIndex: 0, role: "button", "aria-haspopup": "listbox", "aria-expanded": isOpen, children: [_jsx("div", { className: cx(icon != null ? '' : 'block overflow-x-hidden text-ellipsis whitespace-nowrap'), children: renderSelection(selection) }), _jsx("div", { className: cx(icon != null ? '' : 'pointer-events-none text-gray-400'), children: icon ?? _jsx(Icon, { icon: "heroicons:chevron-up-down-20-solid", "aria-hidden": "true" }) })] }), isOpen && (_jsx("div", { ref: optionsRef, className: cx('absolute z-50 mt-1 pt-0 max-h-[50vh] w-max overflow-auto rounded-md bg-gray-50 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:ring-white dark:ring-opacity-20 sm:text-sm', { [optionsClassname]: optionsClassname.length > 0 }), role: "listbox", children: _jsxs("div", { className: cx('relative', { 'pb-6': hasRefreshButton }), children: [searchable && (_jsx("div", { className: "sticky z-10 top-[-5px] w-auto max-w-full", children: _jsx("div", { className: "flex flex-col", children: editable ? (_jsxs(_Fragment, { children: [_jsx("textarea", { ref: searchInputRef, className: "w-full px-4 py-2 text-sm border-b border-gray-200 rounded-none ring-0 outline-none bg-gray-50 dark:bg-gray-800 dark:text-white min-h-[50px]", placeholder: "Type a RegEx to add", value: searchTerm, onChange: e => setSearchTerm(e.target.value), onFocus: e => moveCaretToEnd(e) }), editable && searchTerm.length > 0 && (_jsx("div", { className: "p-2 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800", children: _jsx(Button, { variant: "primary", className: "w-full h-[30px]", onClick: () => {
177
178
  onSelection(searchTerm);
178
179
  setIsOpen(false);
179
- }, children: "Add" }) }))] })) : (_jsx("input", { ref: searchInputRef, type: "text", className: "w-full px-4 h-[45px] text-sm border-none rounded-none ring-0 outline-none bg-gray-50 dark:bg-gray-800 dark:text-white", placeholder: "Search...", value: searchTerm, onChange: e => setSearchTerm(e.target.value) })) }) })), refetchLabelValues !== undefined && loading !== true && (_jsx("div", { className: "absolute w-full bottom-0 px-3 bg-gray-50 dark:bg-gray-800", children: _jsxs("button", { onClick: e => {
180
+ }, children: "Add" }) }))] })) : (_jsx("input", { ref: searchInputRef, type: "text", className: "w-full px-4 h-[45px] text-sm border-none rounded-none ring-0 outline-none bg-gray-50 dark:bg-gray-800 dark:text-white", placeholder: "Search...", value: searchTerm, onChange: e => setSearchTerm(e.target.value) })) }) })), refetchValues !== undefined && loading !== true && (_jsx("div", { className: "absolute w-full flex items-center justify-center bottom-0 px-3 bg-gray-50 dark:bg-gray-900", children: _jsxs("button", { onClick: e => {
180
181
  e.preventDefault();
181
182
  e.stopPropagation();
182
183
  void handleRefetch();
183
- }, disabled: isRefetching, className: cx('p-1 flex items-center gap-1 rounded-full transition-all duration-200 w-full justify-center', isRefetching
184
+ }, disabled: isRefetching, className: cx('py-1 px-2 flex items-center gap-1 rounded-full transition-all duration-200 w-auto justify-center', isRefetching
184
185
  ? 'cursor-wait opacity-50'
185
- : 'hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer'), title: "Refresh label values", type: "button", "data-testid": "label-value-refresh-button", children: [_jsx(Icon, { icon: "system-uicons:reset", className: cx('w-3 h-3 text-gray-500 dark:text-gray-400', isRefetching && 'animate-spin') }), _jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Refresh results" })] }) })), loading === true ? (_jsx("div", { className: "w-[270px]", children: loader })) : groupedFilteredItems.length === 0 ? (_jsx("div", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center", "data-testid": "label-value-no-results", children: "No values found" })) : (groupedFilteredItems.map(group => (_jsxs(_Fragment, { children: [groupedFilteredItems.length > 1 &&
186
+ : 'hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer'), title: "Refresh label values", type: "button", ...testId(TEST_IDS.LABEL_VALUE_REFRESH_BUTTON), children: [_jsx(Icon, { icon: "system-uicons:reset", className: cx('w-3 h-3 text-gray-500 dark:text-gray-400', isRefetching && 'animate-spin') }), _jsx("span", { className: "text-xs text-gray-500 dark:text-gray-400", children: "Refresh results" })] }) })), loading === true ? (_jsx("div", { className: "w-[270px]", children: loader })) : groupedFilteredItems.length === 0 ? (_jsx("div", { className: "px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center", ...testId(TEST_IDS.LABEL_VALUE_NO_RESULTS), children: "No values found" })) : (groupedFilteredItems.map(group => (_jsxs(_Fragment, { children: [groupedFilteredItems.length > 1 &&
186
187
  groupedFilteredItems.every(g => g.type !== '') &&
187
188
  group.type !== '' ? (_jsx("div", { className: "pl-2", children: _jsx(DividerWithLabel, { label: group.type }) })) : null, group.values.map((item, index) => (_jsx(OptionItem, { item: item, index: index, optionRefs: optionRefs, focusedIndex: focusedIndex, selectedKey: selectedKey, handleSelection: handleSelection }, item.key)))] }))))] }) }))] }));
188
189
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAMpC,OAAe,EAAC,KAAK,UAAU,EAAC,MAAM,UAAU,CAAC;AAEjD,UAAU,KAAK;IACb,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAoBD,eAAO,MAAM,wBAAwB,GAAI,YAAY,MAAM,EAAE,KAAG,UAAU,EAQzE,CAAC;AA2cF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAoB3E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAMpC,OAAe,EAAC,KAAK,UAAU,EAAC,MAAM,UAAU,CAAC;AAEjD,UAAU,KAAK;IACb,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAoBD,eAAO,MAAM,wBAAwB,GAAI,YAAY,MAAM,EAAE,KAAG,UAAU,EAQzE,CAAC;AAkdF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAoB3E"}
@@ -126,7 +126,7 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
126
126
  .join(',');
127
127
  setMatchersString(matcherString);
128
128
  }, [setMatchersString]);
129
- const { labelNameOptions, isLoading: labelNamesLoading, refetchLabelValues } = useLabels();
129
+ const { labelNameOptions, isLoading: labelNamesLoading, refetchLabelValues, refetchLabelNames, } = useLabels();
130
130
  // Helper to ensure selected label name is in the options (for page load before API returns)
131
131
  const getLabelNameOptionsWithSelected = useCallback((selectedLabelName) => {
132
132
  if (selectedLabelName === '')
@@ -313,11 +313,11 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
313
313
  };
314
314
  }, [queryRows, fetchLabelValuesUnified]);
315
315
  const isRowRegex = (row) => row.operator === '=~' || row.operator === '!~';
316
- return (_jsxs("div", { className: `flex items-center gap-3 ${maxWidthInPixels} w-full flex-wrap`, id: "simple-matchers", ...testId(TEST_IDS.SIMPLE_MATCHERS_CONTAINER), children: [visibleRows.map((row, index) => (_jsxs("div", { className: "flex items-center", ...testId(TEST_IDS.SIMPLE_MATCHER_ROW), children: [_jsx(Select, { items: getLabelNameOptionsWithSelected(row.labelName), onSelection: value => handleUpdateRow(index, 'labelName', value), placeholder: "Select label name", selectedKey: row.labelName, className: "rounded-tr-none rounded-br-none ring-0 focus:ring-0 outline-none", loading: labelNamesLoading, searchable: true, ...testId(TEST_IDS.LABEL_NAME_SELECT) }), _jsx(Select, { items: operatorOptions, onSelection: value => handleUpdateRow(index, 'operator', value), selectedKey: row.operator, className: "rounded-none ring-0 focus:ring-0 outline-none", ...testId(TEST_IDS.OPERATOR_SELECT) }), _jsx(Select, { items: transformLabelsForSelect(row.labelValue !== '' && !row.labelValues.includes(row.labelValue)
316
+ return (_jsxs("div", { className: `flex items-center gap-3 ${maxWidthInPixels} w-full flex-wrap`, id: "simple-matchers", ...testId(TEST_IDS.SIMPLE_MATCHERS_CONTAINER), children: [visibleRows.map((row, index) => (_jsxs("div", { className: "flex items-center", ...testId(TEST_IDS.SIMPLE_MATCHER_ROW), children: [_jsx(Select, { items: getLabelNameOptionsWithSelected(row.labelName), onSelection: value => handleUpdateRow(index, 'labelName', value), placeholder: "Select label name", selectedKey: row.labelName, className: "rounded-tr-none rounded-br-none ring-0 focus:ring-0 outline-none", loading: labelNamesLoading, searchable: true, ...testId(TEST_IDS.LABEL_NAME_SELECT), refetchValues: refetchLabelNames, hasRefreshButton: true }), _jsx(Select, { items: operatorOptions, onSelection: value => handleUpdateRow(index, 'operator', value), selectedKey: row.operator, className: "rounded-none ring-0 focus:ring-0 outline-none", ...testId(TEST_IDS.OPERATOR_SELECT) }), _jsx(Select, { items: transformLabelsForSelect(row.labelValue !== '' && !row.labelValues.includes(row.labelValue)
317
317
  ? [...row.labelValues, row.labelValue]
318
318
  : row.labelValues), onSelection: value => handleUpdateRow(index, 'labelValue', value), placeholder: "Select label value", selectedKey: row.labelValue, className: "rounded-none ring-0 focus:ring-0 outline-none max-w-48", optionsClassname: cx('max-w-[600px]', {
319
319
  'w-[300px]': isRowRegex(row),
320
- }), searchable: true, disabled: row.labelName === '', loading: row.isLoading, onButtonClick: () => handleLabelValueClick(index), editable: isRowRegex(row), ...testId(TEST_IDS.LABEL_VALUE_SELECT), refetchLabelValues: refetchLabelValues, showLoadingInButton: true, hasRefreshButton: true }), _jsx("button", { onClick: () => removeRow(index), className: cx('p-2 border-gray-200 border rounded rounded-tl-none rounded-bl-none focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900'), ...testId(TEST_IDS.REMOVE_MATCHER_BUTTON), children: _jsx(Icon, { icon: "carbon:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }, index))), queryRows.length > 3 && !isActivelyEditing && (_jsx("button", { onClick: () => {
320
+ }), searchable: true, disabled: row.labelName === '', loading: row.isLoading, onButtonClick: () => handleLabelValueClick(index), editable: isRowRegex(row), ...testId(TEST_IDS.LABEL_VALUE_SELECT), refetchValues: refetchLabelValues, showLoadingInButton: true, hasRefreshButton: true }), _jsx("button", { onClick: () => removeRow(index), className: cx('p-2 border-gray-200 border rounded rounded-tl-none rounded-bl-none focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900'), ...testId(TEST_IDS.REMOVE_MATCHER_BUTTON), children: _jsx(Icon, { icon: "carbon:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }, index))), queryRows.length > 3 && !isActivelyEditing && (_jsx("button", { onClick: () => {
321
321
  if (showAll) {
322
322
  // Clicking "Show less" - collapse and stop editing mode
323
323
  setShowAll(false);
@@ -14,6 +14,7 @@ interface LabelsContextType {
14
14
  setCurrentLabelName: (name: string | null) => void;
15
15
  shouldHandlePrefixes: boolean;
16
16
  refetchLabelValues: () => void;
17
+ refetchLabelNames: () => void;
17
18
  }
18
19
  interface LabelsProviderProps {
19
20
  children: React.ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"MatchersInputLabelsContext.d.ts","sourceRoot":"","sources":["../../src/contexts/MatchersInputLabelsContext.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAKjD,UAAU,gBAAgB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,iBAAiB;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;IACtC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,OAAO,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;CAChC;AAID,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAID,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,WAAW,EACX,WAAW,EACX,KAAK,EACL,GAAG,GACJ,EAAE,mBAAmB,GAAG,GAAG,CAAC,OAAO,CA2EnC;AAED,wBAAgB,SAAS,IAAI,iBAAiB,CAM7C"}
1
+ {"version":3,"file":"MatchersInputLabelsContext.d.ts","sourceRoot":"","sources":["../../src/contexts/MatchersInputLabelsContext.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAKjD,UAAU,gBAAgB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,iBAAiB;IACzB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,EAAE,gBAAgB,EAAE,CAAC;IACtC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,OAAO,CAAC;IAC9B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,MAAM,IAAI,CAAC;CAC/B;AAID,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAID,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,WAAW,EACX,WAAW,EACX,KAAK,EACL,GAAG,GACJ,EAAE,mBAAmB,GAAG,GAAG,CAAC,OAAO,CA4EnC;AAED,wBAAgB,SAAS,IAAI,iBAAiB,CAM7C"}
@@ -20,7 +20,7 @@ const LabelsContext = createContext(null);
20
20
  export function LabelsProvider({ children, queryClient, profileType, start, end, }) {
21
21
  const [currentLabelName, setCurrentLabelName] = React.useState(null);
22
22
  const utilizationLabels = useUtilizationLabels();
23
- const { result: labelNamesResponse, loading: isLabelNamesLoading } = useLabelNames(queryClient, profileType, start, end);
23
+ const { result: labelNamesResponse, loading: isLabelNamesLoading, refetch: refetchLabelNames, } = useLabelNames(queryClient, profileType, start, end);
24
24
  const labelNamesFromAPI = useMemo(() => {
25
25
  return (labelNamesResponse.error === undefined || labelNamesResponse.error == null) &&
26
26
  labelNamesResponse !== undefined &&
@@ -56,6 +56,7 @@ export function LabelsProvider({ children, queryClient, profileType, start, end,
56
56
  setCurrentLabelName,
57
57
  shouldHandlePrefixes,
58
58
  refetchLabelValues,
59
+ refetchLabelNames,
59
60
  }), [
60
61
  labelNames,
61
62
  labelValues,
@@ -65,6 +66,7 @@ export function LabelsProvider({ children, queryClient, profileType, start, end,
65
66
  currentLabelName,
66
67
  shouldHandlePrefixes,
67
68
  refetchLabelValues,
69
+ refetchLabelNames,
68
70
  ]);
69
71
  return _jsx(LabelsContext.Provider, { value: value, children: children });
70
72
  }
@@ -9,6 +9,7 @@ interface LabelContextValue {
9
9
  isLoading: boolean;
10
10
  error: Error | null;
11
11
  refetchLabelValues: () => void;
12
+ refetchLabelNames: () => void;
12
13
  }
13
14
  interface LabelProviderProps {
14
15
  children: React.ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"SimpleMatchersLabelContext.d.ts","sourceRoot":"","sources":["../../src/contexts/SimpleMatchersLabelContext.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAIjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AAGzD,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,UAAU,iBAAiB;IACzB,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,IAAI,CAAC;CAChC;AAID,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAKD,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,WAAW,EACX,WAAW,EACX,qBAAqB,EACrB,KAAK,EACL,GAAG,GACJ,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAuGlC;AAED,wBAAgB,SAAS,IAAI,iBAAiB,CAM7C"}
1
+ {"version":3,"file":"SimpleMatchersLabelContext.d.ts","sourceRoot":"","sources":["../../src/contexts/SimpleMatchersLabelContext.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAIjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAC;AAGzD,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED,UAAU,iBAAiB;IACzB,gBAAgB,EAAE,gBAAgB,EAAE,CAAC;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,iBAAiB,EAAE,MAAM,IAAI,CAAC;CAC/B;AAID,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,EAAE,CAAC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAKD,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,WAAW,EACX,WAAW,EACX,qBAAqB,EACrB,KAAK,EACL,GAAG,GACJ,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAgHlC;AAED,wBAAgB,SAAS,IAAI,iBAAiB,CAM7C"}
@@ -22,7 +22,7 @@ const LabelContext = createContext(null);
22
22
  export function LabelProvider({ children, queryClient, profileType, labelNameFromMatchers, start, end, }) {
23
23
  const reactQueryClient = useQueryClient();
24
24
  const utilizationLabelResponse = useUtilizationLabels();
25
- const { loading, result } = useLabelNames(queryClient, profileType, start, end);
25
+ const { loading, result, refetch: refetchLabelNamesQuery, } = useLabelNames(queryClient, profileType, start, end);
26
26
  const profileValues = useMemo(() => {
27
27
  const profileLabelNames = result.error != null ? [] : result.response?.labelNames.filter(e => e !== '__name__') ?? [];
28
28
  const uniqueProfileLabelNames = Array.from(new Set(profileLabelNames));
@@ -90,10 +90,14 @@ export function LabelProvider({ children, queryClient, profileType, labelNameFro
90
90
  },
91
91
  });
92
92
  }, [reactQueryClient, profileType]);
93
+ const refetchLabelNames = useCallback(() => {
94
+ refetchLabelNamesQuery();
95
+ }, [refetchLabelNamesQuery]);
93
96
  const contextValue = useMemo(() => ({
94
97
  ...value,
95
98
  refetchLabelValues,
96
- }), [value, refetchLabelValues]);
99
+ refetchLabelNames,
100
+ }), [value, refetchLabelValues, refetchLabelNames]);
97
101
  return _jsx(LabelContext.Provider, { value: contextValue, children: children });
98
102
  }
99
103
  export function useLabels() {
package/dist/styles.css CHANGED
@@ -1 +1 @@
1
- /*! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.-inset-2{bottom:-.5rem;left:-.5rem;right:-.5rem;top:-.5rem}.inset-y-0{bottom:0;top:0}.bottom-0{bottom:0}.right-0{right:0}.top-0{top:0}.left-0{left:0}.bottom-3{bottom:.75rem}.top-\[-5px\]{top:-5px}.top-\[-2px\]{top:-2px}.left-\[-7px\]{left:-7px}.right-\[-7px\]{right:-7px}.right-8{right:2rem}.top-\[-46px\]{top:-46px}.right-full{right:100%}.left-full{left:100%}.top-\[-60px\]{top:-60px}.left-1\/2{left:50%}.top-full{top:100%}.z-10{z-index:10}.z-50{z-index:50}.z-30{z-index:30}.z-\[5\]{z-index:5}.z-20{z-index:20}.m-auto{margin:auto}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-0{margin-bottom:0;margin-top:0}.my-20{margin-bottom:5rem;margin-top:5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-4{margin-bottom:1rem;margin-top:1rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.ml-\[70px\]{margin-left:70px}.mb-2{margin-bottom:.5rem}.ml-2{margin-left:.5rem}.mr-6{margin-right:1.5rem}.ml-auto{margin-left:auto}.mt-auto{margin-top:auto}.mb-0\.5{margin-bottom:.125rem}.mt-1\.5{margin-top:.375rem}.mb-0{margin-bottom:0}.mr-2{margin-right:.5rem}.ml-3{margin-left:.75rem}.mt-2{margin-top:.5rem}.mb-px{margin-bottom:1px}.mb-1{margin-bottom:.25rem}.mr-1{margin-right:.25rem}.mt-4{margin-top:1rem}.mb-4{margin-bottom:1rem}.mt-3{margin-top:.75rem}.mt-8{margin-top:2rem}.mt-0{margin-top:0}.ml-1{margin-left:.25rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.\!flex{display:flex!important}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-fit{height:-moz-fit-content;height:fit-content}.h-3{height:.75rem}.h-\[38px\]{height:38px}.h-auto{height:auto}.h-full{height:100%}.h-1{height:.25rem}.h-\[20px\]{height:20px}.h-\[16px\]{height:16px}.h-4{height:1rem}.h-\[30px\]{height:30px}.h-\[45px\]{height:45px}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-\[700px\]{height:700px}.h-\[80vh\]{height:80vh}.h-\[1px\]{height:1px}.h-\[14px\]{height:14px}.h-\[24px\]{height:24px}.h-0{height:0}.max-h-\[400px\]{max-height:400px}.max-h-\[50vh\]{max-height:50vh}.max-h-\[300px\]{max-height:300px}.min-h-52{min-height:13rem}.min-h-5{min-height:1.25rem}.min-h-48{min-height:12rem}.min-h-\[50px\]{min-height:50px}.min-h-\[700px\]{min-height:700px}.min-h-96{min-height:24rem}.w-full{width:100%}.w-\[500px\]{width:500px}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-max{width:-moz-max-content;width:max-content}.w-auto{width:auto}.w-3{width:.75rem}.w-40{width:10rem}.w-\[44px\]{width:44px}.w-\[16px\]{width:16px}.w-4{width:1rem}.w-\[270px\]{width:270px}.w-\[300px\]{width:300px}.w-5{width:1.25rem}.w-7{width:1.75rem}.w-9{width:2.25rem}.w-11{width:2.75rem}.w-\[52px\]{width:52px}.w-\[68px\]{width:68px}.w-\[76px\]{width:76px}.w-\[84px\]{width:84px}.w-\[92px\]{width:92px}.w-\[100px\]{width:100px}.w-\[108px\]{width:108px}.w-\[116px\]{width:116px}.w-56{width:14rem}.w-\[350px\]{width:350px}.w-\[260px\]{width:260px}.w-44{width:11rem}.w-\[460px\]{width:460px}.w-\[19\.25\%\]{width:19.25%}.w-11\/12{width:91.666667%}.w-1\/12{width:8.333333%}.w-8{width:2rem}.w-\[50\%\]{width:50%}.w-32{width:8rem}.w-36{width:9rem}.w-16{width:4rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-\[420px\]{width:420px}.w-48{width:12rem}.w-\[14px\]{width:14px}.w-64{width:16rem}.w-80{width:20rem}.w-\[20px\]{width:20px}.w-\[246px\]{width:246px}.w-52{width:13rem}.w-0{width:0}.min-w-\[300px\]{min-width:300px}.min-w-\[400px\]{min-width:400px}.min-w-\[350px\]{min-width:350px}.min-w-\[260px\]{min-width:260px}.max-w-\[500px\]{max-width:500px}.max-w-md{max-width:28rem}.max-w-80{max-width:20rem}.max-w-full{max-width:100%}.max-w-48{max-width:12rem}.max-w-\[600px\]{max-width:600px}.max-w-\[400px\]{max-width:400px}.max-w-lg{max-width:32rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow-0{flex-grow:0}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.origin-top-right{transform-origin:top right}.origin-top-left{transform-origin:top left}.translate-x-6{--tw-translate-x:1.5rem}.translate-x-0,.translate-x-6{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x:0px}.translate-y-1{--tw-translate-y:0.25rem}.translate-y-0,.translate-y-1{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y:0px}.translate-x-5{--tw-translate-x:1.25rem}.-translate-x-1\/2,.translate-x-5{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\/2{--tw-translate-x:-50%}.rotate-90{--tw-rotate:90deg}.-rotate-180,.rotate-90{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-rotate-180{--tw-rotate:-180deg}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-wait{cursor:wait}.cursor-pointer{cursor:pointer}.cursor-not-allowed{cursor:not-allowed}.cursor-ew-resize{cursor:ew-resize}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-4{gap:1rem}.gap-1{gap:.25rem}.gap-\[2px\]{gap:2px}.gap-2{gap:.5rem}.gap-6{gap:1.5rem}.gap-3{gap:.75rem}.gap-0{gap:0}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.25rem*var(--tw-space-y-reverse));margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-clip{overflow:clip}.overflow-scroll{overflow:scroll}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.scroll-smooth{scroll-behavior:smooth}.text-ellipsis{text-overflow:ellipsis}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-full{border-radius:9999px}.rounded-sm{border-radius:.125rem}.rounded-none{border-radius:0}.rounded-\[4px\]{border-radius:4px}.rounded-l-md{border-bottom-left-radius:.375rem;border-top-left-radius:.375rem}.rounded-l-none{border-bottom-left-radius:0;border-top-left-radius:0}.rounded-r-none{border-bottom-right-radius:0;border-top-right-radius:0}.rounded-r-md{border-bottom-right-radius:.375rem;border-top-right-radius:.375rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.rounded-b{border-bottom-right-radius:.25rem}.rounded-b,.rounded-l{border-bottom-left-radius:.25rem}.rounded-l{border-top-left-radius:.25rem}.rounded-r{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.rounded-tr-none{border-top-right-radius:0}.rounded-br-none{border-bottom-right-radius:0}.rounded-tl-none{border-top-left-radius:0}.rounded-bl-none{border-bottom-left-radius:0}.border{border-width:1px}.border-2{border-width:2px}.border-x-2{border-left-width:2px;border-right-width:2px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-r{border-right-width:1px}.border-l{border-left-width:1px}.border-l-0{border-left-width:0}.border-r-0{border-right-width:0}.border-l-4{border-left-width:4px}.border-r-4{border-right-width:4px}.border-t-4{border-top-width:4px}.border-none{border-style:none}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-400{--tw-border-opacity:1;border-color:rgb(248 113 113/var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-indigo-500{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity))}.border-gray-900{--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-r-gray-200{--tw-border-opacity:1;border-right-color:rgb(229 231 235/var(--tw-border-opacity))}.border-l-amber-900{--tw-border-opacity:1;border-left-color:rgb(120 53 15/var(--tw-border-opacity))}.border-l-transparent{border-left-color:transparent}.border-r-transparent{border-right-color:transparent}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:hsla(0,0%,100%,.5)}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-indigo-100{--tw-bg-opacity:1;background-color:rgb(224 231 255/var(--tw-bg-opacity))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}.bg-gray-500\/50{background-color:hsla(220,9%,46%,.5)}.bg-gray-700\/75{background-color:rgba(55,65,81,.75)}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity))}.bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.bg-indigo-400{--tw-bg-opacity:1;background-color:rgb(129 140 248/var(--tw-bg-opacity))}.bg-opacity-75{--tw-bg-opacity:0.75}.bg-opacity-90{--tw-bg-opacity:0.9}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.stroke-gray-300{stroke:#d1d5db}.stroke-white{stroke:#fff}.stroke-\[3\]{stroke-width:3}.p-3{padding:.75rem}.p-2{padding:.5rem}.p-1{padding:.25rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-0{padding:0}.p-\[6px\]{padding:6px}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.py-4{padding-bottom:1rem;padding-top:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0{padding-bottom:0;padding-top:0}.\!px-3{padding-left:.75rem!important;padding-right:.75rem!important}.pr-0{padding-right:0}.pt-2{padding-top:.5rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.pb-4{padding-bottom:1rem}.pb-12{padding-bottom:3rem}.pr-3{padding-right:.75rem}.pt-0{padding-top:0}.pb-6{padding-bottom:1.5rem}.pl-2{padding-left:.5rem}.pr-4{padding-right:1rem}.pl-1{padding-left:.25rem}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pb-2{padding-bottom:.5rem}.pb-\[10px\]{padding-bottom:10px}.pr-1{padding-right:.25rem}.pr-\[1\.7rem\]{padding-right:1.7rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem}.text-lg,.text-xl{line-height:1.75rem}.text-xl{font-size:1.25rem}.text-\[10px\]{font-size:10px}.font-semibold{font-weight:600}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.leading-6{line-height:1.5rem}.leading-5{line-height:1.25rem}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity))}.\!text-indigo-600{--tw-text-opacity:1!important;color:rgb(79 70 229/var(--tw-text-opacity))!important}.opacity-100{opacity:1}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-80{opacity:.8}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\]{--tw-shadow:0 0 10px 2px rgba(0,0,0,.3);--tw-shadow-colored:0 0 10px 2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-0,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-0{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity:0.05}.blur{--tw-blur:blur(8px)}.blur,.invert{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert:invert(100%)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-150{transition-duration:.15s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.will-change-transform{will-change:transform}.\[stroke-dasharray\:6\2c 4\]{stroke-dasharray:6,4}.\[stroke-linecap\:round\]{stroke-linecap:round}.\[stroke-linejoin\:round\]{stroke-linejoin:round}.\[writing-mode\:vertical-lr\]{writing-mode:vertical-lr}.checked\:border-indigo-600:checked{--tw-border-opacity:1;border-color:rgb(79 70 229/var(--tw-border-opacity))}.checked\:bg-indigo-600:checked{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.hover\:whitespace-normal:hover{white-space:normal}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-indigo-600:hover{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.hover\:bg-indigo-500:hover{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.focus\:relative:focus{position:relative}.focus\:z-50:focus{z-index:50}.focus\:border-indigo-500:focus{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:outline-1:focus{outline-width:1px}.focus\:ring-1:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-1:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-indigo-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.focus\:ring-indigo-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(79 70 229/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.focus\:ring-offset-0:focus{--tw-ring-offset-width:0px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-white\/75:focus-visible{--tw-ring-color:hsla(0,0%,100%,.75)}.focus-visible\:ring-white:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}.focus-visible\:ring-indigo-500:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.focus-visible\:ring-opacity-75:focus-visible{--tw-ring-opacity:0.75}.group:hover .group-hover\:flex{display:flex}[class~=theme-dark] .dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-600{--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-700{--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-r-gray-700{--tw-border-opacity:1;border-right-color:rgb(55 65 81/var(--tw-border-opacity))}[class~=theme-dark] .dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-black\/50{background-color:rgba(0,0,0,.5)}[class~=theme-dark] .dark\:bg-indigo-700{--tw-bg-opacity:1;background-color:rgb(67 56 202/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-100\/90{background-color:rgba(243,244,246,.9)}[class~=theme-dark] .dark\:bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-200\/75{background-color:rgba(229,231,235,.75)}[class~=theme-dark] .dark\:bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-opacity-80{--tw-bg-opacity:0.8}[class~=theme-dark] .dark\:stroke-gray-500{stroke:#6b7280}[class~=theme-dark] .dark\:stroke-gray-700{stroke:#374151}[class~=theme-dark] .dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-200{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-indigo-500{--tw-text-opacity:1;color:rgb(99 102 241/var(--tw-text-opacity))}[class~=theme-dark] .dark\:\!text-indigo-400{--tw-text-opacity:1!important;color:rgb(129 140 248/var(--tw-text-opacity))!important}[class~=theme-dark] .dark\:ring-white{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}[class~=theme-dark] .dark\:ring-opacity-20{--tw-ring-opacity:0.2}[class~=theme-dark] .dark\:hover\:bg-gray-700:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .hover\:dark\:text-gray-100:hover{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:block{display:block}.md\:flex-row{flex-direction:row}}
1
+ /*! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.sr-only{clip:rect(0,0,0,0);border-width:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.-inset-2{bottom:-.5rem;left:-.5rem;right:-.5rem;top:-.5rem}.inset-y-0{bottom:0;top:0}.bottom-0{bottom:0}.right-0{right:0}.top-0{top:0}.left-0{left:0}.bottom-3{bottom:.75rem}.top-\[-5px\]{top:-5px}.top-\[-2px\]{top:-2px}.left-\[-7px\]{left:-7px}.right-\[-7px\]{right:-7px}.right-8{right:2rem}.top-\[-46px\]{top:-46px}.right-full{right:100%}.left-full{left:100%}.top-\[-60px\]{top:-60px}.left-1\/2{left:50%}.top-full{top:100%}.z-10{z-index:10}.z-50{z-index:50}.z-30{z-index:30}.z-\[5\]{z-index:5}.z-20{z-index:20}.m-auto{margin:auto}.m-2{margin:.5rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-0{margin-bottom:0;margin-top:0}.my-20{margin-bottom:5rem;margin-top:5rem}.mx-auto{margin-left:auto;margin-right:auto}.my-4{margin-bottom:1rem;margin-top:1rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.ml-\[70px\]{margin-left:70px}.mb-2{margin-bottom:.5rem}.ml-2{margin-left:.5rem}.mr-6{margin-right:1.5rem}.ml-auto{margin-left:auto}.mt-auto{margin-top:auto}.mb-0\.5{margin-bottom:.125rem}.mt-1\.5{margin-top:.375rem}.mb-0{margin-bottom:0}.mr-2{margin-right:.5rem}.ml-3{margin-left:.75rem}.mt-2{margin-top:.5rem}.mb-px{margin-bottom:1px}.mb-1{margin-bottom:.25rem}.mr-1{margin-right:.25rem}.mt-4{margin-top:1rem}.mb-4{margin-bottom:1rem}.mt-3{margin-top:.75rem}.mt-8{margin-top:2rem}.mt-0{margin-top:0}.ml-1{margin-left:.25rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.\!flex{display:flex!important}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-fit{height:-moz-fit-content;height:fit-content}.h-3{height:.75rem}.h-\[38px\]{height:38px}.h-auto{height:auto}.h-full{height:100%}.h-1{height:.25rem}.h-\[20px\]{height:20px}.h-\[16px\]{height:16px}.h-4{height:1rem}.h-\[30px\]{height:30px}.h-\[45px\]{height:45px}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-\[700px\]{height:700px}.h-\[80vh\]{height:80vh}.h-\[1px\]{height:1px}.h-\[14px\]{height:14px}.h-\[24px\]{height:24px}.h-0{height:0}.max-h-\[400px\]{max-height:400px}.max-h-\[50vh\]{max-height:50vh}.max-h-\[300px\]{max-height:300px}.min-h-52{min-height:13rem}.min-h-5{min-height:1.25rem}.min-h-48{min-height:12rem}.min-h-\[50px\]{min-height:50px}.min-h-\[700px\]{min-height:700px}.min-h-96{min-height:24rem}.w-full{width:100%}.w-\[500px\]{width:500px}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-max{width:-moz-max-content;width:max-content}.w-auto{width:auto}.w-3{width:.75rem}.w-40{width:10rem}.w-\[44px\]{width:44px}.w-\[16px\]{width:16px}.w-4{width:1rem}.w-\[270px\]{width:270px}.w-\[300px\]{width:300px}.w-5{width:1.25rem}.w-7{width:1.75rem}.w-9{width:2.25rem}.w-11{width:2.75rem}.w-\[52px\]{width:52px}.w-\[68px\]{width:68px}.w-\[76px\]{width:76px}.w-\[84px\]{width:84px}.w-\[92px\]{width:92px}.w-\[100px\]{width:100px}.w-\[108px\]{width:108px}.w-\[116px\]{width:116px}.w-56{width:14rem}.w-\[350px\]{width:350px}.w-\[260px\]{width:260px}.w-44{width:11rem}.w-\[460px\]{width:460px}.w-\[19\.25\%\]{width:19.25%}.w-11\/12{width:91.666667%}.w-1\/12{width:8.333333%}.w-8{width:2rem}.w-\[50\%\]{width:50%}.w-32{width:8rem}.w-36{width:9rem}.w-16{width:4rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-\[420px\]{width:420px}.w-48{width:12rem}.w-\[14px\]{width:14px}.w-64{width:16rem}.w-80{width:20rem}.w-\[20px\]{width:20px}.w-\[246px\]{width:246px}.w-52{width:13rem}.w-0{width:0}.min-w-\[300px\]{min-width:300px}.min-w-\[400px\]{min-width:400px}.min-w-\[350px\]{min-width:350px}.min-w-\[260px\]{min-width:260px}.max-w-\[500px\]{max-width:500px}.max-w-md{max-width:28rem}.max-w-80{max-width:20rem}.max-w-full{max-width:100%}.max-w-48{max-width:12rem}.max-w-\[600px\]{max-width:600px}.max-w-\[400px\]{max-width:400px}.max-w-lg{max-width:32rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow-0{flex-grow:0}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.origin-top-right{transform-origin:top right}.origin-top-left{transform-origin:top left}.translate-x-6{--tw-translate-x:1.5rem}.translate-x-0,.translate-x-6{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-0{--tw-translate-x:0px}.translate-y-1{--tw-translate-y:0.25rem}.translate-y-0,.translate-y-1{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y:0px}.translate-x-5{--tw-translate-x:1.25rem}.-translate-x-1\/2,.translate-x-5{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-x-1\/2{--tw-translate-x:-50%}.rotate-90{--tw-rotate:90deg}.-rotate-180,.rotate-90{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-rotate-180{--tw-rotate:-180deg}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-wait{cursor:wait}.cursor-pointer{cursor:pointer}.cursor-not-allowed{cursor:not-allowed}.cursor-ew-resize{cursor:ew-resize}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize{resize:both}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-4{gap:1rem}.gap-1{gap:.25rem}.gap-\[2px\]{gap:2px}.gap-2{gap:.5rem}.gap-6{gap:1.5rem}.gap-3{gap:.75rem}.gap-0{gap:0}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.25rem*var(--tw-space-y-reverse));margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-clip{overflow:clip}.overflow-scroll{overflow:scroll}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.scroll-smooth{scroll-behavior:smooth}.text-ellipsis{text-overflow:ellipsis}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-full{border-radius:9999px}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.rounded-none{border-radius:0}.rounded-\[4px\]{border-radius:4px}.rounded-l-md{border-bottom-left-radius:.375rem;border-top-left-radius:.375rem}.rounded-l-none{border-bottom-left-radius:0;border-top-left-radius:0}.rounded-r-none{border-bottom-right-radius:0;border-top-right-radius:0}.rounded-r-md{border-bottom-right-radius:.375rem;border-top-right-radius:.375rem}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.rounded-b{border-bottom-right-radius:.25rem}.rounded-b,.rounded-l{border-bottom-left-radius:.25rem}.rounded-l{border-top-left-radius:.25rem}.rounded-r{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.rounded-tr-none{border-top-right-radius:0}.rounded-br-none{border-bottom-right-radius:0}.rounded-tl-none{border-top-left-radius:0}.rounded-bl-none{border-bottom-left-radius:0}.border{border-width:1px}.border-2{border-width:2px}.border-x-2{border-left-width:2px;border-right-width:2px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-r{border-right-width:1px}.border-l{border-left-width:1px}.border-l-0{border-left-width:0}.border-r-0{border-right-width:0}.border-l-4{border-left-width:4px}.border-r-4{border-right-width:4px}.border-t-4{border-top-width:4px}.border-none{border-style:none}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-400{--tw-border-opacity:1;border-color:rgb(248 113 113/var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-indigo-500{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity))}.border-gray-900{--tw-border-opacity:1;border-color:rgb(17 24 39/var(--tw-border-opacity))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-r-gray-200{--tw-border-opacity:1;border-right-color:rgb(229 231 235/var(--tw-border-opacity))}.border-l-amber-900{--tw-border-opacity:1;border-left-color:rgb(120 53 15/var(--tw-border-opacity))}.border-l-transparent{border-left-color:transparent}.border-r-transparent{border-right-color:transparent}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-white\/50{background-color:hsla(0,0%,100%,.5)}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(156 163 175/var(--tw-bg-opacity))}.bg-indigo-100{--tw-bg-opacity:1;background-color:rgb(224 231 255/var(--tw-bg-opacity))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}.bg-gray-500\/50{background-color:hsla(220,9%,46%,.5)}.bg-gray-700\/75{background-color:rgba(55,65,81,.75)}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity))}.bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.bg-indigo-400{--tw-bg-opacity:1;background-color:rgb(129 140 248/var(--tw-bg-opacity))}.bg-opacity-75{--tw-bg-opacity:0.75}.bg-opacity-90{--tw-bg-opacity:0.9}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.stroke-gray-300{stroke:#d1d5db}.stroke-white{stroke:#fff}.stroke-\[3\]{stroke-width:3}.p-3{padding:.75rem}.p-2{padding:.5rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-1{padding:.25rem}.p-0{padding:0}.p-\[6px\]{padding:6px}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.py-4{padding-bottom:1rem;padding-top:1rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0{padding-bottom:0;padding-top:0}.\!px-3{padding-left:.75rem!important;padding-right:.75rem!important}.pr-0{padding-right:0}.pt-2{padding-top:.5rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.pb-4{padding-bottom:1rem}.pb-12{padding-bottom:3rem}.pr-3{padding-right:.75rem}.pt-0{padding-top:0}.pb-6{padding-bottom:1.5rem}.pl-2{padding-left:.5rem}.pr-4{padding-right:1rem}.pl-1{padding-left:.25rem}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pb-2{padding-bottom:.5rem}.pb-\[10px\]{padding-bottom:10px}.pr-1{padding-right:.25rem}.pr-\[1\.7rem\]{padding-right:1.7rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.font-sans{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem}.text-lg,.text-xl{line-height:1.75rem}.text-xl{font-size:1.25rem}.text-\[10px\]{font-size:10px}.font-semibold{font-weight:600}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.leading-6{line-height:1.5rem}.leading-5{line-height:1.25rem}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-gray-100{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity))}.\!text-indigo-600{--tw-text-opacity:1!important;color:rgb(79 70 229/var(--tw-text-opacity))!important}.opacity-50{opacity:.5}.opacity-100{opacity:1}.opacity-0{opacity:0}.opacity-80{opacity:.8}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\]{--tw-shadow:0 0 10px 2px rgba(0,0,0,.3);--tw-shadow-colored:0 0 10px 2px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow-md,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-0,.ring-1{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-0{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity:0.05}.blur{--tw-blur:blur(8px)}.blur,.invert{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert:invert(100%)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition-all{transition-duration:.15s;transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-200{transition-duration:.2s}.duration-100{transition-duration:.1s}.duration-150{transition-duration:.15s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.will-change-transform{will-change:transform}.\[stroke-dasharray\:6\2c 4\]{stroke-dasharray:6,4}.\[stroke-linecap\:round\]{stroke-linecap:round}.\[stroke-linejoin\:round\]{stroke-linejoin:round}.\[writing-mode\:vertical-lr\]{writing-mode:vertical-lr}.checked\:border-indigo-600:checked{--tw-border-opacity:1;border-color:rgb(79 70 229/var(--tw-border-opacity))}.checked\:bg-indigo-600:checked{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.hover\:whitespace-normal:hover{white-space:normal}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-indigo-600:hover{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.hover\:bg-indigo-500:hover{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}.hover\:text-white:hover{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.focus\:relative:focus{position:relative}.focus\:z-50:focus{z-index:50}.focus\:border-indigo-500:focus{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:outline-1:focus{outline-width:1px}.focus\:ring-1:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-1:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-indigo-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.focus\:ring-indigo-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(79 70 229/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.focus\:ring-offset-0:focus{--tw-ring-offset-width:0px}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-white\/75:focus-visible{--tw-ring-color:hsla(0,0%,100%,.75)}.focus-visible\:ring-white:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}.focus-visible\:ring-indigo-500:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.focus-visible\:ring-opacity-75:focus-visible{--tw-ring-opacity:0.75}.group:hover .group-hover\:flex{display:flex}[class~=theme-dark] .dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-600{--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-700{--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-r-gray-700{--tw-border-opacity:1;border-right-color:rgb(55 65 81/var(--tw-border-opacity))}[class~=theme-dark] .dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-black\/50{background-color:rgba(0,0,0,.5)}[class~=theme-dark] .dark\:bg-indigo-700{--tw-bg-opacity:1;background-color:rgb(67 56 202/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-100\/90{background-color:rgba(243,244,246,.9)}[class~=theme-dark] .dark\:bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-200\/75{background-color:rgba(229,231,235,.75)}[class~=theme-dark] .dark\:bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-opacity-80{--tw-bg-opacity:0.8}[class~=theme-dark] .dark\:stroke-gray-500{stroke:#6b7280}[class~=theme-dark] .dark\:stroke-gray-700{stroke:#374151}[class~=theme-dark] .dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-200{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-indigo-500{--tw-text-opacity:1;color:rgb(99 102 241/var(--tw-text-opacity))}[class~=theme-dark] .dark\:\!text-indigo-400{--tw-text-opacity:1!important;color:rgb(129 140 248/var(--tw-text-opacity))!important}[class~=theme-dark] .dark\:ring-white{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}[class~=theme-dark] .dark\:ring-opacity-20{--tw-ring-opacity:0.2}[class~=theme-dark] .dark\:hover\:bg-gray-700:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .hover\:dark\:text-gray-100:hover{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:block{display:block}.md\:flex-row{flex-direction:row}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.19.62",
3
+ "version": "0.19.63",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@floating-ui/react": "^0.27.12",
@@ -79,5 +79,5 @@
79
79
  "access": "public",
80
80
  "registry": "https://registry.npmjs.org/"
81
81
  },
82
- "gitHead": "302edbb820e37dd7b033072706e6fe525eaadb8f"
82
+ "gitHead": "c59fb3d63c5ea63e271933a6c1c7565f2e0abd71"
83
83
  }
@@ -19,6 +19,7 @@ import cx from 'classnames';
19
19
  import {usePopper} from 'react-popper';
20
20
 
21
21
  import {useParcaContext} from '@parca/components';
22
+ import {TEST_IDS, testId} from '@parca/test-utils';
22
23
 
23
24
  import SuggestionItem from './SuggestionItem';
24
25
 
@@ -56,6 +57,7 @@ interface Props {
56
57
  isLabelValuesLoading: boolean;
57
58
  shouldTrimPrefix: boolean;
58
59
  refetchLabelValues: () => void;
60
+ refetchLabelNames: () => void;
59
61
  }
60
62
 
61
63
  const LoadingSpinner = (): JSX.Element => {
@@ -64,6 +66,43 @@ const LoadingSpinner = (): JSX.Element => {
64
66
  return <div className="pt-2 pb-4">{Spinner}</div>;
65
67
  };
66
68
 
69
+ interface RefreshButtonProps {
70
+ onClick: () => void;
71
+ disabled: boolean;
72
+ title: string;
73
+ testId: string;
74
+ }
75
+
76
+ const RefreshButton = ({onClick, disabled, title, testId}: RefreshButtonProps): JSX.Element => {
77
+ return (
78
+ <div className="absolute w-full flex items-center justify-center bottom-0 px-3 py-2 bg-gray-50 dark:bg-gray-900">
79
+ <button
80
+ onClick={e => {
81
+ e.preventDefault();
82
+ e.stopPropagation();
83
+ onClick();
84
+ }}
85
+ disabled={disabled}
86
+ className={cx(
87
+ 'py-1 px-2 flex items-center gap-1 rounded-full transition-all duration-200 w-auto justify-center',
88
+ disabled
89
+ ? 'cursor-wait opacity-50'
90
+ : 'hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer'
91
+ )}
92
+ title={title}
93
+ type="button"
94
+ data-testid={testId}
95
+ >
96
+ <Icon
97
+ icon="system-uicons:reset"
98
+ className={cx('w-3 h-3 text-gray-500 dark:text-gray-400', disabled && 'animate-spin')}
99
+ />
100
+ <span className="text-xs text-gray-500 dark:text-gray-400">Refresh results</span>
101
+ </button>
102
+ </div>
103
+ );
104
+ };
105
+
67
106
  const transformLabelsForSuggestions = (labelNames: string, shouldTrimPrefix = false): string => {
68
107
  const trimmedLabel = shouldTrimPrefix ? labelNames.split('.').pop() ?? labelNames : labelNames;
69
108
  return trimmedLabel;
@@ -79,6 +118,7 @@ const SuggestionsList = ({
79
118
  isLabelValuesLoading,
80
119
  shouldTrimPrefix = false,
81
120
  refetchLabelValues,
121
+ refetchLabelNames,
82
122
  }: Props): JSX.Element => {
83
123
  const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
84
124
  const {styles, attributes} = usePopper(inputRef, popperElement, {
@@ -86,18 +126,30 @@ const SuggestionsList = ({
86
126
  });
87
127
  const [highlightedSuggestionIndex, setHighlightedSuggestionIndex] = useState<number>(-1);
88
128
  const [showSuggest, setShowSuggest] = useState(true);
89
- const [isRefetching, setIsRefetching] = useState(false);
129
+ const [isRefetchingValues, setIsRefetchingValues] = useState(false);
130
+ const [isRefetchingNames, setIsRefetchingNames] = useState(false);
90
131
 
91
- const handleRefetch = useCallback(async () => {
92
- if (isRefetching) return;
132
+ const handleRefetchValues = useCallback(async () => {
133
+ if (isRefetchingValues) return;
93
134
 
94
- setIsRefetching(true);
135
+ setIsRefetchingValues(true);
95
136
  try {
96
137
  await refetchLabelValues();
97
138
  } finally {
98
- setIsRefetching(false);
139
+ setIsRefetchingValues(false);
140
+ }
141
+ }, [refetchLabelValues, isRefetchingValues]);
142
+
143
+ const handleRefetchNames = useCallback(async () => {
144
+ if (isRefetchingNames) return;
145
+
146
+ setIsRefetchingNames(true);
147
+ try {
148
+ await refetchLabelNames();
149
+ } finally {
150
+ setIsRefetchingNames(false);
99
151
  }
100
- }, [refetchLabelValues, isRefetching]);
152
+ }, [refetchLabelNames, isRefetchingNames]);
101
153
 
102
154
  const suggestionsLength =
103
155
  suggestions.literals.length + suggestions.labelNames.length + suggestions.labelValues.length;
@@ -227,6 +279,12 @@ const SuggestionsList = ({
227
279
  };
228
280
  }, [inputRef, highlightedSuggestionIndex, suggestions, handleKeyPress, handleKeyDown]);
229
281
 
282
+ useEffect(() => {
283
+ if (suggestionsLength > 0 && focusedInput) {
284
+ setShowSuggest(true);
285
+ }
286
+ }, [suggestionsLength, focusedInput]);
287
+
230
288
  return (
231
289
  <>
232
290
  {suggestionsLength > 0 && (
@@ -247,9 +305,41 @@ const SuggestionsList = ({
247
305
  style={{width: inputRef?.offsetWidth}}
248
306
  className="absolute z-10 mt-1 max-h-[400px] overflow-auto rounded-md bg-gray-50 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:bg-gray-900 sm:text-sm"
249
307
  >
250
- <div className="relative pb-12">
308
+ <div
309
+ className={cx('relative', {
310
+ 'pb-12': suggestions.labelNames.length === 0 && suggestions.literals.length === 0,
311
+ })}
312
+ >
251
313
  {isLabelNamesLoading ? (
252
314
  <LoadingSpinner />
315
+ ) : suggestions.literals.length === 0 && suggestions.labelValues.length === 0 ? (
316
+ <>
317
+ {suggestions.labelNames.length === 0 ? (
318
+ <div
319
+ className="px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center"
320
+ {...testId(TEST_IDS.SUGGESTIONS_NO_RESULTS)}
321
+ >
322
+ No label names found
323
+ </div>
324
+ ) : (
325
+ suggestions.labelNames.map((l, i) => (
326
+ <SuggestionItem
327
+ isHighlighted={highlightedSuggestionIndex === i}
328
+ onHighlight={() => setHighlightedSuggestionIndex(i)}
329
+ onApplySuggestion={() => applySuggestionWithIndex(i)}
330
+ onResetHighlight={() => resetHighlight()}
331
+ value={transformLabelsForSuggestions(l.value, shouldTrimPrefix)}
332
+ key={transformLabelsForSuggestions(l.value, shouldTrimPrefix)}
333
+ />
334
+ ))
335
+ )}
336
+ <RefreshButton
337
+ onClick={() => void handleRefetchNames()}
338
+ disabled={isRefetchingNames}
339
+ title="Refresh label names"
340
+ testId="suggestions-refresh-names-button"
341
+ />
342
+ </>
253
343
  ) : (
254
344
  <>
255
345
  {suggestions.labelNames.map((l, i) => (
@@ -287,7 +377,7 @@ const SuggestionsList = ({
287
377
  {suggestions.labelValues.length === 0 ? (
288
378
  <div
289
379
  className="px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center"
290
- data-testid="suggestions-no-results"
380
+ {...testId(TEST_IDS.SUGGESTIONS_NO_RESULTS)}
291
381
  >
292
382
  No label values found
293
383
  </div>
@@ -314,36 +404,12 @@ const SuggestionsList = ({
314
404
  />
315
405
  ))
316
406
  )}
317
- <div className="absolute w-full flex items-center justify-center bottom-0 px-3 py-2 bg-gray-50 dark:bg-gray-800">
318
- <button
319
- onClick={e => {
320
- e.preventDefault();
321
- e.stopPropagation();
322
- void handleRefetch();
323
- }}
324
- disabled={isRefetching}
325
- className={cx(
326
- 'p-1 flex items-center gap-1 rounded-full transition-all duration-200 w-auto justify-center',
327
- isRefetching
328
- ? 'cursor-wait opacity-50'
329
- : 'hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer'
330
- )}
331
- title="Refresh label values"
332
- type="button"
333
- data-testid="suggestions-refresh-button"
334
- >
335
- <Icon
336
- icon="system-uicons:reset"
337
- className={cx(
338
- 'w-3 h-3 text-gray-500 dark:text-gray-400',
339
- isRefetching && 'animate-spin'
340
- )}
341
- />
342
- <span className="text-xs text-gray-500 dark:text-gray-400">
343
- Refresh results
344
- </span>
345
- </button>
346
- </div>
407
+ <RefreshButton
408
+ onClick={() => void handleRefetchValues()}
409
+ disabled={isRefetchingValues}
410
+ title="Refresh label values"
411
+ testId="suggestions-refresh-values-button"
412
+ />
347
413
  </>
348
414
  ) : (
349
415
  suggestions.labelValues.map((l, i) => (
@@ -46,6 +46,7 @@ export interface ILabelNamesResult {
46
46
  interface UseLabelNames {
47
47
  result: ILabelNamesResult;
48
48
  loading: boolean;
49
+ refetch: () => void;
49
50
  }
50
51
 
51
52
  export const useLabelNames = (
@@ -57,7 +58,7 @@ export const useLabelNames = (
57
58
  ): UseLabelNames => {
58
59
  const metadata = useGrpcMetadata();
59
60
 
60
- const {data, isLoading, error} = useGrpcQuery<LabelsResponse>({
61
+ const {data, isLoading, error, refetch} = useGrpcQuery<LabelsResponse>({
61
62
  key: ['labelNames', profileType, match?.join(','), start, end],
62
63
  queryFn: async signal => {
63
64
  const request: LabelsRequest = {match: match !== undefined ? match : []};
@@ -77,7 +78,13 @@ export const useLabelNames = (
77
78
  },
78
79
  });
79
80
 
80
- return {result: {response: data, error: error as Error}, loading: isLoading};
81
+ return {
82
+ result: {response: data, error: error as Error},
83
+ loading: isLoading,
84
+ refetch: () => {
85
+ void refetch();
86
+ },
87
+ };
81
88
  };
82
89
 
83
90
  interface UseLabelValues {
@@ -163,6 +170,7 @@ const MatchersInput = ({
163
170
  setCurrentLabelName,
164
171
  shouldHandlePrefixes,
165
172
  refetchLabelValues,
173
+ refetchLabelNames,
166
174
  } = useLabels();
167
175
 
168
176
  const value = currentQuery.matchersString();
@@ -333,9 +341,12 @@ const MatchersInput = ({
333
341
  inputRef={inputRef.current}
334
342
  runQuery={runQuery}
335
343
  focusedInput={focusedInput}
336
- isLabelValuesLoading={isLabelValuesLoading && lastCompleted.type === 'literal'}
344
+ isLabelValuesLoading={
345
+ isLabelValuesLoading && lastCompleted.type === 'literal' && lastCompleted.value !== ','
346
+ }
337
347
  shouldTrimPrefix={shouldHandlePrefixes}
338
348
  refetchLabelValues={refetchLabelValues}
349
+ refetchLabelNames={refetchLabelNames}
339
350
  />
340
351
  </div>
341
352
  );
@@ -18,6 +18,7 @@ import cx from 'classnames';
18
18
  import levenshtein from 'fast-levenshtein';
19
19
 
20
20
  import {Button, DividerWithLabel, useParcaContext} from '@parca/components';
21
+ import {TEST_IDS, testId} from '@parca/test-utils/dist/test-ids';
21
22
 
22
23
  export interface SelectElement {
23
24
  active: JSX.Element;
@@ -55,7 +56,7 @@ interface CustomSelectProps {
55
56
  searchable?: boolean;
56
57
  onButtonClick?: () => void;
57
58
  editable?: boolean;
58
- refetchLabelValues?: () => void;
59
+ refetchValues?: () => void;
59
60
  showLoadingInButton?: boolean;
60
61
  hasRefreshButton?: boolean;
61
62
  }
@@ -76,7 +77,7 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
76
77
  searchable = false,
77
78
  onButtonClick,
78
79
  editable = false,
79
- refetchLabelValues,
80
+ refetchValues,
80
81
  showLoadingInButton = false,
81
82
  hasRefreshButton = false,
82
83
  }) => {
@@ -91,15 +92,15 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
91
92
  const optionRefs = useRef<Array<HTMLElement | null>>([]);
92
93
 
93
94
  const handleRefetch = useCallback(async () => {
94
- if (refetchLabelValues == null || isRefetching) return;
95
+ if (refetchValues == null || isRefetching) return;
95
96
 
96
97
  setIsRefetching(true);
97
98
  try {
98
- await refetchLabelValues();
99
+ await refetchValues();
99
100
  } finally {
100
101
  setIsRefetching(false);
101
102
  }
102
- }, [refetchLabelValues, isRefetching]);
103
+ }, [refetchValues, isRefetching]);
103
104
 
104
105
  let items: TypedSelectItem[] = [];
105
106
  if (itemsProp[0] != null && 'type' in itemsProp[0]) {
@@ -212,7 +213,10 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
212
213
  const renderSelection = (selection: SelectItem | string | undefined): string | JSX.Element => {
213
214
  if (showLoadingInButton && loading === true && selectedKey === '') {
214
215
  return (
215
- <span className="flex items-center gap-2" data-testid="label-value-loading-indicator">
216
+ <span
217
+ className="flex items-center gap-2"
218
+ {...testId(TEST_IDS.LABEL_VALUE_LOADING_INDICATOR)}
219
+ >
216
220
  <Icon icon="svg-spinners:ring-resize" className="w-4 h-4" />
217
221
  <span>Loading...</span>
218
222
  </span>
@@ -334,8 +338,8 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
334
338
  </div>
335
339
  </div>
336
340
  )}
337
- {refetchLabelValues !== undefined && loading !== true && (
338
- <div className="absolute w-full bottom-0 px-3 bg-gray-50 dark:bg-gray-800">
341
+ {refetchValues !== undefined && loading !== true && (
342
+ <div className="absolute w-full flex items-center justify-center bottom-0 px-3 bg-gray-50 dark:bg-gray-900">
339
343
  <button
340
344
  onClick={e => {
341
345
  e.preventDefault();
@@ -344,14 +348,14 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
344
348
  }}
345
349
  disabled={isRefetching}
346
350
  className={cx(
347
- 'p-1 flex items-center gap-1 rounded-full transition-all duration-200 w-full justify-center',
351
+ 'py-1 px-2 flex items-center gap-1 rounded-full transition-all duration-200 w-auto justify-center',
348
352
  isRefetching
349
353
  ? 'cursor-wait opacity-50'
350
354
  : 'hover:bg-gray-200 dark:hover:bg-gray-700 cursor-pointer'
351
355
  )}
352
356
  title="Refresh label values"
353
357
  type="button"
354
- data-testid="label-value-refresh-button"
358
+ {...testId(TEST_IDS.LABEL_VALUE_REFRESH_BUTTON)}
355
359
  >
356
360
  <Icon
357
361
  icon="system-uicons:reset"
@@ -369,7 +373,7 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
369
373
  ) : groupedFilteredItems.length === 0 ? (
370
374
  <div
371
375
  className="px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center"
372
- data-testid="label-value-no-results"
376
+ {...testId(TEST_IDS.LABEL_VALUE_NO_RESULTS)}
373
377
  >
374
378
  No values found
375
379
  </div>
@@ -203,7 +203,12 @@ const SimpleMatchers = ({
203
203
  [setMatchersString]
204
204
  );
205
205
 
206
- const {labelNameOptions, isLoading: labelNamesLoading, refetchLabelValues} = useLabels();
206
+ const {
207
+ labelNameOptions,
208
+ isLoading: labelNamesLoading,
209
+ refetchLabelValues,
210
+ refetchLabelNames,
211
+ } = useLabels();
207
212
 
208
213
  // Helper to ensure selected label name is in the options (for page load before API returns)
209
214
  const getLabelNameOptionsWithSelected = useCallback(
@@ -451,6 +456,8 @@ const SimpleMatchers = ({
451
456
  loading={labelNamesLoading}
452
457
  searchable={true}
453
458
  {...testId(TEST_IDS.LABEL_NAME_SELECT)}
459
+ refetchValues={refetchLabelNames}
460
+ hasRefreshButton={true}
454
461
  />
455
462
  <Select
456
463
  items={operatorOptions}
@@ -478,7 +485,7 @@ const SimpleMatchers = ({
478
485
  onButtonClick={() => handleLabelValueClick(index)}
479
486
  editable={isRowRegex(row)}
480
487
  {...testId(TEST_IDS.LABEL_VALUE_SELECT)}
481
- refetchLabelValues={refetchLabelValues}
488
+ refetchValues={refetchLabelValues}
482
489
  showLoadingInButton={true}
483
490
  hasRefreshButton={true}
484
491
  />
@@ -33,6 +33,7 @@ interface LabelsContextType {
33
33
  setCurrentLabelName: (name: string | null) => void;
34
34
  shouldHandlePrefixes: boolean;
35
35
  refetchLabelValues: () => void;
36
+ refetchLabelNames: () => void;
36
37
  }
37
38
 
38
39
  const LabelsContext = createContext<LabelsContextType | null>(null);
@@ -57,12 +58,11 @@ export function LabelsProvider({
57
58
  const [currentLabelName, setCurrentLabelName] = React.useState<string | null>(null);
58
59
  const utilizationLabels = useUtilizationLabels();
59
60
 
60
- const {result: labelNamesResponse, loading: isLabelNamesLoading} = useLabelNames(
61
- queryClient,
62
- profileType,
63
- start,
64
- end
65
- );
61
+ const {
62
+ result: labelNamesResponse,
63
+ loading: isLabelNamesLoading,
64
+ refetch: refetchLabelNames,
65
+ } = useLabelNames(queryClient, profileType, start, end);
66
66
 
67
67
  const labelNamesFromAPI = useMemo(() => {
68
68
  return (labelNamesResponse.error === undefined || labelNamesResponse.error == null) &&
@@ -114,6 +114,7 @@ export function LabelsProvider({
114
114
  setCurrentLabelName,
115
115
  shouldHandlePrefixes,
116
116
  refetchLabelValues,
117
+ refetchLabelNames,
117
118
  }),
118
119
  [
119
120
  labelNames,
@@ -124,6 +125,7 @@ export function LabelsProvider({
124
125
  currentLabelName,
125
126
  shouldHandlePrefixes,
126
127
  refetchLabelValues,
128
+ refetchLabelNames,
127
129
  ]
128
130
  );
129
131
 
@@ -32,6 +32,7 @@ interface LabelContextValue {
32
32
  isLoading: boolean;
33
33
  error: Error | null;
34
34
  refetchLabelValues: () => void;
35
+ refetchLabelNames: () => void;
35
36
  }
36
37
 
37
38
  const LabelContext = createContext<LabelContextValue | null>(null);
@@ -58,7 +59,11 @@ export function LabelProvider({
58
59
  }: LabelProviderProps): JSX.Element {
59
60
  const reactQueryClient = useQueryClient();
60
61
  const utilizationLabelResponse = useUtilizationLabels();
61
- const {loading, result} = useLabelNames(queryClient, profileType, start, end);
62
+ const {
63
+ loading,
64
+ result,
65
+ refetch: refetchLabelNamesQuery,
66
+ } = useLabelNames(queryClient, profileType, start, end);
62
67
 
63
68
  const profileValues = useMemo(() => {
64
69
  const profileLabelNames =
@@ -149,12 +154,17 @@ export function LabelProvider({
149
154
  });
150
155
  }, [reactQueryClient, profileType]);
151
156
 
157
+ const refetchLabelNames = useCallback(() => {
158
+ refetchLabelNamesQuery();
159
+ }, [refetchLabelNamesQuery]);
160
+
152
161
  const contextValue = useMemo(
153
162
  () => ({
154
163
  ...value,
155
164
  refetchLabelValues,
165
+ refetchLabelNames,
156
166
  }),
157
- [value, refetchLabelValues]
167
+ [value, refetchLabelValues, refetchLabelNames]
158
168
  );
159
169
 
160
170
  return <LabelContext.Provider value={contextValue}>{children}</LabelContext.Provider>;