2025-04-27 16:29:35 +05:30
|
|
|
/* eslint-disable import/no-extraneous-dependencies */
|
2025-04-27 12:37:02 +05:30
|
|
|
/* eslint-disable no-nested-ternary */
|
|
|
|
|
|
|
|
|
|
import './CodeMirrorWhereClause.styles.scss';
|
|
|
|
|
|
2025-04-27 15:34:55 +05:30
|
|
|
import {
|
|
|
|
|
CheckCircleFilled,
|
|
|
|
|
CloseCircleFilled,
|
|
|
|
|
InfoCircleOutlined,
|
|
|
|
|
QuestionCircleOutlined,
|
|
|
|
|
} from '@ant-design/icons';
|
2025-04-27 16:29:35 +05:30
|
|
|
import {
|
|
|
|
|
autocompletion,
|
|
|
|
|
CompletionContext,
|
|
|
|
|
CompletionResult,
|
|
|
|
|
} from '@codemirror/autocomplete';
|
2025-04-27 20:06:04 +05:30
|
|
|
import { javascript } from '@codemirror/lang-javascript';
|
|
|
|
|
import { copilot } from '@uiw/codemirror-theme-copilot';
|
2025-04-27 19:34:07 +05:30
|
|
|
import CodeMirror, { EditorView, Extension } from '@uiw/react-codemirror';
|
2025-04-27 15:34:55 +05:30
|
|
|
import { Badge, Card, Divider, Space, Tooltip, Typography } from 'antd';
|
2025-04-27 18:23:53 +05:30
|
|
|
import { useGetQueryKeySuggestions } from 'hooks/querySuggestions/useGetQueryKeySuggestions';
|
|
|
|
|
// import { useGetQueryKeyValueSuggestions } from 'hooks/querySuggestions/useGetQueryKeyValueSuggestions';
|
2025-04-27 12:37:02 +05:30
|
|
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
|
|
import { IQueryContext, IValidationResult } from 'types/antlrQueryTypes';
|
2025-04-27 18:23:53 +05:30
|
|
|
import { QueryKeySuggestionsProps } from 'types/api/querySuggestions/types';
|
2025-04-27 19:34:07 +05:30
|
|
|
import {
|
|
|
|
|
getQueryContextAtCursor,
|
|
|
|
|
queryOperatorSuggestions,
|
|
|
|
|
validateQuery,
|
|
|
|
|
} from 'utils/antlrQueryUtils';
|
2025-04-27 12:37:02 +05:30
|
|
|
|
2025-04-27 15:34:55 +05:30
|
|
|
const { Text, Title } = Typography;
|
2025-04-27 12:37:02 +05:30
|
|
|
|
2025-04-27 19:34:07 +05:30
|
|
|
function collapseSpacesOutsideStrings(): Extension {
|
|
|
|
|
return EditorView.inputHandler.of((view, from, to, text) => {
|
|
|
|
|
// Get the current line text
|
|
|
|
|
const { state } = view;
|
|
|
|
|
const line = state.doc.lineAt(from);
|
|
|
|
|
|
|
|
|
|
// Find the position within the line
|
|
|
|
|
const before = line.text.slice(0, from - line.from);
|
|
|
|
|
const after = line.text.slice(to - line.from);
|
|
|
|
|
|
|
|
|
|
const fullText = before + text + after;
|
|
|
|
|
|
|
|
|
|
let insideString = false;
|
|
|
|
|
let escaped = false;
|
|
|
|
|
let processed = '';
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < fullText.length; i++) {
|
|
|
|
|
const char = fullText[i];
|
|
|
|
|
|
|
|
|
|
if (char === '"' && !escaped) {
|
|
|
|
|
insideString = !insideString;
|
|
|
|
|
}
|
|
|
|
|
if (char === '\\' && !escaped) {
|
|
|
|
|
escaped = true;
|
|
|
|
|
} else {
|
|
|
|
|
escaped = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!insideString && char === ' ' && processed.endsWith(' ')) {
|
|
|
|
|
// Collapse multiple spaces outside strings
|
|
|
|
|
// Skip this space
|
|
|
|
|
} else {
|
|
|
|
|
processed += char;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only dispatch if the processed text differs
|
|
|
|
|
if (processed !== fullText) {
|
|
|
|
|
view.dispatch({
|
|
|
|
|
changes: {
|
|
|
|
|
from: line.from,
|
|
|
|
|
to: line.to,
|
|
|
|
|
insert: processed,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-27 12:37:02 +05:30
|
|
|
function CodeMirrorWhereClause(): JSX.Element {
|
|
|
|
|
const [query, setQuery] = useState<string>('');
|
|
|
|
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
|
|
|
const [queryContext, setQueryContext] = useState<IQueryContext | null>(null);
|
|
|
|
|
const [validation, setValidation] = useState<IValidationResult>({
|
|
|
|
|
isValid: false,
|
|
|
|
|
message: '',
|
|
|
|
|
errors: [],
|
|
|
|
|
});
|
|
|
|
|
|
2025-04-27 18:23:53 +05:30
|
|
|
const [keySuggestions, setKeySuggestions] = useState<
|
|
|
|
|
QueryKeySuggestionsProps[] | null
|
|
|
|
|
>(null);
|
|
|
|
|
|
2025-04-27 12:37:02 +05:30
|
|
|
const [cursorPos, setCursorPos] = useState({ line: 0, ch: 0 });
|
|
|
|
|
const lastPosRef = useRef<{ line: number; ch: number }>({ line: 0, ch: 0 });
|
|
|
|
|
|
2025-04-27 18:23:53 +05:30
|
|
|
const {
|
|
|
|
|
data: queryKeySuggestions,
|
|
|
|
|
// isLoading: queryKeySuggestionsLoading,
|
|
|
|
|
// isRefetching: queryKeySuggestionsRefetching,
|
|
|
|
|
// refetch: queryKeySuggestionsRefetch,
|
|
|
|
|
// error: queryKeySuggestionsError,
|
|
|
|
|
// isError: queryKeySuggestionsIsError,
|
|
|
|
|
} = useGetQueryKeySuggestions({ signal: 'traces' });
|
|
|
|
|
|
|
|
|
|
// const {
|
|
|
|
|
// data: queryKeyValuesSuggestions,
|
|
|
|
|
// isLoading: queryKeyValuesSuggestionsLoading,
|
|
|
|
|
// refetch: refetchQueryKeyValuesSuggestions,
|
|
|
|
|
// } = useGetQueryKeyValueSuggestions({
|
|
|
|
|
// key: 'status',
|
2025-04-27 20:37:42 +05:30
|
|
|
// signal: 'traces',
|
2025-04-27 18:23:53 +05:30
|
|
|
// });
|
|
|
|
|
|
2025-04-27 21:05:00 +05:30
|
|
|
console.log('loading', isLoading);
|
|
|
|
|
|
|
|
|
|
const generateOptions = (data: any): any[] =>
|
|
|
|
|
Object.values(data.keys).flatMap((items: any) =>
|
2025-04-27 18:23:53 +05:30
|
|
|
items.map(({ name, fieldDataType, fieldContext }: any) => ({
|
|
|
|
|
label: name,
|
|
|
|
|
type: fieldDataType === 'string' ? 'keyword' : fieldDataType,
|
|
|
|
|
info: fieldContext,
|
|
|
|
|
details: '',
|
|
|
|
|
})),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (queryKeySuggestions) {
|
|
|
|
|
const options = generateOptions(queryKeySuggestions.data.data);
|
|
|
|
|
|
|
|
|
|
setKeySuggestions(options);
|
|
|
|
|
}
|
|
|
|
|
}, [queryKeySuggestions]);
|
|
|
|
|
|
2025-04-27 12:37:02 +05:30
|
|
|
const handleUpdate = (viewUpdate: { view: EditorView }): void => {
|
|
|
|
|
const selection = viewUpdate.view.state.selection.main;
|
|
|
|
|
const pos = selection.head;
|
|
|
|
|
|
|
|
|
|
const lineInfo = viewUpdate.view.state.doc.lineAt(pos);
|
|
|
|
|
const newPos = {
|
|
|
|
|
line: lineInfo.number,
|
|
|
|
|
ch: pos - lineInfo.from,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const lastPos = lastPosRef.current;
|
|
|
|
|
|
|
|
|
|
// Only update if cursor position actually changed
|
|
|
|
|
if (newPos.line !== lastPos.line || newPos.ch !== lastPos.ch) {
|
|
|
|
|
setCursorPos(newPos);
|
|
|
|
|
lastPosRef.current = newPos;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleQueryChange = useCallback(async (newQuery: string) => {
|
|
|
|
|
setIsLoading(true);
|
|
|
|
|
setQuery(newQuery);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const validationResponse = validateQuery(newQuery);
|
|
|
|
|
setValidation(validationResponse);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
setValidation({
|
|
|
|
|
isValid: false,
|
|
|
|
|
message: 'Failed to process query',
|
|
|
|
|
errors: [error instanceof Error ? error.message : 'Unknown error'],
|
|
|
|
|
});
|
|
|
|
|
} finally {
|
|
|
|
|
setIsLoading(false);
|
|
|
|
|
}
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (query) {
|
|
|
|
|
const context = getQueryContextAtCursor(query, cursorPos.ch);
|
|
|
|
|
setQueryContext(context as IQueryContext);
|
|
|
|
|
}
|
|
|
|
|
}, [query, cursorPos]);
|
|
|
|
|
|
|
|
|
|
const handleChange = (value: string): void => {
|
|
|
|
|
setQuery(value);
|
|
|
|
|
handleQueryChange(value);
|
|
|
|
|
};
|
|
|
|
|
|
2025-04-27 15:34:55 +05:30
|
|
|
const renderContextBadge = (): JSX.Element | null => {
|
|
|
|
|
if (!queryContext) return null;
|
|
|
|
|
|
|
|
|
|
let color = 'black';
|
|
|
|
|
let text = 'Unknown';
|
|
|
|
|
|
|
|
|
|
if (queryContext.isInKey) {
|
|
|
|
|
color = 'blue';
|
|
|
|
|
text = 'Key';
|
|
|
|
|
} else if (queryContext.isInOperator) {
|
|
|
|
|
color = 'purple';
|
|
|
|
|
text = 'Operator';
|
|
|
|
|
} else if (queryContext.isInValue) {
|
|
|
|
|
color = 'green';
|
|
|
|
|
text = 'Value';
|
|
|
|
|
} else if (queryContext.isInFunction) {
|
|
|
|
|
color = 'orange';
|
|
|
|
|
text = 'Function';
|
|
|
|
|
} else if (queryContext.isInConjunction) {
|
|
|
|
|
color = 'magenta';
|
|
|
|
|
text = 'Conjunction';
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-27 19:34:07 +05:30
|
|
|
// else if (queryContext.isInParenthesis) {
|
|
|
|
|
// color = 'grey';
|
|
|
|
|
// text = 'Parenthesis';
|
|
|
|
|
// }
|
|
|
|
|
|
2025-04-27 15:34:55 +05:30
|
|
|
return (
|
|
|
|
|
<Badge
|
|
|
|
|
color={color}
|
|
|
|
|
text={text}
|
|
|
|
|
style={{
|
|
|
|
|
color: 'black',
|
|
|
|
|
}}
|
2025-04-27 12:37:02 +05:30
|
|
|
/>
|
2025-04-27 15:34:55 +05:30
|
|
|
);
|
|
|
|
|
};
|
2025-04-27 12:37:02 +05:30
|
|
|
|
2025-04-27 16:29:35 +05:30
|
|
|
function myCompletions(context: CompletionContext): CompletionResult | null {
|
|
|
|
|
const word = context.matchBefore(/\w*/);
|
|
|
|
|
if (word?.from === word?.to && !context.explicit) return null;
|
2025-04-27 17:01:19 +05:30
|
|
|
|
|
|
|
|
// Get the query context at the cursor position
|
|
|
|
|
const queryContext = getQueryContextAtCursor(query, cursorPos.ch);
|
|
|
|
|
|
|
|
|
|
// Define autocomplete options based on the context
|
|
|
|
|
let options: {
|
|
|
|
|
label: string;
|
|
|
|
|
type: string;
|
|
|
|
|
info?: string;
|
|
|
|
|
apply?: string;
|
|
|
|
|
detail?: string;
|
|
|
|
|
}[] = [];
|
|
|
|
|
|
|
|
|
|
if (queryContext.isInKey) {
|
2025-04-27 18:23:53 +05:30
|
|
|
options = keySuggestions || [];
|
2025-04-27 17:01:19 +05:30
|
|
|
} else if (queryContext.isInOperator) {
|
2025-04-27 19:34:07 +05:30
|
|
|
options = queryOperatorSuggestions;
|
2025-04-27 17:01:19 +05:30
|
|
|
} else if (queryContext.isInValue) {
|
2025-04-27 21:05:00 +05:30
|
|
|
console.log('is In Value', queryContext.currentToken);
|
2025-04-27 18:23:53 +05:30
|
|
|
// refetchQueryKeyValuesSuggestions();
|
|
|
|
|
|
2025-04-27 21:05:00 +05:30
|
|
|
// Fetch values based on the key - use the keyToken if available
|
|
|
|
|
const key = queryContext.keyToken || queryContext.currentToken;
|
2025-04-27 18:23:53 +05:30
|
|
|
|
2025-04-27 21:05:00 +05:30
|
|
|
console.log('key', key);
|
|
|
|
|
|
|
|
|
|
// const response = refetchQueryKeyValuesSuggestions({
|
|
|
|
|
// key: 'status',
|
|
|
|
|
// signal: 'traces',
|
|
|
|
|
// });
|
2025-04-27 18:23:53 +05:30
|
|
|
|
2025-04-27 17:01:19 +05:30
|
|
|
options = [
|
|
|
|
|
{ label: 'error', type: 'value' },
|
|
|
|
|
{ label: 'frontend', type: 'value' },
|
|
|
|
|
// Add more value options here
|
|
|
|
|
];
|
|
|
|
|
} else if (queryContext.isInFunction) {
|
|
|
|
|
options = [
|
|
|
|
|
{ label: 'HAS', type: 'function' },
|
|
|
|
|
{ label: 'HASANY', type: 'function' },
|
|
|
|
|
// Add more function options here
|
|
|
|
|
];
|
|
|
|
|
} else if (queryContext.isInConjunction) {
|
|
|
|
|
options = [
|
|
|
|
|
{ label: 'AND', type: 'conjunction' },
|
|
|
|
|
{ label: 'OR', type: 'conjunction' },
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-27 16:29:35 +05:30
|
|
|
return {
|
|
|
|
|
from: word?.from ?? 0,
|
2025-04-27 17:01:19 +05:30
|
|
|
options,
|
2025-04-27 16:29:35 +05:30
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-27 20:37:42 +05:30
|
|
|
const customTheme = EditorView.theme({
|
|
|
|
|
'&': {
|
|
|
|
|
fontFamily: '"Space Mono", monospace', // Change to any font
|
|
|
|
|
fontSize: '13px', // Set font size
|
|
|
|
|
lineHeight: '1.8', // Set line height
|
|
|
|
|
margin: '8px 0px',
|
|
|
|
|
},
|
|
|
|
|
'.cm-line': {
|
|
|
|
|
lineHeight: '2.2', // Set line height
|
|
|
|
|
},
|
|
|
|
|
'.cm-gutters': {
|
|
|
|
|
lineHeight: '1.8', // Set line height
|
|
|
|
|
display: 'none',
|
|
|
|
|
},
|
|
|
|
|
'.cm-content': {
|
|
|
|
|
lineHeight: '2.2', // Set line height
|
|
|
|
|
borderRadius: '2px',
|
|
|
|
|
border: '1px solid var(--bg-ink-400) !important',
|
|
|
|
|
background: 'var(--bg-ink-400) !important',
|
|
|
|
|
padding: '0px',
|
|
|
|
|
},
|
|
|
|
|
'.cm-focused': {
|
|
|
|
|
border: '1px solid var(--bg-robin-500) !important',
|
|
|
|
|
background: 'var(--bg-ink-400) !important',
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2025-04-27 15:34:55 +05:30
|
|
|
return (
|
|
|
|
|
<div className="code-mirror-where-clause">
|
|
|
|
|
<Card
|
|
|
|
|
size="small"
|
|
|
|
|
title={<Title level={5}>Where Clause</Title>}
|
|
|
|
|
extra={
|
|
|
|
|
<Tooltip title="Write a query to filter your data">
|
|
|
|
|
<QuestionCircleOutlined />
|
|
|
|
|
</Tooltip>
|
|
|
|
|
}
|
|
|
|
|
>
|
|
|
|
|
<CodeMirror
|
|
|
|
|
value={query}
|
2025-04-27 20:06:04 +05:30
|
|
|
theme={copilot}
|
2025-04-27 15:34:55 +05:30
|
|
|
onChange={handleChange}
|
|
|
|
|
onUpdate={handleUpdate}
|
2025-04-27 16:29:35 +05:30
|
|
|
autoFocus
|
2025-04-27 15:34:55 +05:30
|
|
|
placeholder="Enter your query (e.g., status = 'error' AND service = 'frontend')"
|
2025-04-27 19:34:07 +05:30
|
|
|
extensions={[
|
|
|
|
|
autocompletion({ override: [myCompletions] }),
|
|
|
|
|
collapseSpacesOutsideStrings(),
|
2025-04-27 20:06:04 +05:30
|
|
|
javascript({ jsx: false, typescript: false }),
|
2025-04-27 20:37:42 +05:30
|
|
|
customTheme,
|
2025-04-27 19:34:07 +05:30
|
|
|
]}
|
2025-04-27 20:37:42 +05:30
|
|
|
basicSetup={{
|
|
|
|
|
lineNumbers: false,
|
|
|
|
|
}}
|
2025-04-27 15:34:55 +05:30
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<Space className="cursor-position" size={4}>
|
|
|
|
|
<InfoCircleOutlined />
|
|
|
|
|
<Text style={{ color: 'black' }}>
|
|
|
|
|
Line: {cursorPos.line}, Position: {cursorPos.ch}
|
|
|
|
|
</Text>
|
|
|
|
|
</Space>
|
|
|
|
|
|
|
|
|
|
<Divider style={{ margin: '8px 0' }} />
|
|
|
|
|
|
|
|
|
|
<div className="query-validation">
|
|
|
|
|
<Text>Status:</Text>
|
|
|
|
|
<div className={validation.isValid ? 'valid' : 'invalid'}>
|
|
|
|
|
{validation.isValid ? (
|
|
|
|
|
<>
|
|
|
|
|
<CheckCircleFilled /> Valid
|
|
|
|
|
</>
|
|
|
|
|
) : (
|
|
|
|
|
<>
|
|
|
|
|
<CloseCircleFilled /> Invalid
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
{validation.message && (
|
|
|
|
|
<Tooltip title={validation.message}>
|
|
|
|
|
<InfoCircleOutlined style={{ marginLeft: 8 }} />
|
|
|
|
|
</Tooltip>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</Card>
|
2025-04-27 12:37:02 +05:30
|
|
|
|
|
|
|
|
{queryContext && (
|
2025-04-27 15:34:55 +05:30
|
|
|
<Card size="small" title="Current Context" className="query-context">
|
2025-04-27 12:37:02 +05:30
|
|
|
<div className="context-details">
|
2025-04-27 15:34:55 +05:30
|
|
|
<Space direction="vertical" size={4}>
|
|
|
|
|
<Space>
|
|
|
|
|
<Text strong style={{ color: 'black' }}>
|
|
|
|
|
Token:
|
|
|
|
|
</Text>
|
|
|
|
|
<Text code style={{ color: 'black' }}>
|
|
|
|
|
{queryContext.currentToken || '-'}
|
|
|
|
|
</Text>
|
|
|
|
|
</Space>
|
|
|
|
|
<Space>
|
|
|
|
|
<Text strong style={{ color: 'black' }}>
|
|
|
|
|
Type:
|
|
|
|
|
</Text>
|
|
|
|
|
<Text style={{ color: 'black' }}>{queryContext.tokenType || '-'}</Text>
|
|
|
|
|
</Space>
|
|
|
|
|
<Space>
|
|
|
|
|
<Text strong style={{ color: 'black' }}>
|
|
|
|
|
Context:
|
|
|
|
|
</Text>
|
|
|
|
|
{renderContextBadge()}
|
|
|
|
|
</Space>
|
2025-04-27 21:05:00 +05:30
|
|
|
|
|
|
|
|
{/* Display the key-operator-value triplet when available */}
|
|
|
|
|
{queryContext.keyToken && (
|
|
|
|
|
<Space>
|
|
|
|
|
<Text strong style={{ color: 'black' }}>
|
|
|
|
|
Key:
|
|
|
|
|
</Text>
|
|
|
|
|
<Text code style={{ color: 'blue' }}>
|
|
|
|
|
{queryContext.keyToken}
|
|
|
|
|
</Text>
|
|
|
|
|
</Space>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{queryContext.operatorToken && (
|
|
|
|
|
<Space>
|
|
|
|
|
<Text strong style={{ color: 'black' }}>
|
|
|
|
|
Operator:
|
|
|
|
|
</Text>
|
|
|
|
|
<Text code style={{ color: 'purple' }}>
|
|
|
|
|
{queryContext.operatorToken}
|
|
|
|
|
</Text>
|
|
|
|
|
</Space>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{queryContext.valueToken && (
|
|
|
|
|
<Space>
|
|
|
|
|
<Text strong style={{ color: 'black' }}>
|
|
|
|
|
Value:
|
|
|
|
|
</Text>
|
|
|
|
|
<Text code style={{ color: 'green' }}>
|
|
|
|
|
{queryContext.valueToken}
|
|
|
|
|
</Text>
|
|
|
|
|
</Space>
|
|
|
|
|
)}
|
2025-04-27 15:34:55 +05:30
|
|
|
</Space>
|
2025-04-27 12:37:02 +05:30
|
|
|
</div>
|
2025-04-27 15:34:55 +05:30
|
|
|
</Card>
|
2025-04-27 12:37:02 +05:30
|
|
|
)}
|
|
|
|
|
|
2025-04-27 15:34:55 +05:30
|
|
|
<Card
|
|
|
|
|
size="small"
|
|
|
|
|
title="Query Examples"
|
|
|
|
|
className="query-examples"
|
|
|
|
|
style={{
|
|
|
|
|
backgroundColor: 'var(--bg-vanilla-100)',
|
|
|
|
|
color: 'black',
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<div className="query-examples-list">Query Examples</div>
|
2025-04-27 12:37:02 +05:30
|
|
|
<ul>
|
|
|
|
|
<li>
|
2025-04-27 15:34:55 +05:30
|
|
|
<Text code style={{ color: 'black' }}>
|
|
|
|
|
status = 'error'
|
|
|
|
|
</Text>
|
2025-04-27 12:37:02 +05:30
|
|
|
</li>
|
|
|
|
|
<li>
|
2025-04-27 15:34:55 +05:30
|
|
|
<Text code style={{ color: 'black' }}>
|
2025-04-27 12:37:02 +05:30
|
|
|
service = 'frontend' AND level = 'error'
|
|
|
|
|
</Text>
|
|
|
|
|
</li>
|
|
|
|
|
<li>
|
2025-04-27 15:34:55 +05:30
|
|
|
<Text code style={{ color: 'black' }}>
|
|
|
|
|
message LIKE '%timeout%'
|
|
|
|
|
</Text>
|
2025-04-27 12:37:02 +05:30
|
|
|
</li>
|
|
|
|
|
<li>
|
2025-04-27 15:34:55 +05:30
|
|
|
<Text code style={{ color: 'black' }}>
|
|
|
|
|
duration {'>'} 1000
|
|
|
|
|
</Text>
|
2025-04-27 12:37:02 +05:30
|
|
|
</li>
|
|
|
|
|
<li>
|
2025-04-27 15:34:55 +05:30
|
|
|
<Text code style={{ color: 'black' }}>
|
|
|
|
|
tags IN ['prod', 'frontend']
|
|
|
|
|
</Text>
|
2025-04-27 12:37:02 +05:30
|
|
|
</li>
|
|
|
|
|
<li>
|
2025-04-27 15:34:55 +05:30
|
|
|
<Text code style={{ color: 'black' }}>
|
2025-04-27 12:37:02 +05:30
|
|
|
NOT (status = 'error' OR level = 'error')
|
|
|
|
|
</Text>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
2025-04-27 15:34:55 +05:30
|
|
|
</Card>
|
2025-04-27 12:37:02 +05:30
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default CodeMirrorWhereClause;
|