@parca/profile 0.19.44 → 0.19.46
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/GraphTooltipArrow/Content.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/Content.js +1 -1
- package/dist/MetricsGraph/MetricsContextMenu/index.d.ts +20 -11
- package/dist/MetricsGraph/MetricsContextMenu/index.d.ts.map +1 -1
- package/dist/MetricsGraph/MetricsContextMenu/index.js +16 -20
- package/dist/MetricsGraph/MetricsTooltip/index.d.ts +2 -8
- package/dist/MetricsGraph/MetricsTooltip/index.d.ts.map +1 -1
- package/dist/MetricsGraph/MetricsTooltip/index.js +46 -55
- package/dist/MetricsGraph/UtilizationMetrics/Throughput.d.ts +2 -5
- package/dist/MetricsGraph/UtilizationMetrics/Throughput.d.ts.map +1 -1
- package/dist/MetricsGraph/UtilizationMetrics/Throughput.js +126 -205
- package/dist/MetricsGraph/UtilizationMetrics/index.d.ts +9 -17
- package/dist/MetricsGraph/UtilizationMetrics/index.d.ts.map +1 -1
- package/dist/MetricsGraph/UtilizationMetrics/index.js +149 -208
- package/dist/MetricsGraph/index.d.ts +19 -26
- package/dist/MetricsGraph/index.d.ts.map +1 -1
- package/dist/MetricsGraph/index.js +50 -115
- package/dist/ProfileFlameGraph/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/index.js +3 -1
- package/dist/ProfileMetricsGraph/index.d.ts +1 -1
- package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
- package/dist/ProfileMetricsGraph/index.js +232 -23
- package/dist/ProfileSelector/MetricsGraphSection.d.ts +1 -4
- package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
- package/dist/ProfileSelector/MetricsGraphSection.js +8 -4
- package/dist/ProfileSelector/index.d.ts +3 -6
- package/dist/ProfileSelector/index.d.ts.map +1 -1
- package/dist/ProfileSelector/index.js +2 -2
- package/dist/ProfileSource.d.ts +9 -6
- package/dist/ProfileSource.d.ts.map +1 -1
- package/dist/ProfileSource.js +23 -8
- package/dist/ProfileView/components/GroupByLabelsDropdown/index.d.ts.map +1 -1
- package/dist/ProfileView/components/GroupByLabelsDropdown/index.js +5 -1
- package/dist/ProfileView/components/ProfileFilters/index.d.ts.map +1 -1
- package/dist/ProfileView/components/ProfileFilters/index.js +6 -5
- package/dist/styles.css +1 -1
- package/dist/useQuery.js +1 -1
- package/package.json +7 -7
- package/src/GraphTooltipArrow/Content.tsx +2 -4
- package/src/MetricsGraph/MetricsContextMenu/index.tsx +78 -66
- package/src/MetricsGraph/MetricsTooltip/index.tsx +53 -210
- package/src/MetricsGraph/UtilizationMetrics/Throughput.tsx +242 -434
- package/src/MetricsGraph/UtilizationMetrics/index.tsx +312 -448
- package/src/MetricsGraph/index.tsx +99 -185
- package/src/ProfileFlameGraph/index.tsx +3 -1
- package/src/ProfileMetricsGraph/index.tsx +430 -37
- package/src/ProfileSelector/MetricsGraphSection.tsx +12 -8
- package/src/ProfileSelector/index.tsx +5 -5
- package/src/ProfileSource.tsx +34 -17
- package/src/ProfileView/components/GroupByLabelsDropdown/index.tsx +15 -3
- package/src/ProfileView/components/ProfileFilters/index.tsx +23 -3
- package/src/useQuery.tsx +1 -1
|
@@ -14,92 +14,104 @@
|
|
|
14
14
|
import {Icon} from '@iconify/react';
|
|
15
15
|
import {Item, Menu, Submenu} from 'react-contexify';
|
|
16
16
|
|
|
17
|
-
import {Label} from '@parca/client';
|
|
18
17
|
import {useParcaContext} from '@parca/components';
|
|
19
18
|
|
|
20
|
-
import {
|
|
19
|
+
import {Series, SeriesPoint} from '../';
|
|
20
|
+
|
|
21
|
+
export interface ContextMenuItem {
|
|
22
|
+
id: string;
|
|
23
|
+
label: React.ReactNode;
|
|
24
|
+
icon?: string;
|
|
25
|
+
onClick: (closestPoint: SeriesPoint | null, series: Series[]) => void;
|
|
26
|
+
disabled?: (closestPoint: SeriesPoint | null, series: Series[]) => boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ContextMenuSubmenu {
|
|
30
|
+
id: string;
|
|
31
|
+
label: React.ReactNode;
|
|
32
|
+
icon?: string;
|
|
33
|
+
items?: ContextMenuItem[];
|
|
34
|
+
createDynamicItems?: (closestPoint: SeriesPoint | null, series: Series[]) => ContextMenuItem[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export type ContextMenuItemOrSubmenu = ContextMenuItem | ContextMenuSubmenu;
|
|
21
38
|
|
|
22
39
|
interface MetricsContextMenuProps {
|
|
23
40
|
menuId: string;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
) => void;
|
|
27
|
-
highlighted: HighlightedSeries | null;
|
|
41
|
+
closestPoint: SeriesPoint | null;
|
|
42
|
+
series: Series[];
|
|
28
43
|
trackVisibility: (isVisible: boolean) => void;
|
|
29
|
-
|
|
44
|
+
menuItems: ContextMenuItemOrSubmenu[];
|
|
30
45
|
}
|
|
31
46
|
|
|
32
|
-
const transformUtilizationLabels = (label: string, utilizationMetrics: boolean): string => {
|
|
33
|
-
if (utilizationMetrics) {
|
|
34
|
-
return label.replace('attributes.', '').replace('attributes_resource.', '');
|
|
35
|
-
}
|
|
36
|
-
return label;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
47
|
const MetricsContextMenu = ({
|
|
40
48
|
menuId,
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
closestPoint,
|
|
50
|
+
series,
|
|
43
51
|
trackVisibility,
|
|
44
|
-
|
|
52
|
+
menuItems,
|
|
45
53
|
}: MetricsContextMenuProps): JSX.Element => {
|
|
46
54
|
const {isDarkMode} = useParcaContext();
|
|
47
|
-
const labels = highlighted?.labels.filter((label: Label) => label.name !== '__name__');
|
|
48
55
|
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
const renderMenuItem = (item: ContextMenuItemOrSubmenu): React.ReactNode => {
|
|
57
|
+
if ('items' in item || 'createDynamicItems' in item) {
|
|
58
|
+
// This is a submenu
|
|
59
|
+
const submenu = item;
|
|
60
|
+
const items =
|
|
61
|
+
submenu.createDynamicItems != null
|
|
62
|
+
? submenu.createDynamicItems(closestPoint, series)
|
|
63
|
+
: submenu.items ?? [];
|
|
54
64
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
label={
|
|
68
|
-
<div className="flex w-full items-center gap-2">
|
|
69
|
-
<Icon icon="material-symbols:add" />
|
|
70
|
-
<div>Add to query</div>
|
|
71
|
-
</div>
|
|
72
|
-
}
|
|
73
|
-
>
|
|
74
|
-
<div className="max-h-[300px] overflow-auto">
|
|
75
|
-
{labels == null || labels.length === 0 ? (
|
|
76
|
-
<Item disabled>
|
|
77
|
-
<div className="flex w-full items-center gap-2">
|
|
78
|
-
<Icon icon="ph:warning" />
|
|
79
|
-
<div>No labels available</div>
|
|
80
|
-
</div>
|
|
81
|
-
</Item>
|
|
82
|
-
) : (
|
|
83
|
-
labels.map((label: Label) => (
|
|
65
|
+
return (
|
|
66
|
+
<Submenu
|
|
67
|
+
key={submenu.id}
|
|
68
|
+
label={
|
|
69
|
+
<div className="flex w-full items-center gap-2">
|
|
70
|
+
{submenu.icon != null && submenu.icon !== '' && <Icon icon={submenu.icon} />}
|
|
71
|
+
<div>{submenu.label}</div>
|
|
72
|
+
</div>
|
|
73
|
+
}
|
|
74
|
+
>
|
|
75
|
+
<div className="max-h-[300px] overflow-auto">
|
|
76
|
+
{items.map(subItem => (
|
|
84
77
|
<Item
|
|
85
|
-
key={
|
|
86
|
-
id={
|
|
87
|
-
onClick={() =>
|
|
88
|
-
|
|
89
|
-
key: label.name,
|
|
90
|
-
value: label.value,
|
|
91
|
-
});
|
|
92
|
-
}}
|
|
78
|
+
key={subItem.id}
|
|
79
|
+
id={subItem.id}
|
|
80
|
+
onClick={() => subItem.onClick(closestPoint, series)}
|
|
81
|
+
disabled={subItem.disabled?.(closestPoint, series) ?? false}
|
|
93
82
|
className="max-w-[400px] overflow-hidden"
|
|
94
83
|
>
|
|
95
|
-
<div className="
|
|
96
|
-
{
|
|
84
|
+
<div className="flex w-full items-center gap-2">
|
|
85
|
+
{subItem.icon != null && subItem.icon !== '' && <Icon icon={subItem.icon} />}
|
|
86
|
+
<div>{subItem.label}</div>
|
|
97
87
|
</div>
|
|
98
88
|
</Item>
|
|
99
|
-
))
|
|
100
|
-
|
|
101
|
-
</
|
|
102
|
-
|
|
89
|
+
))}
|
|
90
|
+
</div>
|
|
91
|
+
</Submenu>
|
|
92
|
+
);
|
|
93
|
+
} else {
|
|
94
|
+
// This is a regular menu item
|
|
95
|
+
const menuItem = item as ContextMenuItem;
|
|
96
|
+
return (
|
|
97
|
+
<Item
|
|
98
|
+
key={menuItem.id}
|
|
99
|
+
id={menuItem.id}
|
|
100
|
+
onClick={() => menuItem.onClick(closestPoint, series)}
|
|
101
|
+
disabled={menuItem.disabled?.(closestPoint, series) ?? false}
|
|
102
|
+
>
|
|
103
|
+
<div className="flex w-full items-center gap-2">
|
|
104
|
+
{menuItem.icon != null && menuItem.icon !== '' && <Icon icon={menuItem.icon} />}
|
|
105
|
+
<div>{menuItem.label}</div>
|
|
106
|
+
</div>
|
|
107
|
+
</Item>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<Menu id={menuId} onVisibilityChange={trackVisibility} theme={isDarkMode ? 'dark' : ''}>
|
|
114
|
+
{menuItems.map(renderMenuItem)}
|
|
103
115
|
</Menu>
|
|
104
116
|
);
|
|
105
117
|
};
|
|
@@ -13,262 +13,105 @@
|
|
|
13
13
|
|
|
14
14
|
import {useEffect, useMemo, useState} from 'react';
|
|
15
15
|
|
|
16
|
-
import {Icon} from '@iconify/react';
|
|
17
|
-
import type {VirtualElement} from '@popperjs/core';
|
|
18
16
|
import {usePopper} from 'react-popper';
|
|
19
17
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
import {HighlightedSeries} from '../';
|
|
18
|
+
interface VirtualElement {
|
|
19
|
+
getBoundingClientRect: () => DOMRect;
|
|
20
|
+
}
|
|
25
21
|
|
|
26
22
|
interface Props {
|
|
27
23
|
x: number;
|
|
28
24
|
y: number;
|
|
29
|
-
highlighted: HighlightedSeries;
|
|
30
25
|
contextElement: Element | null;
|
|
31
|
-
|
|
32
|
-
sampleUnit: string;
|
|
33
|
-
delta: boolean;
|
|
34
|
-
utilizationMetrics?: boolean;
|
|
35
|
-
valuePrefix?: string;
|
|
26
|
+
content: React.ReactNode;
|
|
36
27
|
}
|
|
37
28
|
|
|
38
29
|
const virtualElement: VirtualElement = {
|
|
39
30
|
getBoundingClientRect: () => {
|
|
40
|
-
|
|
41
|
-
return {
|
|
31
|
+
const emptyRect: DOMRect = {
|
|
42
32
|
width: 0,
|
|
43
33
|
height: 0,
|
|
44
34
|
top: 0,
|
|
45
|
-
left: 0,
|
|
46
35
|
right: 0,
|
|
47
36
|
bottom: 0,
|
|
48
|
-
|
|
37
|
+
left: 0,
|
|
38
|
+
x: 0,
|
|
39
|
+
y: 0,
|
|
40
|
+
toJSON: () => ({}),
|
|
41
|
+
};
|
|
42
|
+
return emptyRect;
|
|
49
43
|
},
|
|
50
44
|
};
|
|
51
45
|
|
|
52
|
-
|
|
53
|
-
const domRect =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const MetricsTooltip = ({
|
|
67
|
-
x,
|
|
68
|
-
y,
|
|
69
|
-
highlighted,
|
|
70
|
-
contextElement,
|
|
71
|
-
sampleType,
|
|
72
|
-
sampleUnit,
|
|
73
|
-
delta,
|
|
74
|
-
utilizationMetrics = false,
|
|
75
|
-
valuePrefix,
|
|
76
|
-
}: Props): JSX.Element => {
|
|
77
|
-
const {timezone} = useParcaContext();
|
|
46
|
+
const createDomRect = (x: number, y: number): DOMRect => {
|
|
47
|
+
const domRect: DOMRect = {
|
|
48
|
+
width: 0,
|
|
49
|
+
height: 0,
|
|
50
|
+
top: y,
|
|
51
|
+
right: x,
|
|
52
|
+
bottom: y,
|
|
53
|
+
left: x,
|
|
54
|
+
x,
|
|
55
|
+
y,
|
|
56
|
+
toJSON: () => ({}),
|
|
57
|
+
};
|
|
58
|
+
return domRect;
|
|
59
|
+
};
|
|
78
60
|
|
|
61
|
+
const MetricsTooltip = ({x, y, contextElement, content}: Props): JSX.Element => {
|
|
79
62
|
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
|
80
63
|
|
|
81
|
-
const {styles, attributes,
|
|
64
|
+
const {styles, attributes, update} = usePopper(virtualElement, popperElement, {
|
|
82
65
|
placement: 'auto-start',
|
|
83
66
|
strategy: 'absolute',
|
|
84
67
|
modifiers: [
|
|
85
68
|
{
|
|
86
69
|
name: 'preventOverflow',
|
|
87
70
|
options: {
|
|
88
|
-
|
|
89
|
-
altAxis: true,
|
|
71
|
+
boundary: contextElement ?? undefined,
|
|
90
72
|
},
|
|
91
73
|
},
|
|
92
74
|
{
|
|
93
75
|
name: 'offset',
|
|
94
76
|
options: {
|
|
95
|
-
offset: [
|
|
77
|
+
offset: [15, 15],
|
|
96
78
|
},
|
|
97
79
|
},
|
|
98
80
|
],
|
|
99
81
|
});
|
|
100
82
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return highlighted.labels
|
|
118
|
-
.filter(label => label.name.startsWith('attributes_resource.'))
|
|
119
|
-
.reduce<Record<string, string>>((acc, label) => {
|
|
120
|
-
const key = label.name.replace('attributes_resource.', '');
|
|
121
|
-
acc[key] = label.value;
|
|
122
|
-
return acc;
|
|
123
|
-
}, {});
|
|
124
|
-
}, [highlighted.labels]);
|
|
83
|
+
useMemo(() => {
|
|
84
|
+
virtualElement.getBoundingClientRect = (): DOMRect => {
|
|
85
|
+
const domRect: DOMRect = (contextElement as Element)?.getBoundingClientRect() ?? {
|
|
86
|
+
width: 0,
|
|
87
|
+
height: 0,
|
|
88
|
+
top: 0,
|
|
89
|
+
right: 0,
|
|
90
|
+
bottom: 0,
|
|
91
|
+
left: 0,
|
|
92
|
+
x: 0,
|
|
93
|
+
y: 0,
|
|
94
|
+
toJSON: () => ({}),
|
|
95
|
+
};
|
|
96
|
+
return createDomRect(domRect.x + x, domRect.y + y);
|
|
97
|
+
};
|
|
98
|
+
}, [x, y, contextElement]);
|
|
125
99
|
|
|
126
100
|
useEffect(() => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
void update?.();
|
|
130
|
-
}
|
|
131
|
-
}, [x, y, contextElement, update]);
|
|
101
|
+
void update?.();
|
|
102
|
+
}, [x, y, update]);
|
|
132
103
|
|
|
133
|
-
|
|
134
|
-
|
|
104
|
+
// Don't render anything if content is null or undefined
|
|
105
|
+
if (content == null) {
|
|
106
|
+
return <></>;
|
|
107
|
+
}
|
|
135
108
|
|
|
136
109
|
return (
|
|
137
110
|
<div ref={setPopperElement} style={styles.popper} {...attributes.popper} className="z-50">
|
|
138
111
|
<div className="flex max-w-lg">
|
|
139
112
|
<div className="m-auto">
|
|
140
|
-
<div
|
|
141
|
-
|
|
142
|
-
style={{borderWidth: 1}}
|
|
143
|
-
>
|
|
144
|
-
<div className="flex flex-row">
|
|
145
|
-
<div className="ml-2 mr-6">
|
|
146
|
-
<span className="font-semibold">{highlightedNameLabel.value}</span>
|
|
147
|
-
<span className="my-2 block text-gray-700 dark:text-gray-300">
|
|
148
|
-
<table className="table-auto">
|
|
149
|
-
<tbody>
|
|
150
|
-
{delta ? (
|
|
151
|
-
<>
|
|
152
|
-
<tr>
|
|
153
|
-
<td className="w-1/4 pr-3">Per Second</td>
|
|
154
|
-
<td className="w-3/4">
|
|
155
|
-
{valueFormatter(
|
|
156
|
-
highlighted.valuePerSecond,
|
|
157
|
-
sampleUnit === 'nanoseconds' && sampleType === 'cpu'
|
|
158
|
-
? 'CPU Cores'
|
|
159
|
-
: sampleUnit,
|
|
160
|
-
5
|
|
161
|
-
)}
|
|
162
|
-
</td>
|
|
163
|
-
</tr>
|
|
164
|
-
<tr>
|
|
165
|
-
<td className="w-1/4">Total</td>
|
|
166
|
-
<td className="w-3/4">
|
|
167
|
-
{valueFormatter(highlighted.value, sampleUnit, 2)}
|
|
168
|
-
</td>
|
|
169
|
-
</tr>
|
|
170
|
-
</>
|
|
171
|
-
) : (
|
|
172
|
-
<tr>
|
|
173
|
-
<td className="w-1/4">
|
|
174
|
-
{valuePrefix ?? ''}
|
|
175
|
-
Value
|
|
176
|
-
</td>
|
|
177
|
-
<td className="w-3/4">
|
|
178
|
-
{valueFormatter(highlighted.valuePerSecond, sampleUnit, 5)}
|
|
179
|
-
</td>
|
|
180
|
-
</tr>
|
|
181
|
-
)}
|
|
182
|
-
{highlighted.duration > 0 && (
|
|
183
|
-
<tr>
|
|
184
|
-
<td className="w-1/4">Duration</td>
|
|
185
|
-
<td className="w-3/4">
|
|
186
|
-
{valueFormatter(highlighted.duration, 'nanoseconds', 2)}
|
|
187
|
-
</td>
|
|
188
|
-
</tr>
|
|
189
|
-
)}
|
|
190
|
-
<tr>
|
|
191
|
-
<td className="w-1/4">At</td>
|
|
192
|
-
<td className="w-3/4">
|
|
193
|
-
{formatDate(
|
|
194
|
-
highlighted.timestamp,
|
|
195
|
-
timePattern(timezone as string),
|
|
196
|
-
timezone
|
|
197
|
-
)}
|
|
198
|
-
</td>
|
|
199
|
-
</tr>
|
|
200
|
-
</tbody>
|
|
201
|
-
</table>
|
|
202
|
-
</span>
|
|
203
|
-
<span className="my-2 block text-gray-500">
|
|
204
|
-
{utilizationMetrics ? (
|
|
205
|
-
<>
|
|
206
|
-
{Object.keys(attributesResourceMap).length > 0 && (
|
|
207
|
-
<span className="text-sm font-bold text-gray-700 dark:text-white">
|
|
208
|
-
Resource Attributes
|
|
209
|
-
</span>
|
|
210
|
-
)}
|
|
211
|
-
<span className="my-2 block text-gray-500">
|
|
212
|
-
{Object.keys(attributesResourceMap).map(name => (
|
|
213
|
-
<div
|
|
214
|
-
key={name}
|
|
215
|
-
className="mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-400"
|
|
216
|
-
>
|
|
217
|
-
<TextWithTooltip
|
|
218
|
-
text={`${name.replace('attributes.', '')}="${
|
|
219
|
-
attributesResourceMap[name]
|
|
220
|
-
}"`}
|
|
221
|
-
maxTextLength={48}
|
|
222
|
-
id={`tooltip-${name}-${attributesResourceMap[name]}`}
|
|
223
|
-
/>
|
|
224
|
-
</div>
|
|
225
|
-
))}
|
|
226
|
-
</span>
|
|
227
|
-
{Object.keys(attributesMap).length > 0 && (
|
|
228
|
-
<span className="text-sm font-bold text-gray-700 dark:text-white">
|
|
229
|
-
Attributes
|
|
230
|
-
</span>
|
|
231
|
-
)}
|
|
232
|
-
<span className="my-2 block text-gray-500">
|
|
233
|
-
{Object.keys(attributesMap).map(name => (
|
|
234
|
-
<div
|
|
235
|
-
key={name}
|
|
236
|
-
className="mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-400"
|
|
237
|
-
>
|
|
238
|
-
<TextWithTooltip
|
|
239
|
-
text={`${name.replace('attributes.', '')}="${attributesMap[name]}"`}
|
|
240
|
-
maxTextLength={48}
|
|
241
|
-
id={`tooltip-${name}-${attributesMap[name]}`}
|
|
242
|
-
/>
|
|
243
|
-
</div>
|
|
244
|
-
))}
|
|
245
|
-
</span>
|
|
246
|
-
</>
|
|
247
|
-
) : (
|
|
248
|
-
<>
|
|
249
|
-
{highlighted.labels
|
|
250
|
-
.filter((label: Label) => label.name !== '__name__')
|
|
251
|
-
.map((label: Label) => (
|
|
252
|
-
<div
|
|
253
|
-
key={label.name}
|
|
254
|
-
className="mr-3 inline-block rounded-lg bg-gray-200 px-2 py-1 text-xs font-bold text-gray-700 dark:bg-gray-700 dark:text-gray-400"
|
|
255
|
-
>
|
|
256
|
-
<TextWithTooltip
|
|
257
|
-
text={`${label.name}="${label.value}"`}
|
|
258
|
-
maxTextLength={37}
|
|
259
|
-
id={`tooltip-${label.name}`}
|
|
260
|
-
/>
|
|
261
|
-
</div>
|
|
262
|
-
))}
|
|
263
|
-
</>
|
|
264
|
-
)}
|
|
265
|
-
</span>
|
|
266
|
-
<div className="flex w-full items-center gap-1 text-xs text-gray-500">
|
|
267
|
-
<Icon icon="iconoir:mouse-button-right" />
|
|
268
|
-
<div>Right click to add labels to query.</div>
|
|
269
|
-
</div>
|
|
270
|
-
</div>
|
|
271
|
-
</div>
|
|
113
|
+
<div className="border border-gray-300 bg-gray-50 dark:border-gray-500 dark:bg-gray-900 rounded-lg shadow-lg px-3 py-2">
|
|
114
|
+
{content}
|
|
272
115
|
</div>
|
|
273
116
|
</div>
|
|
274
117
|
</div>
|