mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-07 02:12:11 +00:00
Compare commits
86 Commits
fix/query-
...
fix/multi-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
070decb102 | ||
|
|
0fbe60d68f | ||
|
|
7e877790d0 | ||
|
|
3b2d3c3849 | ||
|
|
815d3b8bc0 | ||
|
|
e529ad8d57 | ||
|
|
c8f36de6fa | ||
|
|
85caefa945 | ||
|
|
62d8dd929a | ||
|
|
afceff33d6 | ||
|
|
ed77c6abd0 | ||
|
|
5575334893 | ||
|
|
137a3f6d27 | ||
|
|
c332a3c48a | ||
|
|
84ff35100a | ||
|
|
67ce050f53 | ||
|
|
ceefe50d82 | ||
|
|
04c9e852e6 | ||
|
|
97cd377fa6 | ||
|
|
157213defc | ||
|
|
8092df8961 | ||
|
|
3c895981d9 | ||
|
|
a058dac45b | ||
|
|
a18106f5d8 | ||
|
|
ea88177936 | ||
|
|
84a17dd376 | ||
|
|
f699773aec | ||
|
|
d46d1a0f24 | ||
|
|
a3b66935d8 | ||
|
|
1f8c97cd5b | ||
|
|
2659e03564 | ||
|
|
121696c1d7 | ||
|
|
20be9dd600 | ||
|
|
45e4c65c9f | ||
|
|
b7490fcf68 | ||
|
|
4bfd4e536c | ||
|
|
f7d5a26403 | ||
|
|
f87594243e | ||
|
|
dacc3d6d9e | ||
|
|
6b28ec2f7f | ||
|
|
9b757af028 | ||
|
|
ce87bcae71 | ||
|
|
25fb8b6561 | ||
|
|
428a16326a | ||
|
|
78fec2188d | ||
|
|
c5650cc131 | ||
|
|
f67213096c | ||
|
|
d71f85a8ec | ||
|
|
9335261314 | ||
|
|
0f5c54cabb | ||
|
|
0204337396 | ||
|
|
8101fef874 | ||
|
|
2d223fe9e8 | ||
|
|
de464e6042 | ||
|
|
ea42e4db6b | ||
|
|
2b5d2f0061 | ||
|
|
a013cc0fd3 | ||
|
|
e68d860adf | ||
|
|
9ed93ae5ac | ||
|
|
9989af10d6 | ||
|
|
1bc89c9d1a | ||
|
|
3fbe111bc0 | ||
|
|
c449d1da8e | ||
|
|
4635da0ee8 | ||
|
|
67453e27f7 | ||
|
|
fdcc6a6c92 | ||
|
|
62c71e6306 | ||
|
|
e2e535eaca | ||
|
|
2520718afb | ||
|
|
0ffa666903 | ||
|
|
c653e83461 | ||
|
|
b80cf96faf | ||
|
|
a2126ad22c | ||
|
|
5a75df30e2 | ||
|
|
aeca98b6aa | ||
|
|
53b31ae516 | ||
|
|
209828de01 | ||
|
|
491a0140e3 | ||
|
|
b9494a3375 | ||
|
|
d4b379ccc0 | ||
|
|
a7ff27d30c | ||
|
|
6008e8df72 | ||
|
|
27d5e16d18 | ||
|
|
24d6b48ad4 | ||
|
|
78af24b4df | ||
|
|
45fcf746b0 |
@@ -8,4 +8,10 @@ import {
|
||||
export const getKeySuggestions = (
|
||||
props: QueryKeyRequestProps,
|
||||
): Promise<AxiosResponse<QueryKeySuggestionsResponseProps>> =>
|
||||
axios.get(`/fields/keys?signal=${props.signal}&name=${props.name}`);
|
||||
axios.get(
|
||||
`/fields/keys?signal=${props.signal}&searchText=${
|
||||
props.searchText
|
||||
}&metricName=${props.metricName ?? ''}&fieldContext=${
|
||||
props.fieldContext ?? ''
|
||||
}&fieldDataType=${props.fieldDataType ?? ''}`,
|
||||
);
|
||||
|
||||
@@ -4,7 +4,6 @@ import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
|
||||
import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi';
|
||||
import { isEmpty } from 'lodash-es';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import {
|
||||
IBuilderQuery,
|
||||
QueryFunctionProps,
|
||||
@@ -126,10 +125,12 @@ function createBaseSpec(
|
||||
selectFields: isEmpty(queryData.selectColumns)
|
||||
? undefined
|
||||
: queryData.selectColumns?.map(
|
||||
(column: BaseAutocompleteData): TelemetryFieldKey => ({
|
||||
name: column.key,
|
||||
fieldDataType: column?.dataType as FieldDataType,
|
||||
fieldContext: column?.type as FieldContext,
|
||||
(column: any): TelemetryFieldKey => ({
|
||||
name: column.name ?? column.key,
|
||||
fieldDataType:
|
||||
column?.fieldDataType ?? (column?.dataType as FieldDataType),
|
||||
fieldContext: column?.fieldContext ?? (column?.type as FieldContext),
|
||||
signal: column?.signal ?? undefined,
|
||||
}),
|
||||
),
|
||||
};
|
||||
|
||||
@@ -410,18 +410,18 @@ export default function LogsFormatOptionsMenu({
|
||||
)}
|
||||
|
||||
<div className="column-format">
|
||||
{addColumn?.value?.map(({ key, id }) => (
|
||||
<div className="column-name" key={id}>
|
||||
{addColumn?.value?.map(({ name }) => (
|
||||
<div className="column-name" key={name}>
|
||||
<div className="name">
|
||||
<Tooltip placement="left" title={key}>
|
||||
{key}
|
||||
<Tooltip placement="left" title={name}>
|
||||
{name}
|
||||
</Tooltip>
|
||||
</div>
|
||||
{addColumn?.value?.length > 1 && (
|
||||
<X
|
||||
className="delete-btn"
|
||||
size={14}
|
||||
onClick={(): void => addColumn.onRemove(id as string)}
|
||||
onClick={(): void => addColumn.onRemove(name)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -7,9 +7,11 @@ import SpaceAggregationOptions from 'container/QueryBuilder/components/SpaceAggr
|
||||
import { GroupByFilter, OperatorsSelect } from 'container/QueryBuilder/filters';
|
||||
import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations';
|
||||
import { Info } from 'lucide-react';
|
||||
import { memo, useCallback, useMemo } from 'react';
|
||||
import { memo, useCallback, useEffect, useMemo } from 'react';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import { useQueryBuilderV2Context } from '../../QueryBuilderV2Context';
|
||||
|
||||
const MetricsAggregateSection = memo(function MetricsAggregateSection({
|
||||
query,
|
||||
index,
|
||||
@@ -21,6 +23,7 @@ const MetricsAggregateSection = memo(function MetricsAggregateSection({
|
||||
version: string;
|
||||
panelType: PANEL_TYPES | null;
|
||||
}): JSX.Element {
|
||||
const { setAggregationOptions } = useQueryBuilderV2Context();
|
||||
const {
|
||||
operators,
|
||||
spaceAggregationOptions,
|
||||
@@ -33,6 +36,20 @@ const MetricsAggregateSection = memo(function MetricsAggregateSection({
|
||||
entityVersion: version,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setAggregationOptions([
|
||||
{
|
||||
func: query.spaceAggregation || 'count',
|
||||
arg: query.aggregateAttribute.key || '',
|
||||
},
|
||||
]);
|
||||
}, [
|
||||
query.spaceAggregation,
|
||||
query.aggregateAttribute.key,
|
||||
setAggregationOptions,
|
||||
query,
|
||||
]);
|
||||
|
||||
const handleChangeGroupByKeys = useCallback(
|
||||
(value: IBuilderQuery['groupBy']) => {
|
||||
handleChangeQueryData('groupBy', value);
|
||||
|
||||
@@ -53,17 +53,6 @@ const havingOperators = [
|
||||
},
|
||||
];
|
||||
|
||||
// Add common value suggestions
|
||||
const commonValues = [
|
||||
{ label: '0', value: '0 ' },
|
||||
{ label: '1', value: '1 ' },
|
||||
{ label: '5', value: '5 ' },
|
||||
{ label: '10', value: '10 ' },
|
||||
{ label: '50', value: '50 ' },
|
||||
{ label: '100', value: '100 ' },
|
||||
{ label: '1000', value: '1000 ' },
|
||||
];
|
||||
|
||||
const conjunctions = [
|
||||
{ label: 'AND', value: 'AND ' },
|
||||
{ label: 'OR', value: 'OR ' },
|
||||
@@ -250,22 +239,18 @@ function HavingFilter({
|
||||
};
|
||||
}
|
||||
|
||||
// Show value suggestions after operator
|
||||
// Close dropdown after operator to allow custom value entry
|
||||
if (isAfterOperator(tokens)) {
|
||||
return {
|
||||
from: context.pos,
|
||||
options: [
|
||||
...commonValues.map((value) => ({
|
||||
...value,
|
||||
apply: applyValueCompletion,
|
||||
})),
|
||||
{
|
||||
label: 'Enter a custom number value',
|
||||
type: 'text',
|
||||
apply: applyValueCompletion,
|
||||
},
|
||||
],
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
// Hide suggestions while typing a value after an operator
|
||||
if (
|
||||
!text.endsWith(' ') &&
|
||||
tokens.length >= 2 &&
|
||||
havingOperators.some((op) => op.value === tokens[tokens.length - 2])
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Suggest key/operator pairs and ( for grouping
|
||||
@@ -346,6 +331,7 @@ function HavingFilter({
|
||||
havingAutocomplete,
|
||||
javascript({ jsx: false, typescript: false }),
|
||||
stopEventsExtension,
|
||||
EditorView.lineWrapping,
|
||||
keymap.of([
|
||||
...completionKeymap,
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { copilot } from '@uiw/codemirror-theme-copilot';
|
||||
import CodeMirror, { EditorView, keymap, Prec } from '@uiw/react-codemirror';
|
||||
import CodeMirror, { EditorView, keymap } from '@uiw/react-codemirror';
|
||||
import { Button, Card, Collapse, Popover, Tag } from 'antd';
|
||||
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
|
||||
import { getValueSuggestions } from 'api/querySuggestions/getValueSuggestion';
|
||||
@@ -32,9 +32,13 @@ import {
|
||||
queryOperatorSuggestions,
|
||||
validateQuery,
|
||||
} from 'utils/antlrQueryUtils';
|
||||
import { getQueryContextAtCursor } from 'utils/queryContextUtils';
|
||||
import {
|
||||
getQueryContextAtCursor,
|
||||
getCurrentValueIndexAtCursor,
|
||||
} from 'utils/queryContextUtils';
|
||||
|
||||
import { queryExamples } from './constants';
|
||||
import { isNull } from 'lodash-es';
|
||||
|
||||
const { Panel } = Collapse;
|
||||
|
||||
@@ -111,20 +115,12 @@ function QuerySearch({
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
const [isCompleteKeysList, setIsCompleteKeysList] = useState(false);
|
||||
const [isCompleteValuesList, setIsCompleteValuesList] = useState<boolean>(
|
||||
false,
|
||||
);
|
||||
const [
|
||||
isFetchingCompleteValuesList,
|
||||
setIsFetchingCompleteValuesList,
|
||||
] = useState<boolean>(false);
|
||||
|
||||
const lastPosRef = useRef<{ line: number; ch: number }>({ line: 0, ch: 0 });
|
||||
|
||||
// Reference to the editor view for programmatic autocompletion
|
||||
const editorRef = useRef<EditorView | null>(null);
|
||||
const lastKeyRef = useRef<string>('');
|
||||
const lastValueRef = useRef<string>('');
|
||||
const isMountedRef = useRef<boolean>(true);
|
||||
|
||||
// const {
|
||||
@@ -151,7 +147,8 @@ function QuerySearch({
|
||||
const fetchKeySuggestions = async (searchText?: string): Promise<void> => {
|
||||
const response = await getKeySuggestions({
|
||||
signal: dataSource,
|
||||
name: searchText || '',
|
||||
searchText: searchText || '',
|
||||
metricName: queryData.aggregateAttribute.key ?? undefined,
|
||||
});
|
||||
|
||||
if (response.data.data) {
|
||||
@@ -166,7 +163,7 @@ function QuerySearch({
|
||||
setKeySuggestions([]);
|
||||
fetchKeySuggestions();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [dataSource]);
|
||||
}, [dataSource, queryData.aggregateAttribute.key]);
|
||||
|
||||
// Add a state for tracking editing mode
|
||||
const [editingMode, setEditingMode] = useState<
|
||||
@@ -222,10 +219,7 @@ function QuerySearch({
|
||||
|
||||
// If we're already inside bracket list for IN operator and it's a string value
|
||||
// just wrap in quotes but not brackets (we're already in brackets)
|
||||
if (
|
||||
(type === 'value' || type === 'keyword') &&
|
||||
!/^[a-zA-Z0-9_][a-zA-Z0-9_.\[\]]*$/.test(value)
|
||||
) {
|
||||
if (type === 'value' || type === 'keyword') {
|
||||
return wrapStringValueInQuotes(value);
|
||||
}
|
||||
|
||||
@@ -244,29 +238,17 @@ function QuerySearch({
|
||||
// Use callback to prevent dependency changes on each render
|
||||
const fetchValueSuggestions = useCallback(
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
async ({
|
||||
key,
|
||||
searchText,
|
||||
fetchingComplete = false,
|
||||
}: {
|
||||
key: string;
|
||||
searchText?: string;
|
||||
fetchingComplete?: boolean;
|
||||
}): Promise<void> => {
|
||||
async (key: string): Promise<void> => {
|
||||
if (
|
||||
!key ||
|
||||
(key === activeKey && !isLoadingSuggestions && !fetchingComplete) ||
|
||||
(key === activeKey && !isLoadingSuggestions) ||
|
||||
!isMountedRef.current
|
||||
)
|
||||
return;
|
||||
|
||||
// Set loading state and store the key we're fetching for
|
||||
setIsLoadingSuggestions(true);
|
||||
if (fetchingComplete) {
|
||||
setIsFetchingCompleteValuesList(true);
|
||||
}
|
||||
lastKeyRef.current = key;
|
||||
lastValueRef.current = searchText || '';
|
||||
setActiveKey(key);
|
||||
|
||||
setValueSuggestions([
|
||||
@@ -278,21 +260,14 @@ function QuerySearch({
|
||||
},
|
||||
]);
|
||||
|
||||
const sanitizedSearchText = searchText ? searchText?.trim() : '';
|
||||
|
||||
try {
|
||||
const response = await getValueSuggestions({
|
||||
key,
|
||||
searchText: sanitizedSearchText,
|
||||
signal: dataSource,
|
||||
});
|
||||
|
||||
// Skip updates if component unmounted or key changed
|
||||
if (
|
||||
!isMountedRef.current ||
|
||||
lastKeyRef.current !== key ||
|
||||
lastValueRef.current !== sanitizedSearchText
|
||||
) {
|
||||
if (!isMountedRef.current || lastKeyRef.current !== key) {
|
||||
return; // Skip updating if key has changed or component unmounted
|
||||
}
|
||||
|
||||
@@ -371,9 +346,6 @@ function QuerySearch({
|
||||
]);
|
||||
setIsLoadingSuggestions(false);
|
||||
}
|
||||
} finally {
|
||||
setIsLoadingSuggestions(false);
|
||||
setIsFetchingCompleteValuesList(false);
|
||||
}
|
||||
},
|
||||
[activeKey, dataSource, isLoadingSuggestions],
|
||||
@@ -503,8 +475,7 @@ function QuerySearch({
|
||||
// Enhanced myCompletions function to better use context including query pairs
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
function autoSuggestions(context: CompletionContext): CompletionResult | null {
|
||||
// This matches words before the cursor position
|
||||
const word = context.matchBefore(/[a-zA-Z0-9_.:/?&=#%\-\[\]]*/);
|
||||
const word = context.matchBefore(/[.\w]*/);
|
||||
if (word?.from === word?.to && !context.explicit) return null;
|
||||
|
||||
// Get the query context at the cursor position
|
||||
@@ -528,7 +499,7 @@ function QuerySearch({
|
||||
completion: any,
|
||||
from: number,
|
||||
to: number,
|
||||
shouldAddSpace: boolean = true,
|
||||
shouldAddSpace = true,
|
||||
): void => {
|
||||
view.dispatch({
|
||||
changes: {
|
||||
@@ -556,24 +527,47 @@ function QuerySearch({
|
||||
from: number,
|
||||
to: number,
|
||||
): void => {
|
||||
if (queryContext.isInValue && option.type === 'value') {
|
||||
if (
|
||||
queryContext.currentPair?.position &&
|
||||
queryContext.currentPair.position.valueStart &&
|
||||
queryContext.currentPair.position.valueEnd
|
||||
) {
|
||||
const { valueStart, valueEnd } = queryContext.currentPair.position;
|
||||
addSpaceAfterSelection(
|
||||
view,
|
||||
{ apply: originalApply },
|
||||
valueStart,
|
||||
valueEnd + 1,
|
||||
false,
|
||||
let shouldDefaultApply = true;
|
||||
|
||||
// Changes to replace the value in-place with the existing value
|
||||
const isValueType = queryContext.isInValue && option.type === 'value';
|
||||
const pair = queryContext.currentPair;
|
||||
|
||||
if (isValueType) {
|
||||
if (queryContext.isInBracketList && pair?.valuesPosition) {
|
||||
const idx = getCurrentValueIndexAtCursor(
|
||||
pair.valuesPosition,
|
||||
cursorPos.ch,
|
||||
);
|
||||
} else {
|
||||
addSpaceAfterSelection(view, { apply: originalApply }, from, to);
|
||||
if (!isNull(idx)) {
|
||||
const { start, end } = pair.valuesPosition[idx];
|
||||
if (typeof start === 'number' && typeof end === 'number') {
|
||||
shouldDefaultApply = false;
|
||||
addSpaceAfterSelection(
|
||||
view,
|
||||
{ apply: originalApply },
|
||||
start,
|
||||
end + 1,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (pair?.position) {
|
||||
const { valueStart, valueEnd } = pair.position;
|
||||
if (typeof valueStart === 'number' && typeof valueEnd === 'number') {
|
||||
shouldDefaultApply = false;
|
||||
addSpaceAfterSelection(
|
||||
view,
|
||||
{ apply: originalApply },
|
||||
valueStart,
|
||||
valueEnd + 1,
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
if (shouldDefaultApply) {
|
||||
addSpaceAfterSelection(view, { apply: originalApply }, from, to);
|
||||
}
|
||||
},
|
||||
@@ -590,36 +584,21 @@ function QuerySearch({
|
||||
return null;
|
||||
}
|
||||
|
||||
const searchText = word?.text.toLowerCase().trim() ?? '';
|
||||
options = (valueSuggestions || []).filter((option) =>
|
||||
option.label.toLowerCase().includes(searchText),
|
||||
);
|
||||
|
||||
if (
|
||||
keyName &&
|
||||
((options.length === 0 &&
|
||||
(!isCompleteValuesList || lastValueRef.current !== searchText) &&
|
||||
!isFetchingCompleteValuesList) ||
|
||||
keyName !== activeKey ||
|
||||
isLoadingSuggestions) &&
|
||||
(keyName !== activeKey || isLoadingSuggestions) &&
|
||||
!(isLoadingSuggestions && lastKeyRef.current === keyName)
|
||||
) {
|
||||
setTimeout(() => {
|
||||
fetchValueSuggestions({
|
||||
key: keyName,
|
||||
searchText,
|
||||
fetchingComplete: true,
|
||||
});
|
||||
}, 300);
|
||||
fetchValueSuggestions(keyName);
|
||||
}
|
||||
|
||||
// For values in bracket list, just add quotes without enclosing in brackets
|
||||
const processedOptions = options.map((option) => {
|
||||
const processedOptions = valueSuggestions.map((option) => {
|
||||
// Clone the option to avoid modifying the original
|
||||
const processedOption = { ...option };
|
||||
|
||||
// Skip processing for non-selectable items
|
||||
if (!option.apply || typeof option.apply === 'function') {
|
||||
if (option.apply === false || typeof option.apply === 'function') {
|
||||
return option;
|
||||
}
|
||||
|
||||
@@ -759,29 +738,14 @@ function QuerySearch({
|
||||
if (!keyName) {
|
||||
return null;
|
||||
}
|
||||
const searchText = word?.text.toLowerCase().trim() ?? '';
|
||||
|
||||
options = (valueSuggestions || []).filter((option) =>
|
||||
option.label.toLowerCase().includes(searchText),
|
||||
);
|
||||
|
||||
// Trigger fetch only if needed
|
||||
if (
|
||||
keyName &&
|
||||
((options.length === 0 &&
|
||||
(!isCompleteValuesList || lastValueRef.current !== searchText) &&
|
||||
!isFetchingCompleteValuesList) ||
|
||||
keyName !== activeKey ||
|
||||
isLoadingSuggestions) &&
|
||||
(keyName !== activeKey || isLoadingSuggestions) &&
|
||||
!(isLoadingSuggestions && lastKeyRef.current === keyName)
|
||||
) {
|
||||
setTimeout(() => {
|
||||
fetchValueSuggestions({
|
||||
key: keyName,
|
||||
searchText,
|
||||
fetchingComplete: true,
|
||||
});
|
||||
}, 300);
|
||||
fetchValueSuggestions(keyName);
|
||||
}
|
||||
|
||||
// Process options to add appropriate formatting when selected
|
||||
@@ -946,7 +910,7 @@ function QuerySearch({
|
||||
// options: optionsWithSpace,
|
||||
// };
|
||||
|
||||
//Don't show anything if no context detected
|
||||
// Don't show anything if no context detected
|
||||
return {
|
||||
from: word?.from ?? 0,
|
||||
options: [],
|
||||
@@ -980,7 +944,7 @@ function QuerySearch({
|
||||
|
||||
// Only fetch if needed and if we have a valid key
|
||||
if (key && key !== activeKey && !isLoadingSuggestions) {
|
||||
fetchValueSuggestions({ key });
|
||||
fetchValueSuggestions(key);
|
||||
}
|
||||
}
|
||||
}, [queryContext, activeKey, isLoadingSuggestions, fetchValueSuggestions]);
|
||||
@@ -1046,42 +1010,13 @@ function QuerySearch({
|
||||
javascript({ jsx: false, typescript: false }),
|
||||
EditorView.lineWrapping,
|
||||
stopEventsExtension,
|
||||
Prec.highest(
|
||||
keymap.of([
|
||||
...completionKeymap,
|
||||
{
|
||||
key: 'Escape',
|
||||
run: closeCompletion,
|
||||
},
|
||||
{
|
||||
key: 'Enter',
|
||||
preventDefault: true,
|
||||
// Prevent default behavior of Enter to add new line
|
||||
// and instead run a custom action
|
||||
run: (): boolean => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'Mod-Enter',
|
||||
preventDefault: true,
|
||||
// Prevent default behavior of Mod-Enter to add new line
|
||||
// and instead run a custom action
|
||||
// Mod-Enter is usually Ctrl-Enter or Cmd-Enter based on OS
|
||||
run: (): boolean => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'Shift-Enter',
|
||||
preventDefault: true,
|
||||
// Prevent default behavior of Shift-Enter to add new line
|
||||
run: (): boolean => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
]),
|
||||
),
|
||||
keymap.of([
|
||||
...completionKeymap,
|
||||
{
|
||||
key: 'Escape',
|
||||
run: closeCompletion,
|
||||
},
|
||||
]),
|
||||
]}
|
||||
placeholder="Enter your query (e.g., status = 'error' AND service = 'frontend')"
|
||||
basicSetup={{
|
||||
|
||||
@@ -6,10 +6,6 @@ import {
|
||||
import { SelectOption } from 'types/common/select';
|
||||
|
||||
export const metricAggregateOperatorOptions: SelectOption<string, string>[] = [
|
||||
{
|
||||
value: MetricAggregateOperator.NOOP,
|
||||
label: 'NOOP',
|
||||
},
|
||||
{
|
||||
value: MetricAggregateOperator.COUNT,
|
||||
label: 'Count',
|
||||
@@ -130,10 +126,6 @@ export const metricAggregateOperatorOptions: SelectOption<string, string>[] = [
|
||||
];
|
||||
|
||||
export const tracesAggregateOperatorOptions: SelectOption<string, string>[] = [
|
||||
{
|
||||
value: TracesAggregatorOperator.NOOP,
|
||||
label: 'NOOP',
|
||||
},
|
||||
{
|
||||
value: TracesAggregatorOperator.COUNT,
|
||||
label: 'Count',
|
||||
@@ -217,10 +209,6 @@ export const tracesAggregateOperatorOptions: SelectOption<string, string>[] = [
|
||||
];
|
||||
|
||||
export const logsAggregateOperatorOptions: SelectOption<string, string>[] = [
|
||||
{
|
||||
value: LogsAggregatorOperator.NOOP,
|
||||
label: 'NOOP',
|
||||
},
|
||||
{
|
||||
value: LogsAggregatorOperator.COUNT,
|
||||
label: 'Count',
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import axios from 'axios';
|
||||
import cx from 'classnames';
|
||||
import { getViewDetailsUsingViewKey } from 'components/ExplorerCard/utils';
|
||||
@@ -58,7 +59,6 @@ import {
|
||||
} from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { ViewProps } from 'types/api/saveViews/types';
|
||||
import { DataSource, StringOperators } from 'types/common/queryBuilder';
|
||||
@@ -253,7 +253,7 @@ function ExplorerOptions({
|
||||
|
||||
const getUpdatedExtraData = (
|
||||
extraData: string | undefined,
|
||||
newSelectedColumns: BaseAutocompleteData[],
|
||||
newSelectedColumns: TelemetryFieldKey[],
|
||||
formattingOptions?: FormattingOptions,
|
||||
): string => {
|
||||
let updatedExtraData;
|
||||
@@ -337,7 +337,7 @@ function ExplorerOptions({
|
||||
const { handleExplorerTabChange } = useHandleExplorerTabChange();
|
||||
|
||||
type ExtraData = {
|
||||
selectColumns?: BaseAutocompleteData[];
|
||||
selectColumns?: TelemetryFieldKey[];
|
||||
version?: number;
|
||||
};
|
||||
|
||||
|
||||
@@ -87,8 +87,9 @@ function TableView({
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||
selectedOptions.selectColumns.forEach((val) => {
|
||||
const path = findKeyPath(logData, val.key, '');
|
||||
const path = findKeyPath(logData, val.name, '');
|
||||
if (path) {
|
||||
pinnedAttributes[path] = true;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { IField } from 'types/api/logs/fields';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
|
||||
export const convertKeysToColumnFields = (
|
||||
keys: BaseAutocompleteData[],
|
||||
keys: TelemetryFieldKey[],
|
||||
): IField[] =>
|
||||
keys.map((item) => ({
|
||||
dataType: item.dataType as string,
|
||||
name: item.key,
|
||||
type: item.type as string,
|
||||
dataType: item.fieldDataType ?? '',
|
||||
name: item.name,
|
||||
type: item.fieldContext ?? '',
|
||||
}));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { defaultTraceSelectedColumns } from 'container/OptionsMenu/constants';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { LogsAggregatorOperator } from 'types/common/queryBuilder';
|
||||
|
||||
@@ -43,48 +43,7 @@ export const listViewInitialTraceQuery = {
|
||||
orderBy: [{ columnName: 'timestamp', order: 'desc' }],
|
||||
offset: 0,
|
||||
pageSize: 10,
|
||||
selectColumns: [
|
||||
{
|
||||
key: 'serviceName',
|
||||
dataType: 'string',
|
||||
type: 'tag',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'serviceName--string--tag--true',
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
dataType: 'string',
|
||||
type: 'tag',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'name--string--tag--true',
|
||||
},
|
||||
{
|
||||
key: 'durationNano',
|
||||
dataType: 'float64',
|
||||
type: 'tag',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'durationNano--float64--tag--true',
|
||||
},
|
||||
{
|
||||
key: 'httpMethod',
|
||||
dataType: 'string',
|
||||
type: 'tag',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'httpMethod--string--tag--true',
|
||||
},
|
||||
{
|
||||
key: 'responseStatusCode',
|
||||
dataType: 'string',
|
||||
type: 'tag',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'responseStatusCode--string--tag--true',
|
||||
},
|
||||
] as BaseAutocompleteData[],
|
||||
selectColumns: defaultTraceSelectedColumns,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -25,9 +25,11 @@ function ExplorerAttributeColumns({
|
||||
}
|
||||
|
||||
const filteredAttributeKeys =
|
||||
data?.payload?.attributeKeys?.filter((attributeKey: any) =>
|
||||
attributeKey.key.toLowerCase().includes(searchText.toLowerCase()),
|
||||
) || [];
|
||||
Object.values(data?.data?.data?.keys || {})
|
||||
?.flat()
|
||||
?.filter((attributeKey: any) =>
|
||||
attributeKey.name.toLowerCase().includes(searchText.toLowerCase()),
|
||||
) || [];
|
||||
if (filteredAttributeKeys.length === 0) {
|
||||
return (
|
||||
<div className="attribute-columns">
|
||||
@@ -36,16 +38,17 @@ function ExplorerAttributeColumns({
|
||||
);
|
||||
}
|
||||
|
||||
console.log('filteredAttributeKeys', filteredAttributeKeys, data);
|
||||
return (
|
||||
<div className="attribute-columns">
|
||||
{filteredAttributeKeys.map((attributeKey: any) => (
|
||||
<Checkbox
|
||||
checked={isAttributeKeySelected(attributeKey.key)}
|
||||
onChange={(): void => handleCheckboxChange(attributeKey.key)}
|
||||
checked={isAttributeKeySelected(attributeKey.name)}
|
||||
onChange={(): void => handleCheckboxChange(attributeKey.name)}
|
||||
style={{ padding: 0 }}
|
||||
key={attributeKey.key}
|
||||
key={attributeKey.name}
|
||||
>
|
||||
{attributeKey.key}
|
||||
{attributeKey.name}
|
||||
</Checkbox>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable sonarjs/no-identical-functions */
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
/* eslint-disable react/jsx-props-no-spreading */
|
||||
import './ExplorerColumnsRenderer.styles.scss';
|
||||
@@ -5,9 +6,10 @@ import './ExplorerColumnsRenderer.styles.scss';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Divider, Dropdown, Input, Tooltip, Typography } from 'antd';
|
||||
import { MenuProps } from 'antd/lib';
|
||||
import { FieldDataType } from 'api/v5/v5';
|
||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||
import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useGetQueryKeySuggestions } from 'hooks/querySuggestions/useGetQueryKeySuggestions';
|
||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||
import useDebouncedFn from 'hooks/useDebouncedFunction';
|
||||
import {
|
||||
@@ -49,13 +51,27 @@ function ExplorerColumnsRenderer({
|
||||
|
||||
const initialDataSource = currentQuery.builder.queryData[0].dataSource;
|
||||
|
||||
const { data, isLoading, isError } = useGetAggregateKeys(
|
||||
// const { data, isLoading, isError } = useGetAggregateKeys(
|
||||
// {
|
||||
// aggregateAttribute: '',
|
||||
// dataSource: currentQuery.builder.queryData[0].dataSource,
|
||||
// aggregateOperator: currentQuery.builder.queryData[0].aggregateOperator,
|
||||
// searchText: querySearchText,
|
||||
// tagType: '',
|
||||
// },
|
||||
// {
|
||||
// queryKey: [
|
||||
// currentQuery.builder.queryData[0].dataSource,
|
||||
// currentQuery.builder.queryData[0].aggregateOperator,
|
||||
// querySearchText,
|
||||
// ],
|
||||
// },
|
||||
// );
|
||||
|
||||
const { data, isLoading, isError } = useGetQueryKeySuggestions(
|
||||
{
|
||||
aggregateAttribute: '',
|
||||
dataSource: currentQuery.builder.queryData[0].dataSource,
|
||||
aggregateOperator: currentQuery.builder.queryData[0].aggregateOperator,
|
||||
searchText: querySearchText,
|
||||
tagType: '',
|
||||
signal: currentQuery.builder.queryData[0].dataSource,
|
||||
},
|
||||
{
|
||||
queryKey: [
|
||||
@@ -71,7 +87,7 @@ function ExplorerColumnsRenderer({
|
||||
return selectedLogFields.some((field) => field.name === key);
|
||||
}
|
||||
if (initialDataSource === DataSource.TRACES && selectedTracesFields) {
|
||||
return selectedTracesFields.some((field) => field.key === key);
|
||||
return selectedTracesFields.some((field) => field.name === key);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
@@ -99,18 +115,31 @@ function ExplorerColumnsRenderer({
|
||||
initialDataSource === DataSource.TRACES &&
|
||||
setSelectedTracesFields !== undefined
|
||||
) {
|
||||
const selectedField = data?.payload?.attributeKeys?.find(
|
||||
(attributeKey) => attributeKey.key === key,
|
||||
);
|
||||
const selectedField = Object.values(data?.data?.data?.keys || {})
|
||||
?.flat()
|
||||
?.find((attributeKey) => attributeKey.name === key);
|
||||
console.log('selectedField', selectedField);
|
||||
if (selectedTracesFields) {
|
||||
if (isAttributeKeySelected(key)) {
|
||||
setSelectedTracesFields(
|
||||
selectedTracesFields.filter((field) => field.key !== key),
|
||||
selectedTracesFields.filter((field) => field.name !== key),
|
||||
);
|
||||
} else if (selectedField) {
|
||||
setSelectedTracesFields([...selectedTracesFields, selectedField]);
|
||||
setSelectedTracesFields([
|
||||
...selectedTracesFields,
|
||||
{
|
||||
...selectedField,
|
||||
fieldDataType: selectedField.fieldDataType as FieldDataType,
|
||||
},
|
||||
]);
|
||||
}
|
||||
} else if (selectedField) setSelectedTracesFields([selectedField]);
|
||||
} else if (selectedField)
|
||||
setSelectedTracesFields([
|
||||
{
|
||||
...selectedField,
|
||||
fieldDataType: selectedField.fieldDataType as FieldDataType,
|
||||
},
|
||||
]);
|
||||
}
|
||||
setOpen(false);
|
||||
};
|
||||
@@ -175,7 +204,7 @@ function ExplorerColumnsRenderer({
|
||||
selectedTracesFields
|
||||
) {
|
||||
setSelectedTracesFields(
|
||||
selectedTracesFields.filter((field) => field.key !== name),
|
||||
selectedTracesFields.filter((field) => field.name !== name),
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -218,6 +247,8 @@ function ExplorerColumnsRenderer({
|
||||
|
||||
const isDarkMode = useIsDarkMode();
|
||||
|
||||
console.log('selectedTracesFields', selectedTracesFields, selectedLogFields);
|
||||
|
||||
return (
|
||||
<div className="explorer-columns-renderer">
|
||||
<div className="title">
|
||||
@@ -279,12 +310,14 @@ function ExplorerColumnsRenderer({
|
||||
>
|
||||
<div className="explorer-column-title">
|
||||
<GripVertical size={12} color="#5A5A5A" />
|
||||
{field.key}
|
||||
{field?.name || (field as any)?.key}
|
||||
</div>
|
||||
<Trash2
|
||||
size={12}
|
||||
color="red"
|
||||
onClick={(): void => removeSelectedLogField(field.key)}
|
||||
onClick={(): void =>
|
||||
removeSelectedLogField(field?.name || (field as any)?.key)
|
||||
}
|
||||
data-testid="trash-icon"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -3,14 +3,12 @@
|
||||
/* eslint-disable react/jsx-props-no-spreading */
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import React from 'react';
|
||||
import { DropResult } from 'react-beautiful-dnd';
|
||||
import {
|
||||
BaseAutocompleteData,
|
||||
DataTypes,
|
||||
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import ExplorerColumnsRenderer from '../ExplorerColumnsRenderer';
|
||||
@@ -321,7 +319,11 @@ describe('ExplorerColumnsRenderer', () => {
|
||||
selectedLogFields={[]}
|
||||
setSelectedLogFields={mockSetSelectedLogFields}
|
||||
selectedTracesFields={[
|
||||
{ key: 'trace_attribute1', dataType: DataTypes.String, type: 'tag' },
|
||||
{
|
||||
name: 'trace_attribute1',
|
||||
fieldDataType: DataTypes.String,
|
||||
fieldContext: '',
|
||||
},
|
||||
]}
|
||||
setSelectedTracesFields={mockSetSelectedTracesFields}
|
||||
/>,
|
||||
@@ -340,7 +342,11 @@ describe('ExplorerColumnsRenderer', () => {
|
||||
selectedLogFields={[]}
|
||||
setSelectedLogFields={mockSetSelectedLogFields}
|
||||
selectedTracesFields={[
|
||||
{ key: 'trace_attribute1', dataType: DataTypes.String, type: 'tag' },
|
||||
{
|
||||
name: 'trace_attribute1',
|
||||
fieldDataType: DataTypes.String,
|
||||
fieldContext: '',
|
||||
},
|
||||
]}
|
||||
setSelectedTracesFields={mockSetSelectedTracesFields}
|
||||
/>,
|
||||
@@ -355,15 +361,15 @@ describe('ExplorerColumnsRenderer', () => {
|
||||
|
||||
it('reorders trace fields on drag and drop', () => {
|
||||
const initialSelectedFields = [
|
||||
{ key: 'trace_field1', dataType: 'string', type: 'tag' },
|
||||
{ key: 'trace_field2', dataType: 'string', type: 'tag' },
|
||||
{ name: 'trace_field1', fieldDataType: 'string', fieldContext: 'tag' },
|
||||
{ name: 'trace_field2', fieldDataType: 'string', fieldContext: 'tag' },
|
||||
];
|
||||
|
||||
render(
|
||||
<ExplorerColumnsRenderer
|
||||
selectedLogFields={[]}
|
||||
setSelectedLogFields={mockSetSelectedLogFields}
|
||||
selectedTracesFields={initialSelectedFields as BaseAutocompleteData[]}
|
||||
selectedTracesFields={initialSelectedFields as TelemetryFieldKey[]}
|
||||
setSelectedTracesFields={mockSetSelectedTracesFields}
|
||||
/>,
|
||||
);
|
||||
@@ -383,8 +389,8 @@ describe('ExplorerColumnsRenderer', () => {
|
||||
});
|
||||
|
||||
expect(mockSetSelectedTracesFields).toHaveBeenCalledWith([
|
||||
{ key: 'trace_field2', dataType: 'string', type: 'tag' },
|
||||
{ key: 'trace_field1', dataType: 'string', type: 'tag' },
|
||||
{ name: 'trace_field2', fieldDataType: 'string', fieldContext: 'tag' },
|
||||
{ name: 'trace_field1', fieldDataType: 'string', fieldContext: 'tag' },
|
||||
]);
|
||||
} else {
|
||||
fail('DragDropContext or onDragEndMock not found');
|
||||
|
||||
@@ -6,9 +6,12 @@ import {
|
||||
} from 'constants/queryBuilder';
|
||||
import {
|
||||
listViewInitialLogQuery,
|
||||
listViewInitialTraceQuery,
|
||||
PANEL_TYPES_INITIAL_QUERY,
|
||||
} from 'container/NewDashboard/ComponentsSlider/constants';
|
||||
import {
|
||||
defaultLogsSelectedColumns,
|
||||
defaultTraceSelectedColumns,
|
||||
} from 'container/OptionsMenu/constants';
|
||||
import { categoryToSupport } from 'container/QueryBuilder/filters/BuilderUnitsFilter/config';
|
||||
import { cloneDeep, defaultTo, isEmpty, isEqual, set, unset } from 'lodash-es';
|
||||
import { Layout } from 'react-grid-layout';
|
||||
@@ -503,7 +506,6 @@ export function handleQueryChange(
|
||||
supersetQuery: Query,
|
||||
currentPanelType: PANEL_TYPES,
|
||||
): Query {
|
||||
console.log('supersetQuery', supersetQuery);
|
||||
return {
|
||||
...supersetQuery,
|
||||
builder: {
|
||||
@@ -564,21 +566,12 @@ export const getDefaultWidgetData = (
|
||||
timePreferance: 'GLOBAL_TIME',
|
||||
softMax: null,
|
||||
softMin: null,
|
||||
selectedLogFields: [
|
||||
{
|
||||
dataType: 'string',
|
||||
type: '',
|
||||
name: 'body',
|
||||
},
|
||||
{
|
||||
dataType: 'string',
|
||||
type: '',
|
||||
name: 'timestamp',
|
||||
},
|
||||
],
|
||||
selectedTracesFields: [
|
||||
...listViewInitialTraceQuery.builder.queryData[0].selectColumns,
|
||||
],
|
||||
selectedLogFields: defaultLogsSelectedColumns.map((field) => ({
|
||||
...field,
|
||||
type: field.fieldContext ?? '',
|
||||
dataType: field.fieldDataType ?? '',
|
||||
})),
|
||||
selectedTracesFields: defaultTraceSelectedColumns,
|
||||
});
|
||||
|
||||
export const PANEL_TYPE_TO_QUERY_TYPES: Record<PANEL_TYPES, EQueryType[]> = {
|
||||
|
||||
@@ -42,10 +42,10 @@ function AddColumnField({ config }: AddColumnFieldProps): JSX.Element | null {
|
||||
</SearchIconWrapper>
|
||||
</Input.Group>
|
||||
|
||||
{config.value?.map(({ key, id }) => (
|
||||
<AddColumnItem direction="horizontal" key={id}>
|
||||
<Typography>{key}</Typography>
|
||||
<DeleteOutlinedIcon onClick={(): void => config.onRemove(id as string)} />
|
||||
{config.value?.map(({ name }) => (
|
||||
<AddColumnItem direction="horizontal" key={name}>
|
||||
<Typography>{name}</Typography>
|
||||
<DeleteOutlinedIcon onClick={(): void => config.onRemove(name)} />
|
||||
</AddColumnItem>
|
||||
))}
|
||||
</AddColumnWrapper>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
|
||||
import { FontSize, OptionsQuery } from './types';
|
||||
|
||||
@@ -11,71 +11,56 @@ export const defaultOptionsQuery: OptionsQuery = {
|
||||
fontSize: FontSize.SMALL,
|
||||
};
|
||||
|
||||
export const defaultLogsSelectedColumns = [
|
||||
export const defaultLogsSelectedColumns: TelemetryFieldKey[] = [
|
||||
{
|
||||
key: 'timestamp',
|
||||
dataType: DataTypes.String,
|
||||
type: 'tag',
|
||||
name: 'timestamp',
|
||||
signal: 'logs',
|
||||
fieldContext: 'log',
|
||||
fieldDataType: '',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'timestamp--string--tag--true',
|
||||
isIndexed: false,
|
||||
},
|
||||
{
|
||||
key: 'body',
|
||||
dataType: DataTypes.String,
|
||||
type: 'tag',
|
||||
name: 'body',
|
||||
signal: 'logs',
|
||||
fieldContext: 'log',
|
||||
fieldDataType: '',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'body--string--tag--true',
|
||||
isIndexed: false,
|
||||
},
|
||||
];
|
||||
|
||||
export const defaultTraceSelectedColumns = [
|
||||
export const defaultTraceSelectedColumns: TelemetryFieldKey[] = [
|
||||
{
|
||||
key: 'serviceName',
|
||||
dataType: DataTypes.String,
|
||||
type: 'tag',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'serviceName--string--tag--true',
|
||||
isIndexed: false,
|
||||
name: 'service.name',
|
||||
signal: 'traces',
|
||||
fieldContext: 'resource',
|
||||
fieldDataType: 'string',
|
||||
},
|
||||
{
|
||||
key: 'name',
|
||||
dataType: DataTypes.String,
|
||||
type: 'tag',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'name--string--tag--true',
|
||||
isIndexed: false,
|
||||
name: 'name',
|
||||
signal: 'traces',
|
||||
fieldContext: 'span',
|
||||
fieldDataType: 'string',
|
||||
},
|
||||
{
|
||||
key: 'durationNano',
|
||||
dataType: DataTypes.Float64,
|
||||
type: 'tag',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'durationNano--float64--tag--true',
|
||||
isIndexed: false,
|
||||
name: 'duration_nano',
|
||||
signal: 'traces',
|
||||
fieldContext: 'span',
|
||||
fieldDataType: '',
|
||||
},
|
||||
{
|
||||
key: 'httpMethod',
|
||||
dataType: DataTypes.String,
|
||||
type: 'tag',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'httpMethod--string--tag--true',
|
||||
isIndexed: false,
|
||||
name: 'http_method',
|
||||
signal: 'traces',
|
||||
fieldContext: 'span',
|
||||
fieldDataType: '',
|
||||
},
|
||||
{
|
||||
key: 'responseStatusCode',
|
||||
dataType: DataTypes.String,
|
||||
type: 'tag',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
id: 'responseStatusCode--string--tag--true',
|
||||
isIndexed: false,
|
||||
name: 'response_status_code',
|
||||
signal: 'traces',
|
||||
fieldContext: 'span',
|
||||
fieldDataType: '',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { InputNumberProps, RadioProps, SelectProps } from 'antd';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { LogViewMode } from 'container/LogsTable';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
|
||||
export enum FontSize {
|
||||
SMALL = 'small',
|
||||
@@ -13,7 +13,7 @@ interface FontSizeProps {
|
||||
onChange: (val: FontSize) => void;
|
||||
}
|
||||
export interface OptionsQuery {
|
||||
selectColumns: BaseAutocompleteData[];
|
||||
selectColumns: TelemetryFieldKey[];
|
||||
maxLines: number;
|
||||
format: LogViewMode;
|
||||
fontSize: FontSize;
|
||||
@@ -36,7 +36,7 @@ export type OptionsMenuConfig = {
|
||||
'options' | 'onSelect' | 'onFocus' | 'onSearch' | 'onBlur'
|
||||
> & {
|
||||
isFetching: boolean;
|
||||
value: BaseAutocompleteData[];
|
||||
value: TelemetryFieldKey[];
|
||||
onRemove: (key: string) => void;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import { getAggregateKeys } from 'api/queryBuilder/getAttributeKeys';
|
||||
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { LogViewMode } from 'container/LogsTable';
|
||||
import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys';
|
||||
import { useGetQueryKeySuggestions } from 'hooks/querySuggestions/useGetQueryKeySuggestions';
|
||||
import useDebounce from 'hooks/useDebounce';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||
import {
|
||||
AllTraceFilterKeys,
|
||||
AllTraceFilterKeyValue,
|
||||
} from 'pages/TracesExplorer/Filter/filterUtils';
|
||||
import { AllTraceFilterKeyValue } from 'pages/TracesExplorer/Filter/filterUtils';
|
||||
import { usePreferenceContext } from 'providers/preferences/context/PreferenceContextProvider';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useQueries } from 'react-query';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
import {
|
||||
BaseAutocompleteData,
|
||||
IQueryAutocompleteResponse,
|
||||
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
QueryKeyRequestProps,
|
||||
QueryKeySuggestionsResponseProps,
|
||||
} from 'types/api/querySuggestions/types';
|
||||
import {
|
||||
FieldContext,
|
||||
FieldDataType,
|
||||
SignalType,
|
||||
} from 'types/api/v5/queryRange';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import {
|
||||
@@ -47,7 +50,7 @@ interface UseOptionsMenu {
|
||||
|
||||
const useOptionsMenu = ({
|
||||
dataSource,
|
||||
aggregateOperator,
|
||||
// aggregateOperator,
|
||||
initialOptions = {},
|
||||
}: UseOptionsMenuProps): UseOptionsMenu => {
|
||||
const { notifications } = useNotifications();
|
||||
@@ -61,15 +64,23 @@ const useOptionsMenu = ({
|
||||
const [isFocused, setIsFocused] = useState<boolean>(false);
|
||||
const debouncedSearchText = useDebounce(searchText, 300);
|
||||
|
||||
const initialQueryParams = useMemo(
|
||||
// const initialQueryParams = useMemo(
|
||||
// () => ({
|
||||
// searchText: '',
|
||||
// aggregateAttribute: '',
|
||||
// tagType: undefined,
|
||||
// dataSource,
|
||||
// aggregateOperator,
|
||||
// }),
|
||||
// [dataSource, aggregateOperator],
|
||||
// );
|
||||
|
||||
const initialQueryParamsV5: QueryKeyRequestProps = useMemo(
|
||||
() => ({
|
||||
signal: dataSource,
|
||||
searchText: '',
|
||||
aggregateAttribute: '',
|
||||
tagType: undefined,
|
||||
dataSource,
|
||||
aggregateOperator,
|
||||
}),
|
||||
[dataSource, aggregateOperator],
|
||||
[dataSource],
|
||||
);
|
||||
|
||||
const {
|
||||
@@ -77,23 +88,37 @@ const useOptionsMenu = ({
|
||||
redirectWithQuery: redirectWithOptionsData,
|
||||
} = useUrlQueryData<OptionsQuery>(URL_OPTIONS, defaultOptionsQuery);
|
||||
|
||||
const initialQueries = useMemo(
|
||||
// const initialQueries = useMemo(
|
||||
// () =>
|
||||
// initialOptions?.selectColumns?.map((column) => ({
|
||||
// queryKey: column,
|
||||
// queryFn: (): Promise<
|
||||
// SuccessResponse<IQueryAutocompleteResponse> | ErrorResponse
|
||||
// > =>
|
||||
// getAggregateKeys({
|
||||
// ...initialQueryParams,
|
||||
// searchText: column,
|
||||
// }),
|
||||
// enabled: !!column && !optionsQuery,
|
||||
// })) || [],
|
||||
// [initialOptions?.selectColumns, initialQueryParams, optionsQuery],
|
||||
// );
|
||||
|
||||
const initialQueriesV5 = useMemo(
|
||||
() =>
|
||||
initialOptions?.selectColumns?.map((column) => ({
|
||||
queryKey: column,
|
||||
queryFn: (): Promise<
|
||||
SuccessResponse<IQueryAutocompleteResponse> | ErrorResponse
|
||||
> =>
|
||||
getAggregateKeys({
|
||||
...initialQueryParams,
|
||||
queryFn: (): Promise<AxiosResponse<QueryKeySuggestionsResponseProps>> =>
|
||||
getKeySuggestions({
|
||||
...initialQueryParamsV5,
|
||||
searchText: column,
|
||||
}),
|
||||
enabled: !!column && !optionsQuery,
|
||||
})) || [],
|
||||
[initialOptions?.selectColumns, initialQueryParams, optionsQuery],
|
||||
[initialOptions?.selectColumns, initialQueryParamsV5, optionsQuery],
|
||||
);
|
||||
|
||||
const initialAttributesResult = useQueries(initialQueries);
|
||||
const initialAttributesResult = useQueries(initialQueriesV5);
|
||||
|
||||
const isFetchedInitialAttributes = useMemo(
|
||||
() => initialAttributesResult.every((result) => result.isFetched),
|
||||
@@ -106,42 +131,52 @@ const useOptionsMenu = ({
|
||||
}
|
||||
|
||||
const attributesData = initialAttributesResult?.reduce(
|
||||
(acc, attributeResponse) => {
|
||||
const data = attributeResponse?.data?.payload?.attributeKeys || [];
|
||||
(acc: TelemetryFieldKey[], attributeResponse): TelemetryFieldKey[] => {
|
||||
const suggestions =
|
||||
Object.values(attributeResponse?.data?.data?.data?.keys || {}).flat() ||
|
||||
[];
|
||||
|
||||
return [...acc, ...data];
|
||||
const mappedSuggestions: TelemetryFieldKey[] = suggestions.map(
|
||||
(suggestion) => ({
|
||||
name: suggestion.name,
|
||||
signal: suggestion.signal as SignalType,
|
||||
fieldDataType: suggestion.fieldDataType as FieldDataType,
|
||||
fieldContext: suggestion.fieldContext as FieldContext,
|
||||
}),
|
||||
);
|
||||
|
||||
return [...acc, ...mappedSuggestions];
|
||||
},
|
||||
[] as BaseAutocompleteData[],
|
||||
[],
|
||||
);
|
||||
|
||||
let initialSelected = initialOptions.selectColumns
|
||||
?.map((column) => attributesData.find(({ key }) => key === column))
|
||||
.filter(Boolean) as BaseAutocompleteData[];
|
||||
let initialSelected: TelemetryFieldKey[] | undefined =
|
||||
initialOptions.selectColumns
|
||||
?.map((column) => attributesData.find(({ name }) => name === column))
|
||||
.filter((e) => !!e) || [];
|
||||
|
||||
if (dataSource === DataSource.TRACES) {
|
||||
initialSelected = initialSelected
|
||||
?.map((col) => {
|
||||
if (col && Object.keys(AllTraceFilterKeyValue).includes(col?.key)) {
|
||||
if (col && Object.keys(AllTraceFilterKeyValue).includes(col?.name)) {
|
||||
const metaData = defaultTraceSelectedColumns.find(
|
||||
(coln) => coln.key === (col.key as AllTraceFilterKeys),
|
||||
(coln) => coln.name === col.name,
|
||||
);
|
||||
|
||||
return {
|
||||
...metaData,
|
||||
key: metaData?.key,
|
||||
dataType: metaData?.dataType,
|
||||
type: metaData?.type,
|
||||
isColumn: metaData?.isColumn,
|
||||
isJSON: metaData?.isJSON,
|
||||
id: metaData?.id,
|
||||
name: metaData?.name || '',
|
||||
};
|
||||
}
|
||||
return col;
|
||||
})
|
||||
.filter(Boolean) as BaseAutocompleteData[];
|
||||
.filter((e) => !!e);
|
||||
|
||||
if (!initialSelected || !initialSelected?.length) {
|
||||
initialSelected = defaultTraceSelectedColumns;
|
||||
initialSelected = defaultTraceSelectedColumns.map((e) => ({
|
||||
...e,
|
||||
name: e.name,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,41 +189,91 @@ const useOptionsMenu = ({
|
||||
]);
|
||||
|
||||
const {
|
||||
data: searchedAttributesData,
|
||||
isFetching: isSearchedAttributesFetching,
|
||||
} = useGetAggregateKeys(
|
||||
data: searchedAttributesDataV5,
|
||||
isFetching: isSearchedAttributesFetchingV5,
|
||||
} = useGetQueryKeySuggestions(
|
||||
{
|
||||
...initialQueryParams,
|
||||
...initialQueryParamsV5,
|
||||
searchText: debouncedSearchText,
|
||||
},
|
||||
{ queryKey: [debouncedSearchText, isFocused], enabled: isFocused },
|
||||
);
|
||||
|
||||
const searchedAttributeKeys = useMemo(() => {
|
||||
if (searchedAttributesData?.payload?.attributeKeys?.length) {
|
||||
// const {
|
||||
// data: searchedAttributesData,
|
||||
// isFetching: isSearchedAttributesFetching,
|
||||
// } = useGetAggregateKeys(
|
||||
// {
|
||||
// ...initialQueryParams,
|
||||
// searchText: debouncedSearchText,
|
||||
// },
|
||||
// { queryKey: [debouncedSearchText, isFocused], enabled: isFocused },
|
||||
// );
|
||||
|
||||
const searchedAttributeKeys: TelemetryFieldKey[] = useMemo(() => {
|
||||
const searchedAttributesDataList = Object.values(
|
||||
searchedAttributesDataV5?.data.data.keys || {},
|
||||
).flat();
|
||||
if (searchedAttributesDataList.length) {
|
||||
if (dataSource === DataSource.LOGS) {
|
||||
const logsSelectedColumns: TelemetryFieldKey[] = defaultLogsSelectedColumns.map(
|
||||
(e) => ({
|
||||
...e,
|
||||
name: e.name,
|
||||
signal: e.signal as SignalType,
|
||||
fieldContext: e.fieldContext as FieldContext,
|
||||
fieldDataType: e.fieldDataType as FieldDataType,
|
||||
}),
|
||||
);
|
||||
return [
|
||||
...defaultLogsSelectedColumns,
|
||||
...searchedAttributesData.payload.attributeKeys.filter(
|
||||
(attribute) => attribute.key !== 'body',
|
||||
),
|
||||
...logsSelectedColumns,
|
||||
...searchedAttributesDataList
|
||||
.filter((attribute) => attribute.name !== 'body')
|
||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||
.map((e) => ({
|
||||
...e,
|
||||
name: e.name,
|
||||
signal: e.signal as SignalType,
|
||||
fieldContext: e.fieldContext as FieldContext,
|
||||
fieldDataType: e.fieldDataType as FieldDataType,
|
||||
})),
|
||||
];
|
||||
}
|
||||
return searchedAttributesData.payload.attributeKeys;
|
||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||
return searchedAttributesDataList.map((e) => ({
|
||||
...e,
|
||||
name: e.name,
|
||||
signal: e.signal as SignalType,
|
||||
fieldContext: e.fieldContext as FieldContext,
|
||||
fieldDataType: e.fieldDataType as FieldDataType,
|
||||
}));
|
||||
}
|
||||
if (dataSource === DataSource.TRACES) {
|
||||
return defaultTraceSelectedColumns;
|
||||
return defaultTraceSelectedColumns.map((e) => ({
|
||||
...e,
|
||||
name: e.name,
|
||||
}));
|
||||
}
|
||||
|
||||
return [];
|
||||
}, [dataSource, searchedAttributesData?.payload?.attributeKeys]);
|
||||
}, [dataSource, searchedAttributesDataV5?.data.data.keys]);
|
||||
|
||||
const initialOptionsQuery: OptionsQuery = useMemo(() => {
|
||||
let defaultColumns = defaultOptionsQuery.selectColumns;
|
||||
let defaultColumns: TelemetryFieldKey[] = defaultOptionsQuery.selectColumns;
|
||||
if (dataSource === DataSource.TRACES) {
|
||||
defaultColumns = defaultTraceSelectedColumns;
|
||||
defaultColumns = defaultTraceSelectedColumns.map((e) => ({
|
||||
...e,
|
||||
name: e.name,
|
||||
}));
|
||||
} else if (dataSource === DataSource.LOGS) {
|
||||
defaultColumns = defaultLogsSelectedColumns;
|
||||
// eslint-disable-next-line sonarjs/no-identical-functions
|
||||
defaultColumns = defaultLogsSelectedColumns.map((e) => ({
|
||||
...e,
|
||||
name: e.name,
|
||||
signal: e.signal as SignalType,
|
||||
fieldContext: e.fieldContext as FieldContext,
|
||||
fieldDataType: e.fieldDataType as FieldDataType,
|
||||
}));
|
||||
}
|
||||
|
||||
const finalSelectColumns = initialOptions?.selectColumns
|
||||
@@ -203,14 +288,14 @@ const useOptionsMenu = ({
|
||||
}, [dataSource, initialOptions, initialSelectedColumns]);
|
||||
|
||||
const selectedColumnKeys = useMemo(
|
||||
() => preferences?.columns?.map(({ id }) => id) || [],
|
||||
() => preferences?.columns?.map(({ name }) => name) || [],
|
||||
[preferences?.columns],
|
||||
);
|
||||
|
||||
const optionsFromAttributeKeys = useMemo(() => {
|
||||
const filteredAttributeKeys = searchedAttributeKeys.filter((item) => {
|
||||
if (dataSource !== DataSource.LOGS) {
|
||||
return item.key !== 'body';
|
||||
return item.name !== 'body';
|
||||
}
|
||||
return true;
|
||||
});
|
||||
@@ -232,11 +317,11 @@ const useOptionsMenu = ({
|
||||
const column = [
|
||||
...searchedAttributeKeys,
|
||||
...(preferences?.columns || []),
|
||||
].find(({ id }) => id === key);
|
||||
].find(({ name }) => name === key);
|
||||
|
||||
if (!column) return acc;
|
||||
return [...acc, column];
|
||||
}, [] as BaseAutocompleteData[]);
|
||||
}, [] as TelemetryFieldKey[]);
|
||||
|
||||
const optionsData: OptionsQuery = {
|
||||
...defaultOptionsQuery,
|
||||
@@ -261,7 +346,7 @@ const useOptionsMenu = ({
|
||||
const handleRemoveSelectedColumn = useCallback(
|
||||
(columnKey: string) => {
|
||||
const newSelectedColumns = preferences?.columns?.filter(
|
||||
({ id }) => id !== columnKey,
|
||||
({ name }) => name !== columnKey,
|
||||
);
|
||||
|
||||
if (!newSelectedColumns?.length && dataSource !== DataSource.LOGS) {
|
||||
@@ -367,7 +452,7 @@ const useOptionsMenu = ({
|
||||
const optionsMenuConfig: Required<OptionsMenuConfig> = useMemo(
|
||||
() => ({
|
||||
addColumn: {
|
||||
isFetching: isSearchedAttributesFetching,
|
||||
isFetching: isSearchedAttributesFetchingV5,
|
||||
value: preferences?.columns || defaultOptionsQuery.selectColumns,
|
||||
options: optionsFromAttributeKeys || [],
|
||||
onFocus: handleFocus,
|
||||
@@ -390,7 +475,7 @@ const useOptionsMenu = ({
|
||||
},
|
||||
}),
|
||||
[
|
||||
isSearchedAttributesFetching,
|
||||
isSearchedAttributesFetchingV5,
|
||||
preferences,
|
||||
optionsFromAttributeKeys,
|
||||
handleSelectColumns,
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { SelectProps } from 'antd';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
|
||||
export const getOptionsFromKeys = (
|
||||
keys: BaseAutocompleteData[],
|
||||
keys: TelemetryFieldKey[],
|
||||
selectedKeys: (string | undefined)[],
|
||||
): SelectProps['options'] => {
|
||||
const options = keys.map(({ id, key }) => ({
|
||||
label: key,
|
||||
value: id,
|
||||
const options = keys.map(({ name }) => ({
|
||||
label: name,
|
||||
value: name,
|
||||
}));
|
||||
|
||||
return options.filter(
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
export const selectStyle = { width: '100%', minWidth: '7.7rem' };
|
||||
export const selectStyle = {
|
||||
width: '100%',
|
||||
minWidth: '7.7rem',
|
||||
height: '100%',
|
||||
};
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { DEFAULT_PER_PAGE_OPTIONS } from 'hooks/queryPagination';
|
||||
|
||||
export const defaultSelectedColumns: string[] = [
|
||||
'serviceName',
|
||||
'service.name',
|
||||
'name',
|
||||
'durationNano',
|
||||
'httpMethod',
|
||||
'responseStatusCode',
|
||||
'duration_nano',
|
||||
'http_method',
|
||||
'response_status_code',
|
||||
'timestamp',
|
||||
];
|
||||
|
||||
export const PER_PAGE_OPTIONS: number[] = [10, ...DEFAULT_PER_PAGE_OPTIONS];
|
||||
|
||||
@@ -21,6 +21,7 @@ import useDragColumns from 'hooks/useDragColumns';
|
||||
import { getDraggedColumns } from 'hooks/useDragColumns/utils';
|
||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||
import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { ArrowUp10, Minus } from 'lucide-react';
|
||||
import { useTimezone } from 'providers/Timezone';
|
||||
import { memo, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
@@ -46,7 +47,7 @@ function ListView({ isFilterApplied }: ListViewProps): JSX.Element {
|
||||
|
||||
const panelType = panelTypeFromQueryBuilder || PANEL_TYPES.LIST;
|
||||
|
||||
const [orderDirection, setOrderDirection] = useState<string>('asc');
|
||||
const [orderDirection, setOrderDirection] = useState<string>('desc');
|
||||
|
||||
const {
|
||||
selectedTime: globalSelectedTime,
|
||||
@@ -64,6 +65,8 @@ function ListView({ isFilterApplied }: ListViewProps): JSX.Element {
|
||||
},
|
||||
});
|
||||
|
||||
console.log('options', options);
|
||||
|
||||
const { draggedColumns, onDragColumns } = useDragColumns<RowData>(
|
||||
LOCALSTORAGE.TRACES_LIST_COLUMNS,
|
||||
);
|
||||
@@ -74,6 +77,23 @@ function ListView({ isFilterApplied }: ListViewProps): JSX.Element {
|
||||
const paginationConfig =
|
||||
paginationQueryData ?? getDefaultPaginationConfig(PER_PAGE_OPTIONS);
|
||||
|
||||
const requestQuery = useMemo(() => {
|
||||
const query = stagedQuery
|
||||
? cloneDeep(stagedQuery)
|
||||
: cloneDeep(initialQueriesMap.traces);
|
||||
|
||||
if (query.builder.queryData[0]) {
|
||||
query.builder.queryData[0].orderBy = [
|
||||
{
|
||||
columnName: 'timestamp',
|
||||
order: orderDirection as 'asc' | 'desc',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return query;
|
||||
}, [stagedQuery, orderDirection]);
|
||||
|
||||
const queryKey = useMemo(
|
||||
() => [
|
||||
REACT_QUERY_KEY.GET_QUERY_RANGE,
|
||||
@@ -84,6 +104,7 @@ function ListView({ isFilterApplied }: ListViewProps): JSX.Element {
|
||||
panelType,
|
||||
paginationConfig,
|
||||
options?.selectColumns,
|
||||
orderDirection,
|
||||
],
|
||||
[
|
||||
stagedQuery,
|
||||
@@ -93,12 +114,13 @@ function ListView({ isFilterApplied }: ListViewProps): JSX.Element {
|
||||
options?.selectColumns,
|
||||
maxTime,
|
||||
minTime,
|
||||
orderDirection,
|
||||
],
|
||||
);
|
||||
|
||||
const { data, isFetching, isLoading, isError } = useGetQueryRange(
|
||||
{
|
||||
query: stagedQuery || initialQueriesMap.traces,
|
||||
query: requestQuery,
|
||||
graphType: panelType,
|
||||
selectedTime: 'GLOBAL_TIME' as const,
|
||||
globalSelectedInterval: globalSelectedTime as CustomTimeType,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Tag, Typography } from 'antd';
|
||||
import { ColumnsType } from 'antd/es/table';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { getMs } from 'container/Trace/Filters/Panel/PanelBody/Duration/util';
|
||||
@@ -9,7 +10,6 @@ import { RowData } from 'lib/query/createTableColumnsFromQuery';
|
||||
import LineClampedText from 'periscope/components/LineClampedText/LineClampedText';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { ILog } from 'types/api/logs/log';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { QueryDataV3 } from 'types/api/widgets/getQuery';
|
||||
|
||||
export function BlockLink({
|
||||
@@ -47,7 +47,7 @@ export const getTraceLink = (record: RowData): string =>
|
||||
})}`;
|
||||
|
||||
export const getListColumns = (
|
||||
selectedColumns: BaseAutocompleteData[],
|
||||
selectedColumns: TelemetryFieldKey[],
|
||||
formatTimezoneAdjustedTimestamp: (
|
||||
input: TimestampInput,
|
||||
format?: string,
|
||||
@@ -80,48 +80,58 @@ export const getListColumns = (
|
||||
];
|
||||
|
||||
const columns: ColumnsType<RowData> =
|
||||
selectedColumns.map(({ dataType, key, type }) => ({
|
||||
title: key,
|
||||
dataIndex: key,
|
||||
key: `${key}-${dataType}-${type}`,
|
||||
width: 145,
|
||||
render: (value, item): JSX.Element => {
|
||||
if (value === '') {
|
||||
selectedColumns.map((props) => {
|
||||
const name = props?.name || (props as any)?.key;
|
||||
const fieldDataType = props?.fieldDataType || (props as any)?.dataType;
|
||||
const fieldContext = props?.fieldContext || (props as any)?.type;
|
||||
return {
|
||||
title: name,
|
||||
dataIndex: name,
|
||||
key: `${name}-${fieldDataType}-${fieldContext}`,
|
||||
width: 145,
|
||||
render: (value, item): JSX.Element => {
|
||||
if (value === '') {
|
||||
return (
|
||||
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
|
||||
<Typography data-testid={name}>N/A</Typography>
|
||||
</BlockLink>
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
name === 'httpMethod' ||
|
||||
name === 'responseStatusCode' ||
|
||||
name === 'response_status_code' ||
|
||||
name === 'http_method'
|
||||
) {
|
||||
return (
|
||||
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
|
||||
<Tag data-testid={name} color="magenta">
|
||||
{value}
|
||||
</Tag>
|
||||
</BlockLink>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'durationNano' || name === 'duration_nano') {
|
||||
return (
|
||||
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
|
||||
<Typography data-testid={name}>{getMs(value)}ms</Typography>
|
||||
</BlockLink>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
|
||||
<Typography data-testid={key}>N/A</Typography>
|
||||
<Typography data-testid={name}>
|
||||
<LineClampedText text={value} lines={3} />
|
||||
</Typography>
|
||||
</BlockLink>
|
||||
);
|
||||
}
|
||||
|
||||
if (key === 'httpMethod' || key === 'responseStatusCode') {
|
||||
return (
|
||||
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
|
||||
<Tag data-testid={key} color="magenta">
|
||||
{value}
|
||||
</Tag>
|
||||
</BlockLink>
|
||||
);
|
||||
}
|
||||
|
||||
if (key === 'durationNano' || key === 'duration_nano') {
|
||||
return (
|
||||
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
|
||||
<Typography data-testid={key}>{getMs(value)}ms</Typography>
|
||||
</BlockLink>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<BlockLink to={getTraceLink(item)} openInNewTab={false}>
|
||||
<Typography data-testid={key}>
|
||||
<LineClampedText text={value} lines={3} />
|
||||
</Typography>
|
||||
</BlockLink>
|
||||
);
|
||||
},
|
||||
responsive: ['md'],
|
||||
})) || [];
|
||||
},
|
||||
responsive: ['md'],
|
||||
};
|
||||
}) || [];
|
||||
|
||||
return [...initialColumns, ...columns];
|
||||
};
|
||||
|
||||
@@ -42,6 +42,8 @@ function TracesTableComponent({
|
||||
});
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
|
||||
console.log('widget.selectedTracesFields', widget.selectedTracesFields);
|
||||
|
||||
useEffect(() => {
|
||||
setRequestData((prev) => ({
|
||||
...prev,
|
||||
@@ -79,6 +81,7 @@ function TracesTableComponent({
|
||||
[queryTableData],
|
||||
);
|
||||
|
||||
console.log('transformedQueryTableData', transformedQueryTableData, columns);
|
||||
const handleRow = useCallback(
|
||||
(record: RowData): HTMLAttributes<RowData> => ({
|
||||
onClick: (event): void => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { convertKeysToColumnFields } from 'container/LogsExplorerList/utils';
|
||||
import { placeWidgetAtBottom } from 'container/NewWidget/utils';
|
||||
import { Dashboard } from 'types/api/dashboard/getAll';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
const baseLogsSelectedColumns = {
|
||||
@@ -16,7 +16,7 @@ export const addEmptyWidgetInDashboardJSONWithQuery = (
|
||||
query: Query,
|
||||
widgetId: string,
|
||||
panelType?: PANEL_TYPES,
|
||||
selectedColumns?: BaseAutocompleteData[] | null,
|
||||
selectedColumns?: TelemetryFieldKey[] | null,
|
||||
): Dashboard => {
|
||||
const logsSelectedColumns = [
|
||||
baseLogsSelectedColumns,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ENTITY_VERSION_V5 } from 'constants/app';
|
||||
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import { GetQueryResultsProps } from 'lib/dashboard/getQueryResults';
|
||||
@@ -58,7 +59,8 @@ export const useGetExplorerQueryRange = (
|
||||
query: requestData || initialQueriesMap.metrics,
|
||||
params,
|
||||
},
|
||||
version,
|
||||
// version,
|
||||
ENTITY_VERSION_V5,
|
||||
{
|
||||
...options,
|
||||
retry: false,
|
||||
|
||||
@@ -369,13 +369,13 @@ export const useQueryOperations: UseQueryOperations = ({
|
||||
setOperators(initialOperators);
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
dataSource,
|
||||
initialDataSource,
|
||||
panelType,
|
||||
entityVersion,
|
||||
query,
|
||||
operators,
|
||||
handleMetricAggregateAtributeTypes,
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,19 +1,66 @@
|
||||
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import { useQuery, UseQueryResult } from 'react-query';
|
||||
import { QueryKeySuggestionsResponseProps } from 'types/api/querySuggestions/types';
|
||||
import { useMemo } from 'react';
|
||||
import { useQuery, UseQueryOptions, UseQueryResult } from 'react-query';
|
||||
import {
|
||||
QueryKeyRequestProps,
|
||||
QueryKeySuggestionsResponseProps,
|
||||
} from 'types/api/querySuggestions/types';
|
||||
|
||||
export const useGetQueryKeySuggestions = ({
|
||||
signal,
|
||||
name,
|
||||
}: {
|
||||
signal: string;
|
||||
name: string;
|
||||
}): UseQueryResult<
|
||||
type UseGetQueryKeySuggestions = (
|
||||
requestData: QueryKeyRequestProps,
|
||||
options?: UseQueryOptions<
|
||||
AxiosResponse<QueryKeySuggestionsResponseProps>,
|
||||
AxiosError
|
||||
>,
|
||||
) => UseQueryResult<
|
||||
AxiosResponse<QueryKeySuggestionsResponseProps>,
|
||||
AxiosError
|
||||
> =>
|
||||
useQuery<AxiosResponse<QueryKeySuggestionsResponseProps>, AxiosError>({
|
||||
queryKey: ['queryKeySuggestions', signal, name],
|
||||
queryFn: () => getKeySuggestions({ signal, name }),
|
||||
>;
|
||||
|
||||
export const useGetQueryKeySuggestions: UseGetQueryKeySuggestions = (
|
||||
{
|
||||
signal,
|
||||
searchText,
|
||||
fieldContext,
|
||||
fieldDataType,
|
||||
metricName,
|
||||
}: QueryKeyRequestProps,
|
||||
options?: UseQueryOptions<
|
||||
AxiosResponse<QueryKeySuggestionsResponseProps>,
|
||||
AxiosError
|
||||
>,
|
||||
) => {
|
||||
const queryKey = useMemo(() => {
|
||||
if (options?.queryKey && Array.isArray(options.queryKey)) {
|
||||
return ['queryKeySuggestions', ...options.queryKey];
|
||||
}
|
||||
return [
|
||||
'queryKeySuggestions',
|
||||
signal,
|
||||
searchText,
|
||||
metricName,
|
||||
fieldContext,
|
||||
fieldDataType,
|
||||
];
|
||||
}, [
|
||||
options?.queryKey,
|
||||
signal,
|
||||
searchText,
|
||||
metricName,
|
||||
fieldContext,
|
||||
fieldDataType,
|
||||
]);
|
||||
return useQuery<AxiosResponse<QueryKeySuggestionsResponseProps>, AxiosError>({
|
||||
queryKey,
|
||||
queryFn: () =>
|
||||
getKeySuggestions({
|
||||
signal,
|
||||
searchText,
|
||||
metricName,
|
||||
fieldContext,
|
||||
fieldDataType,
|
||||
}),
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import './LogsExplorer.styles.scss';
|
||||
import * as Sentry from '@sentry/react';
|
||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
import setLocalStorageApi from 'api/browser/localstorage/set';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import cx from 'classnames';
|
||||
import ExplorerCard from 'components/ExplorerCard/ExplorerCard';
|
||||
import QuickFilters from 'components/QuickFilters/QuickFilters';
|
||||
@@ -31,7 +32,7 @@ import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFall
|
||||
import { usePreferenceContext } from 'providers/preferences/context/PreferenceContextProvider';
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom-v5-compat';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
import {
|
||||
getExplorerViewForPanelType,
|
||||
@@ -82,6 +83,8 @@ function LogsExplorer(): JSX.Element {
|
||||
handleRunQuery,
|
||||
handleSetConfig,
|
||||
updateAllQueriesOperators,
|
||||
currentQuery,
|
||||
updateQueriesData,
|
||||
} = useQueryBuilder();
|
||||
|
||||
const { handleExplorerTabChange } = useHandleExplorerTabChange();
|
||||
@@ -94,6 +97,14 @@ function LogsExplorer(): JSX.Element {
|
||||
|
||||
const [shouldReset, setShouldReset] = useState(false);
|
||||
|
||||
const [defaultQuery, setDefaultQuery] = useState<Query>(() =>
|
||||
updateAllQueriesOperators(
|
||||
initialQueriesMap.logs,
|
||||
PANEL_TYPES.LIST,
|
||||
DataSource.LOGS,
|
||||
),
|
||||
);
|
||||
|
||||
const handleChangeSelectedView = useCallback(
|
||||
(view: ExplorerViews): void => {
|
||||
if (selectedView === ExplorerViews.LIST) {
|
||||
@@ -101,6 +112,30 @@ function LogsExplorer(): JSX.Element {
|
||||
}
|
||||
|
||||
if (view === ExplorerViews.LIST) {
|
||||
if (
|
||||
selectedView !== ExplorerViews.LIST &&
|
||||
currentQuery?.builder?.queryData?.[0]
|
||||
) {
|
||||
const filterToRetain = currentQuery.builder.queryData[0].filter;
|
||||
|
||||
const newDefaultQuery = updateAllQueriesOperators(
|
||||
initialQueriesMap.logs,
|
||||
PANEL_TYPES.LIST,
|
||||
DataSource.LOGS,
|
||||
);
|
||||
|
||||
const newListQuery = updateQueriesData(
|
||||
newDefaultQuery,
|
||||
'queryData',
|
||||
(item, index) => {
|
||||
if (index === 0) {
|
||||
return { ...item, filter: filterToRetain };
|
||||
}
|
||||
return item;
|
||||
},
|
||||
);
|
||||
setDefaultQuery(newListQuery);
|
||||
}
|
||||
setShouldReset(true);
|
||||
}
|
||||
|
||||
@@ -109,27 +144,34 @@ function LogsExplorer(): JSX.Element {
|
||||
view === ExplorerViews.TIMESERIES ? PANEL_TYPES.TIME_SERIES : view,
|
||||
);
|
||||
},
|
||||
[handleSetConfig, handleExplorerTabChange, selectedView],
|
||||
);
|
||||
|
||||
const defaultListQuery = useMemo(
|
||||
() =>
|
||||
updateAllQueriesOperators(
|
||||
initialQueriesMap.logs,
|
||||
PANEL_TYPES.LIST,
|
||||
DataSource.LOGS,
|
||||
),
|
||||
[updateAllQueriesOperators],
|
||||
[
|
||||
handleSetConfig,
|
||||
handleExplorerTabChange,
|
||||
selectedView,
|
||||
currentQuery,
|
||||
updateAllQueriesOperators,
|
||||
updateQueriesData,
|
||||
setSelectedView,
|
||||
],
|
||||
);
|
||||
|
||||
useShareBuilderUrl({
|
||||
defaultValue: defaultListQuery,
|
||||
defaultValue: defaultQuery,
|
||||
forceReset: shouldReset,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldReset) setShouldReset(false);
|
||||
}, [shouldReset]);
|
||||
if (shouldReset) {
|
||||
setShouldReset(false);
|
||||
setDefaultQuery(
|
||||
updateAllQueriesOperators(
|
||||
initialQueriesMap.logs,
|
||||
PANEL_TYPES.LIST,
|
||||
DataSource.LOGS,
|
||||
),
|
||||
);
|
||||
}
|
||||
}, [shouldReset, updateAllQueriesOperators]);
|
||||
|
||||
const handleFilterVisibilityChange = (): void => {
|
||||
setLocalStorageApi(
|
||||
@@ -158,11 +200,11 @@ function LogsExplorer(): JSX.Element {
|
||||
|
||||
// Check if the columns have the required columns (timestamp, body)
|
||||
const hasRequiredColumns = useCallback(
|
||||
(columns?: Array<{ key: string }> | null): boolean => {
|
||||
(columns?: TelemetryFieldKey[] | null): boolean => {
|
||||
if (!columns?.length) return false;
|
||||
|
||||
const hasTimestamp = columns.some((col) => col.key === 'timestamp');
|
||||
const hasBody = columns.some((col) => col.key === 'body');
|
||||
const hasTimestamp = columns.some((col) => col.name === 'timestamp');
|
||||
const hasBody = columns.some((col) => col.name === 'body');
|
||||
|
||||
return hasTimestamp && hasBody;
|
||||
},
|
||||
@@ -171,7 +213,7 @@ function LogsExplorer(): JSX.Element {
|
||||
|
||||
// Merge the columns with the required columns (timestamp, body) if missing
|
||||
const mergeWithRequiredColumns = useCallback(
|
||||
(columns: BaseAutocompleteData[]): BaseAutocompleteData[] => [
|
||||
(columns: TelemetryFieldKey[]): TelemetryFieldKey[] => [
|
||||
// Add required columns (timestamp, body) if missing
|
||||
...(!hasRequiredColumns(columns) ? defaultLogsSelectedColumns : []),
|
||||
...columns,
|
||||
|
||||
@@ -29,7 +29,7 @@ function MetricsExplorerPage(): JSX.Element {
|
||||
[updateAllQueriesOperators],
|
||||
);
|
||||
|
||||
useShareBuilderUrl(defaultQuery);
|
||||
useShareBuilderUrl({ defaultValue: defaultQuery });
|
||||
|
||||
return (
|
||||
<div className="metrics-explorer-page">
|
||||
|
||||
@@ -12,18 +12,28 @@ import { DataSource } from 'types/common/queryBuilder';
|
||||
export const AllTraceFilterKeyValue: Record<string, string> = {
|
||||
durationNanoMin: 'Duration',
|
||||
durationNano: 'Duration',
|
||||
duration_nano: 'Duration',
|
||||
durationNanoMax: 'Duration',
|
||||
'deployment.environment': 'Environment',
|
||||
hasError: 'Status',
|
||||
has_error: 'Status',
|
||||
serviceName: 'Service Name',
|
||||
'service.name': 'service.name',
|
||||
name: 'Operation / Name',
|
||||
rpcMethod: 'RPC Method',
|
||||
'rpc.method': 'RPC Method',
|
||||
responseStatusCode: 'Status Code',
|
||||
response_status_code: 'Status Code',
|
||||
httpHost: 'HTTP Host',
|
||||
http_host: 'HTTP Host',
|
||||
httpMethod: 'HTTP Method',
|
||||
http_method: 'HTTP Method',
|
||||
httpRoute: 'HTTP Route',
|
||||
'http.route': 'HTTP Route',
|
||||
httpUrl: 'HTTP URL',
|
||||
'http.url': 'HTTP URL',
|
||||
traceID: 'Trace ID',
|
||||
trace_id: 'Trace ID',
|
||||
} as const;
|
||||
|
||||
export type AllTraceFilterKeys = keyof typeof AllTraceFilterKeyValue;
|
||||
|
||||
@@ -51,6 +51,7 @@ function TracesExplorer(): JSX.Element {
|
||||
handleRunQuery,
|
||||
stagedQuery,
|
||||
handleSetConfig,
|
||||
updateQueriesData,
|
||||
} = useQueryBuilder();
|
||||
|
||||
const { options } = useOptionsMenu({
|
||||
@@ -94,6 +95,14 @@ function TracesExplorer(): JSX.Element {
|
||||
|
||||
const [shouldReset, setShouldReset] = useState(false);
|
||||
|
||||
const [defaultQuery, setDefaultQuery] = useState<Query>(() =>
|
||||
updateAllQueriesOperators(
|
||||
initialQueriesMap.traces,
|
||||
PANEL_TYPES.LIST,
|
||||
DataSource.TRACES,
|
||||
),
|
||||
);
|
||||
|
||||
const handleChangeSelectedView = useCallback(
|
||||
(view: ExplorerViews): void => {
|
||||
if (selectedView === ExplorerViews.LIST) {
|
||||
@@ -101,6 +110,30 @@ function TracesExplorer(): JSX.Element {
|
||||
}
|
||||
|
||||
if (view === ExplorerViews.LIST) {
|
||||
if (
|
||||
selectedView !== ExplorerViews.LIST &&
|
||||
currentQuery?.builder?.queryData?.[0]
|
||||
) {
|
||||
const filterToRetain = currentQuery.builder.queryData[0].filter;
|
||||
|
||||
const newDefaultQuery = updateAllQueriesOperators(
|
||||
initialQueriesMap.traces,
|
||||
PANEL_TYPES.LIST,
|
||||
DataSource.TRACES,
|
||||
);
|
||||
|
||||
const newListQuery = updateQueriesData(
|
||||
newDefaultQuery,
|
||||
'queryData',
|
||||
(item, index) => {
|
||||
if (index === 0) {
|
||||
return { ...item, filter: filterToRetain };
|
||||
}
|
||||
return item;
|
||||
},
|
||||
);
|
||||
setDefaultQuery(newListQuery);
|
||||
}
|
||||
setShouldReset(true);
|
||||
}
|
||||
|
||||
@@ -109,7 +142,15 @@ function TracesExplorer(): JSX.Element {
|
||||
view === ExplorerViews.TIMESERIES ? PANEL_TYPES.TIME_SERIES : view,
|
||||
);
|
||||
},
|
||||
[handleSetConfig, handleExplorerTabChange, selectedView],
|
||||
[
|
||||
handleSetConfig,
|
||||
handleExplorerTabChange,
|
||||
selectedView,
|
||||
currentQuery,
|
||||
updateAllQueriesOperators,
|
||||
updateQueriesData,
|
||||
setSelectedView,
|
||||
],
|
||||
);
|
||||
|
||||
const listQuery = useMemo(() => {
|
||||
@@ -118,16 +159,6 @@ function TracesExplorer(): JSX.Element {
|
||||
return stagedQuery.builder.queryData.find((item) => !item.disabled) || null;
|
||||
}, [stagedQuery]);
|
||||
|
||||
const defaultQuery = useMemo(
|
||||
() =>
|
||||
updateAllQueriesOperators(
|
||||
initialQueriesMap.traces,
|
||||
PANEL_TYPES.LIST,
|
||||
DataSource.TRACES,
|
||||
),
|
||||
[updateAllQueriesOperators],
|
||||
);
|
||||
|
||||
const exportDefaultQuery = useMemo(
|
||||
() =>
|
||||
updateAllQueriesOperators(
|
||||
@@ -186,8 +217,17 @@ function TracesExplorer(): JSX.Element {
|
||||
useShareBuilderUrl({ defaultValue: defaultQuery, forceReset: shouldReset });
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldReset) setShouldReset(false);
|
||||
}, [shouldReset]);
|
||||
if (shouldReset) {
|
||||
setShouldReset(false);
|
||||
setDefaultQuery(
|
||||
updateAllQueriesOperators(
|
||||
initialQueriesMap.traces,
|
||||
PANEL_TYPES.LIST,
|
||||
DataSource.TRACES,
|
||||
),
|
||||
);
|
||||
}
|
||||
}, [shouldReset, updateAllQueriesOperators]);
|
||||
|
||||
const [isOpen, setOpen] = useState<boolean>(true);
|
||||
const logEventCalledRef = useRef(false);
|
||||
|
||||
@@ -144,7 +144,7 @@ export function QueryBuilderProvider({
|
||||
.includes(queryData.aggregateOperator);
|
||||
|
||||
if (!isCurrentOperatorAvailableInList) {
|
||||
return { ...queryData, aggregateOperator: initialOperators[0].value };
|
||||
return { ...queryData, aggregateOperator: initialOperators[0]?.value };
|
||||
}
|
||||
|
||||
return queryData;
|
||||
@@ -247,6 +247,8 @@ export function QueryBuilderProvider({
|
||||
getElementWithActualOperator(item, dataSource, panelType),
|
||||
);
|
||||
|
||||
console.log('queryData', queryData, panelType, dataSource);
|
||||
|
||||
return { ...query, builder: { ...query.builder, queryData } };
|
||||
},
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/* eslint-disable sonarjs/no-identical-functions */
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import {
|
||||
FormattingOptions,
|
||||
PreferenceMode,
|
||||
Preferences,
|
||||
} from 'providers/preferences/types';
|
||||
import { MemoryRouter, Route, Switch } from 'react-router-dom';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
|
||||
import {
|
||||
PreferenceContextProvider,
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
jest.mock('../sync/usePreferenceSync', () => ({
|
||||
usePreferenceSync: jest.fn().mockReturnValue({
|
||||
preferences: {
|
||||
columns: [] as BaseAutocompleteData[],
|
||||
columns: [] as TelemetryFieldKey[],
|
||||
formatting: {
|
||||
maxLines: 2,
|
||||
format: 'table',
|
||||
|
||||
@@ -150,7 +150,7 @@ describe('logsLoaderConfig', () => {
|
||||
const result = await logsLoaderConfig.default();
|
||||
|
||||
expect(result).toEqual({
|
||||
columns: defaultLogsSelectedColumns as BaseAutocompleteData[],
|
||||
columns: defaultLogsSelectedColumns,
|
||||
formatting: {
|
||||
maxLines: 2,
|
||||
format: 'table' as LogViewMode,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { LogViewMode } from 'container/LogsTable';
|
||||
import { defaultOptionsQuery } from 'container/OptionsMenu/constants';
|
||||
@@ -7,10 +8,7 @@ import {
|
||||
PreferenceMode,
|
||||
Preferences,
|
||||
} from 'providers/preferences/types';
|
||||
import {
|
||||
BaseAutocompleteData,
|
||||
DataTypes,
|
||||
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
|
||||
import getLogsUpdaterConfig from '../configs/logsUpdaterConfig';
|
||||
|
||||
@@ -65,11 +63,11 @@ describe('logsUpdaterConfig', () => {
|
||||
setSavedViewPreferences,
|
||||
);
|
||||
|
||||
const newColumns: BaseAutocompleteData[] = [
|
||||
const newColumns: TelemetryFieldKey[] = [
|
||||
{
|
||||
key: 'new-column',
|
||||
type: 'tag',
|
||||
dataType: DataTypes.String,
|
||||
name: 'new-column',
|
||||
fieldContext: '',
|
||||
fieldDataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
];
|
||||
@@ -114,11 +112,11 @@ describe('logsUpdaterConfig', () => {
|
||||
setSavedViewPreferences,
|
||||
);
|
||||
|
||||
const newColumns: BaseAutocompleteData[] = [
|
||||
const newColumns: TelemetryFieldKey[] = [
|
||||
{
|
||||
key: 'new-column',
|
||||
type: 'tag',
|
||||
dataType: DataTypes.String,
|
||||
name: 'new-column',
|
||||
fieldContext: '',
|
||||
fieldDataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
BaseAutocompleteData,
|
||||
DataTypes,
|
||||
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { TelemetryFieldKey } from 'types/api/v5/queryRange';
|
||||
|
||||
import tracesLoaderConfig from '../configs/tracesLoaderConfig';
|
||||
|
||||
@@ -125,7 +126,7 @@ describe('tracesLoaderConfig', () => {
|
||||
const result = await tracesLoaderConfig.default();
|
||||
|
||||
expect(result).toEqual({
|
||||
columns: defaultTraceSelectedColumns as BaseAutocompleteData[],
|
||||
columns: defaultTraceSelectedColumns as TelemetryFieldKey[],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { defaultOptionsQuery } from 'container/OptionsMenu/constants';
|
||||
import {
|
||||
BaseAutocompleteData,
|
||||
DataTypes,
|
||||
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
|
||||
import getTracesUpdaterConfig from '../configs/tracesUpdaterConfig';
|
||||
import { PreferenceMode } from '../types';
|
||||
@@ -34,11 +32,11 @@ describe('tracesUpdaterConfig', () => {
|
||||
const mockSetSavedViewPreferences = jest.fn();
|
||||
|
||||
// Test data
|
||||
const mockColumns: BaseAutocompleteData[] = [
|
||||
const mockColumns: TelemetryFieldKey[] = [
|
||||
{
|
||||
key: 'test-trace-column',
|
||||
type: 'tag',
|
||||
dataType: DataTypes.String,
|
||||
name: 'test-trace-column',
|
||||
fieldContext: '',
|
||||
fieldDataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable sonarjs/no-identical-functions */
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { LogViewMode } from 'container/LogsTable';
|
||||
import { FontSize } from 'container/OptionsMenu/types';
|
||||
import {
|
||||
@@ -8,10 +9,7 @@ import {
|
||||
Preferences,
|
||||
} from 'providers/preferences/types';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import {
|
||||
BaseAutocompleteData,
|
||||
DataTypes,
|
||||
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { usePreferenceUpdater } from '../updater/usePreferenceUpdater';
|
||||
@@ -81,11 +79,11 @@ describe('usePreferenceUpdater', () => {
|
||||
it('should call the logs updater for updateColumns with logs dataSource', () => {
|
||||
const setReSync = jest.fn();
|
||||
const setSavedViewPreferences = jest.fn();
|
||||
const newColumns: BaseAutocompleteData[] = [
|
||||
const newColumns: TelemetryFieldKey[] = [
|
||||
{
|
||||
key: 'new-column',
|
||||
type: 'tag',
|
||||
dataType: DataTypes.String,
|
||||
name: 'new-column',
|
||||
fieldContext: '',
|
||||
fieldDataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
];
|
||||
@@ -147,11 +145,11 @@ describe('usePreferenceUpdater', () => {
|
||||
it('should call the traces updater for updateColumns with traces dataSource', () => {
|
||||
const setReSync = jest.fn();
|
||||
const setSavedViewPreferences = jest.fn();
|
||||
const newColumns: BaseAutocompleteData[] = [
|
||||
const newColumns: TelemetryFieldKey[] = [
|
||||
{
|
||||
key: 'new-trace-column',
|
||||
type: 'tag',
|
||||
dataType: DataTypes.String,
|
||||
name: 'new-trace-column',
|
||||
fieldContext: '',
|
||||
fieldDataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
];
|
||||
@@ -227,9 +225,9 @@ describe('usePreferenceUpdater', () => {
|
||||
act(() => {
|
||||
result.current.updateColumns([
|
||||
{
|
||||
key: 'column',
|
||||
type: 'tag',
|
||||
dataType: DataTypes.String,
|
||||
name: 'column',
|
||||
fieldContext: '',
|
||||
fieldDataType: DataTypes.String,
|
||||
isColumn: true,
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-empty */
|
||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
|
||||
import { FontSize } from 'container/OptionsMenu/types';
|
||||
@@ -50,10 +51,10 @@ const logsLoaders = {
|
||||
return { columns: [], formatting: undefined } as any;
|
||||
},
|
||||
default: async (): Promise<{
|
||||
columns: BaseAutocompleteData[];
|
||||
columns: TelemetryFieldKey[];
|
||||
formatting: FormattingOptions;
|
||||
}> => ({
|
||||
columns: defaultLogsSelectedColumns as BaseAutocompleteData[],
|
||||
columns: defaultLogsSelectedColumns,
|
||||
formatting: {
|
||||
maxLines: 2,
|
||||
format: 'table',
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import setLocalStorageKey from 'api/browser/localstorage/set';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { defaultOptionsQuery } from 'container/OptionsMenu/constants';
|
||||
import { FontSize, OptionsQuery } from 'container/OptionsMenu/types';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
|
||||
import { FormattingOptions, PreferenceMode, Preferences } from '../types';
|
||||
|
||||
@@ -13,10 +13,10 @@ const getLogsUpdaterConfig = (
|
||||
redirectWithOptionsData: (options: OptionsQuery) => void,
|
||||
setSavedViewPreferences: Dispatch<SetStateAction<Preferences | null>>,
|
||||
): {
|
||||
updateColumns: (newColumns: BaseAutocompleteData[], mode: string) => void;
|
||||
updateColumns: (newColumns: TelemetryFieldKey[], mode: string) => void;
|
||||
updateFormatting: (newFormatting: FormattingOptions, mode: string) => void;
|
||||
} => ({
|
||||
updateColumns: (newColumns: BaseAutocompleteData[], mode: string): void => {
|
||||
updateColumns: (newColumns: TelemetryFieldKey[], mode: string): void => {
|
||||
if (mode === PreferenceMode.SAVED_VIEW) {
|
||||
setSavedViewPreferences((prev) => {
|
||||
if (!prev) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable no-empty */
|
||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { defaultTraceSelectedColumns } from 'container/OptionsMenu/constants';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
@@ -33,9 +34,9 @@ const tracesLoaders = {
|
||||
return { columns: [] };
|
||||
},
|
||||
default: async (): Promise<{
|
||||
columns: BaseAutocompleteData[];
|
||||
columns: TelemetryFieldKey[];
|
||||
}> => ({
|
||||
columns: defaultTraceSelectedColumns as BaseAutocompleteData[],
|
||||
columns: defaultTraceSelectedColumns,
|
||||
}),
|
||||
priority: ['local', 'url', 'default'] as const,
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import setLocalStorageKey from 'api/browser/localstorage/set';
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||
import { defaultOptionsQuery } from 'container/OptionsMenu/constants';
|
||||
import { FontSize, OptionsQuery } from 'container/OptionsMenu/types';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
|
||||
import { PreferenceMode, Preferences } from '../types';
|
||||
|
||||
@@ -12,10 +12,10 @@ const getTracesUpdaterConfig = (
|
||||
redirectWithOptionsData: (options: OptionsQuery) => void,
|
||||
setSavedViewPreferences: Dispatch<SetStateAction<Preferences | null>>,
|
||||
): {
|
||||
updateColumns: (newColumns: BaseAutocompleteData[], mode: string) => void;
|
||||
updateColumns: (newColumns: TelemetryFieldKey[], mode: string) => void;
|
||||
updateFormatting: () => void;
|
||||
} => ({
|
||||
updateColumns: (newColumns: BaseAutocompleteData[], mode: string): void => {
|
||||
updateColumns: (newColumns: TelemetryFieldKey[], mode: string): void => {
|
||||
// remove the formatting props
|
||||
if (mode === PreferenceMode.SAVED_VIEW) {
|
||||
setSavedViewPreferences({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable sonarjs/cognitive-complexity */
|
||||
/* eslint-disable no-empty */
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import logsLoaderConfig from '../configs/logsLoaderConfig';
|
||||
@@ -43,14 +43,14 @@ async function preferencesLoader<T>(config: {
|
||||
|
||||
// Use the generic loader with specific configs
|
||||
async function logsPreferencesLoader(): Promise<{
|
||||
columns: BaseAutocompleteData[];
|
||||
columns: TelemetryFieldKey[];
|
||||
formatting: FormattingOptions;
|
||||
}> {
|
||||
return preferencesLoader(logsLoaderConfig);
|
||||
}
|
||||
|
||||
async function tracesPreferencesLoader(): Promise<{
|
||||
columns: BaseAutocompleteData[];
|
||||
columns: TelemetryFieldKey[];
|
||||
}> {
|
||||
return preferencesLoader(tracesLoaderConfig);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { defaultLogsSelectedColumns } from 'container/OptionsMenu/constants';
|
||||
import { defaultSelectedColumns as defaultTracesSelectedColumns } from 'container/TracesExplorer/ListView/configs';
|
||||
import { useGetAllViews } from 'hooks/saveViews/useGetAllViews';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import { usePreferenceLoader } from '../loader/usePreferenceLoader';
|
||||
@@ -21,7 +21,7 @@ export function usePreferenceSync({
|
||||
preferences: Preferences | null;
|
||||
loading: boolean;
|
||||
error: Error | null;
|
||||
updateColumns: (newColumns: BaseAutocompleteData[]) => void;
|
||||
updateColumns: (newColumns: TelemetryFieldKey[]) => void;
|
||||
updateFormatting: (newFormatting: FormattingOptions) => void;
|
||||
} {
|
||||
const { data: viewsData } = useGetAllViews(dataSource);
|
||||
@@ -37,7 +37,7 @@ export function usePreferenceSync({
|
||||
)?.extraData;
|
||||
|
||||
const parsedExtraData = JSON.parse(extraData || '{}');
|
||||
let columns: BaseAutocompleteData[] = [];
|
||||
let columns: TelemetryFieldKey[] = [];
|
||||
let formatting: FormattingOptions | undefined;
|
||||
if (dataSource === DataSource.LOGS) {
|
||||
columns = parsedExtraData?.selectColumns || defaultLogsSelectedColumns;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { LogViewMode } from 'container/LogsTable';
|
||||
import { FontSize } from 'container/OptionsMenu/types';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
export enum PreferenceMode {
|
||||
@@ -15,7 +15,7 @@ export interface PreferenceContextValue {
|
||||
mode: PreferenceMode;
|
||||
savedViewId?: string;
|
||||
dataSource: DataSource;
|
||||
updateColumns: (newColumns: BaseAutocompleteData[]) => void;
|
||||
updateColumns: (newColumns: TelemetryFieldKey[]) => void;
|
||||
updateFormatting: (newFormatting: FormattingOptions) => void;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,6 @@ export interface FormattingOptions {
|
||||
}
|
||||
|
||||
export interface Preferences {
|
||||
columns: BaseAutocompleteData[];
|
||||
columns: TelemetryFieldKey[];
|
||||
formatting?: FormattingOptions;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import {
|
||||
defaultOptionsQuery,
|
||||
URL_OPTIONS,
|
||||
@@ -5,7 +6,6 @@ import {
|
||||
import { OptionsQuery } from 'container/OptionsMenu/types';
|
||||
import useUrlQueryData from 'hooks/useUrlQueryData';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { BaseAutocompleteData } from 'types/api/queryBuilder/queryAutocompleteResponse';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
import getLogsUpdaterConfig from '../configs/logsUpdaterConfig';
|
||||
@@ -24,7 +24,7 @@ const getUpdaterConfig = (
|
||||
): Record<
|
||||
DataSource,
|
||||
{
|
||||
updateColumns: (newColumns: BaseAutocompleteData[], mode: string) => void;
|
||||
updateColumns: (newColumns: TelemetryFieldKey[], mode: string) => void;
|
||||
updateFormatting: (newFormatting: FormattingOptions, mode: string) => void;
|
||||
}
|
||||
> => ({
|
||||
@@ -53,7 +53,7 @@ export function usePreferenceUpdater({
|
||||
setReSync: Dispatch<SetStateAction<boolean>>;
|
||||
setSavedViewPreferences: Dispatch<SetStateAction<Preferences | null>>;
|
||||
}): {
|
||||
updateColumns: (newColumns: BaseAutocompleteData[]) => void;
|
||||
updateColumns: (newColumns: TelemetryFieldKey[]) => void;
|
||||
updateFormatting: (newFormatting: FormattingOptions) => void;
|
||||
} {
|
||||
const {
|
||||
@@ -66,7 +66,7 @@ export function usePreferenceUpdater({
|
||||
)[dataSource];
|
||||
|
||||
return {
|
||||
updateColumns: (newColumns: BaseAutocompleteData[]): void => {
|
||||
updateColumns: (newColumns: TelemetryFieldKey[]): void => {
|
||||
updater.updateColumns(newColumns, mode);
|
||||
setReSync(true);
|
||||
},
|
||||
|
||||
@@ -16,7 +16,9 @@ export interface IQueryPair {
|
||||
key: string;
|
||||
operator: string;
|
||||
value?: string;
|
||||
valueList?: string[];
|
||||
hasNegation?: boolean;
|
||||
isMultiValue?: boolean;
|
||||
position: {
|
||||
keyStart: number;
|
||||
keyEnd: number;
|
||||
@@ -27,6 +29,10 @@ export interface IQueryPair {
|
||||
negationStart?: number;
|
||||
negationEnd?: number;
|
||||
};
|
||||
valuesPosition?: {
|
||||
start?: number;
|
||||
end?: number;
|
||||
}[];
|
||||
isComplete: boolean; // true if the pair has all three components
|
||||
}
|
||||
|
||||
@@ -44,7 +50,6 @@ export interface IQueryContext {
|
||||
isInConjunction?: boolean;
|
||||
isInParenthesis?: boolean;
|
||||
isInBracketList?: boolean; // For multi-value operators like IN where values are in brackets
|
||||
isValueWrappedInQuotes?: boolean;
|
||||
keyToken?: string;
|
||||
operatorToken?: string;
|
||||
valueToken?: string;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Layout } from 'react-grid-layout';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
|
||||
import { IField } from '../logs/fields';
|
||||
import { BaseAutocompleteData } from '../queryBuilder/queryAutocompleteResponse';
|
||||
import { TelemetryFieldKey } from '../v5/queryRange';
|
||||
|
||||
export const VariableQueryTypeArr = ['QUERY', 'TEXTBOX', 'CUSTOM'] as const;
|
||||
export type TVariableQueryType = typeof VariableQueryTypeArr[number];
|
||||
@@ -115,7 +115,7 @@ export interface IBaseWidget {
|
||||
fillSpans?: boolean;
|
||||
columnUnits?: ColumnUnit;
|
||||
selectedLogFields: IField[] | null;
|
||||
selectedTracesFields: BaseAutocompleteData[] | null;
|
||||
selectedTracesFields: TelemetryFieldKey[] | null;
|
||||
isLogScale?: boolean;
|
||||
columnWidths?: Record<string, number>;
|
||||
legendPosition?: LegendPosition;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { TelemetryFieldKey } from 'api/v5/v5';
|
||||
import { Format } from 'container/NewWidget/RightContainer/types';
|
||||
import { EQueryType } from 'types/common/dashboard';
|
||||
import {
|
||||
@@ -85,7 +86,7 @@ export type IBuilderQuery = {
|
||||
legend: string;
|
||||
pageSize?: number;
|
||||
offset?: number;
|
||||
selectColumns?: BaseAutocompleteData[];
|
||||
selectColumns?: BaseAutocompleteData[] | TelemetryFieldKey[];
|
||||
};
|
||||
|
||||
export interface IClickHouseQuery {
|
||||
|
||||
@@ -4,10 +4,10 @@ export interface QueryKeyDataSuggestionsProps {
|
||||
info?: string;
|
||||
apply?: string;
|
||||
detail?: string;
|
||||
fieldContext: string;
|
||||
fieldDataType: string;
|
||||
fieldContext?: 'resource' | 'scope' | 'attribute' | 'span';
|
||||
fieldDataType?: 'string' | 'number' | 'boolean';
|
||||
name: string;
|
||||
signal: string;
|
||||
signal: 'traces' | 'logs' | 'metrics';
|
||||
}
|
||||
|
||||
export interface QueryKeySuggestionsResponseProps {
|
||||
@@ -21,8 +21,11 @@ export interface QueryKeySuggestionsResponseProps {
|
||||
}
|
||||
|
||||
export interface QueryKeyRequestProps {
|
||||
signal: string;
|
||||
name: string;
|
||||
signal: 'traces' | 'logs' | 'metrics';
|
||||
searchText: string;
|
||||
fieldContext?: 'resource' | 'scope' | 'attribute' | 'span';
|
||||
fieldDataType?: 'string' | 'number' | 'boolean';
|
||||
metricName?: string;
|
||||
}
|
||||
|
||||
export interface QueryKeyValueSuggestionsProps {
|
||||
|
||||
@@ -130,6 +130,9 @@ export interface TelemetryFieldKey {
|
||||
fieldContext?: FieldContext;
|
||||
fieldDataType?: FieldDataType;
|
||||
materialized?: boolean;
|
||||
isColumn?: boolean;
|
||||
isJSON?: boolean;
|
||||
isIndexed?: boolean;
|
||||
}
|
||||
|
||||
export interface Filter {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
isNonValueOperatorToken,
|
||||
isOperatorToken,
|
||||
isValueToken,
|
||||
isWrappedUnderQuotes,
|
||||
} from './tokenUtils';
|
||||
|
||||
// Function to normalize multiple spaces to single spaces when not in quotes
|
||||
@@ -152,6 +153,32 @@ function determineTokenContext(
|
||||
};
|
||||
}
|
||||
|
||||
export function getCurrentValueIndexAtCursor(
|
||||
valuesPosition: {
|
||||
start?: number;
|
||||
end?: number;
|
||||
}[],
|
||||
cursorIndex: number,
|
||||
): number | null {
|
||||
if (!valuesPosition || valuesPosition.length === 0) return null;
|
||||
|
||||
// Find the value that contains the cursor index
|
||||
for (let i = 0; i < valuesPosition.length; i++) {
|
||||
const start = valuesPosition[i].start;
|
||||
const end = valuesPosition[i].end;
|
||||
if (
|
||||
start !== undefined &&
|
||||
end !== undefined &&
|
||||
start <= cursorIndex &&
|
||||
cursorIndex <= end
|
||||
) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Function to determine token context boundaries more precisely
|
||||
function determineContextBoundaries(
|
||||
query: string,
|
||||
@@ -170,32 +197,7 @@ function determineContextBoundaries(
|
||||
let currentPair: IQueryPair | null = null;
|
||||
|
||||
if (queryPairs.length > 0) {
|
||||
// Look for the rightmost pair whose end position is before or at the cursor
|
||||
let bestMatch: IQueryPair | null = null;
|
||||
|
||||
for (const pair of queryPairs) {
|
||||
const { position } = pair;
|
||||
|
||||
// Find the rightmost position of this pair
|
||||
const pairEnd = position.valueEnd || position.operatorEnd || position.keyEnd;
|
||||
|
||||
// FIXED: Consider cursor position at the end of a token (including the last character)
|
||||
if (
|
||||
(pairEnd <= cursorIndex || pairEnd + 1 === cursorIndex) &&
|
||||
(!bestMatch ||
|
||||
pairEnd >
|
||||
(bestMatch.position.valueEnd ||
|
||||
bestMatch.position.operatorEnd ||
|
||||
bestMatch.position.keyEnd))
|
||||
) {
|
||||
bestMatch = pair;
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a match, use it
|
||||
if (bestMatch) {
|
||||
currentPair = bestMatch;
|
||||
}
|
||||
currentPair = getCurrentQueryPair(queryPairs, query, cursorIndex);
|
||||
}
|
||||
|
||||
// Check for bracket context first (could be part of an IN operator's value)
|
||||
@@ -642,38 +644,7 @@ export function getQueryContextAtCursor(
|
||||
// Find the current pair without causing a circular dependency
|
||||
let currentPair: IQueryPair | null = null;
|
||||
if (queryPairs.length > 0) {
|
||||
// Look for the rightmost pair whose end position is before or at the cursor
|
||||
let bestMatch: IQueryPair | null = null;
|
||||
|
||||
for (const pair of queryPairs) {
|
||||
const { position } = pair;
|
||||
|
||||
// Find the rightmost position of this pair
|
||||
const pairEnd =
|
||||
position.valueEnd || position.operatorEnd || position.keyEnd;
|
||||
|
||||
// FIXED: If this pair ends at or before the cursor (including exactly at the end),
|
||||
// and it's further right than our previous best match
|
||||
if (
|
||||
(pairEnd <= adjustedCursorIndex || pairEnd + 1 === adjustedCursorIndex) &&
|
||||
(!bestMatch ||
|
||||
pairEnd >
|
||||
(bestMatch.position.valueEnd ||
|
||||
bestMatch.position.operatorEnd ||
|
||||
bestMatch.position.keyEnd))
|
||||
) {
|
||||
bestMatch = pair;
|
||||
}
|
||||
}
|
||||
|
||||
// If we found a match, use it
|
||||
if (bestMatch) {
|
||||
currentPair = bestMatch;
|
||||
}
|
||||
// If cursor is at the end, use the last pair
|
||||
else if (adjustedCursorIndex >= input.length) {
|
||||
currentPair = queryPairs[queryPairs.length - 1];
|
||||
}
|
||||
currentPair = getCurrentQueryPair(queryPairs, query, adjustedCursorIndex);
|
||||
}
|
||||
|
||||
// Determine precise context boundaries
|
||||
@@ -754,8 +725,6 @@ export function getQueryContextAtCursor(
|
||||
const operatorToken = currentPair?.operator || '';
|
||||
const valueToken = currentPair?.value || '';
|
||||
|
||||
const isValueWrappedInQuotes = isWrappedUnderQuotes(valueToken);
|
||||
|
||||
// Determine if we're in a multi-value operator context
|
||||
const isForMultiValueOperator = isMultiValueOperator(operatorToken);
|
||||
|
||||
@@ -782,7 +751,6 @@ export function getQueryContextAtCursor(
|
||||
isInFunction: false,
|
||||
isInParenthesis: isInParenthesisBoundary || false,
|
||||
isInBracketList: isInBracketListBoundary || false,
|
||||
isValueWrappedInQuotes: isValueWrappedInQuotes,
|
||||
keyToken: isInKeyBoundary
|
||||
? keyToken
|
||||
: isInOperatorBoundary || finalIsInValue
|
||||
@@ -1237,9 +1205,12 @@ export function extractQueryPairs(query: string): IQueryPair[] {
|
||||
const queryPairs: IQueryPair[] = [];
|
||||
let currentPair: Partial<IQueryPair> | null = null;
|
||||
|
||||
let iterator = 0;
|
||||
|
||||
// Process tokens to build triplets
|
||||
for (let i = 0; i < allTokens.length; i++) {
|
||||
const token = allTokens[i];
|
||||
while (iterator < allTokens.length) {
|
||||
const token = allTokens[iterator];
|
||||
iterator += 1;
|
||||
|
||||
// Skip EOF and whitespace tokens
|
||||
if (token.type === FilterQueryLexer.EOF || token.channel !== 0) {
|
||||
@@ -1257,7 +1228,10 @@ export function extractQueryPairs(query: string): IQueryPair[] {
|
||||
key: currentPair.key,
|
||||
operator: currentPair.operator || '',
|
||||
value: currentPair.value,
|
||||
valueList: currentPair.valueList || [],
|
||||
valuesPosition: currentPair.valuesPosition || [],
|
||||
hasNegation: currentPair.hasNegation || false,
|
||||
isMultiValue: currentPair.isMultiValue || false,
|
||||
position: {
|
||||
keyStart: currentPair.position?.keyStart || 0,
|
||||
keyEnd: currentPair.position?.keyEnd || 0,
|
||||
@@ -1310,6 +1284,55 @@ export function extractQueryPairs(query: string): IQueryPair[] {
|
||||
currentPair.key &&
|
||||
!currentPair.operator
|
||||
) {
|
||||
let multiValueStart: number | undefined;
|
||||
let multiValueEnd: number | undefined;
|
||||
|
||||
if (isMultiValueOperator(token.text)) {
|
||||
currentPair.isMultiValue = true;
|
||||
|
||||
// Iterate from '[' || '(' till ']' || ')' to get all the values
|
||||
const valueList: string[] = [];
|
||||
const valuesPosition: { start: number; end: number }[] = [];
|
||||
|
||||
if (
|
||||
[FilterQueryLexer.LPAREN, FilterQueryLexer.LBRACK].includes(
|
||||
allTokens[iterator].type,
|
||||
)
|
||||
) {
|
||||
multiValueStart = allTokens[iterator].start;
|
||||
iterator += 1;
|
||||
const closingToken =
|
||||
allTokens[iterator].type === FilterQueryLexer.LPAREN
|
||||
? FilterQueryLexer.RPAREN
|
||||
: FilterQueryLexer.RBRACK;
|
||||
|
||||
while (
|
||||
allTokens[iterator].type !== closingToken &&
|
||||
iterator < allTokens.length
|
||||
) {
|
||||
if (isValueToken(allTokens[iterator].type)) {
|
||||
valueList.push(allTokens[iterator].text);
|
||||
valuesPosition.push({
|
||||
start: allTokens[iterator].start,
|
||||
end: allTokens[iterator].stop,
|
||||
});
|
||||
}
|
||||
iterator += 1;
|
||||
}
|
||||
|
||||
if (allTokens[iterator].type === closingToken) {
|
||||
multiValueEnd = allTokens[iterator].stop;
|
||||
}
|
||||
}
|
||||
|
||||
currentPair.valuesPosition = valuesPosition;
|
||||
currentPair.valueList = valueList;
|
||||
|
||||
if (multiValueStart && multiValueEnd) {
|
||||
currentPair.value = query.substring(multiValueStart, multiValueEnd + 1);
|
||||
}
|
||||
}
|
||||
|
||||
currentPair.operator = token.text;
|
||||
// Ensure we create a valid position object with all required fields
|
||||
currentPair.position = {
|
||||
@@ -1317,8 +1340,8 @@ export function extractQueryPairs(query: string): IQueryPair[] {
|
||||
keyEnd: currentPair.position?.keyEnd || 0,
|
||||
operatorStart: token.start,
|
||||
operatorEnd: token.stop,
|
||||
valueStart: currentPair.position?.valueStart,
|
||||
valueEnd: currentPair.position?.valueEnd,
|
||||
valueStart: multiValueStart || currentPair.position?.valueStart,
|
||||
valueEnd: multiValueEnd || currentPair.position?.valueEnd,
|
||||
negationStart: currentPair.position?.negationStart || 0,
|
||||
negationEnd: currentPair.position?.negationEnd || 0,
|
||||
};
|
||||
@@ -1350,7 +1373,10 @@ export function extractQueryPairs(query: string): IQueryPair[] {
|
||||
key: currentPair.key,
|
||||
operator: currentPair.operator || '',
|
||||
value: currentPair.value,
|
||||
valueList: currentPair.valueList || [],
|
||||
valuesPosition: currentPair.valuesPosition || [],
|
||||
hasNegation: currentPair.hasNegation || false,
|
||||
isMultiValue: currentPair.isMultiValue || false,
|
||||
position: {
|
||||
keyStart: currentPair.position?.keyStart || 0,
|
||||
keyEnd: currentPair.position?.keyEnd || 0,
|
||||
@@ -1379,7 +1405,10 @@ export function extractQueryPairs(query: string): IQueryPair[] {
|
||||
key: currentPair.key,
|
||||
operator: currentPair.operator || '',
|
||||
value: currentPair.value,
|
||||
valueList: currentPair.valueList || [],
|
||||
valuesPosition: currentPair.valuesPosition || [],
|
||||
hasNegation: currentPair.hasNegation || false,
|
||||
isMultiValue: currentPair.isMultiValue || false,
|
||||
position: {
|
||||
keyStart: currentPair.position?.keyStart || 0,
|
||||
keyEnd: currentPair.position?.keyEnd || 0,
|
||||
@@ -1410,18 +1439,17 @@ export function extractQueryPairs(query: string): IQueryPair[] {
|
||||
* This is useful for getting suggestions based on the current context
|
||||
* The function finds the rightmost complete pair that ends before or at the cursor position
|
||||
*
|
||||
* @param query The query string
|
||||
* @param queryPairs An array of IQueryPair objects representing the key-operator-value triplets
|
||||
* @param query The full query string
|
||||
* @param cursorIndex The position of the cursor in the query
|
||||
* @returns The query pair at the cursor position, or null if not found
|
||||
*/
|
||||
export function getCurrentQueryPair(
|
||||
queryPairs: IQueryPair[],
|
||||
query: string,
|
||||
cursorIndex: number,
|
||||
): IQueryPair | null {
|
||||
try {
|
||||
const queryPairs = extractQueryPairs(query);
|
||||
// Removed the circular dependency by not calling getQueryContextAtCursor here
|
||||
|
||||
// If we have pairs, try to find the one at the cursor position
|
||||
if (queryPairs.length > 0) {
|
||||
// Look for the rightmost pair whose end position is before or at the cursor
|
||||
@@ -1434,9 +1462,13 @@ export function getCurrentQueryPair(
|
||||
const pairEnd =
|
||||
position.valueEnd || position.operatorEnd || position.keyEnd;
|
||||
|
||||
const pairStart =
|
||||
position.keyStart || position.operatorStart || position.valueStart || 0;
|
||||
|
||||
// If this pair ends at or before the cursor, and it's further right than our previous best match
|
||||
if (
|
||||
pairEnd <= cursorIndex &&
|
||||
pairEnd >= cursorIndex &&
|
||||
pairStart <= cursorIndex &&
|
||||
(!bestMatch ||
|
||||
pairEnd >
|
||||
(bestMatch.position.valueEnd ||
|
||||
|
||||
@@ -60,7 +60,7 @@ export function isMultiValueOperator(operatorToken?: string): boolean {
|
||||
if (!operatorToken) return false;
|
||||
|
||||
const upperOp = operatorToken.toUpperCase();
|
||||
return upperOp === 'IN' || upperOp === 'NOT IN';
|
||||
return upperOp === 'IN';
|
||||
}
|
||||
|
||||
export function isFunctionToken(tokenType: number): boolean {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,44 +0,0 @@
|
||||
LPAREN=1
|
||||
RPAREN=2
|
||||
LBRACK=3
|
||||
RBRACK=4
|
||||
COMMA=5
|
||||
EQUALS=6
|
||||
NOT_EQUALS=7
|
||||
NEQ=8
|
||||
LT=9
|
||||
LE=10
|
||||
GT=11
|
||||
GE=12
|
||||
LIKE=13
|
||||
NOT_LIKE=14
|
||||
ILIKE=15
|
||||
NOT_ILIKE=16
|
||||
BETWEEN=17
|
||||
EXISTS=18
|
||||
REGEXP=19
|
||||
CONTAINS=20
|
||||
IN=21
|
||||
NOT=22
|
||||
AND=23
|
||||
OR=24
|
||||
HAS=25
|
||||
HASANY=26
|
||||
HASALL=27
|
||||
BOOL=28
|
||||
NUMBER=29
|
||||
QUOTED_TEXT=30
|
||||
KEY=31
|
||||
WS=32
|
||||
FREETEXT=33
|
||||
'('=1
|
||||
')'=2
|
||||
'['=3
|
||||
']'=4
|
||||
','=5
|
||||
'!='=7
|
||||
'<>'=8
|
||||
'<'=9
|
||||
'<='=10
|
||||
'>'=11
|
||||
'>='=12
|
||||
File diff suppressed because one or more lines are too long
@@ -1,356 +0,0 @@
|
||||
// Generated from /Users/abhikumar/Documents/Projects/signoz/grammar/FilterQuery.g4 by ANTLR 4.13.1
|
||||
import org.antlr.v4.runtime.Lexer;
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.TokenStream;
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.atn.*;
|
||||
import org.antlr.v4.runtime.dfa.DFA;
|
||||
import org.antlr.v4.runtime.misc.*;
|
||||
|
||||
@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"})
|
||||
public class FilterQueryLexer extends Lexer {
|
||||
static { RuntimeMetaData.checkVersion("4.13.1", RuntimeMetaData.VERSION); }
|
||||
|
||||
protected static final DFA[] _decisionToDFA;
|
||||
protected static final PredictionContextCache _sharedContextCache =
|
||||
new PredictionContextCache();
|
||||
public static final int
|
||||
LPAREN=1, RPAREN=2, LBRACK=3, RBRACK=4, COMMA=5, EQUALS=6, NOT_EQUALS=7,
|
||||
NEQ=8, LT=9, LE=10, GT=11, GE=12, LIKE=13, NOT_LIKE=14, ILIKE=15, NOT_ILIKE=16,
|
||||
BETWEEN=17, EXISTS=18, REGEXP=19, CONTAINS=20, IN=21, NOT=22, AND=23,
|
||||
OR=24, HAS=25, HASANY=26, HASALL=27, BOOL=28, NUMBER=29, QUOTED_TEXT=30,
|
||||
KEY=31, WS=32, FREETEXT=33;
|
||||
public static String[] channelNames = {
|
||||
"DEFAULT_TOKEN_CHANNEL", "HIDDEN"
|
||||
};
|
||||
|
||||
public static String[] modeNames = {
|
||||
"DEFAULT_MODE"
|
||||
};
|
||||
|
||||
private static String[] makeRuleNames() {
|
||||
return new String[] {
|
||||
"LPAREN", "RPAREN", "LBRACK", "RBRACK", "COMMA", "EQUALS", "NOT_EQUALS",
|
||||
"NEQ", "LT", "LE", "GT", "GE", "LIKE", "NOT_LIKE", "ILIKE", "NOT_ILIKE",
|
||||
"BETWEEN", "EXISTS", "REGEXP", "CONTAINS", "IN", "NOT", "AND", "OR",
|
||||
"HAS", "HASANY", "HASALL", "BOOL", "SIGN", "NUMBER", "QUOTED_TEXT", "SEGMENT",
|
||||
"EMPTY_BRACKS", "OLD_JSON_BRACKS", "KEY", "WS", "DIGIT", "FREETEXT"
|
||||
};
|
||||
}
|
||||
public static final String[] ruleNames = makeRuleNames();
|
||||
|
||||
private static String[] makeLiteralNames() {
|
||||
return new String[] {
|
||||
null, "'('", "')'", "'['", "']'", "','", null, "'!='", "'<>'", "'<'",
|
||||
"'<='", "'>'", "'>='"
|
||||
};
|
||||
}
|
||||
private static final String[] _LITERAL_NAMES = makeLiteralNames();
|
||||
private static String[] makeSymbolicNames() {
|
||||
return new String[] {
|
||||
null, "LPAREN", "RPAREN", "LBRACK", "RBRACK", "COMMA", "EQUALS", "NOT_EQUALS",
|
||||
"NEQ", "LT", "LE", "GT", "GE", "LIKE", "NOT_LIKE", "ILIKE", "NOT_ILIKE",
|
||||
"BETWEEN", "EXISTS", "REGEXP", "CONTAINS", "IN", "NOT", "AND", "OR",
|
||||
"HAS", "HASANY", "HASALL", "BOOL", "NUMBER", "QUOTED_TEXT", "KEY", "WS",
|
||||
"FREETEXT"
|
||||
};
|
||||
}
|
||||
private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames();
|
||||
public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #VOCABULARY} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String[] tokenNames;
|
||||
static {
|
||||
tokenNames = new String[_SYMBOLIC_NAMES.length];
|
||||
for (int i = 0; i < tokenNames.length; i++) {
|
||||
tokenNames[i] = VOCABULARY.getLiteralName(i);
|
||||
if (tokenNames[i] == null) {
|
||||
tokenNames[i] = VOCABULARY.getSymbolicName(i);
|
||||
}
|
||||
|
||||
if (tokenNames[i] == null) {
|
||||
tokenNames[i] = "<INVALID>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public String[] getTokenNames() {
|
||||
return tokenNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public Vocabulary getVocabulary() {
|
||||
return VOCABULARY;
|
||||
}
|
||||
|
||||
|
||||
public FilterQueryLexer(CharStream input) {
|
||||
super(input);
|
||||
_interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGrammarFileName() { return "FilterQuery.g4"; }
|
||||
|
||||
@Override
|
||||
public String[] getRuleNames() { return ruleNames; }
|
||||
|
||||
@Override
|
||||
public String getSerializedATN() { return _serializedATN; }
|
||||
|
||||
@Override
|
||||
public String[] getChannelNames() { return channelNames; }
|
||||
|
||||
@Override
|
||||
public String[] getModeNames() { return modeNames; }
|
||||
|
||||
@Override
|
||||
public ATN getATN() { return _ATN; }
|
||||
|
||||
public static final String _serializedATN =
|
||||
"\u0004\u0000!\u014e\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+
|
||||
"\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004"+
|
||||
"\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007"+
|
||||
"\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b"+
|
||||
"\u0007\u000b\u0002\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002"+
|
||||
"\u000f\u0007\u000f\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002"+
|
||||
"\u0012\u0007\u0012\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002"+
|
||||
"\u0015\u0007\u0015\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0002"+
|
||||
"\u0018\u0007\u0018\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002"+
|
||||
"\u001b\u0007\u001b\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002"+
|
||||
"\u001e\u0007\u001e\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007"+
|
||||
"!\u0002\"\u0007\"\u0002#\u0007#\u0002$\u0007$\u0002%\u0007%\u0001\u0000"+
|
||||
"\u0001\u0000\u0001\u0001\u0001\u0001\u0001\u0002\u0001\u0002\u0001\u0003"+
|
||||
"\u0001\u0003\u0001\u0004\u0001\u0004\u0001\u0005\u0001\u0005\u0001\u0005"+
|
||||
"\u0003\u0005[\b\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0007"+
|
||||
"\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001"+
|
||||
"\n\u0001\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\f\u0001\f\u0001\f"+
|
||||
"\u0001\f\u0001\f\u0001\r\u0001\r\u0001\r\u0001\r\u0004\rv\b\r\u000b\r"+
|
||||
"\f\rw\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\u000e\u0001\u000e"+
|
||||
"\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f"+
|
||||
"\u0001\u000f\u0001\u000f\u0004\u000f\u0089\b\u000f\u000b\u000f\f\u000f"+
|
||||
"\u008a\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+
|
||||
"\u000f\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+
|
||||
"\u0010\u0001\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0001"+
|
||||
"\u0011\u0001\u0011\u0001\u0011\u0003\u0011\u00a1\b\u0011\u0001\u0012\u0001"+
|
||||
"\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001"+
|
||||
"\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+
|
||||
"\u0013\u0001\u0013\u0003\u0013\u00b2\b\u0013\u0001\u0014\u0001\u0014\u0001"+
|
||||
"\u0014\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0016\u0001"+
|
||||
"\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017\u0001\u0017\u0001"+
|
||||
"\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001"+
|
||||
"\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u001a\u0001"+
|
||||
"\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001"+
|
||||
"\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001"+
|
||||
"\u001b\u0001\u001b\u0001\u001b\u0003\u001b\u00dd\b\u001b\u0001\u001c\u0001"+
|
||||
"\u001c\u0001\u001d\u0003\u001d\u00e2\b\u001d\u0001\u001d\u0004\u001d\u00e5"+
|
||||
"\b\u001d\u000b\u001d\f\u001d\u00e6\u0001\u001d\u0001\u001d\u0005\u001d"+
|
||||
"\u00eb\b\u001d\n\u001d\f\u001d\u00ee\t\u001d\u0003\u001d\u00f0\b\u001d"+
|
||||
"\u0001\u001d\u0001\u001d\u0003\u001d\u00f4\b\u001d\u0001\u001d\u0004\u001d"+
|
||||
"\u00f7\b\u001d\u000b\u001d\f\u001d\u00f8\u0003\u001d\u00fb\b\u001d\u0001"+
|
||||
"\u001d\u0003\u001d\u00fe\b\u001d\u0001\u001d\u0001\u001d\u0004\u001d\u0102"+
|
||||
"\b\u001d\u000b\u001d\f\u001d\u0103\u0001\u001d\u0001\u001d\u0003\u001d"+
|
||||
"\u0108\b\u001d\u0001\u001d\u0004\u001d\u010b\b\u001d\u000b\u001d\f\u001d"+
|
||||
"\u010c\u0003\u001d\u010f\b\u001d\u0003\u001d\u0111\b\u001d\u0001\u001e"+
|
||||
"\u0001\u001e\u0001\u001e\u0001\u001e\u0005\u001e\u0117\b\u001e\n\u001e"+
|
||||
"\f\u001e\u011a\t\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e"+
|
||||
"\u0001\u001e\u0005\u001e\u0121\b\u001e\n\u001e\f\u001e\u0124\t\u001e\u0001"+
|
||||
"\u001e\u0003\u001e\u0127\b\u001e\u0001\u001f\u0001\u001f\u0005\u001f\u012b"+
|
||||
"\b\u001f\n\u001f\f\u001f\u012e\t\u001f\u0001 \u0001 \u0001 \u0001!\u0001"+
|
||||
"!\u0001!\u0001!\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0005\"\u013c"+
|
||||
"\b\"\n\"\f\"\u013f\t\"\u0001#\u0004#\u0142\b#\u000b#\f#\u0143\u0001#\u0001"+
|
||||
"#\u0001$\u0001$\u0001%\u0004%\u014b\b%\u000b%\f%\u014c\u0000\u0000&\u0001"+
|
||||
"\u0001\u0003\u0002\u0005\u0003\u0007\u0004\t\u0005\u000b\u0006\r\u0007"+
|
||||
"\u000f\b\u0011\t\u0013\n\u0015\u000b\u0017\f\u0019\r\u001b\u000e\u001d"+
|
||||
"\u000f\u001f\u0010!\u0011#\u0012%\u0013\'\u0014)\u0015+\u0016-\u0017/"+
|
||||
"\u00181\u00193\u001a5\u001b7\u001c9\u0000;\u001d=\u001e?\u0000A\u0000"+
|
||||
"C\u0000E\u001fG I\u0000K!\u0001\u0000\u001e\u0002\u0000LLll\u0002\u0000"+
|
||||
"IIii\u0002\u0000KKkk\u0002\u0000EEee\u0002\u0000NNnn\u0002\u0000OOoo\u0002"+
|
||||
"\u0000TTtt\u0002\u0000\t\t \u0002\u0000BBbb\u0002\u0000WWww\u0002\u0000"+
|
||||
"XXxx\u0002\u0000SSss\u0002\u0000RRrr\u0002\u0000GGgg\u0002\u0000PPpp\u0002"+
|
||||
"\u0000CCcc\u0002\u0000AAaa\u0002\u0000DDdd\u0002\u0000HHhh\u0002\u0000"+
|
||||
"YYyy\u0002\u0000UUuu\u0002\u0000FFff\u0002\u0000++--\u0002\u0000\"\"\\"+
|
||||
"\\\u0002\u0000\'\'\\\\\u0003\u0000$$AZaz\u0006\u0000$$--0:AZ__az\u0003"+
|
||||
"\u0000\t\n\r\r \u0001\u000009\b\u0000\t\n\r\r \"\'),,<>[[]]\u0166\u0000"+
|
||||
"\u0001\u0001\u0000\u0000\u0000\u0000\u0003\u0001\u0000\u0000\u0000\u0000"+
|
||||
"\u0005\u0001\u0000\u0000\u0000\u0000\u0007\u0001\u0000\u0000\u0000\u0000"+
|
||||
"\t\u0001\u0000\u0000\u0000\u0000\u000b\u0001\u0000\u0000\u0000\u0000\r"+
|
||||
"\u0001\u0000\u0000\u0000\u0000\u000f\u0001\u0000\u0000\u0000\u0000\u0011"+
|
||||
"\u0001\u0000\u0000\u0000\u0000\u0013\u0001\u0000\u0000\u0000\u0000\u0015"+
|
||||
"\u0001\u0000\u0000\u0000\u0000\u0017\u0001\u0000\u0000\u0000\u0000\u0019"+
|
||||
"\u0001\u0000\u0000\u0000\u0000\u001b\u0001\u0000\u0000\u0000\u0000\u001d"+
|
||||
"\u0001\u0000\u0000\u0000\u0000\u001f\u0001\u0000\u0000\u0000\u0000!\u0001"+
|
||||
"\u0000\u0000\u0000\u0000#\u0001\u0000\u0000\u0000\u0000%\u0001\u0000\u0000"+
|
||||
"\u0000\u0000\'\u0001\u0000\u0000\u0000\u0000)\u0001\u0000\u0000\u0000"+
|
||||
"\u0000+\u0001\u0000\u0000\u0000\u0000-\u0001\u0000\u0000\u0000\u0000/"+
|
||||
"\u0001\u0000\u0000\u0000\u00001\u0001\u0000\u0000\u0000\u00003\u0001\u0000"+
|
||||
"\u0000\u0000\u00005\u0001\u0000\u0000\u0000\u00007\u0001\u0000\u0000\u0000"+
|
||||
"\u0000;\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000\u0000\u0000E"+
|
||||
"\u0001\u0000\u0000\u0000\u0000G\u0001\u0000\u0000\u0000\u0000K\u0001\u0000"+
|
||||
"\u0000\u0000\u0001M\u0001\u0000\u0000\u0000\u0003O\u0001\u0000\u0000\u0000"+
|
||||
"\u0005Q\u0001\u0000\u0000\u0000\u0007S\u0001\u0000\u0000\u0000\tU\u0001"+
|
||||
"\u0000\u0000\u0000\u000bZ\u0001\u0000\u0000\u0000\r\\\u0001\u0000\u0000"+
|
||||
"\u0000\u000f_\u0001\u0000\u0000\u0000\u0011b\u0001\u0000\u0000\u0000\u0013"+
|
||||
"d\u0001\u0000\u0000\u0000\u0015g\u0001\u0000\u0000\u0000\u0017i\u0001"+
|
||||
"\u0000\u0000\u0000\u0019l\u0001\u0000\u0000\u0000\u001bq\u0001\u0000\u0000"+
|
||||
"\u0000\u001d~\u0001\u0000\u0000\u0000\u001f\u0084\u0001\u0000\u0000\u0000"+
|
||||
"!\u0092\u0001\u0000\u0000\u0000#\u009a\u0001\u0000\u0000\u0000%\u00a2"+
|
||||
"\u0001\u0000\u0000\u0000\'\u00a9\u0001\u0000\u0000\u0000)\u00b3\u0001"+
|
||||
"\u0000\u0000\u0000+\u00b6\u0001\u0000\u0000\u0000-\u00ba\u0001\u0000\u0000"+
|
||||
"\u0000/\u00be\u0001\u0000\u0000\u00001\u00c1\u0001\u0000\u0000\u00003"+
|
||||
"\u00c5\u0001\u0000\u0000\u00005\u00cc\u0001\u0000\u0000\u00007\u00dc\u0001"+
|
||||
"\u0000\u0000\u00009\u00de\u0001\u0000\u0000\u0000;\u0110\u0001\u0000\u0000"+
|
||||
"\u0000=\u0126\u0001\u0000\u0000\u0000?\u0128\u0001\u0000\u0000\u0000A"+
|
||||
"\u012f\u0001\u0000\u0000\u0000C\u0132\u0001\u0000\u0000\u0000E\u0136\u0001"+
|
||||
"\u0000\u0000\u0000G\u0141\u0001\u0000\u0000\u0000I\u0147\u0001\u0000\u0000"+
|
||||
"\u0000K\u014a\u0001\u0000\u0000\u0000MN\u0005(\u0000\u0000N\u0002\u0001"+
|
||||
"\u0000\u0000\u0000OP\u0005)\u0000\u0000P\u0004\u0001\u0000\u0000\u0000"+
|
||||
"QR\u0005[\u0000\u0000R\u0006\u0001\u0000\u0000\u0000ST\u0005]\u0000\u0000"+
|
||||
"T\b\u0001\u0000\u0000\u0000UV\u0005,\u0000\u0000V\n\u0001\u0000\u0000"+
|
||||
"\u0000W[\u0005=\u0000\u0000XY\u0005=\u0000\u0000Y[\u0005=\u0000\u0000"+
|
||||
"ZW\u0001\u0000\u0000\u0000ZX\u0001\u0000\u0000\u0000[\f\u0001\u0000\u0000"+
|
||||
"\u0000\\]\u0005!\u0000\u0000]^\u0005=\u0000\u0000^\u000e\u0001\u0000\u0000"+
|
||||
"\u0000_`\u0005<\u0000\u0000`a\u0005>\u0000\u0000a\u0010\u0001\u0000\u0000"+
|
||||
"\u0000bc\u0005<\u0000\u0000c\u0012\u0001\u0000\u0000\u0000de\u0005<\u0000"+
|
||||
"\u0000ef\u0005=\u0000\u0000f\u0014\u0001\u0000\u0000\u0000gh\u0005>\u0000"+
|
||||
"\u0000h\u0016\u0001\u0000\u0000\u0000ij\u0005>\u0000\u0000jk\u0005=\u0000"+
|
||||
"\u0000k\u0018\u0001\u0000\u0000\u0000lm\u0007\u0000\u0000\u0000mn\u0007"+
|
||||
"\u0001\u0000\u0000no\u0007\u0002\u0000\u0000op\u0007\u0003\u0000\u0000"+
|
||||
"p\u001a\u0001\u0000\u0000\u0000qr\u0007\u0004\u0000\u0000rs\u0007\u0005"+
|
||||
"\u0000\u0000su\u0007\u0006\u0000\u0000tv\u0007\u0007\u0000\u0000ut\u0001"+
|
||||
"\u0000\u0000\u0000vw\u0001\u0000\u0000\u0000wu\u0001\u0000\u0000\u0000"+
|
||||
"wx\u0001\u0000\u0000\u0000xy\u0001\u0000\u0000\u0000yz\u0007\u0000\u0000"+
|
||||
"\u0000z{\u0007\u0001\u0000\u0000{|\u0007\u0002\u0000\u0000|}\u0007\u0003"+
|
||||
"\u0000\u0000}\u001c\u0001\u0000\u0000\u0000~\u007f\u0007\u0001\u0000\u0000"+
|
||||
"\u007f\u0080\u0007\u0000\u0000\u0000\u0080\u0081\u0007\u0001\u0000\u0000"+
|
||||
"\u0081\u0082\u0007\u0002\u0000\u0000\u0082\u0083\u0007\u0003\u0000\u0000"+
|
||||
"\u0083\u001e\u0001\u0000\u0000\u0000\u0084\u0085\u0007\u0004\u0000\u0000"+
|
||||
"\u0085\u0086\u0007\u0005\u0000\u0000\u0086\u0088\u0007\u0006\u0000\u0000"+
|
||||
"\u0087\u0089\u0007\u0007\u0000\u0000\u0088\u0087\u0001\u0000\u0000\u0000"+
|
||||
"\u0089\u008a\u0001\u0000\u0000\u0000\u008a\u0088\u0001\u0000\u0000\u0000"+
|
||||
"\u008a\u008b\u0001\u0000\u0000\u0000\u008b\u008c\u0001\u0000\u0000\u0000"+
|
||||
"\u008c\u008d\u0007\u0001\u0000\u0000\u008d\u008e\u0007\u0000\u0000\u0000"+
|
||||
"\u008e\u008f\u0007\u0001\u0000\u0000\u008f\u0090\u0007\u0002\u0000\u0000"+
|
||||
"\u0090\u0091\u0007\u0003\u0000\u0000\u0091 \u0001\u0000\u0000\u0000\u0092"+
|
||||
"\u0093\u0007\b\u0000\u0000\u0093\u0094\u0007\u0003\u0000\u0000\u0094\u0095"+
|
||||
"\u0007\u0006\u0000\u0000\u0095\u0096\u0007\t\u0000\u0000\u0096\u0097\u0007"+
|
||||
"\u0003\u0000\u0000\u0097\u0098\u0007\u0003\u0000\u0000\u0098\u0099\u0007"+
|
||||
"\u0004\u0000\u0000\u0099\"\u0001\u0000\u0000\u0000\u009a\u009b\u0007\u0003"+
|
||||
"\u0000\u0000\u009b\u009c\u0007\n\u0000\u0000\u009c\u009d\u0007\u0001\u0000"+
|
||||
"\u0000\u009d\u009e\u0007\u000b\u0000\u0000\u009e\u00a0\u0007\u0006\u0000"+
|
||||
"\u0000\u009f\u00a1\u0007\u000b\u0000\u0000\u00a0\u009f\u0001\u0000\u0000"+
|
||||
"\u0000\u00a0\u00a1\u0001\u0000\u0000\u0000\u00a1$\u0001\u0000\u0000\u0000"+
|
||||
"\u00a2\u00a3\u0007\f\u0000\u0000\u00a3\u00a4\u0007\u0003\u0000\u0000\u00a4"+
|
||||
"\u00a5\u0007\r\u0000\u0000\u00a5\u00a6\u0007\u0003\u0000\u0000\u00a6\u00a7"+
|
||||
"\u0007\n\u0000\u0000\u00a7\u00a8\u0007\u000e\u0000\u0000\u00a8&\u0001"+
|
||||
"\u0000\u0000\u0000\u00a9\u00aa\u0007\u000f\u0000\u0000\u00aa\u00ab\u0007"+
|
||||
"\u0005\u0000\u0000\u00ab\u00ac\u0007\u0004\u0000\u0000\u00ac\u00ad\u0007"+
|
||||
"\u0006\u0000\u0000\u00ad\u00ae\u0007\u0010\u0000\u0000\u00ae\u00af\u0007"+
|
||||
"\u0001\u0000\u0000\u00af\u00b1\u0007\u0004\u0000\u0000\u00b0\u00b2\u0007"+
|
||||
"\u000b\u0000\u0000\u00b1\u00b0\u0001\u0000\u0000\u0000\u00b1\u00b2\u0001"+
|
||||
"\u0000\u0000\u0000\u00b2(\u0001\u0000\u0000\u0000\u00b3\u00b4\u0007\u0001"+
|
||||
"\u0000\u0000\u00b4\u00b5\u0007\u0004\u0000\u0000\u00b5*\u0001\u0000\u0000"+
|
||||
"\u0000\u00b6\u00b7\u0007\u0004\u0000\u0000\u00b7\u00b8\u0007\u0005\u0000"+
|
||||
"\u0000\u00b8\u00b9\u0007\u0006\u0000\u0000\u00b9,\u0001\u0000\u0000\u0000"+
|
||||
"\u00ba\u00bb\u0007\u0010\u0000\u0000\u00bb\u00bc\u0007\u0004\u0000\u0000"+
|
||||
"\u00bc\u00bd\u0007\u0011\u0000\u0000\u00bd.\u0001\u0000\u0000\u0000\u00be"+
|
||||
"\u00bf\u0007\u0005\u0000\u0000\u00bf\u00c0\u0007\f\u0000\u0000\u00c00"+
|
||||
"\u0001\u0000\u0000\u0000\u00c1\u00c2\u0007\u0012\u0000\u0000\u00c2\u00c3"+
|
||||
"\u0007\u0010\u0000\u0000\u00c3\u00c4\u0007\u000b\u0000\u0000\u00c42\u0001"+
|
||||
"\u0000\u0000\u0000\u00c5\u00c6\u0007\u0012\u0000\u0000\u00c6\u00c7\u0007"+
|
||||
"\u0010\u0000\u0000\u00c7\u00c8\u0007\u000b\u0000\u0000\u00c8\u00c9\u0007"+
|
||||
"\u0010\u0000\u0000\u00c9\u00ca\u0007\u0004\u0000\u0000\u00ca\u00cb\u0007"+
|
||||
"\u0013\u0000\u0000\u00cb4\u0001\u0000\u0000\u0000\u00cc\u00cd\u0007\u0012"+
|
||||
"\u0000\u0000\u00cd\u00ce\u0007\u0010\u0000\u0000\u00ce\u00cf\u0007\u000b"+
|
||||
"\u0000\u0000\u00cf\u00d0\u0007\u0010\u0000\u0000\u00d0\u00d1\u0007\u0000"+
|
||||
"\u0000\u0000\u00d1\u00d2\u0007\u0000\u0000\u0000\u00d26\u0001\u0000\u0000"+
|
||||
"\u0000\u00d3\u00d4\u0007\u0006\u0000\u0000\u00d4\u00d5\u0007\f\u0000\u0000"+
|
||||
"\u00d5\u00d6\u0007\u0014\u0000\u0000\u00d6\u00dd\u0007\u0003\u0000\u0000"+
|
||||
"\u00d7\u00d8\u0007\u0015\u0000\u0000\u00d8\u00d9\u0007\u0010\u0000\u0000"+
|
||||
"\u00d9\u00da\u0007\u0000\u0000\u0000\u00da\u00db\u0007\u000b\u0000\u0000"+
|
||||
"\u00db\u00dd\u0007\u0003\u0000\u0000\u00dc\u00d3\u0001\u0000\u0000\u0000"+
|
||||
"\u00dc\u00d7\u0001\u0000\u0000\u0000\u00dd8\u0001\u0000\u0000\u0000\u00de"+
|
||||
"\u00df\u0007\u0016\u0000\u0000\u00df:\u0001\u0000\u0000\u0000\u00e0\u00e2"+
|
||||
"\u00039\u001c\u0000\u00e1\u00e0\u0001\u0000\u0000\u0000\u00e1\u00e2\u0001"+
|
||||
"\u0000\u0000\u0000\u00e2\u00e4\u0001\u0000\u0000\u0000\u00e3\u00e5\u0003"+
|
||||
"I$\u0000\u00e4\u00e3\u0001\u0000\u0000\u0000\u00e5\u00e6\u0001\u0000\u0000"+
|
||||
"\u0000\u00e6\u00e4\u0001\u0000\u0000\u0000\u00e6\u00e7\u0001\u0000\u0000"+
|
||||
"\u0000\u00e7\u00ef\u0001\u0000\u0000\u0000\u00e8\u00ec\u0005.\u0000\u0000"+
|
||||
"\u00e9\u00eb\u0003I$\u0000\u00ea\u00e9\u0001\u0000\u0000\u0000\u00eb\u00ee"+
|
||||
"\u0001\u0000\u0000\u0000\u00ec\u00ea\u0001\u0000\u0000\u0000\u00ec\u00ed"+
|
||||
"\u0001\u0000\u0000\u0000\u00ed\u00f0\u0001\u0000\u0000\u0000\u00ee\u00ec"+
|
||||
"\u0001\u0000\u0000\u0000\u00ef\u00e8\u0001\u0000\u0000\u0000\u00ef\u00f0"+
|
||||
"\u0001\u0000\u0000\u0000\u00f0\u00fa\u0001\u0000\u0000\u0000\u00f1\u00f3"+
|
||||
"\u0007\u0003\u0000\u0000\u00f2\u00f4\u00039\u001c\u0000\u00f3\u00f2\u0001"+
|
||||
"\u0000\u0000\u0000\u00f3\u00f4\u0001\u0000\u0000\u0000\u00f4\u00f6\u0001"+
|
||||
"\u0000\u0000\u0000\u00f5\u00f7\u0003I$\u0000\u00f6\u00f5\u0001\u0000\u0000"+
|
||||
"\u0000\u00f7\u00f8\u0001\u0000\u0000\u0000\u00f8\u00f6\u0001\u0000\u0000"+
|
||||
"\u0000\u00f8\u00f9\u0001\u0000\u0000\u0000\u00f9\u00fb\u0001\u0000\u0000"+
|
||||
"\u0000\u00fa\u00f1\u0001\u0000\u0000\u0000\u00fa\u00fb\u0001\u0000\u0000"+
|
||||
"\u0000\u00fb\u0111\u0001\u0000\u0000\u0000\u00fc\u00fe\u00039\u001c\u0000"+
|
||||
"\u00fd\u00fc\u0001\u0000\u0000\u0000\u00fd\u00fe\u0001\u0000\u0000\u0000"+
|
||||
"\u00fe\u00ff\u0001\u0000\u0000\u0000\u00ff\u0101\u0005.\u0000\u0000\u0100"+
|
||||
"\u0102\u0003I$\u0000\u0101\u0100\u0001\u0000\u0000\u0000\u0102\u0103\u0001"+
|
||||
"\u0000\u0000\u0000\u0103\u0101\u0001\u0000\u0000\u0000\u0103\u0104\u0001"+
|
||||
"\u0000\u0000\u0000\u0104\u010e\u0001\u0000\u0000\u0000\u0105\u0107\u0007"+
|
||||
"\u0003\u0000\u0000\u0106\u0108\u00039\u001c\u0000\u0107\u0106\u0001\u0000"+
|
||||
"\u0000\u0000\u0107\u0108\u0001\u0000\u0000\u0000\u0108\u010a\u0001\u0000"+
|
||||
"\u0000\u0000\u0109\u010b\u0003I$\u0000\u010a\u0109\u0001\u0000\u0000\u0000"+
|
||||
"\u010b\u010c\u0001\u0000\u0000\u0000\u010c\u010a\u0001\u0000\u0000\u0000"+
|
||||
"\u010c\u010d\u0001\u0000\u0000\u0000\u010d\u010f\u0001\u0000\u0000\u0000"+
|
||||
"\u010e\u0105\u0001\u0000\u0000\u0000\u010e\u010f\u0001\u0000\u0000\u0000"+
|
||||
"\u010f\u0111\u0001\u0000\u0000\u0000\u0110\u00e1\u0001\u0000\u0000\u0000"+
|
||||
"\u0110\u00fd\u0001\u0000\u0000\u0000\u0111<\u0001\u0000\u0000\u0000\u0112"+
|
||||
"\u0118\u0005\"\u0000\u0000\u0113\u0117\b\u0017\u0000\u0000\u0114\u0115"+
|
||||
"\u0005\\\u0000\u0000\u0115\u0117\t\u0000\u0000\u0000\u0116\u0113\u0001"+
|
||||
"\u0000\u0000\u0000\u0116\u0114\u0001\u0000\u0000\u0000\u0117\u011a\u0001"+
|
||||
"\u0000\u0000\u0000\u0118\u0116\u0001\u0000\u0000\u0000\u0118\u0119\u0001"+
|
||||
"\u0000\u0000\u0000\u0119\u011b\u0001\u0000\u0000\u0000\u011a\u0118\u0001"+
|
||||
"\u0000\u0000\u0000\u011b\u0127\u0005\"\u0000\u0000\u011c\u0122\u0005\'"+
|
||||
"\u0000\u0000\u011d\u0121\b\u0018\u0000\u0000\u011e\u011f\u0005\\\u0000"+
|
||||
"\u0000\u011f\u0121\t\u0000\u0000\u0000\u0120\u011d\u0001\u0000\u0000\u0000"+
|
||||
"\u0120\u011e\u0001\u0000\u0000\u0000\u0121\u0124\u0001\u0000\u0000\u0000"+
|
||||
"\u0122\u0120\u0001\u0000\u0000\u0000\u0122\u0123\u0001\u0000\u0000\u0000"+
|
||||
"\u0123\u0125\u0001\u0000\u0000\u0000\u0124\u0122\u0001\u0000\u0000\u0000"+
|
||||
"\u0125\u0127\u0005\'\u0000\u0000\u0126\u0112\u0001\u0000\u0000\u0000\u0126"+
|
||||
"\u011c\u0001\u0000\u0000\u0000\u0127>\u0001\u0000\u0000\u0000\u0128\u012c"+
|
||||
"\u0007\u0019\u0000\u0000\u0129\u012b\u0007\u001a\u0000\u0000\u012a\u0129"+
|
||||
"\u0001\u0000\u0000\u0000\u012b\u012e\u0001\u0000\u0000\u0000\u012c\u012a"+
|
||||
"\u0001\u0000\u0000\u0000\u012c\u012d\u0001\u0000\u0000\u0000\u012d@\u0001"+
|
||||
"\u0000\u0000\u0000\u012e\u012c\u0001\u0000\u0000\u0000\u012f\u0130\u0005"+
|
||||
"[\u0000\u0000\u0130\u0131\u0005]\u0000\u0000\u0131B\u0001\u0000\u0000"+
|
||||
"\u0000\u0132\u0133\u0005[\u0000\u0000\u0133\u0134\u0005*\u0000\u0000\u0134"+
|
||||
"\u0135\u0005]\u0000\u0000\u0135D\u0001\u0000\u0000\u0000\u0136\u013d\u0003"+
|
||||
"?\u001f\u0000\u0137\u0138\u0005.\u0000\u0000\u0138\u013c\u0003?\u001f"+
|
||||
"\u0000\u0139\u013c\u0003A \u0000\u013a\u013c\u0003C!\u0000\u013b\u0137"+
|
||||
"\u0001\u0000\u0000\u0000\u013b\u0139\u0001\u0000\u0000\u0000\u013b\u013a"+
|
||||
"\u0001\u0000\u0000\u0000\u013c\u013f\u0001\u0000\u0000\u0000\u013d\u013b"+
|
||||
"\u0001\u0000\u0000\u0000\u013d\u013e\u0001\u0000\u0000\u0000\u013eF\u0001"+
|
||||
"\u0000\u0000\u0000\u013f\u013d\u0001\u0000\u0000\u0000\u0140\u0142\u0007"+
|
||||
"\u001b\u0000\u0000\u0141\u0140\u0001\u0000\u0000\u0000\u0142\u0143\u0001"+
|
||||
"\u0000\u0000\u0000\u0143\u0141\u0001\u0000\u0000\u0000\u0143\u0144\u0001"+
|
||||
"\u0000\u0000\u0000\u0144\u0145\u0001\u0000\u0000\u0000\u0145\u0146\u0006"+
|
||||
"#\u0000\u0000\u0146H\u0001\u0000\u0000\u0000\u0147\u0148\u0007\u001c\u0000"+
|
||||
"\u0000\u0148J\u0001\u0000\u0000\u0000\u0149\u014b\b\u001d\u0000\u0000"+
|
||||
"\u014a\u0149\u0001\u0000\u0000\u0000\u014b\u014c\u0001\u0000\u0000\u0000"+
|
||||
"\u014c\u014a\u0001\u0000\u0000\u0000\u014c\u014d\u0001\u0000\u0000\u0000"+
|
||||
"\u014dL\u0001\u0000\u0000\u0000\u001e\u0000Zw\u008a\u00a0\u00b1\u00dc"+
|
||||
"\u00e1\u00e6\u00ec\u00ef\u00f3\u00f8\u00fa\u00fd\u0103\u0107\u010c\u010e"+
|
||||
"\u0110\u0116\u0118\u0120\u0122\u0126\u012c\u013b\u013d\u0143\u014c\u0001"+
|
||||
"\u0006\u0000\u0000";
|
||||
public static final ATN _ATN =
|
||||
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
|
||||
static {
|
||||
_decisionToDFA = new DFA[_ATN.getNumberOfDecisions()];
|
||||
for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) {
|
||||
_decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
LPAREN=1
|
||||
RPAREN=2
|
||||
LBRACK=3
|
||||
RBRACK=4
|
||||
COMMA=5
|
||||
EQUALS=6
|
||||
NOT_EQUALS=7
|
||||
NEQ=8
|
||||
LT=9
|
||||
LE=10
|
||||
GT=11
|
||||
GE=12
|
||||
LIKE=13
|
||||
NOT_LIKE=14
|
||||
ILIKE=15
|
||||
NOT_ILIKE=16
|
||||
BETWEEN=17
|
||||
EXISTS=18
|
||||
REGEXP=19
|
||||
CONTAINS=20
|
||||
IN=21
|
||||
NOT=22
|
||||
AND=23
|
||||
OR=24
|
||||
HAS=25
|
||||
HASANY=26
|
||||
HASALL=27
|
||||
BOOL=28
|
||||
NUMBER=29
|
||||
QUOTED_TEXT=30
|
||||
KEY=31
|
||||
WS=32
|
||||
FREETEXT=33
|
||||
'('=1
|
||||
')'=2
|
||||
'['=3
|
||||
']'=4
|
||||
','=5
|
||||
'!='=7
|
||||
'<>'=8
|
||||
'<'=9
|
||||
'<='=10
|
||||
'>'=11
|
||||
'>='=12
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user