Skip to content

Commit adc767b

Browse files
authored
Merge branch 'main' into SIG-9416
2 parents e5f385f + 8752022 commit adc767b

File tree

10 files changed

+339
-169
lines changed

10 files changed

+339
-169
lines changed

deploy/docker-swarm/docker-compose.ha.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ services:
176176
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
177177
signoz:
178178
!!merge <<: *db-depend
179-
image: signoz/signoz:v0.100.0
179+
image: signoz/signoz:v0.100.1
180180
command:
181181
- --config=/root/config/prometheus.yml
182182
ports:

deploy/docker-swarm/docker-compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ services:
117117
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
118118
signoz:
119119
!!merge <<: *db-depend
120-
image: signoz/signoz:v0.100.0
120+
image: signoz/signoz:v0.100.1
121121
command:
122122
- --config=/root/config/prometheus.yml
123123
ports:

deploy/docker/docker-compose.ha.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ services:
179179
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
180180
signoz:
181181
!!merge <<: *db-depend
182-
image: signoz/signoz:${VERSION:-v0.100.0}
182+
image: signoz/signoz:${VERSION:-v0.100.1}
183183
container_name: signoz
184184
command:
185185
- --config=/root/config/prometheus.yml

deploy/docker/docker-compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ services:
111111
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
112112
signoz:
113113
!!merge <<: *db-depend
114-
image: signoz/signoz:${VERSION:-v0.100.0}
114+
image: signoz/signoz:${VERSION:-v0.100.1}
115115
container_name: signoz
116116
command:
117117
- --config=/root/config/prometheus.yml

frontend/src/container/GridCardLayout/styles.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,6 @@ export const Card = styled(CardComponent)<CardProps>`
1717
overflow: hidden;
1818
border-radius: 3px;
1919
border: 1px solid var(--bg-slate-500);
20-
background: linear-gradient(
21-
0deg,
22-
rgba(171, 189, 255, 0) 0%,
23-
rgba(171, 189, 255, 0) 100%
24-
),
25-
#0b0c0e;
2620
2721
${({ isDarkMode }): StyledCSS =>
2822
!isDarkMode &&

frontend/src/container/QueryTable/QueryTable.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,9 @@ export function QueryTable({
9090
column: any,
9191
tableColumns: any,
9292
): void => {
93-
e.stopPropagation();
9493
if (isQueryTypeBuilder && enableDrillDown) {
94+
e.stopPropagation();
95+
9596
onClick({ x: e.clientX, y: e.clientY }, { record, column, tableColumns });
9697
}
9798
},

frontend/src/lib/uPlotLib/placement.ts

Lines changed: 232 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,20 @@
1616

1717
// https://tobyzerner.github.io/placement.js/dist/index.js
1818

19+
/**
20+
* Positions an element (tooltip/popover) relative to a reference element.
21+
* Automatically flips to the opposite side if there's insufficient space.
22+
*
23+
* @param element - The HTMLElement to position
24+
* @param reference - Reference element/Range or bounding rect
25+
* @param side - Preferred side: 'top', 'bottom', 'left', 'right' (default: 'bottom')
26+
* @param align - Alignment: 'start', 'center', 'end' (default: 'center')
27+
* @param options - Optional bounds for constraining the element
28+
* - bound: Custom boundary rect/element
29+
* - followCursor: { x, y } - If provided, tooltip follows cursor with smart positioning
30+
*/
1931
export const placement = (function () {
20-
const e = {
32+
const AXIS_PROPS = {
2133
size: ['height', 'width'],
2234
clientSize: ['clientHeight', 'clientWidth'],
2335
offsetSize: ['offsetHeight', 'offsetWidth'],
@@ -28,87 +40,241 @@ export const placement = (function () {
2840
marginAfter: ['marginBottom', 'marginRight'],
2941
scrollOffset: ['pageYOffset', 'pageXOffset'],
3042
};
31-
function t(e) {
32-
return { top: e.top, bottom: e.bottom, left: e.left, right: e.right };
43+
44+
function extractRect(source) {
45+
return {
46+
top: source.top,
47+
bottom: source.bottom,
48+
left: source.left,
49+
right: source.right,
50+
};
3351
}
34-
return function (o, r, f, a, i) {
35-
void 0 === f && (f = 'bottom'),
36-
void 0 === a && (a = 'center'),
37-
void 0 === i && (i = {}),
38-
(r instanceof Element || r instanceof Range) &&
39-
(r = t(r.getBoundingClientRect()));
40-
const n = {
41-
top: r.bottom,
42-
bottom: r.top,
43-
left: r.right,
44-
right: r.left,
45-
...r,
52+
53+
return function (element, reference, side, align, options) {
54+
// Default parameters
55+
void 0 === side && (side = 'bottom');
56+
void 0 === align && (align = 'center');
57+
void 0 === options && (options = {});
58+
59+
// Handle cursor following mode
60+
if (options.followCursor) {
61+
const cursorX = options.followCursor.x;
62+
const cursorY = options.followCursor.y;
63+
const offset = options.followCursor.offset || 10; // Default 10px offset from cursor
64+
65+
element.style.position = 'absolute';
66+
element.style.maxWidth = '';
67+
element.style.maxHeight = '';
68+
69+
const elementWidth = element.offsetWidth;
70+
const elementHeight = element.offsetHeight;
71+
72+
// Use viewport bounds for cursor following (not chart bounds)
73+
const viewportBounds = {
74+
top: 0,
75+
left: 0,
76+
bottom: window.innerHeight,
77+
right: window.innerWidth,
78+
};
79+
80+
// Vertical positioning: follow cursor Y with offset, clamped to viewport
81+
const topPosition = cursorY + offset;
82+
const clampedTop = Math.max(
83+
viewportBounds.top,
84+
Math.min(topPosition, viewportBounds.bottom - elementHeight),
85+
);
86+
element.style.top = `${clampedTop}px`;
87+
element.style.bottom = 'auto';
88+
89+
// Horizontal positioning: auto-detect left or right based on available space
90+
const spaceOnRight = viewportBounds.right - cursorX;
91+
const spaceOnLeft = cursorX - viewportBounds.left;
92+
93+
if (spaceOnRight >= elementWidth + offset) {
94+
// Enough space on the right
95+
element.style.left = `${cursorX + offset}px`;
96+
element.style.right = 'auto';
97+
element.dataset.side = 'right';
98+
} else if (spaceOnLeft >= elementWidth + offset) {
99+
// Not enough space on right, use left
100+
element.style.left = `${cursorX - elementWidth - offset}px`;
101+
element.style.right = 'auto';
102+
element.dataset.side = 'left';
103+
} else if (spaceOnRight > spaceOnLeft) {
104+
// Not enough space on either side, pick the side with more space
105+
const leftPos = cursorX + offset;
106+
const clampedLeft = Math.max(
107+
viewportBounds.left,
108+
Math.min(leftPos, viewportBounds.right - elementWidth),
109+
);
110+
element.style.left = `${clampedLeft}px`;
111+
element.style.right = 'auto';
112+
element.dataset.side = 'right';
113+
} else {
114+
const leftPos = cursorX - elementWidth - offset;
115+
const clampedLeft = Math.max(
116+
viewportBounds.left,
117+
Math.min(leftPos, viewportBounds.right - elementWidth),
118+
);
119+
element.style.left = `${clampedLeft}px`;
120+
element.style.right = 'auto';
121+
element.dataset.side = 'left';
122+
}
123+
124+
element.dataset.align = 'cursor';
125+
return; // Exit early, don't run normal positioning logic
126+
}
127+
128+
// Normalize reference to rect object
129+
(reference instanceof Element || reference instanceof Range) &&
130+
(reference = extractRect(reference.getBoundingClientRect()));
131+
132+
// Create anchor rect with swapped opposite edges for positioning
133+
const anchorRect = {
134+
top: reference.bottom,
135+
bottom: reference.top,
136+
left: reference.right,
137+
right: reference.left,
138+
...reference,
46139
};
47-
const s = {
140+
141+
// Viewport bounds (can be overridden via options.bound)
142+
const bounds = {
48143
top: 0,
49144
left: 0,
50145
bottom: window.innerHeight,
51146
right: window.innerWidth,
52147
};
53-
i.bound &&
54-
((i.bound instanceof Element || i.bound instanceof Range) &&
55-
(i.bound = t(i.bound.getBoundingClientRect())),
56-
Object.assign(s, i.bound));
57-
const l = getComputedStyle(o);
58-
const m = {};
59-
const b = {};
60-
for (const g in e)
61-
(m[g] = e[g][f === 'top' || f === 'bottom' ? 0 : 1]),
62-
(b[g] = e[g][f === 'top' || f === 'bottom' ? 1 : 0]);
63-
(o.style.position = 'absolute'),
64-
(o.style.maxWidth = ''),
65-
(o.style.maxHeight = '');
66-
const d = parseInt(l[b.marginBefore]);
67-
const c = parseInt(l[b.marginAfter]);
68-
const u = d + c;
69-
const p = s[b.after] - s[b.before] - u;
70-
const h = parseInt(l[b.maxSize]);
71-
(!h || p < h) && (o.style[b.maxSize] = `${p}px`);
72-
const x = parseInt(l[m.marginBefore]) + parseInt(l[m.marginAfter]);
73-
const y = n[m.before] - s[m.before] - x;
74-
const z = s[m.after] - n[m.after] - x;
75-
((f === m.before && o[m.offsetSize] > y) ||
76-
(f === m.after && o[m.offsetSize] > z)) &&
77-
(f = y > z ? m.before : m.after);
78-
const S = f === m.before ? y : z;
79-
const v = parseInt(l[m.maxSize]);
80-
(!v || S < v) && (o.style[m.maxSize] = `${S}px`);
81-
const w = window[m.scrollOffset];
82-
const O = function (e) {
83-
return Math.max(s[m.before], Math.min(e, s[m.after] - o[m.offsetSize] - x));
148+
149+
options.bound &&
150+
((options.bound instanceof Element || options.bound instanceof Range) &&
151+
(options.bound = extractRect(options.bound.getBoundingClientRect())),
152+
Object.assign(bounds, options.bound));
153+
154+
const styles = getComputedStyle(element);
155+
const isVertical = side === 'top' || side === 'bottom';
156+
157+
// Build axis property maps based on orientation
158+
const mainAxis = {}; // Properties for the main positioning axis
159+
const crossAxis = {}; // Properties for the perpendicular axis
160+
161+
for (const prop in AXIS_PROPS) {
162+
mainAxis[prop] = AXIS_PROPS[prop][isVertical ? 0 : 1];
163+
crossAxis[prop] = AXIS_PROPS[prop][isVertical ? 1 : 0];
164+
}
165+
166+
// Reset element positioning
167+
element.style.position = 'absolute';
168+
element.style.maxWidth = '';
169+
element.style.maxHeight = '';
170+
171+
// Cross-axis: calculate and apply max size constraint
172+
const crossMarginBefore = parseInt(styles[crossAxis.marginBefore]);
173+
const crossMarginAfter = parseInt(styles[crossAxis.marginAfter]);
174+
const crossMarginTotal = crossMarginBefore + crossMarginAfter;
175+
const crossAvailableSpace =
176+
bounds[crossAxis.after] - bounds[crossAxis.before] - crossMarginTotal;
177+
const crossMaxSize = parseInt(styles[crossAxis.maxSize]);
178+
179+
(!crossMaxSize || crossAvailableSpace < crossMaxSize) &&
180+
(element.style[crossAxis.maxSize] = `${crossAvailableSpace}px`);
181+
182+
// Main-axis: calculate space on both sides
183+
const mainMarginTotal =
184+
parseInt(styles[mainAxis.marginBefore]) +
185+
parseInt(styles[mainAxis.marginAfter]);
186+
const spaceBefore =
187+
anchorRect[mainAxis.before] - bounds[mainAxis.before] - mainMarginTotal;
188+
const spaceAfter =
189+
bounds[mainAxis.after] - anchorRect[mainAxis.after] - mainMarginTotal;
190+
191+
// Auto-flip to the side with more space if needed
192+
((side === mainAxis.before && element[mainAxis.offsetSize] > spaceBefore) ||
193+
(side === mainAxis.after && element[mainAxis.offsetSize] > spaceAfter)) &&
194+
(side = spaceBefore > spaceAfter ? mainAxis.before : mainAxis.after);
195+
196+
// Apply main-axis max size constraint
197+
const mainAvailableSpace =
198+
side === mainAxis.before ? spaceBefore : spaceAfter;
199+
const mainMaxSize = parseInt(styles[mainAxis.maxSize]);
200+
201+
(!mainMaxSize || mainAvailableSpace < mainMaxSize) &&
202+
(element.style[mainAxis.maxSize] = `${mainAvailableSpace}px`);
203+
204+
// Position on main axis
205+
const mainScrollOffset = window[mainAxis.scrollOffset];
206+
const clampMainPosition = function (pos) {
207+
return Math.max(
208+
bounds[mainAxis.before],
209+
Math.min(
210+
pos,
211+
bounds[mainAxis.after] - element[mainAxis.offsetSize] - mainMarginTotal,
212+
),
213+
);
84214
};
85-
f === m.before
86-
? ((o.style[m.before] = `${w + O(n[m.before] - o[m.offsetSize] - x)}px`),
87-
(o.style[m.after] = 'auto'))
88-
: ((o.style[m.before] = `${w + O(n[m.after])}px`),
89-
(o.style[m.after] = 'auto'));
90-
const B = window[b.scrollOffset];
91-
const I = function (e) {
92-
return Math.max(s[b.before], Math.min(e, s[b.after] - o[b.offsetSize] - u));
215+
216+
side === mainAxis.before
217+
? ((element.style[mainAxis.before] = `${
218+
mainScrollOffset +
219+
clampMainPosition(
220+
anchorRect[mainAxis.before] -
221+
element[mainAxis.offsetSize] -
222+
mainMarginTotal,
223+
)
224+
}px`),
225+
(element.style[mainAxis.after] = 'auto'))
226+
: ((element.style[mainAxis.before] = `${
227+
mainScrollOffset + clampMainPosition(anchorRect[mainAxis.after])
228+
}px`),
229+
(element.style[mainAxis.after] = 'auto'));
230+
231+
// Position on cross axis based on alignment
232+
const crossScrollOffset = window[crossAxis.scrollOffset];
233+
const clampCrossPosition = function (pos) {
234+
return Math.max(
235+
bounds[crossAxis.before],
236+
Math.min(
237+
pos,
238+
bounds[crossAxis.after] - element[crossAxis.offsetSize] - crossMarginTotal,
239+
),
240+
);
93241
};
94-
switch (a) {
242+
243+
switch (align) {
95244
case 'start':
96-
(o.style[b.before] = `${B + I(n[b.before] - d)}px`),
97-
(o.style[b.after] = 'auto');
245+
(element.style[crossAxis.before] = `${
246+
crossScrollOffset +
247+
clampCrossPosition(anchorRect[crossAxis.before] - crossMarginBefore)
248+
}px`),
249+
(element.style[crossAxis.after] = 'auto');
98250
break;
99251
case 'end':
100-
(o.style[b.before] = 'auto'),
101-
(o.style[b.after] = `${
102-
B + I(document.documentElement[b.clientSize] - n[b.after] - c)
252+
(element.style[crossAxis.before] = 'auto'),
253+
(element.style[crossAxis.after] = `${
254+
crossScrollOffset +
255+
clampCrossPosition(
256+
document.documentElement[crossAxis.clientSize] -
257+
anchorRect[crossAxis.after] -
258+
crossMarginAfter,
259+
)
103260
}px`);
104261
break;
105262
default:
106-
var H = n[b.after] - n[b.before];
107-
(o.style[b.before] = `${
108-
B + I(n[b.before] + H / 2 - o[b.offsetSize] / 2 - d)
263+
// 'center'
264+
var crossSize = anchorRect[crossAxis.after] - anchorRect[crossAxis.before];
265+
(element.style[crossAxis.before] = `${
266+
crossScrollOffset +
267+
clampCrossPosition(
268+
anchorRect[crossAxis.before] +
269+
crossSize / 2 -
270+
element[crossAxis.offsetSize] / 2 -
271+
crossMarginBefore,
272+
)
109273
}px`),
110-
(o.style[b.after] = 'auto');
274+
(element.style[crossAxis.after] = 'auto');
111275
}
112-
(o.dataset.side = f), (o.dataset.align = a);
276+
277+
// Store final placement as data attributes
278+
(element.dataset.side = side), (element.dataset.align = align);
113279
};
114280
})();

0 commit comments

Comments
 (0)