@parca/profile 0.16.438 → 0.16.440
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/ProfileIcicleGraph/IcicleGraph/utils.d.ts +2 -2
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraph/utils.js +3 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.js +4 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts +5 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.js +20 -8
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +3 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +25 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useMappingList.d.ts +2 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useMappingList.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useMappingList.js +25 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.d.ts +4 -4
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.js +2 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.d.ts +3 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.js +9 -3
- package/dist/ProfileIcicleGraph/index.d.ts +3 -3
- package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/index.js +20 -5
- package/dist/ProfileView/index.d.ts +3 -3
- package/dist/ProfileView/index.d.ts.map +1 -1
- package/dist/ProfileView/index.js +2 -2
- package/dist/ProfileViewWithData.js +4 -4
- package/dist/components/VisualisationToolbar/MultiLevelDropdown.d.ts.map +1 -1
- package/dist/components/VisualisationToolbar/MultiLevelDropdown.js +52 -6
- package/dist/styles.css +1 -1
- package/package.json +5 -5
- package/src/ProfileIcicleGraph/IcicleGraph/useColoredGraph.ts +5 -5
- package/src/ProfileIcicleGraph/IcicleGraph/utils.ts +4 -4
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.tsx +7 -2
- package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +32 -10
- package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +42 -6
- package/src/ProfileIcicleGraph/IcicleGraphArrow/useMappingList.ts +32 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.ts +6 -6
- package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +18 -4
- package/src/ProfileIcicleGraph/index.tsx +32 -7
- package/src/ProfileView/index.tsx +6 -6
- package/src/ProfileViewWithData.tsx +4 -4
- package/src/components/VisualisationToolbar/MultiLevelDropdown.tsx +85 -13
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import {EVERYTHING_ELSE} from '@parca/store';
|
|
15
15
|
import {diffColor, getLastItem} from '@parca/utilities';
|
|
16
16
|
|
|
17
|
-
interface
|
|
17
|
+
interface colors {
|
|
18
18
|
[key: string]: string;
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -23,8 +23,8 @@ interface Props {
|
|
|
23
23
|
compareMode: boolean;
|
|
24
24
|
cumulative: bigint;
|
|
25
25
|
diff: bigint | null;
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
colorsMap: colors;
|
|
27
|
+
colorAttribute: string | null;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
const useNodeColor = ({
|
|
@@ -32,14 +32,14 @@ const useNodeColor = ({
|
|
|
32
32
|
compareMode,
|
|
33
33
|
cumulative,
|
|
34
34
|
diff,
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
colorsMap,
|
|
36
|
+
colorAttribute,
|
|
37
37
|
}: Props): string => {
|
|
38
38
|
if (compareMode) {
|
|
39
39
|
return diffColor(diff ?? 0n, cumulative, isDarkMode);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
return
|
|
42
|
+
return colorsMap[getLastItem(colorAttribute ?? '') ?? EVERYTHING_ELSE];
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
export default useNodeColor;
|
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
|
|
14
14
|
import {Table} from 'apache-arrow';
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
BINARY_FEATURE_TYPES,
|
|
18
|
+
EVERYTHING_ELSE,
|
|
19
|
+
FILENAMES_FEATURE_TYPES,
|
|
20
|
+
type BinaryFeature,
|
|
21
|
+
type FilenameFeature,
|
|
22
|
+
} from '@parca/store';
|
|
17
23
|
import {divide, getLastItem, valueFormatter} from '@parca/utilities';
|
|
18
24
|
|
|
19
25
|
import {hexifyAddress} from '../../utils';
|
|
@@ -65,12 +71,20 @@ export function nodeLabel(
|
|
|
65
71
|
return fallback === '' ? '<unknown>' : fallback;
|
|
66
72
|
}
|
|
67
73
|
|
|
68
|
-
export const extractFeature = (mapping: string):
|
|
74
|
+
export const extractFeature = (mapping: string): BinaryFeature => {
|
|
69
75
|
if (mapping != null && mapping !== '') {
|
|
70
|
-
return {name: mapping, type:
|
|
76
|
+
return {name: mapping, type: BINARY_FEATURE_TYPES.Binary};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {name: EVERYTHING_ELSE, type: BINARY_FEATURE_TYPES.Misc};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const extractFilenameFeature = (filename: string): FilenameFeature => {
|
|
83
|
+
if (filename != null && filename !== '') {
|
|
84
|
+
return {name: filename, type: FILENAMES_FEATURE_TYPES.Filename};
|
|
71
85
|
}
|
|
72
86
|
|
|
73
|
-
return {name: EVERYTHING_ELSE, type:
|
|
87
|
+
return {name: EVERYTHING_ELSE, type: FILENAMES_FEATURE_TYPES.Misc};
|
|
74
88
|
};
|
|
75
89
|
|
|
76
90
|
export const getTextForCumulative = (
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import React, {useEffect, useMemo, useState} from 'react';
|
|
15
15
|
|
|
16
|
+
import {Table, tableFromIPC} from 'apache-arrow';
|
|
16
17
|
import {AnimatePresence, motion} from 'framer-motion';
|
|
17
18
|
|
|
18
19
|
import {Flamegraph, FlamegraphArrow} from '@parca/client';
|
|
@@ -25,7 +26,7 @@ import DiffLegend from '../components/DiffLegend';
|
|
|
25
26
|
import {IcicleGraph} from './IcicleGraph';
|
|
26
27
|
import {FIELD_FUNCTION_NAME, IcicleGraphArrow} from './IcicleGraphArrow';
|
|
27
28
|
import ColorStackLegend from './IcicleGraphArrow/ColorStackLegend';
|
|
28
|
-
import useMappingList from './IcicleGraphArrow/useMappingList';
|
|
29
|
+
import useMappingList, {useFilenamesList} from './IcicleGraphArrow/useMappingList';
|
|
29
30
|
|
|
30
31
|
const numberFormatter = new Intl.NumberFormat('en-US');
|
|
31
32
|
|
|
@@ -44,8 +45,8 @@ interface ProfileIcicleGraphProps {
|
|
|
44
45
|
setActionButtons?: (buttons: React.JSX.Element) => void;
|
|
45
46
|
error?: any;
|
|
46
47
|
isHalfScreen: boolean;
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
metadataMappingFiles?: string[];
|
|
49
|
+
metadataLoading?: boolean;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
const ErrorContent = ({errorMessage}: {errorMessage: string}): JSX.Element => {
|
|
@@ -64,16 +65,22 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
64
65
|
error,
|
|
65
66
|
width,
|
|
66
67
|
isHalfScreen,
|
|
67
|
-
|
|
68
|
+
metadataMappingFiles,
|
|
68
69
|
}: ProfileIcicleGraphProps): JSX.Element {
|
|
69
70
|
const {onError, authenticationErrorMessage, isDarkMode} = useParcaContext();
|
|
70
71
|
const {compareMode} = useProfileViewContext();
|
|
71
72
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
|
72
73
|
const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
|
|
73
74
|
|
|
74
|
-
const
|
|
75
|
+
const table: Table<any> | null = useMemo(() => {
|
|
76
|
+
return arrow !== undefined ? tableFromIPC(arrow.record) : null;
|
|
77
|
+
}, [arrow]);
|
|
78
|
+
|
|
79
|
+
const mappingsList = useMappingList(metadataMappingFiles);
|
|
80
|
+
const filenamesList = useFilenamesList(table);
|
|
75
81
|
|
|
76
82
|
const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState('sort_by');
|
|
83
|
+
const [colorBy, setColorBy] = useURLState('color_by');
|
|
77
84
|
|
|
78
85
|
// By default, we want delta profiles (CPU) to be relatively compared.
|
|
79
86
|
// For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
|
|
@@ -82,6 +89,12 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
82
89
|
const [compareAbsolute = compareAbsoluteDefault] = useURLState('compare_absolute');
|
|
83
90
|
const isCompareAbsolute = compareAbsolute === 'true';
|
|
84
91
|
|
|
92
|
+
const colorByValue = colorBy === undefined || colorBy === '' ? 'binary' : (colorBy as string);
|
|
93
|
+
const mappingsListCount = useMemo(
|
|
94
|
+
() => mappingsList.filter(m => m !== '').length,
|
|
95
|
+
[mappingsList]
|
|
96
|
+
);
|
|
97
|
+
|
|
85
98
|
const [
|
|
86
99
|
totalFormatted,
|
|
87
100
|
totalUnfilteredFormatted,
|
|
@@ -113,7 +126,15 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
113
126
|
}, [graph, arrow, filtered, total]);
|
|
114
127
|
|
|
115
128
|
const loadingState =
|
|
116
|
-
!loading && (arrow !== undefined || graph !== undefined) &&
|
|
129
|
+
!loading && (arrow !== undefined || graph !== undefined) && metadataMappingFiles !== undefined;
|
|
130
|
+
|
|
131
|
+
// If there is only one mapping file, we want to color by filename by default.
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
if (mappingsListCount === 1 && colorBy !== 'filename') {
|
|
134
|
+
setColorBy('filename');
|
|
135
|
+
}
|
|
136
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
137
|
+
}, [mappingsListCount]);
|
|
117
138
|
|
|
118
139
|
useEffect(() => {
|
|
119
140
|
if (loadingState) {
|
|
@@ -211,7 +232,11 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
|
|
|
211
232
|
>
|
|
212
233
|
{compareMode ? <DiffLegend /> : null}
|
|
213
234
|
{isColorStackLegendEnabled && (
|
|
214
|
-
<ColorStackLegend
|
|
235
|
+
<ColorStackLegend
|
|
236
|
+
compareMode={compareMode}
|
|
237
|
+
mappings={colorByValue === 'binary' ? mappingsList : filenamesList}
|
|
238
|
+
loading={isLoading}
|
|
239
|
+
/>
|
|
215
240
|
)}
|
|
216
241
|
<div className="min-h-48" id="h-icicle-graph">
|
|
217
242
|
<>{icicleGraph}</>
|
|
@@ -56,9 +56,9 @@ export interface FlamegraphData {
|
|
|
56
56
|
total?: bigint;
|
|
57
57
|
filtered?: bigint;
|
|
58
58
|
error?: any;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
metadataMappingFiles?: string[];
|
|
60
|
+
metadataLoading: boolean;
|
|
61
|
+
metadataLabels?: string[];
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
export interface TopTableData {
|
|
@@ -231,8 +231,8 @@ export const ProfileView = ({
|
|
|
231
231
|
: dimensions.width - 16
|
|
232
232
|
: 0
|
|
233
233
|
}
|
|
234
|
-
|
|
235
|
-
|
|
234
|
+
metadataMappingFiles={flamegraphData.metadataMappingFiles}
|
|
235
|
+
metadataLoading={flamegraphData.metadataLoading}
|
|
236
236
|
/>
|
|
237
237
|
</ConditionalWrapper>
|
|
238
238
|
);
|
|
@@ -397,7 +397,7 @@ export const ProfileView = ({
|
|
|
397
397
|
filtered={filtered}
|
|
398
398
|
currentSearchString={currentSearchString}
|
|
399
399
|
setSearchString={setSearchString}
|
|
400
|
-
groupByLabels={flamegraphData.
|
|
400
|
+
groupByLabels={flamegraphData.metadataLabels ?? []}
|
|
401
401
|
/>
|
|
402
402
|
|
|
403
403
|
<div className="w-full" ref={ref}>
|
|
@@ -199,15 +199,15 @@ export const ProfileViewWithData = ({
|
|
|
199
199
|
total: BigInt(flamegraphResponse?.total ?? '0'),
|
|
200
200
|
filtered: BigInt(flamegraphResponse?.filtered ?? '0'),
|
|
201
201
|
error: flamegraphError,
|
|
202
|
-
|
|
202
|
+
metadataMappingFiles:
|
|
203
203
|
profileMetadataResponse?.report.oneofKind === 'profileMetadata'
|
|
204
204
|
? profileMetadataResponse?.report?.profileMetadata?.mappingFiles
|
|
205
205
|
: undefined,
|
|
206
|
-
|
|
207
|
-
groupByLabels:
|
|
206
|
+
metadataLabels:
|
|
208
207
|
profileMetadataResponse?.report.oneofKind === 'profileMetadata'
|
|
209
208
|
? profileMetadataResponse?.report?.profileMetadata?.labels
|
|
210
|
-
:
|
|
209
|
+
: undefined,
|
|
210
|
+
metadataLoading: profileMetadataLoading,
|
|
211
211
|
}}
|
|
212
212
|
topTableData={{
|
|
213
213
|
loading: tableLoading,
|
|
@@ -37,6 +37,7 @@ interface MenuItemType {
|
|
|
37
37
|
active?: boolean;
|
|
38
38
|
value?: string;
|
|
39
39
|
icon?: string;
|
|
40
|
+
customSubmenu?: React.ReactNode;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
type MenuItemProps = MenuItemType & {
|
|
@@ -44,7 +45,8 @@ type MenuItemProps = MenuItemType & {
|
|
|
44
45
|
path?: string[];
|
|
45
46
|
closeDropdown: () => void;
|
|
46
47
|
isNested?: boolean;
|
|
47
|
-
|
|
48
|
+
activeValueForSortBy?: string;
|
|
49
|
+
activeValueForColorBy?: string;
|
|
48
50
|
icon?: string;
|
|
49
51
|
};
|
|
50
52
|
|
|
@@ -57,12 +59,22 @@ const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
57
59
|
id,
|
|
58
60
|
closeDropdown,
|
|
59
61
|
isNested = false,
|
|
60
|
-
|
|
62
|
+
activeValueForSortBy,
|
|
63
|
+
activeValueForColorBy,
|
|
61
64
|
value,
|
|
62
65
|
disabled = false,
|
|
63
66
|
icon,
|
|
67
|
+
customSubmenu,
|
|
64
68
|
}) => {
|
|
65
|
-
|
|
69
|
+
let isActive = false;
|
|
70
|
+
if (isNested) {
|
|
71
|
+
if (activeValueForSortBy !== undefined && value === activeValueForSortBy) {
|
|
72
|
+
isActive = true;
|
|
73
|
+
}
|
|
74
|
+
if (activeValueForColorBy !== undefined && value === activeValueForColorBy) {
|
|
75
|
+
isActive = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
66
78
|
|
|
67
79
|
const handleSelect = (): void => {
|
|
68
80
|
if (items === undefined) {
|
|
@@ -93,13 +105,17 @@ const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
93
105
|
id={id}
|
|
94
106
|
disabled={disabled}
|
|
95
107
|
>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
108
|
+
{customSubmenu !== undefined ? (
|
|
109
|
+
customSubmenu
|
|
110
|
+
) : (
|
|
111
|
+
<span className="flex items-center">
|
|
112
|
+
<div className="flex items-center">
|
|
113
|
+
<span>{label}</span>
|
|
114
|
+
{icon !== undefined && <Icon icon={icon} className="ml-2 h-4 w-4" />}
|
|
115
|
+
</div>
|
|
116
|
+
{isActive && <Icon icon="heroicons-solid:check" className="ml-2 h-4 w-4" />}
|
|
117
|
+
</span>
|
|
118
|
+
)}
|
|
103
119
|
{items !== undefined && (
|
|
104
120
|
<Icon icon="flowbite:caret-right-solid" className="h-[14px] w-[14px]" />
|
|
105
121
|
)}
|
|
@@ -118,7 +134,8 @@ const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
118
134
|
path={[...path, label]}
|
|
119
135
|
closeDropdown={closeDropdown}
|
|
120
136
|
isNested={true}
|
|
121
|
-
|
|
137
|
+
activeValueForSortBy={activeValueForSortBy}
|
|
138
|
+
activeValueForColorBy={activeValueForColorBy}
|
|
122
139
|
/>
|
|
123
140
|
))}
|
|
124
141
|
</Menu.Items>
|
|
@@ -141,6 +158,11 @@ const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = ({onSelect, profil
|
|
|
141
158
|
});
|
|
142
159
|
const [colorStackLegend, setStoreColorStackLegend] = useURLState('color_stack_legend');
|
|
143
160
|
const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
|
|
161
|
+
const [colorBy, setColorBy] = useURLState('color_by');
|
|
162
|
+
const [hiddenBinaries, setHiddenBinaries] = useURLState('binary_frame_filter', {
|
|
163
|
+
defaultValue: [],
|
|
164
|
+
alwaysReturnArray: true,
|
|
165
|
+
});
|
|
144
166
|
const {compareMode} = useProfileViewContext();
|
|
145
167
|
const [colorProfileName] = useUserPreference<string>(
|
|
146
168
|
USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key
|
|
@@ -157,6 +179,12 @@ const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = ({onSelect, profil
|
|
|
157
179
|
useURLState('compare_absolute');
|
|
158
180
|
const isCompareAbsolute = compareAbsolute === 'true';
|
|
159
181
|
|
|
182
|
+
const handleBinaryToggle = (index: number): void => {
|
|
183
|
+
const updatedBinaries = [...(hiddenBinaries as string[])];
|
|
184
|
+
updatedBinaries.splice(index, 1);
|
|
185
|
+
setHiddenBinaries(updatedBinaries);
|
|
186
|
+
};
|
|
187
|
+
|
|
160
188
|
const setColorStackLegend = useCallback(
|
|
161
189
|
(value: string): void => {
|
|
162
190
|
setStoreColorStackLegend(value);
|
|
@@ -193,6 +221,25 @@ const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = ({onSelect, profil
|
|
|
193
221
|
hide: false,
|
|
194
222
|
icon: 'material-symbols:sort',
|
|
195
223
|
},
|
|
224
|
+
{
|
|
225
|
+
label: 'Color by',
|
|
226
|
+
id: 'h-solor-by-filter',
|
|
227
|
+
items: [
|
|
228
|
+
{
|
|
229
|
+
label: 'Binary',
|
|
230
|
+
onclick: () => setColorBy('binary'),
|
|
231
|
+
value: 'binary',
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
label: 'Filename',
|
|
235
|
+
onclick: () => setColorBy('filename'),
|
|
236
|
+
value: 'filename',
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
hide: false,
|
|
240
|
+
icon: 'carbon:color-palette',
|
|
241
|
+
},
|
|
242
|
+
|
|
196
243
|
{
|
|
197
244
|
label: isColorStackLegendEnabled ? 'Hide legend' : 'Show legend',
|
|
198
245
|
onclick: () => setColorStackLegend(isColorStackLegendEnabled ? 'false' : 'true'),
|
|
@@ -219,6 +266,28 @@ const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = ({onSelect, profil
|
|
|
219
266
|
id: 'h-reset-legend-button',
|
|
220
267
|
icon: 'system-uicons:reset',
|
|
221
268
|
},
|
|
269
|
+
{
|
|
270
|
+
label: 'Hidden Binaries',
|
|
271
|
+
id: 'h-hidden-binaries',
|
|
272
|
+
items: (hiddenBinaries as string[])?.map((binary, index) => ({
|
|
273
|
+
label: binary,
|
|
274
|
+
customSubmenu: (
|
|
275
|
+
<div className="flex items-center gap-2 w-full">
|
|
276
|
+
<input
|
|
277
|
+
id={binary}
|
|
278
|
+
name={binary}
|
|
279
|
+
type="checkbox"
|
|
280
|
+
className="h-4 w-4 rounded-md border-2 border-gray-300 text-indigo-600 focus:ring-indigo-600 focus:ring-offset-0 checked:bg-indigo-600 checked:border-indigo-600"
|
|
281
|
+
checked={hiddenBinaries?.includes(binary)}
|
|
282
|
+
onChange={() => handleBinaryToggle(index)}
|
|
283
|
+
/>
|
|
284
|
+
<span>{binary}</span>
|
|
285
|
+
</div>
|
|
286
|
+
),
|
|
287
|
+
})),
|
|
288
|
+
hide: hiddenBinaries === undefined || hiddenBinaries.length === 0,
|
|
289
|
+
icon: 'ph:eye-closed',
|
|
290
|
+
},
|
|
222
291
|
];
|
|
223
292
|
|
|
224
293
|
return (
|
|
@@ -233,7 +302,7 @@ const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = ({onSelect, profil
|
|
|
233
302
|
/>
|
|
234
303
|
</Menu.Button>
|
|
235
304
|
{open && (
|
|
236
|
-
<Menu.Items className="absolute z-30
|
|
305
|
+
<Menu.Items className="absolute z-30 left-0 w-56 mt-2 py-2 origin-top-right bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none border dark:bg-gray-900 dark:border-gray-600">
|
|
237
306
|
<span className="text-xs text-gray-400 capitalize px-4 py-3">actions</span>
|
|
238
307
|
{menuItems
|
|
239
308
|
.filter(item => item.hide !== undefined && !item.hide)
|
|
@@ -243,7 +312,10 @@ const MultiLevelDropdown: React.FC<MultiLevelDropdownProps> = ({onSelect, profil
|
|
|
243
312
|
{...item}
|
|
244
313
|
onSelect={onSelect}
|
|
245
314
|
closeDropdown={close}
|
|
246
|
-
|
|
315
|
+
activeValueForSortBy={storeSortBy as string}
|
|
316
|
+
activeValueForColorBy={
|
|
317
|
+
colorBy === undefined || colorBy === '' ? 'binary' : (colorBy as string)
|
|
318
|
+
}
|
|
247
319
|
/>
|
|
248
320
|
))}
|
|
249
321
|
</Menu.Items>
|