@parca/profile 0.16.459 → 0.16.461
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 +8 -0
- package/dist/MatchersInput/index.d.ts +8 -0
- package/dist/MatchersInput/index.d.ts.map +1 -1
- package/dist/MatchersInput/index.js +22 -18
- package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.js +1 -1
- package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -1
- package/dist/ProfileView/components/ColorStackLegend.js +2 -2
- package/dist/ProfileView/hooks/useProfileMetadata.js +1 -1
- package/dist/SimpleMatchers/Select.d.ts.map +1 -1
- package/dist/SimpleMatchers/Select.js +6 -1
- package/dist/SimpleMatchers/index.d.ts.map +1 -1
- package/dist/SimpleMatchers/index.js +14 -4
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +8 -4
- package/dist/Table/utils/functions.d.ts +4 -1
- package/dist/Table/utils/functions.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/MatchersInput/index.tsx +42 -24
- package/src/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.tsx +4 -1
- package/src/ProfileView/components/ColorStackLegend.tsx +5 -2
- package/src/ProfileView/hooks/useProfileMetadata.ts +1 -1
- package/src/SimpleMatchers/Select.tsx +7 -0
- package/src/SimpleMatchers/index.tsx +21 -7
- package/src/Table/index.tsx +25 -11
- package/src/Table/utils/functions.ts +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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.16.461](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.460...@parca/profile@0.16.461) (2025-01-13)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.16.460](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.459...@parca/profile@0.16.460) (2025-01-09)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## [0.16.459](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.458...@parca/profile@0.16.459) (2025-01-08)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -16,6 +16,14 @@ interface UseLabelNames {
|
|
|
16
16
|
loading: boolean;
|
|
17
17
|
}
|
|
18
18
|
export declare const useLabelNames: (client: QueryServiceClient, profileType: string, start?: number, end?: number, match?: string[]) => UseLabelNames;
|
|
19
|
+
interface UseLabelValues {
|
|
20
|
+
result: {
|
|
21
|
+
response: string[];
|
|
22
|
+
error?: Error;
|
|
23
|
+
};
|
|
24
|
+
loading: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare const useLabelValues: (client: QueryServiceClient, labelName: string, profileType: string) => UseLabelValues;
|
|
19
27
|
declare const MatchersInput: ({ queryClient, setMatchersString, runQuery, currentQuery, profileType, }: MatchersInputProps) => JSX.Element;
|
|
20
28
|
export default MatchersInput;
|
|
21
29
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,EAAgB,MAAM,eAAe,CAAC;AAE/F,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAMpC,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;CACrB;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,WAChB,kBAAkB,eACb,MAAM,UACX,MAAM,QACR,MAAM,UACJ,MAAM,EAAE,KACf,aAyBF,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;CAClB;AAED,eAAO,MAAM,cAAc,WACjB,kBAAkB,aACf,MAAM,eACJ,MAAM,KAClB,cAsBF,CAAC;AAEF,QAAA,MAAM,aAAa,6EAMhB,kBAAkB,KAAG,GAAG,CAAC,OAkK3B,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -11,7 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
|
-
import {
|
|
14
|
+
import { useMemo, useRef, useState } from 'react';
|
|
15
15
|
import cx from 'classnames';
|
|
16
16
|
import TextareaAutosize from 'react-textarea-autosize';
|
|
17
17
|
import { useGrpcMetadata } from '@parca/components';
|
|
@@ -43,30 +43,34 @@ export const useLabelNames = (client, profileType, start, end, match) => {
|
|
|
43
43
|
});
|
|
44
44
|
return { result: { response: data, error: error }, loading: isLoading };
|
|
45
45
|
};
|
|
46
|
+
export const useLabelValues = (client, labelName, profileType) => {
|
|
47
|
+
const metadata = useGrpcMetadata();
|
|
48
|
+
const { data, isLoading, error } = useGrpcQuery({
|
|
49
|
+
key: ['labelValues', labelName, profileType],
|
|
50
|
+
queryFn: async () => {
|
|
51
|
+
const request = { labelName, match: [], profileType };
|
|
52
|
+
const { response } = await client.values(request, { meta: metadata });
|
|
53
|
+
return sanitizeLabelValue(response.labelValues);
|
|
54
|
+
},
|
|
55
|
+
options: {
|
|
56
|
+
enabled: profileType !== undefined &&
|
|
57
|
+
profileType !== '' &&
|
|
58
|
+
labelName !== undefined &&
|
|
59
|
+
labelName !== '',
|
|
60
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
61
|
+
keepPreviousData: false,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
return { result: { response: data ?? [], error: error }, loading: isLoading };
|
|
65
|
+
};
|
|
46
66
|
const MatchersInput = ({ queryClient, setMatchersString, runQuery, currentQuery, profileType, }) => {
|
|
47
67
|
const inputRef = useRef(null);
|
|
48
68
|
const [focusedInput, setFocusedInput] = useState(false);
|
|
49
|
-
const [labelValuesLoading, setLabelValuesLoading] = useState(false);
|
|
50
69
|
const [lastCompleted, setLastCompleted] = useState(new Suggestion('', '', ''));
|
|
51
|
-
const [labelValues, setLabelValues] = useState(null);
|
|
52
70
|
const [currentLabelName, setCurrentLabelName] = useState(null);
|
|
53
|
-
const metadata = useGrpcMetadata();
|
|
54
71
|
const { loading: labelNamesLoading, result } = useLabelNames(queryClient, profileType);
|
|
55
72
|
const { response: labelNamesResponse, error: labelNamesError } = result;
|
|
56
|
-
|
|
57
|
-
if (currentLabelName !== null) {
|
|
58
|
-
const call = queryClient.values({ labelName: currentLabelName, match: [], profileType }, { meta: metadata });
|
|
59
|
-
setLabelValuesLoading(true);
|
|
60
|
-
call.response
|
|
61
|
-
.then(response => {
|
|
62
|
-
// replace single `\` in the `labelValues` string with doubles `\\` if available.
|
|
63
|
-
const newValues = sanitizeLabelValue(response.labelValues);
|
|
64
|
-
return setLabelValues(newValues);
|
|
65
|
-
})
|
|
66
|
-
.catch(() => setLabelValues(null))
|
|
67
|
-
.finally(() => setLabelValuesLoading(false));
|
|
68
|
-
}
|
|
69
|
-
}, [currentLabelName, metadata, profileType, queryClient]);
|
|
73
|
+
const { loading: labelValuesLoading, result: { response: labelValues }, } = useLabelValues(queryClient, currentLabelName ?? '', profileType);
|
|
70
74
|
const labelNames = useMemo(() => {
|
|
71
75
|
return (labelNamesError === undefined || labelNamesError == null) &&
|
|
72
76
|
labelNamesResponse !== undefined &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorStackLegend.d.ts","sourceRoot":"","sources":["../../../src/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.tsx"],"names":[],"mappings":"AAsBA,UAAU,KAAK;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,gBAAgB,oBAA2B,KAAK,KAAG,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"ColorStackLegend.d.ts","sourceRoot":"","sources":["../../../src/ProfileIcicleGraph/IcicleGraph/ColorStackLegend.tsx"],"names":[],"mappings":"AAsBA,UAAU,KAAK;IACb,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,gBAAgB,oBAA2B,KAAK,KAAG,GAAG,CAAC,OAmE5D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -50,7 +50,7 @@ const ColorStackLegend = ({ compareMode = false }) => {
|
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
setSearchString(feature);
|
|
53
|
-
}, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "mr-1 inline-block h-4 w-4", style: { backgroundColor: color } }), _jsx("span", { className: "text-sm", children: feature })] }), isHighlighted ? (_jsx(Icon, { icon: "radix-icons:cross-circled", onClick: e => {
|
|
53
|
+
}, children: [_jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "mr-1 inline-block h-4 w-4 rounded-[4px]", style: { backgroundColor: color } }), _jsx("span", { className: "text-sm", children: feature })] }), isHighlighted ? (_jsx(Icon, { icon: "radix-icons:cross-circled", onClick: e => {
|
|
54
54
|
setSearchString('');
|
|
55
55
|
e.stopPropagation();
|
|
56
56
|
} })) : null] }, feature));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ColorStackLegend.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/components/ColorStackLegend.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAgB,MAAM,OAAO,CAAC;AAYrC,UAAU,KAAK;IACb,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,gBAAgB,uCAA8C,KAAK,KAAG,KAAK,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"ColorStackLegend.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/components/ColorStackLegend.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAgB,MAAM,OAAO,CAAC;AAYrC,UAAU,KAAK;IACb,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,gBAAgB,uCAA8C,KAAK,KAAG,KAAK,CAAC,GAAG,CAAC,OAsGrF,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -58,7 +58,7 @@ const ColorStackLegend = ({ mappings, compareMode = false, loading }) => {
|
|
|
58
58
|
const filteringAllowed = feature !== EVERYTHING_ELSE;
|
|
59
59
|
const isHighlighted = currentSearchString !== undefined ? currentSearchString.includes(feature) : false;
|
|
60
60
|
return (_jsxs("div", { className: cx('flex-no-wrap mb-1 flex w-[19.25%] items-center justify-between text-ellipsis p-1', {
|
|
61
|
-
'cursor-pointer': filteringAllowed,
|
|
61
|
+
'cursor-pointer': filteringAllowed && colorBy === 'binary',
|
|
62
62
|
'bg-gray-200 dark:bg-gray-800': isHighlighted,
|
|
63
63
|
}), onClick: () => {
|
|
64
64
|
if (!filteringAllowed || isHighlighted || colorBy !== 'binary') {
|
|
@@ -67,7 +67,7 @@ const ColorStackLegend = ({ mappings, compareMode = false, loading }) => {
|
|
|
67
67
|
// Check if the current search string is defined and an array
|
|
68
68
|
const updatedSearchString = [...currentSearchString, feature]; // If array, append the feature
|
|
69
69
|
setSearchString(updatedSearchString);
|
|
70
|
-
}, children: [_jsxs("div", { className: "flex w-11/12 items-center justify-start", children: [_jsx("div", { className: "flex w-5 items-center", children: _jsx("div", { className: "mr-1 inline-block h-4 w-4", style: { backgroundColor: color } }) }), _jsx("div", { className: "shrink overflow-hidden text-ellipsis whitespace-nowrap text-sm hover:whitespace-normal", children: feature })] }), _jsx("div", { className: "flex w-1/12 justify-end", children: isHighlighted && (_jsx(Icon, { icon: "radix-icons:cross-circled", onClick: e => {
|
|
70
|
+
}, children: [_jsxs("div", { className: "flex w-11/12 items-center justify-start", children: [_jsx("div", { className: "flex w-5 items-center", children: _jsx("div", { className: "mr-1 inline-block h-4 w-4 rounded-[4px]", style: { backgroundColor: color } }) }), _jsx("div", { className: "shrink overflow-hidden text-ellipsis whitespace-nowrap text-sm hover:whitespace-normal", children: feature })] }), _jsx("div", { className: "flex w-1/12 justify-end", children: isHighlighted && (_jsx(Icon, { icon: "radix-icons:cross-circled", onClick: e => {
|
|
71
71
|
// remove the current feature from the search string array of strings
|
|
72
72
|
setSearchString(currentSearchString.filter((f) => f !== feature));
|
|
73
73
|
e.stopPropagation();
|
|
@@ -19,7 +19,7 @@ export const useProfileMetadata = ({ flamegraphArrow, metadataMappingFiles, meta
|
|
|
19
19
|
}, [flamegraphArrow]);
|
|
20
20
|
const mappingsList = useMappingList(metadataMappingFiles);
|
|
21
21
|
const filenamesList = useFilenamesList(table);
|
|
22
|
-
const colorMappings = colorBy === 'binary' ? mappingsList : filenamesList;
|
|
22
|
+
const colorMappings = colorBy === 'binary' || colorBy === '' ? mappingsList : filenamesList;
|
|
23
23
|
return {
|
|
24
24
|
table,
|
|
25
25
|
mappingsList,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/Select.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAOzD,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,UAAU,iBAAiB;IACzB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,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;CACpB;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,
|
|
1
|
+
{"version":3,"file":"Select.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/Select.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAoC,MAAM,OAAO,CAAC;AAOzD,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,UAAU,iBAAiB;IACzB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,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;CACpB;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAuQ7C,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -126,7 +126,12 @@ const CustomSelect = ({ items, selectedKey, onSelection, placeholder = 'Select a
|
|
|
126
126
|
setIsOpen(false);
|
|
127
127
|
}
|
|
128
128
|
};
|
|
129
|
-
|
|
129
|
+
const moveCaretToEnd = (e) => {
|
|
130
|
+
const value = e.target.value;
|
|
131
|
+
e.target.value = '';
|
|
132
|
+
e.target.value = value;
|
|
133
|
+
};
|
|
134
|
+
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 && (_jsxs("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: [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: () => {
|
|
130
135
|
onSelection(searchTerm);
|
|
131
136
|
setIsOpen(false);
|
|
132
137
|
}, 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) })) }) })), loading === true ? (_jsx("div", { className: "w-[270px]", children: loader })) : (filteredItems.map((item, index) => (_jsxs("div", { ref: el => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/index.tsx"],"names":[],"mappings":"
|
|
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,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;CAClD;AAgED,QAAA,MAAM,cAAc,oFAOjB,KAAK,KAAG,GAAG,CAAC,OA8Qd,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -13,6 +13,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
15
15
|
import { Icon } from '@iconify/react';
|
|
16
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
16
17
|
import cx from 'classnames';
|
|
17
18
|
import { useGrpcMetadata } from '@parca/components';
|
|
18
19
|
import { sanitizeLabelValue } from '@parca/utilities';
|
|
@@ -60,6 +61,7 @@ currentQuery, profileType, queryBrowserRef, }) => {
|
|
|
60
61
|
const [queryRows, setQueryRows] = useState([
|
|
61
62
|
{ labelName: '', operator: '=', labelValue: '', labelValues: [], isLoading: false },
|
|
62
63
|
]);
|
|
64
|
+
const reactQueryClient = useQueryClient();
|
|
63
65
|
const metadata = useGrpcMetadata();
|
|
64
66
|
const { loading: labelNamesLoading, result } = useLabelNames(queryClient, profileType);
|
|
65
67
|
const { response: labelNamesResponse, error: labelNamesError } = result;
|
|
@@ -75,16 +77,24 @@ currentQuery, profileType, queryBrowserRef, }) => {
|
|
|
75
77
|
return matchers.map(matcher => matcher.key);
|
|
76
78
|
}, [currentQuery]);
|
|
77
79
|
const fetchLabelValues = useCallback(async (labelName) => {
|
|
80
|
+
if (labelName == null || labelName === '' || profileType == null || profileType === '') {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
78
83
|
try {
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
const values = await reactQueryClient.fetchQuery([labelName, profileType], async () => {
|
|
85
|
+
const response = await queryClient.values({ labelName, match: [], profileType }, { meta: metadata }).response;
|
|
86
|
+
const sanitizedValues = sanitizeLabelValue(response.labelValues);
|
|
87
|
+
return sanitizedValues;
|
|
88
|
+
}, {
|
|
89
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
90
|
+
});
|
|
91
|
+
return values;
|
|
82
92
|
}
|
|
83
93
|
catch (error) {
|
|
84
94
|
console.error('Error fetching label values:', error);
|
|
85
95
|
return [];
|
|
86
96
|
}
|
|
87
|
-
}, [queryClient, metadata, profileType]);
|
|
97
|
+
}, [queryClient, metadata, profileType, reactQueryClient]);
|
|
88
98
|
const updateMatchersString = useCallback((rows) => {
|
|
89
99
|
const matcherString = rows
|
|
90
100
|
.filter(row => row.labelName.length > 0 && row.labelValue)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Table/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA0D,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Table/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAuB/E,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAS1C,OAAO,EAEL,OAAO,EACP,QAAQ,EAgBT,MAAM,mBAAmB,CAAC;AAe3B,MAAM,MAAM,GAAG,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErC,eAAO,MAAM,UAAU,QAAS,GAAG,KAAG,GAAG,IAAI,QAE5C,CAAC;AAIF,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAkID,eAAO,MAAM,KAAK,wCAydhB,CAAC;AAEH,eAAe,KAAK,CAAC"}
|
package/dist/Table/index.js
CHANGED
|
@@ -17,9 +17,10 @@ import { createColumnHelper, } from '@tanstack/table-core';
|
|
|
17
17
|
import { tableFromIPC, vectorFromArray } from 'apache-arrow';
|
|
18
18
|
import cx from 'classnames';
|
|
19
19
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
20
|
+
import { Tooltip } from 'react-tooltip';
|
|
20
21
|
import { Table as TableComponent, TableSkeleton, useParcaContext, useURLState, } from '@parca/components';
|
|
21
22
|
import { useCurrentColorProfile } from '@parca/hooks';
|
|
22
|
-
import { isSearchMatch, valueFormatter } from '@parca/utilities';
|
|
23
|
+
import { getLastItem, isSearchMatch, valueFormatter } from '@parca/utilities';
|
|
23
24
|
import { getFilenameColors, getMappingColors } from '../ProfileIcicleGraph/IcicleGraphArrow/';
|
|
24
25
|
import useMappingList, { useFilenamesList, } from '../ProfileIcicleGraph/IcicleGraphArrow/useMappingList';
|
|
25
26
|
import { useProfileViewContext } from '../ProfileView/context/ProfileViewContext';
|
|
@@ -148,12 +149,12 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
|
|
|
148
149
|
unit = useMemo(() => unit ?? profileType?.sampleUnit ?? '', [unit, profileType?.sampleUnit]);
|
|
149
150
|
const columns = useMemo(() => {
|
|
150
151
|
return [
|
|
151
|
-
columnHelper.accessor('
|
|
152
|
+
columnHelper.accessor('colorProperty', {
|
|
152
153
|
id: 'color',
|
|
153
154
|
header: '',
|
|
154
155
|
cell: info => {
|
|
155
156
|
const color = info.getValue();
|
|
156
|
-
return _jsx("div", { className: "w-4 h-4 rounded-[4px]", style: { backgroundColor: color } });
|
|
157
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "w-4 h-4 rounded-[4px]", style: { backgroundColor: color.color }, "data-tooltip-id": "table-color-tooltip", "data-tooltip-content": getLastItem(color.mappingFile) }), _jsx(Tooltip, { id: "table-color-tooltip" })] }));
|
|
157
158
|
},
|
|
158
159
|
size: 10,
|
|
159
160
|
}),
|
|
@@ -390,7 +391,10 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
|
|
|
390
391
|
const mappingFile = mappingFileColumn?.get(i) ?? '';
|
|
391
392
|
return {
|
|
392
393
|
id: i,
|
|
393
|
-
|
|
394
|
+
colorProperty: {
|
|
395
|
+
color: getRowColor(colorByColors, mappingFileColumn, i, functionFileNameColumn, colorBy),
|
|
396
|
+
mappingFile,
|
|
397
|
+
},
|
|
394
398
|
name: RowName(mappingFileColumn, locationAddressColumn, functionNameColumn, i),
|
|
395
399
|
flat,
|
|
396
400
|
flatDiff,
|
|
@@ -3,7 +3,10 @@ import { Vector } from 'apache-arrow';
|
|
|
3
3
|
import { colorByColors } from '../../ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes';
|
|
4
4
|
export interface DataRow {
|
|
5
5
|
id: number;
|
|
6
|
-
|
|
6
|
+
colorProperty: {
|
|
7
|
+
color: string;
|
|
8
|
+
mappingFile: string;
|
|
9
|
+
};
|
|
7
10
|
name: string;
|
|
8
11
|
flat: bigint;
|
|
9
12
|
flatDiff: bigint;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../../src/Table/utils/functions.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,KAAK,GAAG,IAAI,OAAO,EAAC,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAC,MAAM,EAAC,MAAM,cAAc,CAAC;AAIpC,OAAO,EAAC,aAAa,EAAC,MAAM,4DAA4D,CAAC;AAGzF,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../../src/Table/utils/functions.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.461",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@headlessui/react": "^1.7.19",
|
|
@@ -74,5 +74,5 @@
|
|
|
74
74
|
"access": "public",
|
|
75
75
|
"registry": "https://registry.npmjs.org/"
|
|
76
76
|
},
|
|
77
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "e004a5ef188bda51bfef2f4a4d2b488b3990d533"
|
|
78
78
|
}
|
|
@@ -11,12 +11,12 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
-
import React, {
|
|
14
|
+
import React, {useMemo, useRef, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import cx from 'classnames';
|
|
17
17
|
import TextareaAutosize from 'react-textarea-autosize';
|
|
18
18
|
|
|
19
|
-
import {LabelsRequest, LabelsResponse, QueryServiceClient} from '@parca/client';
|
|
19
|
+
import {LabelsRequest, LabelsResponse, QueryServiceClient, ValuesRequest} from '@parca/client';
|
|
20
20
|
import {useGrpcMetadata} from '@parca/components';
|
|
21
21
|
import {Query} from '@parca/parser';
|
|
22
22
|
import {millisToProtoTimestamp, sanitizeLabelValue} from '@parca/utilities';
|
|
@@ -75,6 +75,42 @@ export const useLabelNames = (
|
|
|
75
75
|
return {result: {response: data, error: error as Error}, loading: isLoading};
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
+
interface UseLabelValues {
|
|
79
|
+
result: {
|
|
80
|
+
response: string[];
|
|
81
|
+
error?: Error;
|
|
82
|
+
};
|
|
83
|
+
loading: boolean;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export const useLabelValues = (
|
|
87
|
+
client: QueryServiceClient,
|
|
88
|
+
labelName: string,
|
|
89
|
+
profileType: string
|
|
90
|
+
): UseLabelValues => {
|
|
91
|
+
const metadata = useGrpcMetadata();
|
|
92
|
+
|
|
93
|
+
const {data, isLoading, error} = useGrpcQuery<string[]>({
|
|
94
|
+
key: ['labelValues', labelName, profileType],
|
|
95
|
+
queryFn: async () => {
|
|
96
|
+
const request: ValuesRequest = {labelName, match: [], profileType};
|
|
97
|
+
const {response} = await client.values(request, {meta: metadata});
|
|
98
|
+
return sanitizeLabelValue(response.labelValues);
|
|
99
|
+
},
|
|
100
|
+
options: {
|
|
101
|
+
enabled:
|
|
102
|
+
profileType !== undefined &&
|
|
103
|
+
profileType !== '' &&
|
|
104
|
+
labelName !== undefined &&
|
|
105
|
+
labelName !== '',
|
|
106
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
107
|
+
keepPreviousData: false,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return {result: {response: data ?? [], error: error as Error}, loading: isLoading};
|
|
112
|
+
};
|
|
113
|
+
|
|
78
114
|
const MatchersInput = ({
|
|
79
115
|
queryClient,
|
|
80
116
|
setMatchersString,
|
|
@@ -84,34 +120,16 @@ const MatchersInput = ({
|
|
|
84
120
|
}: MatchersInputProps): JSX.Element => {
|
|
85
121
|
const inputRef = useRef<HTMLTextAreaElement | null>(null);
|
|
86
122
|
const [focusedInput, setFocusedInput] = useState(false);
|
|
87
|
-
const [labelValuesLoading, setLabelValuesLoading] = useState(false);
|
|
88
123
|
const [lastCompleted, setLastCompleted] = useState<Suggestion>(new Suggestion('', '', ''));
|
|
89
|
-
const [labelValues, setLabelValues] = useState<string[] | null>(null);
|
|
90
124
|
const [currentLabelName, setCurrentLabelName] = useState<string | null>(null);
|
|
91
|
-
const metadata = useGrpcMetadata();
|
|
92
125
|
|
|
93
126
|
const {loading: labelNamesLoading, result} = useLabelNames(queryClient, profileType);
|
|
94
127
|
const {response: labelNamesResponse, error: labelNamesError} = result;
|
|
95
128
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{meta: metadata}
|
|
101
|
-
);
|
|
102
|
-
setLabelValuesLoading(true);
|
|
103
|
-
|
|
104
|
-
call.response
|
|
105
|
-
.then(response => {
|
|
106
|
-
// replace single `\` in the `labelValues` string with doubles `\\` if available.
|
|
107
|
-
const newValues = sanitizeLabelValue(response.labelValues);
|
|
108
|
-
|
|
109
|
-
return setLabelValues(newValues);
|
|
110
|
-
})
|
|
111
|
-
.catch(() => setLabelValues(null))
|
|
112
|
-
.finally(() => setLabelValuesLoading(false));
|
|
113
|
-
}
|
|
114
|
-
}, [currentLabelName, metadata, profileType, queryClient]);
|
|
129
|
+
const {
|
|
130
|
+
loading: labelValuesLoading,
|
|
131
|
+
result: {response: labelValues},
|
|
132
|
+
} = useLabelValues(queryClient, currentLabelName ?? '', profileType);
|
|
115
133
|
|
|
116
134
|
const labelNames = useMemo(() => {
|
|
117
135
|
return (labelNamesError === undefined || labelNamesError == null) &&
|
|
@@ -71,7 +71,10 @@ const ColorStackLegend = ({compareMode = false}: Props): JSX.Element => {
|
|
|
71
71
|
}}
|
|
72
72
|
>
|
|
73
73
|
<div className="flex items-center">
|
|
74
|
-
<div
|
|
74
|
+
<div
|
|
75
|
+
className="mr-1 inline-block h-4 w-4 rounded-[4px]"
|
|
76
|
+
style={{backgroundColor: color}}
|
|
77
|
+
/>
|
|
75
78
|
<span className="text-sm">{feature}</span>
|
|
76
79
|
</div>
|
|
77
80
|
{isHighlighted ? (
|
|
@@ -88,7 +88,7 @@ const ColorStackLegend = ({mappings, compareMode = false, loading}: Props): Reac
|
|
|
88
88
|
className={cx(
|
|
89
89
|
'flex-no-wrap mb-1 flex w-[19.25%] items-center justify-between text-ellipsis p-1',
|
|
90
90
|
{
|
|
91
|
-
'cursor-pointer': filteringAllowed,
|
|
91
|
+
'cursor-pointer': filteringAllowed && colorBy === 'binary',
|
|
92
92
|
'bg-gray-200 dark:bg-gray-800': isHighlighted,
|
|
93
93
|
}
|
|
94
94
|
)}
|
|
@@ -105,7 +105,10 @@ const ColorStackLegend = ({mappings, compareMode = false, loading}: Props): Reac
|
|
|
105
105
|
>
|
|
106
106
|
<div className="flex w-11/12 items-center justify-start">
|
|
107
107
|
<div className="flex w-5 items-center">
|
|
108
|
-
<div
|
|
108
|
+
<div
|
|
109
|
+
className="mr-1 inline-block h-4 w-4 rounded-[4px]"
|
|
110
|
+
style={{backgroundColor: color}}
|
|
111
|
+
/>
|
|
109
112
|
</div>
|
|
110
113
|
<div className="shrink overflow-hidden text-ellipsis whitespace-nowrap text-sm hover:whitespace-normal">
|
|
111
114
|
{feature}
|
|
@@ -47,7 +47,7 @@ export const useProfileMetadata = ({
|
|
|
47
47
|
const mappingsList = useMappingList(metadataMappingFiles);
|
|
48
48
|
const filenamesList = useFilenamesList(table);
|
|
49
49
|
|
|
50
|
-
const colorMappings = colorBy === 'binary' ? mappingsList : filenamesList;
|
|
50
|
+
const colorMappings = colorBy === 'binary' || colorBy === '' ? mappingsList : filenamesList;
|
|
51
51
|
|
|
52
52
|
return {
|
|
53
53
|
table,
|
|
@@ -183,6 +183,12 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
|
|
|
183
183
|
}
|
|
184
184
|
};
|
|
185
185
|
|
|
186
|
+
const moveCaretToEnd = (e: React.FocusEvent<HTMLTextAreaElement>): void => {
|
|
187
|
+
const value = e.target.value;
|
|
188
|
+
e.target.value = '';
|
|
189
|
+
e.target.value = value;
|
|
190
|
+
};
|
|
191
|
+
|
|
186
192
|
return (
|
|
187
193
|
<div ref={containerRef} className="relative" onKeyDown={handleKeyDown} onClick={onButtonClick}>
|
|
188
194
|
<div
|
|
@@ -232,6 +238,7 @@ const CustomSelect: React.FC<CustomSelectProps> = ({
|
|
|
232
238
|
placeholder="Type a RegEx to add"
|
|
233
239
|
value={searchTerm}
|
|
234
240
|
onChange={e => setSearchTerm(e.target.value)}
|
|
241
|
+
onFocus={e => moveCaretToEnd(e)}
|
|
235
242
|
/>
|
|
236
243
|
{editable && searchTerm.length > 0 && (
|
|
237
244
|
<div className="p-2 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800">
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import {useCallback, useEffect, useMemo, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import {Icon} from '@iconify/react';
|
|
17
|
+
import {useQueryClient} from '@tanstack/react-query';
|
|
17
18
|
import cx from 'classnames';
|
|
18
19
|
|
|
19
20
|
import {QueryServiceClient} from '@parca/client';
|
|
@@ -106,6 +107,7 @@ const SimpleMatchers = ({
|
|
|
106
107
|
const [queryRows, setQueryRows] = useState<QueryRow[]>([
|
|
107
108
|
{labelName: '', operator: '=', labelValue: '', labelValues: [], isLoading: false},
|
|
108
109
|
]);
|
|
110
|
+
const reactQueryClient = useQueryClient();
|
|
109
111
|
const metadata = useGrpcMetadata();
|
|
110
112
|
|
|
111
113
|
const {loading: labelNamesLoading, result} = useLabelNames(queryClient, profileType);
|
|
@@ -129,19 +131,31 @@ const SimpleMatchers = ({
|
|
|
129
131
|
|
|
130
132
|
const fetchLabelValues = useCallback(
|
|
131
133
|
async (labelName: string): Promise<string[]> => {
|
|
134
|
+
if (labelName == null || labelName === '' || profileType == null || profileType === '') {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
132
137
|
try {
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
{
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
const values = await reactQueryClient.fetchQuery(
|
|
139
|
+
[labelName, profileType],
|
|
140
|
+
async () => {
|
|
141
|
+
const response = await queryClient.values(
|
|
142
|
+
{labelName, match: [], profileType},
|
|
143
|
+
{meta: metadata}
|
|
144
|
+
).response;
|
|
145
|
+
const sanitizedValues = sanitizeLabelValue(response.labelValues);
|
|
146
|
+
return sanitizedValues;
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
return values;
|
|
139
153
|
} catch (error) {
|
|
140
154
|
console.error('Error fetching label values:', error);
|
|
141
155
|
return [];
|
|
142
156
|
}
|
|
143
157
|
},
|
|
144
|
-
[queryClient, metadata, profileType]
|
|
158
|
+
[queryClient, metadata, profileType, reactQueryClient]
|
|
145
159
|
);
|
|
146
160
|
|
|
147
161
|
const updateMatchersString = useCallback(
|
package/src/Table/index.tsx
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import {Int64, Vector, tableFromIPC, vectorFromArray} from 'apache-arrow';
|
|
25
25
|
import cx from 'classnames';
|
|
26
26
|
import {AnimatePresence, motion} from 'framer-motion';
|
|
27
|
+
import {Tooltip} from 'react-tooltip';
|
|
27
28
|
|
|
28
29
|
import {
|
|
29
30
|
Table as TableComponent,
|
|
@@ -34,7 +35,7 @@ import {
|
|
|
34
35
|
import {type RowRendererProps} from '@parca/components/dist/Table';
|
|
35
36
|
import {useCurrentColorProfile} from '@parca/hooks';
|
|
36
37
|
import {ProfileType} from '@parca/parser';
|
|
37
|
-
import {isSearchMatch, valueFormatter} from '@parca/utilities';
|
|
38
|
+
import {getLastItem, isSearchMatch, valueFormatter} from '@parca/utilities';
|
|
38
39
|
|
|
39
40
|
import {getFilenameColors, getMappingColors} from '../ProfileIcicleGraph/IcicleGraphArrow/';
|
|
40
41
|
import {colorByColors} from '../ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes';
|
|
@@ -303,12 +304,22 @@ export const Table = React.memo(function Table({
|
|
|
303
304
|
|
|
304
305
|
const columns = useMemo<Array<ColumnDef<Row>>>(() => {
|
|
305
306
|
return [
|
|
306
|
-
columnHelper.accessor('
|
|
307
|
+
columnHelper.accessor('colorProperty', {
|
|
307
308
|
id: 'color',
|
|
308
309
|
header: '',
|
|
309
310
|
cell: info => {
|
|
310
|
-
const color = info.getValue() as string;
|
|
311
|
-
return
|
|
311
|
+
const color = info.getValue() as {color: string; mappingFile: string};
|
|
312
|
+
return (
|
|
313
|
+
<>
|
|
314
|
+
<div
|
|
315
|
+
className="w-4 h-4 rounded-[4px]"
|
|
316
|
+
style={{backgroundColor: color.color}}
|
|
317
|
+
data-tooltip-id="table-color-tooltip"
|
|
318
|
+
data-tooltip-content={getLastItem(color.mappingFile)}
|
|
319
|
+
/>
|
|
320
|
+
<Tooltip id="table-color-tooltip" />
|
|
321
|
+
</>
|
|
322
|
+
);
|
|
312
323
|
},
|
|
313
324
|
size: 10,
|
|
314
325
|
}),
|
|
@@ -577,13 +588,16 @@ export const Table = React.memo(function Table({
|
|
|
577
588
|
|
|
578
589
|
return {
|
|
579
590
|
id: i,
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
591
|
+
colorProperty: {
|
|
592
|
+
color: getRowColor(
|
|
593
|
+
colorByColors,
|
|
594
|
+
mappingFileColumn,
|
|
595
|
+
i,
|
|
596
|
+
functionFileNameColumn,
|
|
597
|
+
colorBy as string
|
|
598
|
+
),
|
|
599
|
+
mappingFile,
|
|
600
|
+
},
|
|
587
601
|
name: RowName(mappingFileColumn, locationAddressColumn, functionNameColumn, i),
|
|
588
602
|
flat,
|
|
589
603
|
flatDiff,
|