mirror of
https://github.com/SigNoz/signoz.git
synced 2026-10-21 09:30:41 +01:00
Compare commits
1 Commits
fix/jsmops
...
fix/dynami
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de6fbfeb2d |
@@ -193,6 +193,40 @@ describe('ValueSelector', () => {
|
||||
|
||||
expect(onSearch).toHaveBeenLastCalledWith('pay');
|
||||
});
|
||||
|
||||
it('commits ALL even when the selection holds a value outside the list', async () => {
|
||||
// A search pick, or one an older time window offered: ALL must still go out as
|
||||
// `__all__`, not as a list that filters the panels to the truncated options.
|
||||
const onChange = jest.fn();
|
||||
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
|
||||
render(
|
||||
<ValueSelector
|
||||
options={OPTIONS}
|
||||
variableType="dynamic"
|
||||
multiSelect
|
||||
showAllOption
|
||||
selection={{ value: ['searched'], allSelected: false }}
|
||||
onChange={onChange}
|
||||
emptyFallback={{ value: null, allSelected: true }}
|
||||
testId="variable-select-env"
|
||||
dynamic={{
|
||||
values: OPTIONS,
|
||||
relatedValues: [],
|
||||
complete: false,
|
||||
onSearch: jest.fn(),
|
||||
onSearchReset: jest.fn(),
|
||||
}}
|
||||
/>,
|
||||
);
|
||||
|
||||
await openDropdown();
|
||||
await user.click(screen.getByText('ALL'));
|
||||
await user.keyboard('{Escape}');
|
||||
|
||||
expect(onChange).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ allSelected: true }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('clearing', () => {
|
||||
|
||||
@@ -12,6 +12,7 @@ function commit(
|
||||
values,
|
||||
options: OPTIONS,
|
||||
showAllOption: true,
|
||||
isDynamic: false,
|
||||
emptyFallback: FALLBACK,
|
||||
...overrides,
|
||||
});
|
||||
@@ -60,6 +61,20 @@ describe('selectionFromCommittedValues', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// A dynamic ALL is sent as `__all__`, so reading it as a list would filter the
|
||||
// panels down to the truncated option set.
|
||||
it('reads every option PLUS a value outside the list as ALL for a dynamic variable', () => {
|
||||
expect(
|
||||
commit([...OPTIONS, 'searched'], { isDynamic: true }).allSelected,
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('does not read a dynamic subset PLUS a value outside the list as ALL', () => {
|
||||
expect(
|
||||
commit(['checkout', 'searched'], { isDynamic: true }).allSelected,
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
// Derived from the values + options at commit time, never from the old selection.
|
||||
it('recomputes the marker: a typed value the data now offers is a normal pick', () => {
|
||||
expect(
|
||||
|
||||
@@ -102,6 +102,7 @@ function ValueSelector({
|
||||
values,
|
||||
options,
|
||||
showAllOption,
|
||||
isDynamic: !!dynamic,
|
||||
emptyFallback,
|
||||
});
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ interface CommittedValues {
|
||||
values: string[];
|
||||
options: string[];
|
||||
showAllOption: boolean;
|
||||
isDynamic: boolean;
|
||||
emptyFallback: VariableSelection;
|
||||
}
|
||||
|
||||
@@ -62,6 +63,7 @@ export function selectionFromCommittedValues({
|
||||
values,
|
||||
options,
|
||||
showAllOption,
|
||||
isDynamic,
|
||||
emptyFallback,
|
||||
}: CommittedValues): VariableSelection {
|
||||
if (values.length === 0) {
|
||||
@@ -71,10 +73,12 @@ export function selectionFromCommittedValues({
|
||||
const customValues = values.filter((value) => !options.includes(value));
|
||||
// ALL re-materializes to the option set, so a set carrying a typed value is not ALL
|
||||
// — the next refetch would expand it back and drop what the user typed.
|
||||
// A dynamic ALL travels as `__all__` and is never re-materialized, so a value outside
|
||||
// its truncated list (a search pick, an older window's pick) loses nothing.
|
||||
const allSelected =
|
||||
showAllOption &&
|
||||
options.length > 0 &&
|
||||
customValues.length === 0 &&
|
||||
(isDynamic || customValues.length === 0) &&
|
||||
options.every((option) => values.includes(option));
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import {
|
||||
IBuilderQuery,
|
||||
@@ -8,10 +7,6 @@ import { DataSource } from 'types/common/queryBuilder';
|
||||
import { getParsedAggregationOptionsForOrderBy } from 'utils/aggregationConverter';
|
||||
import { sanitizeOrderByForExplorer } from 'utils/sanitizeOrderBy';
|
||||
|
||||
jest.mock('@sentry/react', () => ({
|
||||
captureEvent: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('utils/aggregationConverter', () => ({
|
||||
getParsedAggregationOptionsForOrderBy: jest.fn(),
|
||||
}));
|
||||
@@ -122,7 +117,6 @@ describe('sanitizeOrderByForExplorer', () => {
|
||||
|
||||
const result = sanitizeOrderByForExplorer(query);
|
||||
expect(result).toStrictEqual([]);
|
||||
expect(Sentry.captureEvent).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles missing orderBy by returning an empty array', () => {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import * as Sentry from '@sentry/react';
|
||||
import {
|
||||
IBuilderQuery,
|
||||
OrderByPayload,
|
||||
@@ -19,5 +20,15 @@ export function sanitizeOrderByForExplorer(
|
||||
|
||||
const current = query.orderBy || [];
|
||||
|
||||
const hasInvalidOrderBy = current.some((o) => !allowed.has(o.columnName));
|
||||
|
||||
if (hasInvalidOrderBy) {
|
||||
Sentry.captureEvent({
|
||||
message: `Invalid orderBy: current: ${JSON.stringify(
|
||||
current,
|
||||
)} - allowed: ${JSON.stringify(Array.from(allowed))}`,
|
||||
level: 'warning',
|
||||
});
|
||||
}
|
||||
return current.filter((o) => allowed.has(o.columnName));
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ var DefaultJSMOpsReceiverConfig = JSMOpsReceiverConfig{
|
||||
},
|
||||
Message: DefaultJSMOpsMessageTemplate,
|
||||
Description: DefaultJSMOpsDescriptionTemplate,
|
||||
Tags: "signoz-alert",
|
||||
Tags: "signoz",
|
||||
}
|
||||
|
||||
func (c *JSMOpsReceiverConfig) UnmarshalYAML(unmarshal func(any) error) error {
|
||||
|
||||
@@ -17,7 +17,7 @@ func TestJSMOpsReceiverConfigDefaults(t *testing.T) {
|
||||
assert.Equal(t, "key-123", string(c.APIKey))
|
||||
assert.Equal(t, DefaultJSMOpsMessageTemplate, c.Message)
|
||||
assert.Equal(t, DefaultJSMOpsDescriptionTemplate, c.Description)
|
||||
assert.Equal(t, "signoz-alert", c.Tags)
|
||||
assert.Equal(t, "signoz", c.Tags)
|
||||
assert.False(t, c.SendResolved()) // default off when omitted, like other channels
|
||||
|
||||
ch, err := NewChannelFromReceiver(r, "org-1")
|
||||
|
||||
Reference in New Issue
Block a user